1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2007 Marvell Semiconductor, Inc. 5 * Copyright (c) 2007 Sam Leffler, Errno Consulting 6 * Copyright (c) 2008 Weongyo Jeong <weongyo@freebsd.org> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer, 14 * without modification. 15 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 16 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 17 * redistribution must be conditioned upon including a substantially 18 * similar Disclaimer requirement for further binary redistribution. 19 * 20 * NO WARRANTY 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 24 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 25 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 26 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 29 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGES. 32 */ 33 34 /* 35 * PCI front-end for the Marvell 88W8335 Wireless LAN controller driver. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/kernel.h> 40 #include <sys/malloc.h> 41 #include <sys/module.h> 42 #include <sys/socket.h> 43 #include <sys/sysctl.h> 44 45 #include <machine/bus.h> 46 #include <sys/bus.h> 47 #include <sys/rman.h> 48 49 #include <net/if.h> 50 #include <net/if_var.h> 51 #include <net/if_media.h> 52 #include <net/ethernet.h> 53 54 #include <net80211/ieee80211_var.h> 55 56 #include <dev/malo/if_malo.h> 57 58 #include <dev/pci/pcivar.h> 59 #include <dev/pci/pcireg.h> 60 61 /* 62 * PCI glue. 63 */ 64 65 #define MALO_RESOURCE_MAX 2 66 #define MALO_MSI_MESSAGES 1 67 68 struct malo_pci_softc { 69 struct malo_softc malo_sc; 70 struct resource_spec *malo_mem_spec; 71 struct resource *malo_res_mem[MALO_RESOURCE_MAX]; 72 struct resource_spec *malo_irq_spec; 73 struct resource *malo_res_irq[MALO_MSI_MESSAGES]; 74 void *malo_intrhand[MALO_MSI_MESSAGES]; 75 int malo_msi; 76 }; 77 78 /* 79 * Tunable variables. 80 */ 81 SYSCTL_DECL(_hw_malo); 82 static SYSCTL_NODE(_hw_malo, OID_AUTO, pci, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 83 "Marvell 88W8335 driver PCI parameters"); 84 85 static int msi_disable = 0; /* MSI disabled */ 86 SYSCTL_INT(_hw_malo_pci, OID_AUTO, msi_disable, CTLFLAG_RWTUN, &msi_disable, 87 0, "MSI disabled"); 88 89 /* 90 * Devices supported by this driver. 91 */ 92 #define VENDORID_MARVELL 0X11AB 93 #define DEVICEID_MRVL_88W8310 0X1FA7 94 #define DEVICEID_MRVL_88W8335R1 0X1FAA 95 #define DEVICEID_MRVL_88W8335R2 0X1FAB 96 97 static struct malo_product { 98 uint16_t mp_vendorid; 99 uint16_t mp_deviceid; 100 const char *mp_name; 101 } malo_products[] = { 102 { VENDORID_MARVELL, DEVICEID_MRVL_88W8310, 103 "Marvell Libertas 88W8310 802.11g Wireless Adapter" }, 104 { VENDORID_MARVELL, DEVICEID_MRVL_88W8335R1, 105 "Marvell Libertas 88W8335 802.11g Wireless Adapter" }, 106 { VENDORID_MARVELL, DEVICEID_MRVL_88W8335R2, 107 "Marvell Libertas 88W8335 802.11g Wireless Adapter" } 108 }; 109 110 static struct resource_spec malo_res_spec_mem[] = { 111 { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, 112 { SYS_RES_MEMORY, PCIR_BAR(1), RF_ACTIVE }, 113 { -1, 0, 0 } 114 }; 115 116 static struct resource_spec malo_res_spec_legacy[] = { 117 { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, 118 { -1, 0, 0 } 119 }; 120 121 static struct resource_spec malo_res_spec_msi[] = { 122 { SYS_RES_IRQ, 1, RF_ACTIVE }, 123 { -1, 0, 0 } 124 }; 125 126 static int malo_pci_detach(device_t); 127 128 static int 129 malo_pci_probe(device_t dev) 130 { 131 struct malo_product *mp; 132 uint16_t vendor, devid; 133 int i; 134 135 vendor = pci_get_vendor(dev); 136 devid = pci_get_device(dev); 137 mp = malo_products; 138 139 for (i = 0; i < nitems(malo_products); i++, mp++) { 140 if (vendor == mp->mp_vendorid && devid == mp->mp_deviceid) { 141 device_set_desc(dev, mp->mp_name); 142 return (BUS_PROBE_DEFAULT); 143 } 144 } 145 146 return (ENXIO); 147 } 148 149 static int 150 malo_pci_attach(device_t dev) 151 { 152 int error = ENXIO, i, msic, reg; 153 struct malo_pci_softc *psc = device_get_softc(dev); 154 struct malo_softc *sc = &psc->malo_sc; 155 156 sc->malo_dev = dev; 157 158 pci_enable_busmaster(dev); 159 160 /* 161 * Setup memory-mapping of PCI registers. 162 */ 163 psc->malo_mem_spec = malo_res_spec_mem; 164 error = bus_alloc_resources(dev, psc->malo_mem_spec, psc->malo_res_mem); 165 if (error) { 166 device_printf(dev, "couldn't allocate memory resources\n"); 167 return (ENXIO); 168 } 169 170 /* 171 * Arrange and allocate interrupt line. 172 */ 173 sc->malo_invalid = 1; 174 175 if (pci_find_cap(dev, PCIY_EXPRESS, ®) == 0) { 176 msic = pci_msi_count(dev); 177 if (bootverbose) 178 device_printf(dev, "MSI count : %d\n", msic); 179 } else 180 msic = 0; 181 182 psc->malo_irq_spec = malo_res_spec_legacy; 183 if (msic == MALO_MSI_MESSAGES && msi_disable == 0) { 184 if (pci_alloc_msi(dev, &msic) == 0) { 185 if (msic == MALO_MSI_MESSAGES) { 186 device_printf(dev, "Using %d MSI messages\n", 187 msic); 188 psc->malo_irq_spec = malo_res_spec_msi; 189 psc->malo_msi = 1; 190 } else 191 pci_release_msi(dev); 192 } 193 } 194 195 error = bus_alloc_resources(dev, psc->malo_irq_spec, psc->malo_res_irq); 196 if (error) { 197 device_printf(dev, "couldn't allocate IRQ resources\n"); 198 goto bad; 199 } 200 201 if (psc->malo_msi == 0) 202 error = bus_setup_intr(dev, psc->malo_res_irq[0], 203 INTR_TYPE_NET | INTR_MPSAFE, malo_intr, NULL, sc, 204 &psc->malo_intrhand[0]); 205 else { 206 for (i = 0; i < MALO_MSI_MESSAGES; i++) { 207 error = bus_setup_intr(dev, psc->malo_res_irq[i], 208 INTR_TYPE_NET | INTR_MPSAFE, malo_intr, NULL, sc, 209 &psc->malo_intrhand[i]); 210 if (error != 0) 211 break; 212 } 213 } 214 215 /* 216 * Setup DMA descriptor area. 217 */ 218 if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 219 1, 0, /* alignment, bounds */ 220 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 221 BUS_SPACE_MAXADDR, /* highaddr */ 222 NULL, NULL, /* filter, filterarg */ 223 BUS_SPACE_MAXSIZE, /* maxsize */ 224 0, /* nsegments */ 225 BUS_SPACE_MAXSIZE, /* maxsegsize */ 226 0, /* flags */ 227 NULL, /* lockfunc */ 228 NULL, /* lockarg */ 229 &sc->malo_dmat)) { 230 device_printf(dev, "cannot allocate DMA tag\n"); 231 goto bad1; 232 } 233 234 sc->malo_io0t = rman_get_bustag(psc->malo_res_mem[0]); 235 sc->malo_io0h = rman_get_bushandle(psc->malo_res_mem[0]); 236 sc->malo_io1t = rman_get_bustag(psc->malo_res_mem[1]); 237 sc->malo_io1h = rman_get_bushandle(psc->malo_res_mem[1]); 238 239 error = malo_attach(pci_get_device(dev), sc); 240 241 if (error != 0) 242 goto bad2; 243 244 return (error); 245 246 bad2: 247 bus_dma_tag_destroy(sc->malo_dmat); 248 bad1: 249 if (psc->malo_msi == 0) 250 bus_teardown_intr(dev, psc->malo_res_irq[0], 251 psc->malo_intrhand[0]); 252 else { 253 for (i = 0; i < MALO_MSI_MESSAGES; i++) 254 bus_teardown_intr(dev, psc->malo_res_irq[i], 255 psc->malo_intrhand[i]); 256 } 257 bus_release_resources(dev, psc->malo_irq_spec, psc->malo_res_irq); 258 bad: 259 if (psc->malo_msi != 0) 260 pci_release_msi(dev); 261 bus_release_resources(dev, psc->malo_mem_spec, psc->malo_res_mem); 262 263 return (error); 264 } 265 266 static int 267 malo_pci_detach(device_t dev) 268 { 269 int i; 270 struct malo_pci_softc *psc = device_get_softc(dev); 271 struct malo_softc *sc = &psc->malo_sc; 272 273 /* check if device was removed */ 274 sc->malo_invalid = !bus_child_present(dev); 275 276 malo_detach(sc); 277 278 bus_generic_detach(dev); 279 280 if (psc->malo_msi == 0) 281 bus_teardown_intr(dev, psc->malo_res_irq[0], 282 psc->malo_intrhand[0]); 283 else { 284 for (i = 0; i < MALO_MSI_MESSAGES; i++) 285 bus_teardown_intr(dev, psc->malo_res_irq[i], 286 psc->malo_intrhand[i]); 287 288 pci_release_msi(dev); 289 } 290 291 bus_release_resources(dev, psc->malo_irq_spec, psc->malo_res_irq); 292 bus_dma_tag_destroy(sc->malo_dmat); 293 bus_release_resources(dev, psc->malo_mem_spec, psc->malo_res_mem); 294 295 return (0); 296 } 297 298 static int 299 malo_pci_shutdown(device_t dev) 300 { 301 struct malo_pci_softc *psc = device_get_softc(dev); 302 303 malo_shutdown(&psc->malo_sc); 304 305 return (0); 306 } 307 308 static int 309 malo_pci_suspend(device_t dev) 310 { 311 struct malo_pci_softc *psc = device_get_softc(dev); 312 313 malo_suspend(&psc->malo_sc); 314 315 return (0); 316 } 317 318 static int 319 malo_pci_resume(device_t dev) 320 { 321 struct malo_pci_softc *psc = device_get_softc(dev); 322 323 malo_resume(&psc->malo_sc); 324 325 return (0); 326 } 327 328 static device_method_t malo_pci_methods[] = { 329 /* Device interface */ 330 DEVMETHOD(device_probe, malo_pci_probe), 331 DEVMETHOD(device_attach, malo_pci_attach), 332 DEVMETHOD(device_detach, malo_pci_detach), 333 DEVMETHOD(device_shutdown, malo_pci_shutdown), 334 DEVMETHOD(device_suspend, malo_pci_suspend), 335 DEVMETHOD(device_resume, malo_pci_resume), 336 { 0,0 } 337 }; 338 339 static driver_t malo_pci_driver = { 340 "malo", 341 malo_pci_methods, 342 sizeof(struct malo_pci_softc) 343 }; 344 345 DRIVER_MODULE(malo, pci, malo_pci_driver, 0, 0); 346 MODULE_VERSION(malo, 1); 347 MODULE_DEPEND(malo, wlan, 1, 1, 1); /* 802.11 media layer */ 348 MODULE_DEPEND(malo, firmware, 1, 1, 1); 349