if_malo_pci.c revision 177595
1177595Sweongyo/*- 2177595Sweongyo * Copyright (c) 2007 Marvell Semiconductor, Inc. 3177595Sweongyo * Copyright (c) 2007 Sam Leffler, Errno Consulting 4177595Sweongyo * Copyright (c) 2008 Weongyo Jeong <weongyo@freebsd.org> 5177595Sweongyo * All rights reserved. 6177595Sweongyo * 7177595Sweongyo * Redistribution and use in source and binary forms, with or without 8177595Sweongyo * modification, are permitted provided that the following conditions 9177595Sweongyo * are met: 10177595Sweongyo * 1. Redistributions of source code must retain the above copyright 11177595Sweongyo * notice, this list of conditions and the following disclaimer, 12177595Sweongyo * without modification. 13177595Sweongyo * 2. Redistributions in binary form must reproduce at minimum a disclaimer 14177595Sweongyo * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 15177595Sweongyo * redistribution must be conditioned upon including a substantially 16177595Sweongyo * similar Disclaimer requirement for further binary redistribution. 17177595Sweongyo * 18177595Sweongyo * NO WARRANTY 19177595Sweongyo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20177595Sweongyo * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21177595Sweongyo * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 22177595Sweongyo * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 23177595Sweongyo * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 24177595Sweongyo * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25177595Sweongyo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26177595Sweongyo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27177595Sweongyo * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28177595Sweongyo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 29177595Sweongyo * THE POSSIBILITY OF SUCH DAMAGES. 30177595Sweongyo */ 31177595Sweongyo 32177595Sweongyo#include <sys/cdefs.h> 33177595Sweongyo#ifdef __FreeBSD__ 34177595Sweongyo__FBSDID("$FreeBSD: head/sys/dev/malo/if_malo_pci.c 177595 2008-03-25 06:32:33Z weongyo $"); 35177595Sweongyo#endif 36177595Sweongyo 37177595Sweongyo/* 38177595Sweongyo * PCI front-end for the Marvell 88W8335 Wireless LAN controller driver. 39177595Sweongyo */ 40177595Sweongyo 41177595Sweongyo#include <sys/param.h> 42177595Sweongyo#include <sys/kernel.h> 43177595Sweongyo#include <sys/module.h> 44177595Sweongyo#include <sys/socket.h> 45177595Sweongyo#include <sys/sysctl.h> 46177595Sweongyo 47177595Sweongyo#include <machine/bus.h> 48177595Sweongyo#include <sys/bus.h> 49177595Sweongyo#include <sys/rman.h> 50177595Sweongyo 51177595Sweongyo#include <net/if.h> 52177595Sweongyo#include <net/if_media.h> 53177595Sweongyo 54177595Sweongyo#include <net80211/ieee80211_var.h> 55177595Sweongyo 56177595Sweongyo#include <dev/malo/if_malo.h> 57177595Sweongyo 58177595Sweongyo#include <dev/pci/pcivar.h> 59177595Sweongyo#include <dev/pci/pcireg.h> 60177595Sweongyo 61177595Sweongyo/* 62177595Sweongyo * PCI glue. 63177595Sweongyo */ 64177595Sweongyo 65177595Sweongyo#define MALO_RESOURCE_MAX 2 66177595Sweongyo#define MALO_MSI_MESSAGES 1 67177595Sweongyo 68177595Sweongyostruct malo_pci_softc { 69177595Sweongyo struct malo_softc malo_sc; 70177595Sweongyo struct resource_spec *malo_mem_spec; 71177595Sweongyo struct resource *malo_res_mem[MALO_RESOURCE_MAX]; 72177595Sweongyo struct resource_spec *malo_irq_spec; 73177595Sweongyo struct resource *malo_res_irq[MALO_MSI_MESSAGES]; 74177595Sweongyo void *malo_intrhand[MALO_MSI_MESSAGES]; 75177595Sweongyo int malo_msi; 76177595Sweongyo}; 77177595Sweongyo 78177595Sweongyo/* 79177595Sweongyo * Tunable variables. 80177595Sweongyo */ 81177595SweongyoSYSCTL_DECL(_hw_malo); 82177595SweongyoSYSCTL_NODE(_hw_malo, OID_AUTO, pci, CTLFLAG_RD, 0, 83177595Sweongyo "Marvell 88W8335 driver PCI parameters"); 84177595Sweongyo 85177595Sweongyostatic int msi_disable = 0; /* MSI disabled */ 86177595SweongyoSYSCTL_INT(_hw_malo_pci, OID_AUTO, msi_disable, CTLFLAG_RW, &msi_disable, 87177595Sweongyo 0, "MSI disabled"); 88177595SweongyoTUNABLE_INT("hw.malo.pci.msi_disable", &msi_disable); 89177595Sweongyo 90177595Sweongyo/* 91177595Sweongyo * Devices supported by this driver. 92177595Sweongyo */ 93177595Sweongyo#define VENDORID_MARVELL 0X11AB 94177595Sweongyo#define DEVICEID_MRVL_88W8310 0X1FA7 95177595Sweongyo#define DEVICEID_MRVL_88W8335R1 0X1FAA 96177595Sweongyo#define DEVICEID_MRVL_88W8335R2 0X1FAB 97177595Sweongyo 98177595Sweongyostatic struct malo_product { 99177595Sweongyo uint16_t mp_vendorid; 100177595Sweongyo uint16_t mp_deviceid; 101177595Sweongyo const char *mp_name; 102177595Sweongyo} malo_products[] = { 103177595Sweongyo { VENDORID_MARVELL, DEVICEID_MRVL_88W8310, 104177595Sweongyo "Marvell Libertas 88W8310 802.11g Wireless Adapter" }, 105177595Sweongyo { VENDORID_MARVELL, DEVICEID_MRVL_88W8335R1, 106177595Sweongyo "Marvell Libertas 88W8335 802.11g Wireless Adapter" }, 107177595Sweongyo { VENDORID_MARVELL, DEVICEID_MRVL_88W8335R2, 108177595Sweongyo "Marvell Libertas 88W8335 802.11g Wireless Adapter" } 109177595Sweongyo}; 110177595Sweongyo 111177595Sweongyostatic struct resource_spec malo_res_spec_mem[] = { 112177595Sweongyo { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, 113177595Sweongyo { SYS_RES_MEMORY, PCIR_BAR(1), RF_ACTIVE }, 114177595Sweongyo { -1, 0, 0 } 115177595Sweongyo}; 116177595Sweongyo 117177595Sweongyostatic struct resource_spec malo_res_spec_legacy[] = { 118177595Sweongyo { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, 119177595Sweongyo { -1, 0, 0 } 120177595Sweongyo}; 121177595Sweongyo 122177595Sweongyostatic struct resource_spec malo_res_spec_msi[] = { 123177595Sweongyo { SYS_RES_IRQ, 1, RF_ACTIVE }, 124177595Sweongyo { -1, 0, 0 } 125177595Sweongyo}; 126177595Sweongyo 127177595Sweongyostatic int malo_pci_detach(device_t); 128177595Sweongyo 129177595Sweongyostatic int 130177595Sweongyomalo_pci_probe(device_t dev) 131177595Sweongyo{ 132177595Sweongyo#define N(a) (sizeof(a) / sizeof((a)[0])) 133177595Sweongyo struct malo_product *mp; 134177595Sweongyo uint16_t vendor, devid; 135177595Sweongyo int i; 136177595Sweongyo 137177595Sweongyo vendor = pci_get_vendor(dev); 138177595Sweongyo devid = pci_get_device(dev); 139177595Sweongyo mp = malo_products; 140177595Sweongyo 141177595Sweongyo for (i = 0; i < N(malo_products); i++, mp++) { 142177595Sweongyo if (vendor == mp->mp_vendorid && devid == mp->mp_deviceid) { 143177595Sweongyo device_set_desc(dev, mp->mp_name); 144177595Sweongyo return (BUS_PROBE_DEFAULT); 145177595Sweongyo } 146177595Sweongyo } 147177595Sweongyo 148177595Sweongyo return (ENXIO); 149177595Sweongyo#undef N 150177595Sweongyo} 151177595Sweongyo 152177595Sweongyostatic int 153177595Sweongyomalo_pci_setup(device_t dev) 154177595Sweongyo{ 155177595Sweongyo 156177595Sweongyo /* 157177595Sweongyo * Enable memory mapping and bus mastering. 158177595Sweongyo */ 159177595Sweongyo if (pci_enable_busmaster(dev) != 0) 160177595Sweongyo return -1; 161177595Sweongyo if (pci_enable_io(dev, SYS_RES_MEMORY) != 0) 162177595Sweongyo return -1; 163177595Sweongyo 164177595Sweongyo return 0; 165177595Sweongyo} 166177595Sweongyo 167177595Sweongyostatic int 168177595Sweongyomalo_pci_attach(device_t dev) 169177595Sweongyo{ 170177595Sweongyo int error = ENXIO, i, msic, reg; 171177595Sweongyo struct malo_pci_softc *psc = device_get_softc(dev); 172177595Sweongyo struct malo_softc *sc = &psc->malo_sc; 173177595Sweongyo 174177595Sweongyo sc->malo_dev = dev; 175177595Sweongyo 176177595Sweongyo /* 177177595Sweongyo * Enable memory mapping and bus mastering. 178177595Sweongyo */ 179177595Sweongyo if (malo_pci_setup(dev)) 180177595Sweongyo return (ENXIO); 181177595Sweongyo 182177595Sweongyo /* 183177595Sweongyo * Setup memory-mapping of PCI registers. 184177595Sweongyo */ 185177595Sweongyo psc->malo_mem_spec = malo_res_spec_mem; 186177595Sweongyo error = bus_alloc_resources(dev, psc->malo_mem_spec, psc->malo_res_mem); 187177595Sweongyo if (error) { 188177595Sweongyo device_printf(dev, "couldn't allocate memory resources\n"); 189177595Sweongyo return (ENXIO); 190177595Sweongyo } 191177595Sweongyo 192177595Sweongyo /* 193177595Sweongyo * Arrange and allocate interrupt line. 194177595Sweongyo */ 195177595Sweongyo sc->malo_invalid = 1; 196177595Sweongyo 197177595Sweongyo if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 198177595Sweongyo msic = pci_msi_count(dev); 199177595Sweongyo if (bootverbose) 200177595Sweongyo device_printf(dev, "MSI count : %d\n", msic); 201177595Sweongyo } else 202177595Sweongyo msic = 0; 203177595Sweongyo 204177595Sweongyo psc->malo_irq_spec = malo_res_spec_legacy; 205177595Sweongyo if (msic == MALO_MSI_MESSAGES && msi_disable == 0) { 206177595Sweongyo if (pci_alloc_msi(dev, &msic) == 0) { 207177595Sweongyo if (msic == MALO_MSI_MESSAGES) { 208177595Sweongyo device_printf(dev, "Using %d MSI messages\n", 209177595Sweongyo msic); 210177595Sweongyo psc->malo_irq_spec = malo_res_spec_msi; 211177595Sweongyo psc->malo_msi = 1; 212177595Sweongyo } else 213177595Sweongyo pci_release_msi(dev); 214177595Sweongyo } 215177595Sweongyo } 216177595Sweongyo 217177595Sweongyo error = bus_alloc_resources(dev, psc->malo_irq_spec, psc->malo_res_irq); 218177595Sweongyo if (error) { 219177595Sweongyo device_printf(dev, "couldn't allocate IRQ resources\n"); 220177595Sweongyo goto bad; 221177595Sweongyo } 222177595Sweongyo 223177595Sweongyo if (psc->malo_msi == 0) 224177595Sweongyo error = bus_setup_intr(dev, psc->malo_res_irq[0], 225177595Sweongyo INTR_TYPE_NET | INTR_MPSAFE, malo_intr, NULL, sc, 226177595Sweongyo &psc->malo_intrhand[0]); 227177595Sweongyo else { 228177595Sweongyo for (i = 0; i < MALO_MSI_MESSAGES; i++) { 229177595Sweongyo error = bus_setup_intr(dev, psc->malo_res_irq[i], 230177595Sweongyo INTR_TYPE_NET | INTR_MPSAFE, malo_intr, NULL, sc, 231177595Sweongyo &psc->malo_intrhand[i]); 232177595Sweongyo if (error != 0) 233177595Sweongyo break; 234177595Sweongyo } 235177595Sweongyo } 236177595Sweongyo 237177595Sweongyo /* 238177595Sweongyo * Setup DMA descriptor area. 239177595Sweongyo */ 240177595Sweongyo if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ 241177595Sweongyo 1, 0, /* alignment, bounds */ 242177595Sweongyo BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 243177595Sweongyo BUS_SPACE_MAXADDR, /* highaddr */ 244177595Sweongyo NULL, NULL, /* filter, filterarg */ 245177595Sweongyo BUS_SPACE_MAXADDR, /* maxsize */ 246177595Sweongyo 0, /* nsegments */ 247177595Sweongyo BUS_SPACE_MAXADDR, /* maxsegsize */ 248177595Sweongyo BUS_DMA_ALLOCNOW, /* flags */ 249177595Sweongyo NULL, /* lockfunc */ 250177595Sweongyo NULL, /* lockarg */ 251177595Sweongyo &sc->malo_dmat)) { 252177595Sweongyo device_printf(dev, "cannot allocate DMA tag\n"); 253177595Sweongyo goto bad1; 254177595Sweongyo } 255177595Sweongyo 256177595Sweongyo sc->malo_io0t = rman_get_bustag(psc->malo_res_mem[0]); 257177595Sweongyo sc->malo_io0h = rman_get_bushandle(psc->malo_res_mem[0]); 258177595Sweongyo sc->malo_io1t = rman_get_bustag(psc->malo_res_mem[1]); 259177595Sweongyo sc->malo_io1h = rman_get_bushandle(psc->malo_res_mem[1]); 260177595Sweongyo 261177595Sweongyo error = malo_attach(pci_get_device(dev), sc); 262177595Sweongyo 263177595Sweongyo if (error != 0) { 264177595Sweongyo malo_pci_detach(dev); 265177595Sweongyo return (error); 266177595Sweongyo } 267177595Sweongyo 268177595Sweongyo return (error); 269177595Sweongyobad1: 270177595Sweongyo if (psc->malo_msi == 0) 271177595Sweongyo bus_teardown_intr(dev, psc->malo_res_irq[0], 272177595Sweongyo psc->malo_intrhand[0]); 273177595Sweongyo else { 274177595Sweongyo for (i = 0; i < MALO_MSI_MESSAGES; i++) 275177595Sweongyo bus_teardown_intr(dev, psc->malo_res_irq[i], 276177595Sweongyo psc->malo_intrhand[i]); 277177595Sweongyo } 278177595Sweongyo 279177595Sweongyobad: 280177595Sweongyo if (psc->malo_msi != 0) 281177595Sweongyo pci_release_msi(dev); 282177595Sweongyo 283177595Sweongyo return (error); 284177595Sweongyo} 285177595Sweongyo 286177595Sweongyostatic int 287177595Sweongyomalo_pci_detach(device_t dev) 288177595Sweongyo{ 289177595Sweongyo int i; 290177595Sweongyo struct malo_pci_softc *psc = device_get_softc(dev); 291177595Sweongyo struct malo_softc *sc = &psc->malo_sc; 292177595Sweongyo 293177595Sweongyo /* check if device was removed */ 294177595Sweongyo sc->malo_invalid = !bus_child_present(dev); 295177595Sweongyo 296177595Sweongyo malo_detach(sc); 297177595Sweongyo 298177595Sweongyo bus_generic_detach(dev); 299177595Sweongyo 300177595Sweongyo if (psc->malo_msi == 0) 301177595Sweongyo bus_teardown_intr(dev, psc->malo_res_irq[0], 302177595Sweongyo psc->malo_intrhand[0]); 303177595Sweongyo else { 304177595Sweongyo for (i = 0; i < MALO_MSI_MESSAGES; i++) 305177595Sweongyo bus_teardown_intr(dev, psc->malo_res_irq[i], 306177595Sweongyo psc->malo_intrhand[i]); 307177595Sweongyo 308177595Sweongyo pci_release_msi(dev); 309177595Sweongyo } 310177595Sweongyo 311177595Sweongyo bus_release_resources(dev, psc->malo_irq_spec, psc->malo_res_irq); 312177595Sweongyo bus_dma_tag_destroy(sc->malo_dmat); 313177595Sweongyo bus_release_resources(dev, psc->malo_mem_spec, psc->malo_res_mem); 314177595Sweongyo 315177595Sweongyo return (0); 316177595Sweongyo} 317177595Sweongyo 318177595Sweongyostatic int 319177595Sweongyomalo_pci_shutdown(device_t dev) 320177595Sweongyo{ 321177595Sweongyo struct malo_pci_softc *psc = device_get_softc(dev); 322177595Sweongyo 323177595Sweongyo malo_shutdown(&psc->malo_sc); 324177595Sweongyo 325177595Sweongyo return (0); 326177595Sweongyo} 327177595Sweongyo 328177595Sweongyostatic int 329177595Sweongyomalo_pci_suspend(device_t dev) 330177595Sweongyo{ 331177595Sweongyo struct malo_pci_softc *psc = device_get_softc(dev); 332177595Sweongyo 333177595Sweongyo malo_suspend(&psc->malo_sc); 334177595Sweongyo 335177595Sweongyo return (0); 336177595Sweongyo} 337177595Sweongyo 338177595Sweongyostatic int 339177595Sweongyomalo_pci_resume(device_t dev) 340177595Sweongyo{ 341177595Sweongyo struct malo_pci_softc *psc = device_get_softc(dev); 342177595Sweongyo 343177595Sweongyo if (!malo_pci_setup(dev)) 344177595Sweongyo return ENXIO; 345177595Sweongyo 346177595Sweongyo malo_resume(&psc->malo_sc); 347177595Sweongyo 348177595Sweongyo return (0); 349177595Sweongyo} 350177595Sweongyo 351177595Sweongyostatic device_method_t malo_pci_methods[] = { 352177595Sweongyo /* Device interface */ 353177595Sweongyo DEVMETHOD(device_probe, malo_pci_probe), 354177595Sweongyo DEVMETHOD(device_attach, malo_pci_attach), 355177595Sweongyo DEVMETHOD(device_detach, malo_pci_detach), 356177595Sweongyo DEVMETHOD(device_shutdown, malo_pci_shutdown), 357177595Sweongyo DEVMETHOD(device_suspend, malo_pci_suspend), 358177595Sweongyo DEVMETHOD(device_resume, malo_pci_resume), 359177595Sweongyo { 0,0 } 360177595Sweongyo}; 361177595Sweongyo 362177595Sweongyostatic driver_t malo_pci_driver = { 363177595Sweongyo "malo", 364177595Sweongyo malo_pci_methods, 365177595Sweongyo sizeof(struct malo_pci_softc) 366177595Sweongyo}; 367177595Sweongyo 368177595Sweongyostatic devclass_t malo_devclass; 369177595SweongyoDRIVER_MODULE(if_malo, pci, malo_pci_driver, malo_devclass, 0, 0); 370177595SweongyoDRIVER_MODULE(if_malo, cardbus, malo_pci_driver, malo_devclass, 0, 0); 371177595SweongyoMODULE_VERSION(if_malo, 1); 372177595SweongyoMODULE_DEPEND(if_malo, wlan, 1, 1, 1); /* 802.11 media layer */ 373177595SweongyoMODULE_DEPEND(if_malo, malofw_fw, 1, 1, 1); 374