1 /* $OpenBSD: if_acx_cardbus.c,v 1.19 2010/09/06 19:20:21 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2005, 2006 6 * Damien Bergamini <damien.bergamini@free.fr> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 /* 22 * CardBus front-end for the Texas Instruments ACX driver 23 */ 24 25 #include "bpfilter.h" 26 27 #include <sys/param.h> 28 #include <sys/sockio.h> 29 #include <sys/mbuf.h> 30 #include <sys/kernel.h> 31 #include <sys/socket.h> 32 #include <sys/systm.h> 33 #include <sys/malloc.h> 34 #include <sys/timeout.h> 35 #include <sys/device.h> 36 37 #include <machine/bus.h> 38 #include <machine/intr.h> 39 40 #include <net/if.h> 41 #include <net/if_dl.h> 42 #include <net/if_media.h> 43 44 #ifdef INET 45 #include <netinet/in.h> 46 #include <netinet/if_ether.h> 47 #endif 48 49 #include <net80211/ieee80211_var.h> 50 #include <net80211/ieee80211_amrr.h> 51 #include <net80211/ieee80211_radiotap.h> 52 53 #include <dev/ic/acxvar.h> 54 #include <dev/ic/acxreg.h> 55 56 #include <dev/pci/pcireg.h> 57 #include <dev/pci/pcivar.h> 58 #include <dev/pci/pcidevs.h> 59 60 #include <dev/cardbus/cardbusvar.h> 61 62 struct acx_cardbus_softc { 63 struct acx_softc sc_acx; 64 65 /* cardbus specific goo */ 66 cardbus_devfunc_t sc_ct; 67 pcitag_t sc_tag; 68 void *sc_ih; 69 bus_size_t sc_mapsize1; 70 bus_size_t sc_mapsize2; 71 pcireg_t sc_iobar_val; /* acx100 only */ 72 pcireg_t sc_bar1_val; 73 pcireg_t sc_bar2_val; 74 int sc_intrline; 75 76 /* hack for ACX100A */ 77 bus_space_tag_t sc_io_bt; 78 bus_space_handle_t sc_io_bh; 79 bus_size_t sc_iomapsize; 80 81 int sc_acx_attached; 82 pci_chipset_tag_t sc_pc; 83 }; 84 85 int acx_cardbus_match(struct device *, void *, void *); 86 void acx_cardbus_attach(struct device *, struct device *, void *); 87 int acx_cardbus_detach(struct device *, int); 88 89 struct cfattach acx_cardbus_ca = { 90 sizeof (struct acx_cardbus_softc), acx_cardbus_match, 91 acx_cardbus_attach, acx_cardbus_detach 92 }; 93 94 static const struct pci_matchid acx_cardbus_devices[] = { 95 { PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX100A }, 96 { PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX100B }, 97 { PCI_VENDOR_TI, PCI_PRODUCT_TI_ACX111 }, 98 }; 99 100 int acx_cardbus_enable(struct acx_softc *); 101 void acx_cardbus_disable(struct acx_softc *); 102 void acx_cardbus_power(struct acx_softc *, int); 103 void acx_cardbus_setup(struct acx_cardbus_softc *); 104 105 int 106 acx_cardbus_match(struct device *parent, void *match, void *aux) 107 { 108 return (cardbus_matchbyid((struct cardbus_attach_args *)aux, 109 acx_cardbus_devices, 110 sizeof (acx_cardbus_devices) / sizeof (acx_cardbus_devices[0]))); 111 } 112 113 void 114 acx_cardbus_attach(struct device *parent, struct device *self, void *aux) 115 { 116 struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)self; 117 struct acx_softc *sc = &csc->sc_acx; 118 struct cardbus_attach_args *ca = aux; 119 cardbus_devfunc_t ct = ca->ca_ct; 120 bus_addr_t base; 121 int error, b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG; 122 123 sc->sc_dmat = ca->ca_dmat; 124 csc->sc_ct = ct; 125 csc->sc_tag = ca->ca_tag; 126 csc->sc_intrline = ca->ca_intrline; 127 csc->sc_pc = ca->ca_pc; 128 129 /* power management hooks */ 130 sc->sc_enable = acx_cardbus_enable; 131 sc->sc_disable = acx_cardbus_disable; 132 sc->sc_power = acx_cardbus_power; 133 134 if (PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_TI_ACX100A) { 135 /* first map I/O space as seen in the dragonfly code */ 136 error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG, 137 PCI_MAPREG_TYPE_IO, 0, &csc->sc_io_bt, &csc->sc_io_bh, 138 &base, &csc->sc_iomapsize); 139 if (error != 0) { 140 printf(": can't map i/o space\n"); 141 return; 142 } 143 csc->sc_iobar_val = base | PCI_MAPREG_TYPE_IO; 144 b1 = CARDBUS_BASE1_REG; 145 b2 = CARDBUS_BASE2_REG; 146 } 147 148 /* map control/status registers */ 149 error = Cardbus_mapreg_map(ct, b1, PCI_MAPREG_TYPE_MEM, 0, 150 &sc->sc_mem1_bt, &sc->sc_mem1_bh, &base, &csc->sc_mapsize1); 151 if (error != 0) { 152 printf(": can't map mem1 space\n"); 153 return; 154 } 155 156 csc->sc_bar1_val = base | PCI_MAPREG_TYPE_MEM; 157 158 /* map the other memory region */ 159 error = Cardbus_mapreg_map(ct, b2, PCI_MAPREG_TYPE_MEM, 0, 160 &sc->sc_mem2_bt, &sc->sc_mem2_bh, &base, &csc->sc_mapsize2); 161 if (error != 0) { 162 printf(": can't map mem2 space\n"); 163 return; 164 } 165 166 csc->sc_bar2_val = base | PCI_MAPREG_TYPE_MEM; 167 168 /* set up the PCI configuration registers */ 169 acx_cardbus_setup(csc); 170 171 printf(": irq %d\n", csc->sc_intrline); 172 173 if (PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_TI_ACX111) 174 acx111_set_param(sc); 175 else 176 acx100_set_param(sc); 177 178 error = acx_attach(sc); 179 csc->sc_acx_attached = error == 0; 180 181 Cardbus_function_disable(ct); 182 } 183 184 int 185 acx_cardbus_detach(struct device *self, int flags) 186 { 187 struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)self; 188 struct acx_softc *sc = &csc->sc_acx; 189 cardbus_devfunc_t ct = csc->sc_ct; 190 cardbus_chipset_tag_t cc = ct->ct_cc; 191 cardbus_function_tag_t cf = ct->ct_cf; 192 int error, b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG; 193 194 if (csc->sc_acx_attached) { 195 error = acx_detach(sc); 196 if (error != 0) 197 return (error); 198 } 199 200 /* unhook the interrupt handler */ 201 if (csc->sc_ih != NULL) { 202 cardbus_intr_disestablish(cc, cf, csc->sc_ih); 203 csc->sc_ih = NULL; 204 } 205 206 /* release bus space and close window */ 207 if (csc->sc_iomapsize) { 208 b1 = CARDBUS_BASE1_REG; 209 b2 = CARDBUS_BASE2_REG; 210 } 211 Cardbus_mapreg_unmap(ct, b1, sc->sc_mem1_bt, 212 sc->sc_mem1_bh, csc->sc_mapsize1); 213 Cardbus_mapreg_unmap(ct, b2, sc->sc_mem2_bt, 214 sc->sc_mem2_bh, csc->sc_mapsize2); 215 if (csc->sc_iomapsize) 216 Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, csc->sc_io_bt, 217 csc->sc_io_bh, csc->sc_iomapsize); 218 219 return (0); 220 } 221 222 int 223 acx_cardbus_enable(struct acx_softc *sc) 224 { 225 struct acx_cardbus_softc *csc; 226 int error; 227 228 csc = (struct acx_cardbus_softc *)sc; 229 cardbus_devfunc_t ct = csc->sc_ct; 230 cardbus_chipset_tag_t cc = ct->ct_cc; 231 cardbus_function_tag_t cf = ct->ct_cf; 232 233 /* power on the socket */ 234 error = Cardbus_function_enable(ct); 235 if (error) 236 return error; 237 238 /* setup the PCI configuration registers */ 239 acx_cardbus_setup(csc); 240 241 /* map and establish the interrupt handler */ 242 csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline, IPL_NET, 243 acx_intr, sc, sc->sc_dev.dv_xname); 244 if (csc->sc_ih == NULL) { 245 printf("%s: could not establish interrupt at %d\n", 246 sc->sc_dev.dv_xname, csc->sc_intrline); 247 Cardbus_function_disable(ct); 248 return (1); 249 } 250 251 return (0); 252 } 253 254 void 255 acx_cardbus_disable(struct acx_softc *sc) 256 { 257 struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)sc; 258 cardbus_devfunc_t ct = csc->sc_ct; 259 cardbus_chipset_tag_t cc = ct->ct_cc; 260 cardbus_function_tag_t cf = ct->ct_cf; 261 262 /* unhook the interrupt handler */ 263 cardbus_intr_disestablish(cc, cf, csc->sc_ih); 264 csc->sc_ih = NULL; 265 266 /* power down the socket */ 267 Cardbus_function_disable(ct); 268 } 269 270 void 271 acx_cardbus_power(struct acx_softc *sc, int why) 272 { 273 struct acx_cardbus_softc *csc = (struct acx_cardbus_softc *)sc; 274 275 if (why == DVACT_RESUME) { 276 /* kick the PCI configuration registers */ 277 acx_cardbus_setup(csc); 278 } 279 } 280 281 void 282 acx_cardbus_setup(struct acx_cardbus_softc *csc) 283 { 284 cardbus_devfunc_t ct = csc->sc_ct; 285 cardbus_chipset_tag_t cc = ct->ct_cc; 286 pci_chipset_tag_t pc = csc->sc_pc; 287 cardbus_function_tag_t cf = ct->ct_cf; 288 pcireg_t reg; 289 int b1 = CARDBUS_BASE0_REG, b2 = CARDBUS_BASE1_REG; 290 291 if (csc->sc_iobar_val) { 292 pci_conf_write(pc, csc->sc_tag, CARDBUS_BASE0_REG, 293 csc->sc_iobar_val); 294 b1 = CARDBUS_BASE1_REG; 295 b2 = CARDBUS_BASE2_REG; 296 /* (*cf->cardbus_ctrl)(cc, CARDBUS_IO_ENABLE); */ 297 } 298 299 /* program the BAR */ 300 pci_conf_write(pc, csc->sc_tag, b1, csc->sc_bar1_val); 301 pci_conf_write(pc, csc->sc_tag, b2, csc->sc_bar2_val); 302 303 /* make sure the right access type is on the cardbus bridge */ 304 (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); 305 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 306 307 /* enable the appropriate bits in the PCI CSR */ 308 reg = pci_conf_read(pc, csc->sc_tag, 309 PCI_COMMAND_STATUS_REG); 310 reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE; 311 #if 0 312 if (csc->sc_iobar_val) 313 reg |= PCI_COMMAND_IO_ENABLE; 314 #endif 315 pci_conf_write(pc, csc->sc_tag, PCI_COMMAND_STATUS_REG, 316 reg); 317 } 318