if_pgt_cardbus.c revision 1.6
1/* $OpenBSD: if_pgt_cardbus.c,v 1.6 2006/11/10 20:20:04 damien Exp $ */ 2 3/* 4 * Copyright (c) 2006 Marcus Glocker <mglocker@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19/* 20 * CardBus front-end for the PrismGT 21 */ 22 23#include "bpfilter.h" 24 25#include <sys/param.h> 26#include <sys/sockio.h> 27#include <sys/mbuf.h> 28#include <sys/kernel.h> 29#include <sys/socket.h> 30#include <sys/systm.h> 31#include <sys/malloc.h> 32#include <sys/timeout.h> 33#include <sys/device.h> 34 35#include <machine/bus.h> 36#include <machine/intr.h> 37 38#include <net/if.h> 39#include <net/if_dl.h> 40#include <net/if_media.h> 41 42#include <netinet/in.h> 43#include <netinet/if_ether.h> 44 45#include <net80211/ieee80211_var.h> 46#include <net80211/ieee80211_radiotap.h> 47 48#include <dev/ic/pgtreg.h> 49#include <dev/ic/pgtvar.h> 50 51#include <dev/pci/pcireg.h> 52#include <dev/pci/pcivar.h> 53#include <dev/pci/pcidevs.h> 54 55#include <dev/cardbus/cardbusvar.h> 56 57struct pgt_cardbus_softc { 58 struct pgt_softc sc_pgt; 59 cardbus_devfunc_t sc_ct; 60 cardbustag_t sc_tag; 61 int sc_intrline; 62 63 void *sc_ih; 64 bus_size_t sc_mapsize; 65 pcireg_t sc_bar0_val; 66}; 67 68int pgt_cardbus_match(struct device *, void *, void *); 69void pgt_cardbus_attach(struct device *, struct device *, void *); 70int pgt_cardbus_detach(struct device *, int); 71int pgt_cardbus_enable(struct pgt_softc *); 72void pgt_cardbus_disable(struct pgt_softc *); 73void pgt_cardbus_power(struct pgt_softc *, int); 74void pgt_cardbus_setup(struct pgt_cardbus_softc *); 75 76struct cfattach pgt_cardbus_ca = { 77 sizeof(struct pgt_cardbus_softc), pgt_cardbus_match, pgt_cardbus_attach, 78 pgt_cardbus_detach 79}; 80 81const struct cardbus_matchid pgt_cardbus_devices[] = { 82 { PCI_VENDOR_INTERSIL, PCI_PRODUCT_INTERSIL_ISL3877 }, 83 { PCI_VENDOR_INTERSIL, PCI_PRODUCT_INTERSIL_ISL3890 } 84}; 85 86int 87pgt_cardbus_match(struct device *parent, void *match, void *aux) 88{ 89 return (cardbus_matchbyid((struct cardbus_attach_args *)aux, 90 pgt_cardbus_devices, 91 sizeof(pgt_cardbus_devices) / sizeof(pgt_cardbus_devices[0]))); 92} 93 94void 95pgt_cardbus_attach(struct device *parent, struct device *self, void *aux) 96{ 97 struct pgt_cardbus_softc *csc = (struct pgt_cardbus_softc *)self; 98 struct pgt_softc *sc = &csc->sc_pgt; 99 struct cardbus_attach_args *ca = aux; 100 cardbus_devfunc_t ct = ca->ca_ct; 101 bus_addr_t base; 102 int error; 103 104 sc->sc_dmat = ca->ca_dmat; 105 csc->sc_ct = ct; 106 csc->sc_tag = ca->ca_tag; 107 csc->sc_intrline = ca->ca_intrline; 108 109 /* power management hooks */ 110 sc->sc_enable = pgt_cardbus_enable; 111 sc->sc_disable = pgt_cardbus_disable; 112 sc->sc_power = pgt_cardbus_power; 113 114 /* remember chipset */ 115 if (CARDBUS_PRODUCT(ca->ca_id) == PCI_PRODUCT_INTERSIL_ISL3877) 116 sc->sc_flags |= SC_ISL3877; 117 118 /* map control / status registers */ 119 error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG, 120 PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, 121 &sc->sc_iotag, &sc->sc_iohandle, &base, &csc->sc_mapsize); 122 if (error != 0) { 123 printf(": could not map memory space\n"); 124 return; 125 } 126 csc->sc_bar0_val = base | CARDBUS_MAPREG_TYPE_MEM; 127 128 /* disable all interrupts */ 129 bus_space_write_4(sc->sc_iotag, sc->sc_iohandle, PGT_REG_INT_EN, 0); 130 (void)bus_space_read_4(sc->sc_iotag, sc->sc_iohandle, PGT_REG_INT_EN); 131 DELAY(PGT_WRITEIO_DELAY); 132 133 /* set up the PCI configuration registers */ 134 pgt_cardbus_setup(csc); 135 136 printf(": irq %d\n", csc->sc_intrline); 137 138 if (rootvp == NULL) 139 mountroothook_establish(pgt_attach, sc); 140 else 141 pgt_attach(sc); 142} 143 144int 145pgt_cardbus_detach(struct device *self, int flags) 146{ 147 struct pgt_cardbus_softc *csc = (struct pgt_cardbus_softc *)self; 148 struct pgt_softc *sc = &csc->sc_pgt; 149 cardbus_devfunc_t ct = csc->sc_ct; 150 cardbus_chipset_tag_t cc = ct->ct_cc; 151 cardbus_function_tag_t cf = ct->ct_cf; 152 int error; 153 154 error = pgt_detach(sc); 155 if (error != 0) 156 return (error); 157 158 /* unhook the interrupt handler */ 159 if (csc->sc_ih != NULL) { 160 cardbus_intr_disestablish(cc, cf, csc->sc_ih); 161 csc->sc_ih = NULL; 162 } 163 164 /* release bus space and close window */ 165 Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, 166 sc->sc_iotag, sc->sc_iohandle, csc->sc_mapsize); 167 168 return (0); 169} 170 171int 172pgt_cardbus_enable(struct pgt_softc *sc) 173{ 174 struct pgt_cardbus_softc *csc = (struct pgt_cardbus_softc *)sc; 175 cardbus_devfunc_t ct = csc->sc_ct; 176 cardbus_chipset_tag_t cc = ct->ct_cc; 177 cardbus_function_tag_t cf = ct->ct_cf; 178 179 /* power on the socket */ 180 Cardbus_function_enable(ct); 181 182 /* setup the PCI configuration registers */ 183 pgt_cardbus_setup(csc); 184 185 /* map and establish the interrupt handler */ 186 csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET, 187 pgt_intr, sc, sc->sc_dev.dv_xname); 188 if (csc->sc_ih == NULL) { 189 printf("%s: could not establish interrupt at %d\n", 190 sc->sc_dev.dv_xname, csc->sc_intrline); 191 Cardbus_function_disable(ct); 192 return (1); 193 } 194 195 return (0); 196} 197 198void 199pgt_cardbus_disable(struct pgt_softc *sc) 200{ 201 struct pgt_cardbus_softc *csc = (struct pgt_cardbus_softc *)sc; 202 cardbus_devfunc_t ct = csc->sc_ct; 203 cardbus_chipset_tag_t cc = ct->ct_cc; 204 cardbus_function_tag_t cf = ct->ct_cf; 205 206 /* unhook the interrupt handler */ 207 cardbus_intr_disestablish(cc, cf, csc->sc_ih); 208 csc->sc_ih = NULL; 209 210 /* power down the socket */ 211 Cardbus_function_disable(ct); 212} 213 214void 215pgt_cardbus_power(struct pgt_softc *sc, int why) 216{ 217 if (why == PWR_RESUME) 218 if (sc->sc_enable != NULL) 219 (*sc->sc_enable)(sc); 220 if (why == PWR_SUSPEND) 221 if (sc->sc_disable != NULL) 222 (*sc->sc_disable)(sc); 223} 224 225void 226pgt_cardbus_setup(struct pgt_cardbus_softc *csc) 227{ 228 cardbus_devfunc_t ct = csc->sc_ct; 229 cardbus_chipset_tag_t cc = ct->ct_cc; 230 cardbus_function_tag_t cf = ct->ct_cf; 231 pcireg_t reg; 232 233 /* program the BAR */ 234 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_BASE0_REG, 235 csc->sc_bar0_val); 236 237 /* make sure the right access type is on the cardbus bridge */ 238 (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); 239 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 240 241 /* enable the appropriate bits in the PCI CSR */ 242 reg = cardbus_conf_read(cc, cf, csc->sc_tag, 243 CARDBUS_COMMAND_STATUS_REG); 244 reg |= CARDBUS_COMMAND_MASTER_ENABLE | CARDBUS_COMMAND_MEM_ENABLE; 245 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_COMMAND_STATUS_REG, 246 reg); 247} 248