1139749Simp/*- 2185015Simp * Copyright (c) 2003-2008 M. Warner Losh. All Rights Reserved. 3111056Simp * Copyright (c) 2000,2001 Jonathan Chen. All rights reserved. 453343Simp * 553343Simp * Redistribution and use in source and binary forms, with or without 653343Simp * modification, are permitted provided that the following conditions 753343Simp * are met: 853343Simp * 1. Redistributions of source code must retain the above copyright 9140198Simp * notice, this list of conditions and the following disclaimer. 1053343Simp * 2. Redistributions in binary form must reproduce the above copyright 11140198Simp * notice, this list of conditions and the following disclaimer in the 12140198Simp * documentation and/or other materials provided with the distribution. 1353343Simp * 1467276Sjon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1567276Sjon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1667276Sjon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17140198Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18140198Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1967276Sjon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2067276Sjon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2167276Sjon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2267276Sjon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2367276Sjon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2467276Sjon * SUCH DAMAGE. 2553343Simp */ 2667276Sjon 27119418Sobrien#include <sys/cdefs.h> 28119418Sobrien__FBSDID("$FreeBSD: stable/10/sys/dev/cardbus/cardbus.c 330938 2018-03-14 19:04:40Z jhb $"); 29119418Sobrien 3053343Simp#include <sys/param.h> 3153343Simp#include <sys/systm.h> 3253343Simp#include <sys/malloc.h> 33129876Sphk#include <sys/module.h> 3453343Simp#include <sys/kernel.h> 3591787Simp#include <sys/sysctl.h> 3653343Simp 3767276Sjon#include <sys/bus.h> 3853343Simp#include <machine/bus.h> 3967276Sjon#include <sys/rman.h> 4067276Sjon#include <machine/resource.h> 4153343Simp 4291355Simp#include <sys/pciio.h> 4382378Sjon#include <dev/pci/pcivar.h> 4482378Sjon#include <dev/pci/pcireg.h> 45110975Simp#include <dev/pci/pci_private.h> 4653343Simp 4753343Simp#include <dev/cardbus/cardbusreg.h> 4853343Simp#include <dev/cardbus/cardbusvar.h> 4967276Sjon#include <dev/cardbus/cardbus_cis.h> 50141412Simp#include <dev/pccard/pccard_cis.h> 5197613Stakawata#include <dev/pccard/pccardvar.h> 5253343Simp 5369288Sjon#include "power_if.h" 5467276Sjon#include "pcib_if.h" 5553343Simp 5691787Simp/* sysctl vars */ 57227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, cardbus, CTLFLAG_RD, 0, "CardBus parameters"); 5853343Simp 5992301Simpint cardbus_debug = 0; 6091787SimpTUNABLE_INT("hw.cardbus.debug", &cardbus_debug); 6191787SimpSYSCTL_INT(_hw_cardbus, OID_AUTO, debug, CTLFLAG_RW, 6291787Simp &cardbus_debug, 0, 6391787Simp "CardBus debug"); 6491787Simp 6592301Simpint cardbus_cis_debug = 0; 6691787SimpTUNABLE_INT("hw.cardbus.cis_debug", &cardbus_cis_debug); 6791787SimpSYSCTL_INT(_hw_cardbus, OID_AUTO, cis_debug, CTLFLAG_RW, 6891787Simp &cardbus_cis_debug, 0, 6991787Simp "CardBus CIS debug"); 7091787Simp 7191787Simp#define DPRINTF(a) if (cardbus_debug) printf a 7291787Simp#define DEVPRINTF(x) if (cardbus_debug) device_printf x 7391787Simp 7482375Sjonstatic int cardbus_attach(device_t cbdev); 75104639Simpstatic int cardbus_attach_card(device_t cbdev); 7682375Sjonstatic int cardbus_detach(device_t cbdev); 77106362Simpstatic int cardbus_detach_card(device_t cbdev); 78169633Sjhbstatic void cardbus_device_setup_regs(pcicfgregs *cfg); 7982375Sjonstatic void cardbus_driver_added(device_t cbdev, driver_t *driver); 80104639Simpstatic int cardbus_probe(device_t cbdev); 81104639Simpstatic int cardbus_read_ivar(device_t cbdev, device_t child, int which, 82110975Simp uintptr_t *result); 83189653Simp 8467276Sjon/************************************************************************/ 8567276Sjon/* Probe/Attach */ 8667276Sjon/************************************************************************/ 8753343Simp 8867276Sjonstatic int 8982375Sjoncardbus_probe(device_t cbdev) 9067276Sjon{ 9187975Simp device_set_desc(cbdev, "CardBus bus"); 92153896Simp return (0); 9367276Sjon} 9453343Simp 9567276Sjonstatic int 9682375Sjoncardbus_attach(device_t cbdev) 9767276Sjon{ 98185015Simp struct cardbus_softc *sc; 99280970Sjhb#ifdef PCI_RES_BUS 100280970Sjhb int rid; 101280970Sjhb#endif 102153811Simp 103185015Simp sc = device_get_softc(cbdev); 104153811Simp sc->sc_dev = cbdev; 105280970Sjhb#ifdef PCI_RES_BUS 106280970Sjhb rid = 0; 107280970Sjhb sc->sc_bus = bus_alloc_resource(cbdev, PCI_RES_BUS, &rid, 108280970Sjhb pcib_get_bus(cbdev), pcib_get_bus(cbdev), 1, 0); 109280970Sjhb if (sc->sc_bus == NULL) { 110280970Sjhb device_printf(cbdev, "failed to allocate bus number\n"); 111280970Sjhb return (ENXIO); 112280970Sjhb } 113280970Sjhb#endif 114153896Simp return (0); 11553343Simp} 11653343Simp 11769288Sjonstatic int 11882375Sjoncardbus_detach(device_t cbdev) 11969288Sjon{ 120280970Sjhb#ifdef PCI_RES_BUS 121280970Sjhb struct cardbus_softc *sc; 122280970Sjhb#endif 123153811Simp 124106362Simp cardbus_detach_card(cbdev); 125280970Sjhb#ifdef PCI_RES_BUS 126280970Sjhb sc = device_get_softc(cbdev); 127280970Sjhb (void)bus_release_resource(cbdev, PCI_RES_BUS, 0, sc->sc_bus); 128280970Sjhb#endif 129153896Simp return (0); 13069288Sjon} 13169288Sjon 13287975Simpstatic int 13387975Simpcardbus_suspend(device_t self) 13487975Simp{ 135153896Simp 136106362Simp cardbus_detach_card(self); 13787975Simp return (0); 13887975Simp} 13987975Simp 14087975Simpstatic int 14187975Simpcardbus_resume(device_t self) 14287975Simp{ 143153896Simp 14487975Simp return (0); 14587975Simp} 14687975Simp 14767276Sjon/************************************************************************/ 14867276Sjon/* Attach/Detach card */ 14967276Sjon/************************************************************************/ 15067276Sjon 15167276Sjonstatic void 152169633Sjhbcardbus_device_setup_regs(pcicfgregs *cfg) 15353343Simp{ 154169633Sjhb device_t dev = cfg->dev; 155169620Simp int i; 15669291Sjon 157169620Simp /* 158169620Simp * Some cards power up with garbage in their BARs. This 159169620Simp * code clears all that junk out. 160169620Simp */ 161188033Sjhb for (i = 0; i < PCIR_MAX_BAR_0; i++) 162169620Simp pci_write_config(dev, PCIR_BAR(i), 0, 4); 16367276Sjon 164169633Sjhb cfg->intline = 165169633Sjhb pci_get_irq(device_get_parent(device_get_parent(dev))); 166169633Sjhb pci_write_config(dev, PCIR_INTLINE, cfg->intline, 1); 167169620Simp pci_write_config(dev, PCIR_CACHELNSZ, 0x08, 1); 168169620Simp pci_write_config(dev, PCIR_LATTIMER, 0xa8, 1); 169169620Simp pci_write_config(dev, PCIR_MINGNT, 0x14, 1); 170169620Simp pci_write_config(dev, PCIR_MAXLAT, 0x14, 1); 17153343Simp} 17253343Simp 17367276Sjonstatic int 17482375Sjoncardbus_attach_card(device_t cbdev) 17553343Simp{ 17682375Sjon device_t brdev = device_get_parent(cbdev); 177141412Simp device_t child; 178172394Smarius int bus, domain, slot, func; 17967276Sjon int cardattached = 0; 180151789Simp int cardbusfunchigh = 0; 181185015Simp struct cardbus_softc *sc; 18253343Simp 183185015Simp sc = device_get_softc(cbdev); 184106362Simp cardbus_detach_card(cbdev); /* detach existing cards */ 18582375Sjon POWER_ENABLE_SOCKET(brdev, cbdev); 186172394Smarius domain = pcib_get_domain(cbdev); 18782375Sjon bus = pcib_get_bus(cbdev); 188151789Simp slot = 0; 18982375Sjon /* For each function, set it up and try to attach a driver to it */ 190151789Simp for (func = 0; func <= cardbusfunchigh; func++) { 191151789Simp struct cardbus_devinfo *dinfo; 19292301Simp 193151789Simp dinfo = (struct cardbus_devinfo *) 194172394Smarius pci_read_device(brdev, domain, bus, slot, func, 195151789Simp sizeof(struct cardbus_devinfo)); 196151789Simp if (dinfo == NULL) 197151789Simp continue; 198151789Simp if (dinfo->pci.cfg.mfdev) 199151789Simp cardbusfunchigh = PCI_FUNCMAX; 200106362Simp 201151789Simp child = device_add_child(cbdev, NULL, -1); 202151789Simp if (child == NULL) { 203151789Simp DEVPRINTF((cbdev, "Cannot add child!\n")); 204151789Simp pci_freecfg((struct pci_devinfo *)dinfo); 205151789Simp continue; 20667276Sjon } 207151789Simp dinfo->pci.cfg.dev = child; 208151789Simp resource_list_init(&dinfo->pci.resources); 209151789Simp device_set_ivars(child, dinfo); 210185015Simp cardbus_device_create(sc, dinfo, cbdev, child); 211159532Simp if (cardbus_do_cis(cbdev, child) != 0) 212159532Simp DEVPRINTF((cbdev, "Warning: Bogus CIS ignored\n")); 213153896Simp pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 0); 214153896Simp pci_cfg_restore(dinfo->pci.cfg.dev, &dinfo->pci); 215169633Sjhb cardbus_device_setup_regs(&dinfo->pci.cfg); 216153896Simp pci_add_resources(cbdev, child, 1, dinfo->mprefetchable); 217151789Simp pci_print_verbose(&dinfo->pci); 218153896Simp if (device_probe_and_attach(child) == 0) 219153896Simp cardattached++; 220151789Simp else 221153896Simp pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 1); 22267276Sjon } 22382375Sjon if (cardattached > 0) 224106362Simp return (0); 225186642Simp/* POWER_DISABLE_SOCKET(brdev, cbdev); */ 226106362Simp return (ENOENT); 22753343Simp} 22853343Simp 229330938Sjhbstatic void 230330938Sjhbcardbus_child_deleted(device_t cbdev, device_t child) 231330938Sjhb{ 232330938Sjhb struct cardbus_devinfo *dinfo = device_get_ivars(child); 233330938Sjhb 234330938Sjhb if (dinfo->pci.cfg.dev != child) 235330938Sjhb device_printf(cbdev, "devinfo dev mismatch\n"); 236330938Sjhb cardbus_device_destroy(dinfo); 237330938Sjhb pci_child_deleted(cbdev, child); 238330938Sjhb} 239330938Sjhb 24067276Sjonstatic int 241106362Simpcardbus_detach_card(device_t cbdev) 24253343Simp{ 24382375Sjon int err = 0; 24453343Simp 245330938Sjhb err = bus_generic_detach(cbdev); 246330938Sjhb if (err) 247330938Sjhb return (err); 248330938Sjhb err = device_delete_children(cbdev); 249330938Sjhb if (err) 250330938Sjhb return (err); 25153343Simp 252106362Simp POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev); 253106362Simp return (err); 25467276Sjon} 25553343Simp 25669288Sjonstatic void 25782375Sjoncardbus_driver_added(device_t cbdev, driver_t *driver) 25869288Sjon{ 25970715Sjon int numdevs; 26070715Sjon device_t *devlist; 261110673Simp device_t dev; 262110673Simp int i; 263106362Simp struct cardbus_devinfo *dinfo; 26470715Sjon 265110673Simp DEVICE_IDENTIFY(driver, cbdev); 266166104Simp if (device_get_children(cbdev, &devlist, &numdevs) != 0) 267166104Simp return; 268166104Simp 269110750Simp /* 270110750Simp * If there are no drivers attached, but there are children, 271110750Simp * then power the card up. 272110750Simp */ 273110673Simp for (i = 0; i < numdevs; i++) { 274110673Simp dev = devlist[i]; 275110673Simp if (device_get_state(dev) != DS_NOTPRESENT) 276110750Simp break; 277110750Simp } 278110750Simp if (i > 0 && i == numdevs) 279110750Simp POWER_ENABLE_SOCKET(device_get_parent(cbdev), cbdev); 280110750Simp for (i = 0; i < numdevs; i++) { 281110750Simp dev = devlist[i]; 282110750Simp if (device_get_state(dev) != DS_NOTPRESENT) 283110673Simp continue; 284110673Simp dinfo = device_get_ivars(dev); 285110975Simp pci_print_verbose(&dinfo->pci); 286189619Simp if (bootverbose) 287189619Simp printf("pci%d:%d:%d:%d: reprobing on driver added\n", 288189619Simp dinfo->pci.cfg.domain, dinfo->pci.cfg.bus, 289189619Simp dinfo->pci.cfg.slot, dinfo->pci.cfg.func); 290153896Simp pci_cfg_restore(dinfo->pci.cfg.dev, &dinfo->pci); 291143394Simp if (device_probe_and_attach(dev) != 0) 292153896Simp pci_cfg_save(dev, &dinfo->pci, 1); 29370715Sjon } 29472185Simp free(devlist, M_TEMP); 29569288Sjon} 29669288Sjon 29792301Simp/************************************************************************/ 29892301Simp/* Other Bus Methods */ 29992301Simp/************************************************************************/ 30092301Simp 30192301Simpstatic int 302110975Simpcardbus_read_ivar(device_t cbdev, device_t child, int which, uintptr_t *result) 30392301Simp{ 30492301Simp struct cardbus_devinfo *dinfo; 30592301Simp pcicfgregs *cfg; 30692301Simp 30792301Simp dinfo = device_get_ivars(child); 30892301Simp cfg = &dinfo->pci.cfg; 30992301Simp 31092301Simp switch (which) { 311107301Simp case PCI_IVAR_ETHADDR: 312107301Simp /* 313107301Simp * The generic accessor doesn't deal with failure, so 314107301Simp * we set the return value, then return an error. 315107301Simp */ 316141412Simp if (dinfo->fepresent & (1 << PCCARD_TPLFE_TYPE_LAN_NID)) { 317141412Simp *((uint8_t **) result) = dinfo->funce.lan.nid; 318141412Simp break; 319107301Simp } 320141412Simp *((uint8_t **) result) = NULL; 321141412Simp return (EINVAL); 32292301Simp default: 323110975Simp return (pci_read_ivar(cbdev, child, which, result)); 32492301Simp } 32592301Simp return 0; 32692301Simp} 32792301Simp 32867276Sjonstatic device_method_t cardbus_methods[] = { 32967276Sjon /* Device interface */ 33067276Sjon DEVMETHOD(device_probe, cardbus_probe), 33167276Sjon DEVMETHOD(device_attach, cardbus_attach), 33269288Sjon DEVMETHOD(device_detach, cardbus_detach), 33387975Simp DEVMETHOD(device_suspend, cardbus_suspend), 33487975Simp DEVMETHOD(device_resume, cardbus_resume), 33567276Sjon 33667276Sjon /* Bus interface */ 337330938Sjhb DEVMETHOD(bus_child_deleted, cardbus_child_deleted), 338232403Sjhb DEVMETHOD(bus_get_dma_tag, bus_generic_get_dma_tag), 33992301Simp DEVMETHOD(bus_read_ivar, cardbus_read_ivar), 34069288Sjon DEVMETHOD(bus_driver_added, cardbus_driver_added), 34192301Simp 34267276Sjon /* Card Interface */ 34367276Sjon DEVMETHOD(card_attach_card, cardbus_attach_card), 34467276Sjon DEVMETHOD(card_detach_card, cardbus_detach_card), 34567276Sjon 34667276Sjon {0,0} 34767276Sjon}; 34867276Sjon 349153832SglebiusDEFINE_CLASS_1(cardbus, cardbus_driver, cardbus_methods, 350153832Sglebius sizeof(struct cardbus_softc), pci_driver); 35167276Sjon 35269288Sjonstatic devclass_t cardbus_devclass; 35367276Sjon 354101905SimpDRIVER_MODULE(cardbus, cbb, cardbus_driver, cardbus_devclass, 0, 0); 35597613StakawataMODULE_VERSION(cardbus, 1); 356