Index: sys/sys/rman.h =================================================================== RCS file: /export/ncvs/src/sys/sys/rman.h,v retrieving revision 1.14 diff -u -u -r1.14 rman.h --- sys/sys/rman.h 2001/01/24 12:35:52 1.14 +++ sys/sys/rman.h 2001/07/13 17:59:49 @@ -42,6 +42,7 @@ #define RF_TIMESHARE 0x0008 /* resource permits time-division sharing */ #define RF_WANTED 0x0010 /* somebody is waiting for this resource */ #define RF_FIRSTSHARE 0x0020 /* first in sharing list */ +#define RF_PREFETCHABLE 0x0040 /* resource is prefetchable */ #define RF_ALIGNMENT_SHIFT 10 /* alignment size bit starts bit 10 */ #define RF_ALIGNMENT_MASK (0x003F << RF_ALIGNMENT_SHIFT) Index: sys/dev/pccbb/pccbb.c =================================================================== RCS file: /export/ncvs/src/sys/dev/pccbb/pccbb.c,v retrieving revision 1.20 diff -u -u -r1.20 pccbb.c --- sys/dev/pccbb/pccbb.c 2001/06/30 03:57:20 1.20 +++ sys/dev/pccbb/pccbb.c 2001/07/15 19:39:31 @@ -190,86 +190,14 @@ CB_UNKNOWN, 0}, }; - -static int cb_chipset(u_int32_t pci_id, const char** namep, int* flagp); -static int pccbb_probe(device_t dev); -static void pccbb_chipinit(struct pccbb_softc* sc); -static int pccbb_attach(device_t dev); -static int pccbb_detach(device_t dev); -static void pccbb_driver_added(device_t dev, driver_t *driver); -static void pccbb_child_detached(device_t dev, device_t child); +static void pccbb_intr(void* arg); +static int pccbb_power(device_t brdev, int volts); static void pccbb_event_thread (void *arg); -static void pccbb_create_event_thread (struct pccbb_softc *sc); -static void pccbb_start_threads(void *arg); static void pccbb_insert (struct pccbb_softc *sc); static void pccbb_removal (struct pccbb_softc *sc); -static void pccbb_intr(void* arg); -static int pccbb_detect_voltage(device_t dev); -static int pccbb_power(device_t dev, int volts); -static void pccbb_cardbus_reset(device_t dev); -static int pccbb_cardbus_power_enable_socket(device_t self, device_t child); -static void pccbb_cardbus_power_disable_socket(device_t self, device_t child); -static int pccbb_cardbus_io_open(device_t dev, int win, - u_int32_t start, u_int32_t end); -static int pccbb_cardbus_mem_open(device_t dev, int win, - u_int32_t start, u_int32_t end); -static void pccbb_cardbus_auto_open(struct pccbb_softc *sc, int type); -static int pccbb_cardbus_activate_resource(device_t self, device_t child, - int type, int rid, - struct resource *r); -static int pccbb_cardbus_deactivate_resource(device_t self, device_t child, - int type, int rid, - struct resource *r); -static struct resource* pccbb_cardbus_alloc_resource(device_t self, - device_t child, int type, int* rid, - u_long start, u_long end, u_long count, - u_int flags); -static int pccbb_cardbus_release_resource(device_t self, device_t child, - int type,int rid, - struct resource *r); -static int pccbb_pcic_power_enable_socket(device_t self, device_t child); -static void pccbb_pcic_power_disable_socket(device_t self, device_t child); static void pccbb_pcic_wait_ready(struct pccbb_softc *sc); static void pccbb_pcic_do_mem_map(struct pccbb_softc *sc, int win); -static int pccbb_pcic_mem_map(struct pccbb_softc *sc, int kind, - struct resource *r, bus_addr_t card_addr, - int *win); -static void pccbb_pcic_mem_unmap(struct pccbb_softc *sc, int window); static void pccbb_pcic_do_io_map(struct pccbb_softc *sc, int win); -static int pccbb_pcic_io_map(struct pccbb_softc *sc, int width, - struct resource *r, bus_addr_t card_addr, - int *win); -static void pccbb_pcic_io_unmap(struct pccbb_softc *sc, int window); -static int pccbb_pcic_activate_resource(device_t self, device_t child, - int type, int rid, struct resource *r); -static int pccbb_pcic_deactivate_resource(device_t self, device_t child, - int type,int rid, struct resource *r); -static struct resource* pccbb_pcic_alloc_resource(device_t self,device_t child, - int type, int* rid, u_long start, - u_long end, u_long count, u_int flags); -static int pccbb_pcic_release_resource(device_t self, device_t child, int type, - int rid, struct resource *res); -static int pccbb_pcic_set_res_flags(device_t self, device_t child, int type, - int rid, u_int32_t flags); -static int pccbb_pcic_set_memory_offset(device_t self, device_t child, int rid, - u_int32_t offset, u_int32_t *deltap); -static int pccbb_power_enable_socket(device_t self, device_t child); -static void pccbb_power_disable_socket(device_t self, device_t child); -static int pccbb_activate_resource(device_t self, device_t child, int type, - int rid, struct resource *r); -static int pccbb_deactivate_resource(device_t self, device_t child, int type, - int rid, struct resource *r); -static struct resource* pccbb_alloc_resource(device_t self, device_t child, - int type, int* rid, u_long start, - u_long end, u_long count, - u_int flags); -static int pccbb_release_resource(device_t self, device_t child, - int type, int rid, struct resource *r); -static int pccbb_maxslots(device_t dev); -static u_int32_t pccbb_read_config(device_t dev, int b, int s, int f, - int reg, int width); -static void pccbb_write_config(device_t dev, int b, int s, int f, int reg, - u_int32_t val, int width); /************************************************************************/ @@ -298,13 +226,13 @@ } static int -pccbb_probe(device_t dev) +pccbb_probe(device_t brdev) { const char *name; - if (cb_chipset(pci_get_devid(dev), &name, NULL) == CB_UNKNOWN) + if (cb_chipset(pci_get_devid(brdev), &name, NULL) == CB_UNKNOWN) return ENXIO; - device_set_desc(dev, name); + device_set_desc(brdev, name); return 0; } @@ -385,9 +313,9 @@ } static int -pccbb_attach(device_t dev) +pccbb_attach(device_t brdev) { - struct pccbb_softc *sc = (struct pccbb_softc *)device_get_softc(dev); + struct pccbb_softc *sc = (struct pccbb_softc *)device_get_softc(brdev); int rid; u_int32_t tmp; @@ -395,53 +323,53 @@ softcs_init = 1; STAILQ_INIT(&softcs); } - mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_DEF); - sc->sc_chipset = cb_chipset(pci_get_devid(dev), NULL, &sc->sc_flags); - sc->sc_dev = dev; + mtx_init(&sc->sc_mtx, device_get_nameunit(brdev), MTX_DEF); + sc->sc_chipset = cb_chipset(pci_get_devid(brdev), NULL, &sc->sc_flags); + sc->sc_dev = brdev; sc->sc_cbdev = NULL; sc->sc_pccarddev = NULL; - sc->sc_secbus = pci_read_config(dev, PCIR_SECBUS_2, 1); - sc->sc_subbus = pci_read_config(dev, PCIR_SUBBUS_2, 1); + sc->sc_secbus = pci_read_config(brdev, PCIR_SECBUS_2, 1); + sc->sc_subbus = pci_read_config(brdev, PCIR_SUBBUS_2, 1); sc->memalloc = 0; sc->ioalloc = 0; SLIST_INIT(&sc->rl); /* Ths PCI bus should have given me memory... right? */ rid=PCCBBR_SOCKBASE; - sc->sc_base_res=bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, + sc->sc_base_res=bus_alloc_resource(brdev, SYS_RES_MEMORY, &rid, 0,~0,1, RF_ACTIVE); if (!sc->sc_base_res) { /* - * XXX eVILE HACK BAD THING! XXX + * XXX EVILE HACK BAD THING! XXX * The pci bus device should do this for us. * Some BIOSes doesn't assign a memory space properly. * So we try to manually put one in... */ u_int32_t sockbase; - sockbase = pci_read_config(dev, rid, 4); + sockbase = pci_read_config(brdev, rid, 4); if (sockbase < 0x100000 || sockbase >= 0xfffffff0) { - pci_write_config(dev, rid, 0xffffffff, 4); - sockbase = pci_read_config(dev, rid, 4); + pci_write_config(brdev, rid, 0xffffffff, 4); + sockbase = pci_read_config(brdev, rid, 4); sockbase = (sockbase & 0xfffffff0) & -(sockbase & 0xfffffff0); sc->sc_base_res = bus_generic_alloc_resource( - device_get_parent(dev), dev, SYS_RES_MEMORY, + device_get_parent(brdev), brdev, SYS_RES_MEMORY, &rid, CARDBUS_SYS_RES_MEMORY_START, CARDBUS_SYS_RES_MEMORY_END, sockbase, RF_ACTIVE|rman_make_alignment_flags(sockbase)); if (!sc->sc_base_res){ - device_printf(dev, + device_printf(brdev, "Could not grab register memory\n"); mtx_destroy(&sc->sc_mtx); return ENOMEM; } - pci_write_config(dev, PCCBBR_SOCKBASE, + pci_write_config(brdev, PCCBBR_SOCKBASE, rman_get_start(sc->sc_base_res), 4); - DEVPRINTF((dev, "PCI Memory allocated: %08lx\n", + DEVPRINTF((brdev, "PCI Memory allocated: %08lx\n", rman_get_start(sc->sc_base_res))); } else { - device_printf(dev, "Could not map register memory\n"); + device_printf(brdev, "Could not map register memory\n"); mtx_destroy(&sc->sc_mtx); return ENOMEM; } @@ -460,49 +388,50 @@ /* Map and establish the interrupt. */ rid=0; - sc->sc_irq_res=bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, + sc->sc_irq_res=bus_alloc_resource(brdev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->sc_irq_res == NULL) { printf("pccbb: Unable to map IRQ...\n"); - bus_release_resource(dev, SYS_RES_MEMORY, PCCBBR_SOCKBASE, + bus_release_resource(brdev, SYS_RES_MEMORY, PCCBBR_SOCKBASE, sc->sc_base_res); mtx_destroy(&sc->sc_mtx); return ENOMEM; } - if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO, pccbb_intr, sc, + if (bus_setup_intr(brdev, sc->sc_irq_res, INTR_TYPE_BIO, pccbb_intr, sc, &(sc->sc_intrhand))) { - device_printf(dev, "couldn't establish interrupt"); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); - bus_release_resource(dev, SYS_RES_MEMORY, PCCBBR_SOCKBASE, + device_printf(brdev, "couldn't establish interrupt"); + bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->sc_irq_res); + bus_release_resource(brdev, SYS_RES_MEMORY, PCCBBR_SOCKBASE, sc->sc_base_res); mtx_destroy(&sc->sc_mtx); return ENOMEM; } /* attach children */ - sc->sc_cbdev = device_add_child(dev, "cardbus", -1); + sc->sc_cbdev = device_add_child(brdev, "cardbus", -1); if (sc->sc_cbdev == NULL) - DEVPRINTF((dev, "WARNING: cannot add cardbus bus.\n")); + DEVPRINTF((brdev, "WARNING: cannot add cardbus bus.\n")); else if (device_probe_and_attach(sc->sc_cbdev) != 0) { - DEVPRINTF((dev, "WARNING: cannot attach cardbus bus!\n")); + DEVPRINTF((brdev, "WARNING: cannot attach cardbus bus!\n")); sc->sc_cbdev = NULL; } - sc->sc_pccarddev = device_add_child(dev, "pccard", -1); + sc->sc_pccarddev = device_add_child(brdev, "pccard", -1); if (sc->sc_pccarddev == NULL) - DEVPRINTF((dev, "WARNING: cannot add pccard bus.\n")); + DEVPRINTF((brdev, "WARNING: cannot add pccard bus.\n")); else if (device_probe_and_attach(sc->sc_pccarddev) != 0) { - DEVPRINTF((dev, "WARNING: cannot attach pccard bus.\n")); + DEVPRINTF((brdev, "WARNING: cannot attach pccard bus.\n")); sc->sc_pccarddev = NULL; } #ifndef KLD_MODULE if (sc->sc_cbdev == NULL && sc->sc_pccarddev == NULL) { - device_printf(dev, "ERROR: Failed to attach cardbus/pccard bus!\n"); - bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); - bus_release_resource(dev, SYS_RES_MEMORY, PCCBBR_SOCKBASE, + device_printf(brdev, + "ERROR: Failed to attach cardbus/pccard bus!\n"); + bus_teardown_intr(brdev, sc->sc_irq_res, sc->sc_intrhand); + bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->sc_irq_res); + bus_release_resource(brdev, SYS_RES_MEMORY, PCCBBR_SOCKBASE, sc->sc_base_res); mtx_destroy(&sc->sc_mtx); return ENOMEM; @@ -520,20 +449,20 @@ } static int -pccbb_detach(device_t dev) +pccbb_detach(device_t brdev) { - struct pccbb_softc *sc = device_get_softc(dev); + struct pccbb_softc *sc = device_get_softc(brdev); int numdevs; device_t *devlist; int tmp; int error; - device_get_children(dev, &devlist, &numdevs); + device_get_children(brdev, &devlist, &numdevs); error = 0; for (tmp = 0; tmp < numdevs; tmp++) { if (device_detach(devlist[tmp]) == 0) - device_delete_child(dev, devlist[tmp]); + device_delete_child(brdev, devlist[tmp]); else error++; } @@ -542,13 +471,13 @@ return ENXIO; mtx_lock(&sc->sc_mtx); - bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand); + bus_teardown_intr(brdev, sc->sc_irq_res, sc->sc_intrhand); sc->sc_flags |= PCCBB_KTHREAD_DONE; if (sc->sc_flags & PCCBB_KTHREAD_RUNNING) { wakeup(sc); mtx_unlock(&sc->sc_mtx); - DEVPRINTF((dev, "waiting for kthread exit...")); + DEVPRINTF((brdev, "waiting for kthread exit...")); error = tsleep(sc, PWAIT, "pccbb-detach-wait", 60 * hz); if (error) DPRINTF(("timeout\n")); @@ -557,23 +486,53 @@ } else mtx_unlock(&sc->sc_mtx); - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); - bus_release_resource(dev, SYS_RES_MEMORY, PCCBBR_SOCKBASE, + bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->sc_irq_res); + bus_release_resource(brdev, SYS_RES_MEMORY, PCCBBR_SOCKBASE, sc->sc_base_res); mtx_destroy(&sc->sc_mtx); return 0; } +static int +pccbb_shutdown(device_t brdev) +{ + struct pccbb_softc *sc = (struct pccbb_softc *)device_get_softc(brdev); + /* properly reset everything at shutdown */ + + PCI_MASK_CONFIG(brdev, PCCBBR_BRIDGECTRL, |PCCBBM_BRIDGECTRL_RESET, 2); + PCIC_MASK(sc, PCIC_INTR, & ~PCIC_INTR_RESET); + + sc->sc_socketreg->socket_mask = 0; + + pccbb_power(brdev, CARD_VCC_0V | CARD_VPP_0V); + + PCIC_WRITE(sc, PCIC_ADDRWIN_ENABLE, 0); + pci_write_config(brdev, PCCBBR_MEMBASE0, 0, 4); + pci_write_config(brdev, PCCBBR_MEMLIMIT0, 0, 4); + pci_write_config(brdev, PCCBBR_MEMBASE1, 0, 4); + pci_write_config(brdev, PCCBBR_MEMLIMIT1, 0, 4); + pci_write_config(brdev, PCCBBR_IOBASE0, 0, 4); + pci_write_config(brdev, PCCBBR_IOLIMIT0, 0, 4); + pci_write_config(brdev, PCCBBR_IOBASE1, 0, 4); + pci_write_config(brdev, PCCBBR_IOLIMIT1, 0, 4); + pci_write_config(brdev, PCIR_COMMAND, 0, 2); + return 0; +} + static void -pccbb_driver_added(device_t dev, driver_t *driver) +pccbb_driver_added(device_t brdev, driver_t *driver) { - struct pccbb_softc *sc = device_get_softc(dev); + struct pccbb_softc *sc = device_get_softc(brdev); device_t *devlist; int tmp; int numdevs; + int wake; + u_int32_t sockstate; - DEVICE_IDENTIFY(driver, dev); - device_get_children(dev, &devlist, &numdevs); + DEVICE_IDENTIFY(driver, brdev); + device_get_children(brdev, &devlist, &numdevs); + wake = 0; + sockstate = sc->sc_socketreg->socket_state; for (tmp = 0; tmp < numdevs; tmp++) { if (device_get_state(devlist[tmp]) == DS_NOTPRESENT && device_probe_and_attach(devlist[tmp]) == 0) { @@ -581,42 +540,73 @@ /* NOTHING */; else if (strcmp(driver->name, "cardbus") == 0) { sc->sc_cbdev = devlist[tmp]; - if ((sc->sc_socketreg->socket_state - & PCCBB_SOCKET_STAT_CD) == 0) { - mtx_lock(&sc->sc_mtx); - wakeup(sc); - mtx_unlock(&sc->sc_mtx); - } + if (((sockstate & PCCBB_SOCKET_STAT_CD) == 0) && + (sockstate & PCCBB_SOCKET_STAT_CB)) + wake++; } else if (strcmp(driver->name, "pccard") == 0) { sc->sc_pccarddev = devlist[tmp]; - if ((sc->sc_socketreg->socket_state - & PCCBB_SOCKET_STAT_CD) == 0) { - mtx_lock(&sc->sc_mtx); - wakeup(sc); - mtx_unlock(&sc->sc_mtx); - } + if (((sockstate & PCCBB_SOCKET_STAT_CD) == 0) && + (sockstate & PCCBB_SOCKET_STAT_16BIT)) + wake++; } else - device_printf(dev, + device_printf(brdev, "Unsupported child bus: %s\n", driver->name); } } free(devlist, M_TEMP); + + if (wake>0) { + if ((sc->sc_socketreg->socket_state + & PCCBB_SOCKET_STAT_CD) == 0) { + mtx_lock(&sc->sc_mtx); + wakeup(sc); + mtx_unlock(&sc->sc_mtx); + } + } } static void -pccbb_child_detached(device_t dev, device_t child) +pccbb_child_detached(device_t brdev, device_t child) { - struct pccbb_softc *sc = device_get_softc(dev); + struct pccbb_softc *sc = device_get_softc(brdev); if (child == sc->sc_cbdev) sc->sc_cbdev = NULL; else if (child == sc->sc_pccarddev) sc->sc_pccarddev = NULL; else - device_printf(dev, "Unknown child detached: %s %p/%p\n", - device_get_nameunit(child), sc->sc_cbdev, sc->sc_pccarddev); + device_printf(brdev, "Unknown child detached: %s %p/%p\n", + device_get_nameunit(child), sc->sc_cbdev, + sc->sc_pccarddev); } +static int +pccbb_card_reprobe(device_t brdev, device_t busdev) { + struct pccbb_softc *sc = device_get_softc(brdev); + int wake = 0; + u_int32_t sockstate; + + sockstate = sc->sc_socketreg->socket_state; + + if ((sockstate & PCCBB_SOCKET_STAT_CD) == 0) { + if (busdev == sc->sc_cbdev && + (sockstate & PCCBB_SOCKET_STAT_CB)) + wake++; + else if (busdev == sc->sc_pccarddev && + (sockstate & PCCBB_SOCKET_STAT_16BIT)) + wake++; + + if (wake>0) { + mtx_lock(&sc->sc_mtx); + wakeup(sc); + mtx_unlock(&sc->sc_mtx); + return 0; + } + return EBUSY; + } + return ENOENT; +} + /************************************************************************/ /* Kthreads */ /************************************************************************/ @@ -718,23 +708,21 @@ static void pccbb_removal (struct pccbb_softc *sc) { - u_int32_t sockstate; struct pccbb_reslist *rle; - - sockstate = sc->sc_socketreg->socket_state; - if (sockstate & PCCBB_16BIT_CARD && sc->sc_pccarddev != NULL) + if (sc->sc_flags & PCCBB_16BIT_CARD && sc->sc_pccarddev != NULL) CARD_DETACH_CARD(sc->sc_pccarddev, DETACH_FORCE); - else if ((!(sockstate & PCCBB_16BIT_CARD)) && sc->sc_cbdev != NULL) + else if ((!(sc->sc_flags & PCCBB_16BIT_CARD)) && sc->sc_cbdev != NULL) CARD_DETACH_CARD(sc->sc_cbdev, DETACH_FORCE); - while (NULL != (rle = SLIST_FIRST(&sc->rl))) { + while ((rle = SLIST_FIRST(&sc->rl)) != NULL) { device_printf(sc->sc_dev, "Danger Will Robinson: Resource " - "left allocated! This is a bug... " - "(rid=%x, type=%d, addr=%x)\n", rle->rid, rle->type, - rle->start); - SLIST_REMOVE_HEAD(&sc->rl, entries); - } + "left allocated! This is a bug... " + "(type=%d, rid=%d, addr=%lx)\n", + rle->type, rle->rid, rman_get_start(rle->res)); + SLIST_REMOVE_HEAD(&sc->rl, link); + free(rle, M_DEVBUF); + } } /************************************************************************/ @@ -778,9 +766,9 @@ /************************************************************************/ static int -pccbb_detect_voltage(device_t dev) +pccbb_detect_voltage(device_t brdev) { - struct pccbb_softc *sc = device_get_softc(dev); + struct pccbb_softc *sc = device_get_softc(brdev); u_int32_t psr; int vol = CARD_UKN_CARD; @@ -803,10 +791,10 @@ } static int -pccbb_power(device_t dev, int volts) +pccbb_power(device_t brdev, int volts) { u_int32_t status, sock_ctrl; - struct pccbb_softc *sc = device_get_softc(dev); + struct pccbb_softc *sc = device_get_softc(brdev); DEVPRINTF((sc->sc_dev, "pccbb_power: %s and %s [%x]\n", (volts & CARD_VCCMASK) == CARD_VCC_UC ? "CARD_VCC_UC" : @@ -926,56 +914,56 @@ /************************************************************************/ static void -pccbb_cardbus_reset(device_t dev) +pccbb_cardbus_reset(device_t brdev) { - struct pccbb_softc *sc = device_get_softc(dev); + struct pccbb_softc *sc = device_get_softc(brdev); int delay_us; delay_us = sc->sc_chipset == CB_RF5C47X ? 400*1000 : 20*1000; - PCI_MASK_CONFIG(dev, PCCBBR_BRIDGECTRL, |PCCBBM_BRIDGECTRL_RESET, 2); + PCI_MASK_CONFIG(brdev, PCCBBR_BRIDGECTRL, |PCCBBM_BRIDGECTRL_RESET, 2); DELAY(delay_us); /* If a card exists, unreset it! */ if ((sc->sc_socketreg->socket_state & PCCBB_SOCKET_STAT_CD) == 0) { - PCI_MASK_CONFIG(dev, PCCBBR_BRIDGECTRL, + PCI_MASK_CONFIG(brdev, PCCBBR_BRIDGECTRL, &~PCCBBM_BRIDGECTRL_RESET, 2); DELAY(delay_us); } } static int -pccbb_cardbus_power_enable_socket(device_t self, device_t child) +pccbb_cardbus_power_enable_socket(device_t brdev, device_t child) { - struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_softc *sc = device_get_softc(brdev); int voltage; if ((sc->sc_socketreg->socket_state & PCCBB_SOCKET_STAT_CD) == PCCBB_SOCKET_STAT_CD) return ENODEV; - voltage = pccbb_detect_voltage(self); + voltage = pccbb_detect_voltage(brdev); - pccbb_power(self, CARD_VCC_0V | CARD_VPP_0V); + pccbb_power(brdev, CARD_VCC_0V | CARD_VPP_0V); if (voltage & CARD_5V_CARD) - pccbb_power(self, CARD_VCC_5V | CARD_VPP_VCC); + pccbb_power(brdev, CARD_VCC_5V | CARD_VPP_VCC); else if (voltage & CARD_3V_CARD) - pccbb_power(self, CARD_VCC_3V | CARD_VPP_VCC); + pccbb_power(brdev, CARD_VCC_3V | CARD_VPP_VCC); else { - device_printf(self, "Unknown card voltage\n"); + device_printf(brdev, "Unknown card voltage\n"); return ENXIO; } - pccbb_cardbus_reset(self); + pccbb_cardbus_reset(brdev); return 0; } static void -pccbb_cardbus_power_disable_socket(device_t self, device_t child) +pccbb_cardbus_power_disable_socket(device_t brdev, device_t child) { - pccbb_power(self, CARD_VCC_0V | CARD_VPP_0V); - pccbb_cardbus_reset(self); + pccbb_power(brdev, CARD_VCC_0V | CARD_VPP_0V); + pccbb_cardbus_reset(brdev); } /************************************************************************/ @@ -983,13 +971,13 @@ /************************************************************************/ static int -pccbb_cardbus_io_open(device_t dev, int win, u_int32_t start, u_int32_t end) +pccbb_cardbus_io_open(device_t brdev, int win, u_int32_t start, u_int32_t end) { int basereg; int limitreg; if ((win < 0) || (win > 1)) { - DEVPRINTF((dev, + DEVPRINTF((brdev, "pccbb_cardbus_io_open: window out of range %d\n", win)); return EINVAL; @@ -998,19 +986,19 @@ basereg = win*8 + PCCBBR_IOBASE0; limitreg = win*8 + PCCBBR_IOLIMIT0; - pci_write_config(dev, basereg, start, 4); - pci_write_config(dev, limitreg, end, 4); + pci_write_config(brdev, basereg, start, 4); + pci_write_config(brdev, limitreg, end, 4); return 0; } static int -pccbb_cardbus_mem_open(device_t dev, int win, u_int32_t start, u_int32_t end) +pccbb_cardbus_mem_open(device_t brdev, int win, u_int32_t start, u_int32_t end) { int basereg; int limitreg; if ((win < 0) || (win > 1)) { - DEVPRINTF((dev, + DEVPRINTF((brdev, "pccbb_cardbus_mem_open: window out of range %d\n", win)); return EINVAL; @@ -1019,8 +1007,8 @@ basereg = win*8 + PCCBBR_MEMBASE0; limitreg = win*8 + PCCBBR_MEMLIMIT0; - pci_write_config(dev, basereg, start, 4); - pci_write_config(dev, limitreg, end, 4); + pci_write_config(brdev, basereg, start, 4); + pci_write_config(brdev, limitreg, end, 4); return 0; } @@ -1031,76 +1019,100 @@ u_int32_t ends[2]; struct pccbb_reslist *rle; int align; + int prefetchable[2]; starts[0] = starts[1] = 0xffffffff; ends[0] = ends[1] = 0; + + if (type == SYS_RES_MEMORY) + align = PCCBB_MEMALIGN; + else if (type == SYS_RES_IOPORT) + align = PCCBB_IOALIGN; + else + align = 1; - SLIST_FOREACH(rle, &sc->rl, entries) { + SLIST_FOREACH(rle, &sc->rl, link) { if (rle->type != type) ; - else if (starts[0] == 0xffffffff) { - starts[0] = rle->start; - ends[0] = rle->end; - rle->win = 0; - } else if (rle->end > ends[0] && - rle->start - ends[0] < PCCBB_AUTO_OPEN_SMALLHOLE) { - ends[0] = rle->end; - rle->win = 0; - } else if (rle->start < starts[0] && - starts[0] - rle->end < PCCBB_AUTO_OPEN_SMALLHOLE) { - starts[0] = rle->start; - rle->win = 0; + else if (rle->res == NULL) { + device_printf(sc->sc_dev, "WARNING: Resource not reserved? " + "(type=%d, addr=%lx)\n", + rle->type, rman_get_start(rle->res)); + } else if (!(rman_get_flags(rle->res) & RF_ACTIVE)) { + } else if (starts[0] == 0xffffffff) { + starts[0] = rman_get_start(rle->res); + ends[0] = rman_get_end(rle->res); + prefetchable[0] = + rman_get_flags(rle->res) & RF_PREFETCHABLE; + } else if (rman_get_end(rle->res) > ends[0] && + rman_get_start(rle->res) - ends[0] < + PCCBB_AUTO_OPEN_SMALLHOLE && prefetchable[0] == + (rman_get_flags(rle->res) & RF_PREFETCHABLE)) { + ends[0] = rman_get_end(rle->res); + } else if (rman_get_start(rle->res) < starts[0] && + starts[0] - rman_get_end(rle->res) < + PCCBB_AUTO_OPEN_SMALLHOLE && prefetchable[0] == + (rman_get_flags(rle->res) & RF_PREFETCHABLE)) { + starts[0] = rman_get_start(rle->res); } else if (starts[1] == 0xffffffff) { - starts[1] = rle->start; - ends[1] = rle->end; - rle->win = 1; - } else if (rle->end > ends[1] && - rle->start - ends[1] < PCCBB_AUTO_OPEN_SMALLHOLE) { - ends[1] = rle->end; - rle->win = 1; - } else if (rle->start < starts[1] && - starts[1] - rle->end < PCCBB_AUTO_OPEN_SMALLHOLE) { - starts[1] = rle->start; - rle->win = 1; + starts[1] = rman_get_start(rle->res); + ends[1] = rman_get_end(rle->res); + prefetchable[1] = + rman_get_flags(rle->res) & RF_PREFETCHABLE; + } else if (rman_get_end(rle->res) > ends[1] && + rman_get_start(rle->res) - ends[1] < + PCCBB_AUTO_OPEN_SMALLHOLE && prefetchable[1] == + (rman_get_flags(rle->res) & RF_PREFETCHABLE)) { + ends[1] = rman_get_end(rle->res); + } else if (rman_get_start(rle->res) < starts[1] && + starts[1] - rman_get_end(rle->res) < + PCCBB_AUTO_OPEN_SMALLHOLE && prefetchable[1] == + (rman_get_flags(rle->res) & RF_PREFETCHABLE)) { + starts[1] = rman_get_start(rle->res); } else { u_int32_t diffs[2]; + int win; diffs[0] = diffs[1] = 0xffffffff; - if (rle->start > ends[0]) - diffs[0] = rle->start - ends[0]; - else if (rle->end < starts[0]) - diffs[0] = starts[0] - rle->end; - if (rle->start > ends[1]) - diffs[1] = rle->start - ends[1]; - else if (rle->end < starts[1]) - diffs[1] = starts[1] - rle->end; - - rle->win = (diffs[0] <= diffs[1])?0:1; - if (rle->start > ends[rle->win]) - ends[rle->win] = rle->end; - else if (rle->end < starts[rle->win]) - starts[rle->win] = rle->start; - } + if (rman_get_start(rle->res) > ends[0]) + diffs[0] = rman_get_start(rle->res) - ends[0]; + else if (rman_get_end(rle->res) < starts[0]) + diffs[0] = starts[0] - rman_get_end(rle->res); + if (rman_get_start(rle->res) > ends[1]) + diffs[1] = rman_get_start(rle->res) - ends[1]; + else if (rman_get_end(rle->res) < starts[1]) + diffs[1] = starts[1] - rman_get_end(rle->res); + + win = (diffs[0] <= diffs[1])?0:1; + if (rman_get_start(rle->res) > ends[win]) + ends[win] = rman_get_end(rle->res); + else if (rman_get_end(rle->res) < starts[win]) + starts[win] = rman_get_start(rle->res); + if (!(rman_get_flags(rle->res) & RF_PREFETCHABLE)) + prefetchable[win] = 0; + } + + if (starts[0] != 0xffffffff) + starts[0] -= starts[0] % align; + if (starts[1] != 0xffffffff) + starts[1] -= starts[1] % align; + if (ends[0] % align != 0) + ends[0] += align - ends[0]%align - 1; + if (ends[1] % align != 0) + ends[1] += align - ends[1]%align - 1; } - if (type == SYS_RES_MEMORY) - align = PCCBB_MEMALIGN; - else if (type == SYS_RES_IOPORT) - align = PCCBB_IOALIGN; - else - align = 1; - - if (starts[0] != 0xffffffff) - starts[0] -= starts[0] % align; - if (starts[1] != 0xffffffff) - starts[1] -= starts[1] % align; - if (ends[0] % align != 0) - ends[0] += align - ends[0]%align - 1; - if (ends[1] % align != 0) - ends[1] += align - ends[1]%align - 1; if (type == SYS_RES_MEMORY) { + u_int32_t reg; + pccbb_cardbus_mem_open(sc->sc_dev, 0, starts[0], ends[0]); pccbb_cardbus_mem_open(sc->sc_dev, 1, starts[1], ends[1]); + reg = pci_read_config(sc->sc_dev, PCCBBR_BRIDGECTRL, 2); + reg &= ~(PCCBBM_BRIDGECTRL_PREFETCH_0| + PCCBBM_BRIDGECTRL_PREFETCH_1); + reg |= (prefetchable[0]?PCCBBM_BRIDGECTRL_PREFETCH_0:0)| + (prefetchable[1]?PCCBBM_BRIDGECTRL_PREFETCH_1:0); + pci_write_config(sc->sc_dev, PCCBBR_BRIDGECTRL, reg, 2); } else if (type == SYS_RES_IOPORT) { pccbb_cardbus_io_open(sc->sc_dev, 0, starts[0], ends[0]); pccbb_cardbus_io_open(sc->sc_dev, 1, starts[1], ends[1]); @@ -1108,84 +1120,119 @@ } static int -pccbb_cardbus_activate_resource(device_t self, device_t child, int type, - int rid, struct resource *r) +pccbb_cardbus_activate_resource(device_t brdev, device_t child, int type, + int rid, struct resource *res) { - struct pccbb_softc *sc = device_get_softc(self); - struct pccbb_reslist *rle; + int ret; - if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { - SLIST_FOREACH(rle, &sc->rl, entries) { - if (type == rle->type && rid == rle->rid && - child == rle->odev) - return bus_generic_activate_resource( - self, child, type, rid, r); - } - rle = malloc(sizeof(struct pccbb_reslist), M_DEVBUF, M_WAITOK); - rle->type = type; - rle->rid = rid; - rle->start = rman_get_start(r); - rle->end = rman_get_end(r); - rle->odev = child; - rle->win = -1; - SLIST_INSERT_HEAD(&sc->rl, rle, entries); - - pccbb_cardbus_auto_open(sc, type); - } - return bus_generic_activate_resource(self, child, type, rid, r); + ret = BUS_ACTIVATE_RESOURCE(device_get_parent(brdev), child, + type, rid, res); + if (ret != 0) return ret; + pccbb_cardbus_auto_open(device_get_softc(brdev), type); + return 0; } static int -pccbb_cardbus_deactivate_resource(device_t self, device_t child, int type, - int rid, struct resource *r) +pccbb_cardbus_deactivate_resource(device_t brdev, device_t child, int type, + int rid, struct resource *res) { - struct pccbb_softc *sc = device_get_softc(self); - struct pccbb_reslist *rle; + int ret; - SLIST_FOREACH(rle, &sc->rl, entries) { - if (type == rle->type && rid == rle->rid && - child == rle->odev) { - SLIST_REMOVE(&sc->rl, rle, pccbb_reslist, entries); - if (type == SYS_RES_IOPORT || - type == SYS_RES_MEMORY) - pccbb_cardbus_auto_open(sc, type); - free(rle, M_DEVBUF); - break; - } - } - return bus_generic_deactivate_resource(self, child, type, rid, r); + ret = BUS_DEACTIVATE_RESOURCE(device_get_parent(brdev), child, + type, rid, res); + if (ret != 0) return ret; + pccbb_cardbus_auto_open(device_get_softc(brdev), type); + return 0; } static struct resource* -pccbb_cardbus_alloc_resource(device_t self, device_t child, int type, int* rid, +pccbb_cardbus_alloc_resource(device_t brdev, device_t child, int type, int* rid, u_long start, u_long end, u_long count, u_int flags) { - if (type == SYS_RES_IRQ) { - struct pccbb_softc *sc = device_get_softc(self); - if (start == 0) { - start = end = rman_get_start(sc->sc_irq_res); + struct pccbb_softc *sc = device_get_softc(brdev); + struct pccbb_reslist *rle; + int tmp; + struct resource *res; + + switch (type) { + case SYS_RES_IRQ: + tmp = rman_get_start(sc->sc_irq_res); + if (start > tmp || end < tmp || count != 1) { + device_printf(child, "requested interrupt %ld-%ld," + "count = %ld not supported by pccbb\n", + start, end, count); + return NULL; } - return bus_generic_alloc_resource(self, child, type, rid, - start, end, count, flags); - } else { - if (type == SYS_RES_MEMORY && start == 0 && end == ~0) { - start = CARDBUS_SYS_RES_MEMORY_START; - end = CARDBUS_SYS_RES_MEMORY_END; - } else if (type == SYS_RES_IOPORT && start == 0 && end == ~0) { + start = end = tmp; + break; + case SYS_RES_IOPORT: + if (start < CARDBUS_SYS_RES_IOPORT_START) start = CARDBUS_SYS_RES_IOPORT_START; + if (end > CARDBUS_SYS_RES_IOPORT_END) end = CARDBUS_SYS_RES_IOPORT_END; - } - return bus_generic_alloc_resource(self, child, type, rid, - start, end, count, flags); + break; + case SYS_RES_MEMORY: + if (start < CARDBUS_SYS_RES_MEMORY_START) + start = CARDBUS_SYS_RES_MEMORY_START; + if (end > CARDBUS_SYS_RES_MEMORY_END) + end = CARDBUS_SYS_RES_MEMORY_END; + break; } + + res = BUS_ALLOC_RESOURCE(device_get_parent(brdev), child, type, rid, + start, end, count, flags & ~RF_ACTIVE); + if (res == NULL) { + printf("pccbb alloc res fail\n"); + return NULL; + } + + /* + * Need to record allocated resource so we can iterate through + * it later. + */ + rle = malloc(sizeof(struct pccbb_reslist), M_DEVBUF, M_NOWAIT); + if (!res) + panic("pccbb_cardbus_alloc_resource: can't record entry!"); + rle->res = res; + rle->type = type; + rle->rid = *rid; + rle->cardaddr = 0; + SLIST_INSERT_HEAD(&sc->rl, rle, link); + + if (flags & RF_ACTIVE) + if (bus_activate_resource(child, type, *rid, res) != 0) { + bus_release_resource(child, type, *rid, res); + return NULL; + } + + return res; } static int -pccbb_cardbus_release_resource(device_t self, device_t child, int type, - int rid, struct resource *r) +pccbb_cardbus_release_resource(device_t brdev, device_t child, int type, + int rid, struct resource *res) { - return bus_generic_release_resource(self, child, type, rid, r); + struct pccbb_softc *sc = device_get_softc(brdev); + struct pccbb_reslist *rle; + + if (rman_get_flags(res) & RF_ACTIVE) { + int error; + error = bus_deactivate_resource(child, type, rid, res); + if (error != 0) + return error; + } + + SLIST_FOREACH(rle, &sc->rl, link) { + if (rle->res == res) { + SLIST_REMOVE(&sc->rl, rle, pccbb_reslist, link); + free(rle, M_DEVBUF); + break; + } + } + + return BUS_RELEASE_RESOURCE(device_get_parent(brdev), child, + type, rid, res); } /************************************************************************/ @@ -1193,23 +1240,23 @@ /************************************************************************/ static int -pccbb_pcic_power_enable_socket(device_t self, device_t child) +pccbb_pcic_power_enable_socket(device_t brdev, device_t child) { - struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_softc *sc = device_get_softc(brdev); DPRINTF(("pccbb_pcic_socket_enable:\n")); /* power down/up the socket to reset */ { - int voltage = pccbb_detect_voltage(self); + int voltage = pccbb_detect_voltage(brdev); - pccbb_power(self, CARD_VCC_0V | CARD_VPP_0V); + pccbb_power(brdev, CARD_VCC_0V | CARD_VPP_0V); if (voltage & CARD_5V_CARD) - pccbb_power(self, CARD_VCC_5V | CARD_VPP_VCC); + pccbb_power(brdev, CARD_VCC_5V | CARD_VPP_VCC); else if (voltage & CARD_3V_CARD) - pccbb_power(self, CARD_VCC_3V | CARD_VPP_VCC); + pccbb_power(brdev, CARD_VCC_3V | CARD_VPP_VCC); else { - device_printf(self, "Unknown card voltage\n"); + device_printf(brdev, "Unknown card voltage\n"); return ENXIO; } } @@ -1259,9 +1306,9 @@ } static void -pccbb_pcic_power_disable_socket(device_t self, device_t child) +pccbb_pcic_power_disable_socket(device_t brdev, device_t child) { - struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_softc *sc = device_get_softc(brdev); DPRINTF(("pccbb_pcic_socket_disable\n")); @@ -1270,8 +1317,8 @@ DELAY(2*1000); /* power down the socket */ + pccbb_power(brdev, CARD_VCC_0V | CARD_VPP_0V); PCIC_MASK(sc, PCIC_PWRCTL, &~PCIC_PWRCTL_OE); - pccbb_power(self, CARD_VCC_0V | CARD_VPP_0V); /* wait 300ms until power fails (Tpf). */ DELAY(300 * 1000); @@ -1378,39 +1425,46 @@ } static int -pccbb_pcic_mem_map(struct pccbb_softc *sc, int kind, - struct resource *r, bus_addr_t card_addr, int *win) +pccbb_pcic_mem_map(struct pccbb_softc *sc, int kind, struct resource *res) { - int i; + int win; + struct pccbb_reslist *rle; + bus_addr_t card_addr; - *win = -1; - for (i = 0; i < PCIC_MEM_WINS; i++) { - if ((sc->memalloc & (1 << i)) == 0) { - *win = i; - sc->memalloc |= (1 << i); + for (win = 0; win < PCIC_MEM_WINS; win++) { + if ((sc->memalloc & (1 << win)) == 0) { + sc->memalloc |= (1 << win); break; } } - if (*win == -1) + if (win >= PCIC_MEM_WINS) return (1); - card_addr = card_addr - card_addr % PCIC_MEM_PAGESIZE; - sc->mem[*win].memt = rman_get_bustag(r); - sc->mem[*win].memh = rman_get_bushandle(r); - sc->mem[*win].addr = rman_get_start(r); - sc->mem[*win].size = rman_get_end(r) - sc->mem[*win].addr + 1; - sc->mem[*win].realsize = sc->mem[*win].size + PCIC_MEM_PAGESIZE - 1; - sc->mem[*win].realsize = sc->mem[*win].realsize - - (sc->mem[*win].realsize % PCIC_MEM_PAGESIZE); - sc->mem[*win].offset = ((long)card_addr) - - ((long)(sc->mem[*win].addr)); - sc->mem[*win].kind = kind; + SLIST_FOREACH(rle, &sc->rl, link) { + if (rle->res == res) + break; + } + if (!rle) { + device_printf(sc->sc_dev, "pcic_map_mem: Memory resource not found\n"); + return ENXIO; + } + card_addr = rle->cardaddr - rle->cardaddr % PCIC_MEM_PAGESIZE; + sc->mem[win].memt = rman_get_bustag(res); + sc->mem[win].memh = rman_get_bushandle(res); + sc->mem[win].addr = rman_get_start(res); + sc->mem[win].size = rman_get_end(res) - sc->mem[win].addr + 1; + sc->mem[win].realsize = sc->mem[win].size + PCIC_MEM_PAGESIZE - 1; + sc->mem[win].realsize = sc->mem[win].realsize - + (sc->mem[win].realsize % PCIC_MEM_PAGESIZE); + sc->mem[win].offset = ((long)card_addr) - + ((long)(sc->mem[win].addr)); + sc->mem[win].kind = kind; DPRINTF(("pccbb_pcic_mem_map window %d bus %x+%x+%lx card addr %x\n", - *win, sc->mem[*win].addr, sc->mem[*win].size, - sc->mem[*win].offset, card_addr)); + win, sc->mem[win].addr, sc->mem[win].size, + sc->mem[win].offset, card_addr)); - pccbb_pcic_do_mem_map(sc, *win); + pccbb_pcic_do_mem_map(sc, win); return (0); } @@ -1425,6 +1479,21 @@ sc->memalloc &= ~(1 << window); } +static int +pccbb_pcic_mem_findmap(struct pccbb_softc *sc, struct resource *res) +{ + int win; + + for (win = 0; win < PCIC_MEM_WINS; win++) { + if (sc->mem[win].memt == rman_get_bustag(res) && + sc->mem[win].addr == rman_get_start(res) && + sc->mem[win].size == rman_get_size(res)) + return win; + } + device_printf(sc->sc_dev, "Memory map not found!\n"); + return -1; +} + #define PCIC_IOINFO(NUM) { \ PCIC_IOADDR ## NUM ## _START_LSB, \ PCIC_IOADDR ## NUM ## _START_MSB, \ @@ -1458,7 +1527,8 @@ }; #undef PCIC_IOINFO -static void pccbb_pcic_do_io_map(struct pccbb_softc *sc, int win) +static void +pccbb_pcic_do_io_map(struct pccbb_softc *sc, int win) { PCIC_WRITE(sc, io_map_index[win].start_lsb, sc->io[win].addr & 0xff); PCIC_WRITE(sc, io_map_index[win].start_msb, @@ -1489,37 +1559,34 @@ } static int -pccbb_pcic_io_map(struct pccbb_softc *sc, int width, - struct resource *r, bus_addr_t card_addr, int *win) +pccbb_pcic_io_map(struct pccbb_softc *sc, int width, struct resource *r) { - int i; + int win; #ifdef CBB_DEBUG static char *width_names[] = { "auto", "io8", "io16"}; #endif - *win = -1; - for (i=0; i < PCIC_IO_WINS; i++) { - if ((sc->ioalloc & (1 << i)) == 0) { - *win = i; - sc->ioalloc |= (1 << i); + for (win=0; win < PCIC_IO_WINS; win++) { + if ((sc->ioalloc & (1 << win)) == 0) { + sc->ioalloc |= (1 << win); break; } } - if (*win == -1) + if (win >= PCIC_IO_WINS) return (1); - sc->io[*win].iot = rman_get_bustag(r); - sc->io[*win].ioh = rman_get_bushandle(r); - sc->io[*win].addr = rman_get_start(r); - sc->io[*win].size = rman_get_end(r) - sc->io[*win].addr + 1; - sc->io[*win].flags = 0; - sc->io[*win].width = width; + sc->io[win].iot = rman_get_bustag(r); + sc->io[win].ioh = rman_get_bushandle(r); + sc->io[win].addr = rman_get_start(r); + sc->io[win].size = rman_get_end(r) - sc->io[win].addr + 1; + sc->io[win].flags = 0; + sc->io[win].width = width; DPRINTF(("pccbb_pcic_io_map window %d %s port %x+%x\n", - *win, width_names[width], sc->io[*win].addr, - sc->io[*win].size)); + win, width_names[width], sc->io[win].addr, + sc->io[win].size)); - pccbb_pcic_do_io_map(sc, *win); + pccbb_pcic_do_io_map(sc, win); return (0); } @@ -1543,84 +1610,86 @@ } static int -pccbb_pcic_activate_resource(device_t self, device_t child, int type, int rid, - struct resource *r) +pccbb_pcic_io_findmap(struct pccbb_softc *sc, struct resource *res) { - int err; int win; - struct pccbb_reslist *rle; - struct pccbb_softc *sc = device_get_softc(self); - if (rman_get_flags(r) & RF_ACTIVE) - return 0; - - switch (type) { - case SYS_RES_IOPORT: - err = pccbb_pcic_io_map(sc, 0, r, 0, &win); - if (err) - return err; - break; - case SYS_RES_MEMORY: - err = pccbb_pcic_mem_map(sc, 0, r, 0, &win); - if (err) - return err; - break; - default: - break; + for (win = 0; win < PCIC_IO_WINS; win++) { + if (sc->io[win].iot == rman_get_bustag(res) && + sc->io[win].addr == rman_get_start(res) && + sc->io[win].size == rman_get_size(res)) + return win; } - SLIST_FOREACH(rle, &sc->rl, entries) { - if (type == rle->type && rid == rle->rid && - child == rle->odev) { - rle->win = win; + device_printf(sc->sc_dev, "IO map not found!\n"); + return -1; +} + +static int +pccbb_pcic_activate_resource(device_t brdev, device_t child, int type, int rid, + struct resource *res) +{ + int err; + struct pccbb_softc *sc = device_get_softc(brdev); + if (!(rman_get_flags(res) & RF_ACTIVE)) { /* not already activated */ + switch (type) { + case SYS_RES_IOPORT: + err = pccbb_pcic_io_map(sc, 0, res); + break; + case SYS_RES_MEMORY: + err = pccbb_pcic_mem_map(sc, 0, res); break; + default: + err = 0; + break; } + if (err) + return err; + } - err = bus_generic_activate_resource(self, child, type, rid, r); - return (err); + return BUS_ACTIVATE_RESOURCE(device_get_parent(brdev), child, + type, rid, res); } static int -pccbb_pcic_deactivate_resource(device_t self, device_t child, int type, - int rid, struct resource *r) +pccbb_pcic_deactivate_resource(device_t brdev, device_t child, int type, + int rid, struct resource *res) { - struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_softc *sc = device_get_softc(brdev); int win; - struct pccbb_reslist *rle; - win = -1; - SLIST_FOREACH(rle, &sc->rl, entries) { - if (type == rle->type && rid == rle->rid && - child == rle->odev) { - win = rle->win; + + if (rman_get_flags(res) & RF_ACTIVE) { /* if activated */ + switch (type) { + case SYS_RES_IOPORT: + win = pccbb_pcic_io_findmap(sc, res); + if (win >= 0) + pccbb_pcic_io_unmap(sc, win); + else + return ENOENT; + break; + case SYS_RES_MEMORY: + win = pccbb_pcic_mem_findmap(sc, res); + if (win >= 0) + pccbb_pcic_mem_unmap(sc, win); + else + return ENOENT; break; } - } - if (win == -1) { - panic("pccbb_pcic: deactivating bogus resoure"); - return 1; - } - - switch (type) { - case SYS_RES_IOPORT: - pccbb_pcic_io_unmap(sc, win); - break; - case SYS_RES_MEMORY: - pccbb_pcic_mem_unmap(sc, win); - break; - default: - break; } - return bus_generic_deactivate_resource(self, child, type, rid, r); + return BUS_DEACTIVATE_RESOURCE(device_get_parent(brdev), child, + type, rid, res); } static struct resource* -pccbb_pcic_alloc_resource(device_t self, device_t child, int type, int* rid, +pccbb_pcic_alloc_resource(device_t brdev, device_t child, int type, int* rid, u_long start, u_long end, u_long count, u_int flags) { - struct resource *r = NULL; - struct pccbb_softc *sc = device_get_softc(self); + struct resource *res = NULL; + struct pccbb_softc *sc = device_get_softc(brdev); struct pccbb_reslist *rle; + int tmp; if ((sc->sc_flags & PCCBB_PCIC_MEM_32) == 0) { + /* XXX: how do we do this? */ panic("PCCBB bridge cannot handle non MEM_32 bridges\n"); } @@ -1629,7 +1698,7 @@ /* Nearly default */ if (start == 0 && end == ~0 && count != 1) { start = CARDBUS_SYS_RES_MEMORY_START; /* XXX -- should be tweakable*/ - end = CARDBUS_SYS_RES_MEMORY_END; + end = CARDBUS_SYS_RES_MEMORY_END; /* XXX: do we need this magik? */ } flags = (flags & ~RF_ALIGNMENT_MASK) | rman_make_alignment_flags(PCCBB_MEMALIGN); @@ -1641,41 +1710,47 @@ end = start; break; case SYS_RES_IRQ: + tmp = rman_get_start(sc->sc_irq_res); + if (start > tmp || end < tmp || count != 1) { + device_printf(child, "requested interrupt %ld-%ld," + "count = %ld not supported by pccbb\n", + start, end, count); + return NULL; + } flags |= RF_SHAREABLE; start = end = rman_get_start(sc->sc_irq_res); break; } - r = bus_generic_alloc_resource(self, child, type, rid, start, end, - count, flags & ~RF_ACTIVE); - if (r == NULL) + res = BUS_ALLOC_RESOURCE(device_get_parent(brdev), child, type, rid, + start, end, count, flags & ~RF_ACTIVE); + if (res == NULL) return NULL; - rle = malloc(sizeof(struct pccbb_reslist), M_DEVBUF, M_WAITOK); + rle = malloc(sizeof(struct pccbb_reslist), M_DEVBUF, M_NOWAIT); + if (!rle) + panic("pccbb_pcic_alloc_resource: can't record entry!"); + rle->res = res; rle->type = type; rle->rid = *rid; - rle->start = rman_get_start(r); - rle->end = rman_get_end(r); - rle->odev = child; - rle->win = -1; - SLIST_INSERT_HEAD(&sc->rl, rle, entries); + rle->cardaddr = 0; + SLIST_INSERT_HEAD(&sc->rl, rle, link); if (flags & RF_ACTIVE) { - if (bus_activate_resource(child, type, *rid, r) != 0) { - BUS_RELEASE_RESOURCE(self, child, type, *rid, r); + if (bus_activate_resource(child, type, *rid, res) != 0) { + bus_release_resource(child, type, *rid, res); return NULL; } } - return r; + return res; } static int -pccbb_pcic_release_resource(device_t self, device_t child, int type, +pccbb_pcic_release_resource(device_t brdev, device_t child, int type, int rid, struct resource *res) { - struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_softc *sc = device_get_softc(brdev); struct pccbb_reslist *rle; - int count = 0; if (rman_get_flags(res) & RF_ACTIVE) { int error; @@ -1684,20 +1759,16 @@ return error; } - SLIST_FOREACH(rle, &sc->rl, entries) { - if (type == rle->type && rid == rle->rid && - child == rle->odev) { - SLIST_REMOVE(&sc->rl, rle, pccbb_reslist, entries); + SLIST_FOREACH(rle, &sc->rl, link) { + if (rle->res == res) { + SLIST_REMOVE(&sc->rl, rle, pccbb_reslist, link); free(rle, M_DEVBUF); - count++; break; } } - if (count == 0) { - panic("pccbb_pcic: releasing bogus resource"); - } - return bus_generic_release_resource(self, child, type, rid, res); + return BUS_RELEASE_RESOURCE(device_get_parent(brdev), child, + type, rid, res); } /************************************************************************/ @@ -1705,46 +1776,81 @@ /************************************************************************/ static int -pccbb_pcic_set_res_flags(device_t self, device_t child, int type, int rid, +pccbb_pcic_set_res_flags(device_t brdev, device_t child, int type, int rid, u_int32_t flags) { - struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_softc *sc = device_get_softc(brdev); + struct resource *res; + struct pccbb_reslist *rle; + int win; + res = NULL; if (type != SYS_RES_MEMORY) return (EINVAL); - sc->mem[rid].kind = flags; - pccbb_pcic_do_mem_map(sc, rid); + SLIST_FOREACH(rle, &sc->rl, link) { + if (SYS_RES_MEMORY == rle->type && rid == rle->rid && + child == rle->res->r_dev) { + res = rle->res; + break; + } + } + + if (res == NULL) { + device_printf(brdev, + "set_res_flags: specified rid not found\n"); + return ENOENT; + } + win = pccbb_pcic_mem_findmap(sc, res); + if (win < 0) { + device_printf(brdev, + "set_res_flags: specified resource not active\n"); + return ENOENT; + } + + sc->mem[win].kind = flags; + pccbb_pcic_do_mem_map(sc, win); return 0; } static int -pccbb_pcic_set_memory_offset(device_t self, device_t child, int rid, +pccbb_pcic_set_memory_offset(device_t brdev, device_t child, int rid, u_int32_t cardaddr, u_int32_t *deltap) { - struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_softc *sc = device_get_softc(brdev); int win; struct pccbb_reslist *rle; + struct resource *res; u_int32_t delta; win = -1; - SLIST_FOREACH(rle, &sc->rl, entries) { + res = NULL; + SLIST_FOREACH(rle, &sc->rl, link) { if (SYS_RES_MEMORY == rle->type && rid == rle->rid && - child == rle->odev) { - win = rle->win; + child == rle->res->r_dev) { + res = rle->res; + rle->cardaddr = cardaddr; break; } } - if (win == -1) { - panic("pccbb_pcic: setting memory offset of bogus resource"); - return 1; + + if (res == NULL) { + device_printf(brdev, + "set_memory_offset: specified rid not found\n"); + return ENOENT; + } + win = pccbb_pcic_mem_findmap(sc, res); + if (win < 0) { + device_printf(brdev, + "set_memory_offset: specified resource not active\n"); + return ENOENT; } delta = cardaddr % PCIC_MEM_PAGESIZE; if (deltap) *deltap = delta; cardaddr -= delta; - sc->mem[win].realsize = sc->mem[win].size + delta + + sc->mem[win].realsize = sc->mem[win].size + delta + PCIC_MEM_PAGESIZE - 1; sc->mem[win].realsize = sc->mem[win].realsize - (sc->mem[win].realsize % PCIC_MEM_PAGESIZE); @@ -1759,24 +1865,24 @@ /************************************************************************/ static int -pccbb_power_enable_socket(device_t self, device_t child) +pccbb_power_enable_socket(device_t brdev, device_t child) { - struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_softc *sc = device_get_softc(brdev); if (sc->sc_flags & PCCBB_16BIT_CARD) - return pccbb_pcic_power_enable_socket(self, child); + return pccbb_pcic_power_enable_socket(brdev, child); else - return pccbb_cardbus_power_enable_socket(self, child); + return pccbb_cardbus_power_enable_socket(brdev, child); } static void -pccbb_power_disable_socket(device_t self, device_t child) +pccbb_power_disable_socket(device_t brdev, device_t child) { - struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_softc *sc = device_get_softc(brdev); if (sc->sc_flags & PCCBB_16BIT_CARD) - pccbb_pcic_power_disable_socket(self, child); + pccbb_pcic_power_disable_socket(brdev, child); else - pccbb_cardbus_power_disable_socket(self, child); + pccbb_cardbus_power_disable_socket(brdev, child); } /************************************************************************/ /* BUS Methods */ @@ -1784,64 +1890,64 @@ static int -pccbb_activate_resource(device_t self, device_t child, int type, int rid, +pccbb_activate_resource(device_t brdev, device_t child, int type, int rid, struct resource *r) { - struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_softc *sc = device_get_softc(brdev); if (sc->sc_flags & PCCBB_16BIT_CARD) - return pccbb_pcic_activate_resource(self, child, type, rid, r); + return pccbb_pcic_activate_resource(brdev, child, type, rid, r); else - return pccbb_cardbus_activate_resource(self, child, type, rid, + return pccbb_cardbus_activate_resource(brdev, child, type, rid, r); } static int -pccbb_deactivate_resource(device_t self, device_t child, int type, +pccbb_deactivate_resource(device_t brdev, device_t child, int type, int rid, struct resource *r) { - struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_softc *sc = device_get_softc(brdev); if (sc->sc_flags & PCCBB_16BIT_CARD) - return pccbb_pcic_deactivate_resource(self, child, type, + return pccbb_pcic_deactivate_resource(brdev, child, type, rid, r); else - return pccbb_cardbus_deactivate_resource(self, child, type, + return pccbb_cardbus_deactivate_resource(brdev, child, type, rid, r); } static struct resource* -pccbb_alloc_resource(device_t self, device_t child, int type, int* rid, +pccbb_alloc_resource(device_t brdev, device_t child, int type, int* rid, u_long start, u_long end, u_long count, u_int flags) { - struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_softc *sc = device_get_softc(brdev); if (sc->sc_flags & PCCBB_16BIT_CARD) - return pccbb_pcic_alloc_resource(self, child, type, rid, + return pccbb_pcic_alloc_resource(brdev, child, type, rid, start, end, count, flags); else - return pccbb_cardbus_alloc_resource(self, child, type, rid, + return pccbb_cardbus_alloc_resource(brdev, child, type, rid, start, end, count, flags); } static int -pccbb_release_resource(device_t self, device_t child, int type, int rid, +pccbb_release_resource(device_t brdev, device_t child, int type, int rid, struct resource *r) { - struct pccbb_softc *sc = device_get_softc(self); + struct pccbb_softc *sc = device_get_softc(brdev); if (sc->sc_flags & PCCBB_16BIT_CARD) - return pccbb_pcic_release_resource(self, child, type, + return pccbb_pcic_release_resource(brdev, child, type, rid, r); else - return pccbb_cardbus_release_resource(self, child, type, + return pccbb_cardbus_release_resource(brdev, child, type, rid, r); } static int -pccbb_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +pccbb_read_ivar(device_t brdev, device_t child, int which, uintptr_t *result) { - struct pccbb_softc *sc = device_get_softc(dev); + struct pccbb_softc *sc = device_get_softc(brdev); switch (which) { case PCIB_IVAR_BUS: @@ -1852,9 +1958,9 @@ } static int -pccbb_write_ivar(device_t dev, device_t child, int which, uintptr_t value) +pccbb_write_ivar(device_t brdev, device_t child, int which, uintptr_t value) { - struct pccbb_softc *sc = device_get_softc(dev); + struct pccbb_softc *sc = device_get_softc(brdev); switch (which) { case PCIB_IVAR_BUS: @@ -1869,29 +1975,29 @@ /************************************************************************/ static int -pccbb_maxslots(device_t dev) +pccbb_maxslots(device_t brdev) { return 0; } static u_int32_t -pccbb_read_config(device_t dev, int b, int s, int f, int reg, int width) +pccbb_read_config(device_t brdev, int b, int s, int f, int reg, int width) { /* * Pass through to the next ppb up the chain (i.e. our grandparent). */ - return PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), + return PCIB_READ_CONFIG(device_get_parent(device_get_parent(brdev)), b, s, f, reg, width); } static void -pccbb_write_config(device_t dev, int b, int s, int f, int reg, u_int32_t val, +pccbb_write_config(device_t brdev, int b, int s, int f, int reg, u_int32_t val, int width) { /* * Pass through to the next ppb up the chain (i.e. our grandparent). */ - PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), + PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(brdev)), b, s, f, reg, val, width); } @@ -1900,6 +2006,7 @@ DEVMETHOD(device_probe, pccbb_probe), DEVMETHOD(device_attach, pccbb_attach), DEVMETHOD(device_detach, pccbb_detach), + DEVMETHOD(device_shutdown, pccbb_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), @@ -1919,6 +2026,7 @@ /* 16-bit card interface */ DEVMETHOD(card_set_res_flags, pccbb_pcic_set_res_flags), DEVMETHOD(card_set_memory_offset, pccbb_pcic_set_memory_offset), + DEVMETHOD(card_reprobe_card, pccbb_card_reprobe), /* power interface */ DEVMETHOD(power_enable_socket, pccbb_power_enable_socket), Index: sys/dev/pccbb/pccbbvar.h =================================================================== RCS file: /export/ncvs/src/sys/dev/pccbb/pccbbvar.h,v retrieving revision 1.5 diff -u -u -r1.5 pccbbvar.h --- sys/dev/pccbb/pccbbvar.h 2001/01/06 18:04:55 1.5 +++ sys/dev/pccbb/pccbbvar.h 2001/07/13 12:13:15 @@ -48,13 +48,13 @@ }; struct pccbb_reslist { - SLIST_ENTRY(pccbb_reslist) entries; + SLIST_ENTRY(pccbb_reslist) link; + struct resource *res; int type; - int rid; - u_int32_t start; - u_int32_t end; - device_t odev; - int win; + int rid; /* note: unlike the regular resource list, there can be + * duplicate rid's in the same list. However, the + * combination of rid and res->r_dev should be unique. */ + bus_addr_t cardaddr; /* for 16-bit pccard memory */ }; #define PCCBB_AUTO_OPEN_SMALLHOLE 0x100 Index: sys/dev/cardbus/cardbus.c =================================================================== RCS file: /export/ncvs/src/sys/dev/cardbus/cardbus.c,v retrieving revision 1.10 diff -u -u -r1.10 cardbus.c --- sys/dev/cardbus/cardbus.c 2001/02/08 21:47:45 1.10 +++ sys/dev/cardbus/cardbus.c 2001/07/15 19:36:27 @@ -49,8 +49,8 @@ #include #include -#include -#include +#include +#include #include #include @@ -62,11 +62,9 @@ #include "pcib_if.h" #if defined CARDBUS_DEBUG -#define STATIC #define DPRINTF(a) printf a #define DEVPRINTF(x) device_printf x #else -#define STATIC static #define DPRINTF(a) #define DEVPRINTF(x) #endif @@ -76,85 +74,35 @@ "$FreeBSD: src/sys/dev/cardbus/cardbus.c,v 1.10 2001/02/08 21:47:45 imp Exp $"; #endif -struct cardbus_quirk { - u_int32_t devid; /* Vendor/device of the card */ - int type; -#define CARDBUS_QUIRK_MAP_REG 1 /* PCI map register in weird place */ - int arg1; - int arg2; -}; - -struct cardbus_quirk cardbus_quirks[] = { - { 0 } -}; - -static int cardbus_probe(device_t dev); -static int cardbus_attach(device_t dev); -static void device_setup_regs(device_t cbdev, int b, int s, int f, - pcicfgregs *cfg); -static int cardbus_attach_card(device_t dev); -static int cardbus_detach_card(device_t dev, int flags); -static struct cardbus_devinfo *cardbus_read_device(device_t pcib, - int b, int s, int f); -static void cardbus_hdrtypedata(device_t pcib, int b, int s, int f, - pcicfgregs *cfg); -static int cardbus_freecfg(struct cardbus_devinfo *dinfo); +static int cardbus_detach_card(device_t cbdev, int flags); +static struct cardbus_devinfo * cardbus_read_device(device_t brdev, int b, + int s, int f); static void cardbus_print_verbose(struct cardbus_devinfo *dinfo); -static int cardbus_set_resource(device_t dev, device_t child, int type, - int rid, u_long start, u_long count); -static int cardbus_get_resource(device_t dev, device_t child, int type, - int rid, u_long *startp, u_long *countp); -static void cardbus_delete_resource(device_t dev, device_t child, int type, - int rid); -static int cardbus_set_resource_method(device_t dev, device_t child, int type, - int rid, u_long start, u_long count); -static int cardbus_get_resource_method(device_t dev, device_t child, int type, - int rid, u_long *startp, u_long *countp); -static int cardbus_add_map(device_t bdev, device_t dev, pcicfgregs *cfg, - int reg); -static void cardbus_add_resources(device_t dev, pcicfgregs* cfg); -static void cardbus_release_all_resources(device_t dev, - struct resource_list *rl); -static struct resource* cardbus_alloc_resource(device_t self, device_t child, - int type, int* rid,u_long start, - u_long end, u_long count, - u_int flags); -static int cardbus_release_resource(device_t dev, device_t child, int type, - int rid, struct resource *r); -static int cardbus_print_resources(struct resource_list *rl, const char *name, - int type, const char *format); -static int cardbus_print_child(device_t dev, device_t child); -static void cardbus_probe_nomatch(device_t dev, device_t child); -static int cardbus_read_ivar(device_t dev, device_t child, int which, - u_long *result); -static int cardbus_write_ivar(device_t dev, device_t child, int which, - uintptr_t value); -static u_int32_t cardbus_read_config_method(device_t dev, device_t child, - int reg, int width); -static void cardbus_write_config_method(device_t dev, device_t child, int reg, - u_int32_t val, int width); +static int cardbus_freecfg(struct cardbus_devinfo *dinfo); +static void cardbus_release_all_resources(device_t cbdev, + struct cardbus_devinfo *dinfo); /************************************************************************/ /* Probe/Attach */ /************************************************************************/ static int -cardbus_probe(device_t dev) +cardbus_probe(device_t cbdev) { - device_set_desc(dev, "Cardbus bus (newcard)"); + device_set_desc(cbdev, "Cardbus bus (newcard)"); return 0; } static int -cardbus_attach(device_t dev) +cardbus_attach(device_t cbdev) { return 0; } static int -cardbus_detach(device_t dev) +cardbus_detach(device_t cbdev) { - cardbus_detach_card(dev, DETACH_FORCE); + cardbus_detach_card(cbdev, DETACH_FORCE); return 0; } @@ -163,37 +111,38 @@ /************************************************************************/ static void -device_setup_regs(device_t bdev, int b, int s, int f, pcicfgregs *cfg) +device_setup_regs(device_t brdev, int b, int s, int f, pcicfgregs *cfg) { - PCIB_WRITE_CONFIG(bdev, b, s, f, PCIR_INTLINE, - pci_get_irq(device_get_parent(bdev)), 1); - cfg->intline = PCIB_READ_CONFIG(bdev, b, s, f, PCIR_INTLINE, 1); + PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_INTLINE, + pci_get_irq(device_get_parent(brdev)), 1); + cfg->intline = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_INTLINE, 1); - PCIB_WRITE_CONFIG(bdev, b, s, f, PCIR_CACHELNSZ, 0x08, 1); - cfg->cachelnsz = PCIB_READ_CONFIG(bdev, b, s, f, PCIR_CACHELNSZ, 1); + PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_CACHELNSZ, 0x08, 1); + cfg->cachelnsz = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_CACHELNSZ, 1); - PCIB_WRITE_CONFIG(bdev, b, s, f, PCIR_LATTIMER, 0xa8, 1); - cfg->lattimer = PCIB_READ_CONFIG(bdev, b, s, f, PCIR_LATTIMER, 1); + PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_LATTIMER, 0xa8, 1); + cfg->lattimer = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_LATTIMER, 1); - PCIB_WRITE_CONFIG(bdev, b, s, f, PCIR_MINGNT, 0x14, 1); - cfg->mingnt = PCIB_READ_CONFIG(bdev, b, s, f, PCIR_MINGNT, 1); + PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_MINGNT, 0x14, 1); + cfg->mingnt = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_MINGNT, 1); - PCIB_WRITE_CONFIG(bdev, b, s, f, PCIR_MAXLAT, 0x14, 1); - cfg->maxlat = PCIB_READ_CONFIG(bdev, b, s, f, PCIR_MAXLAT, 1); + PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_MAXLAT, 0x14, 1); + cfg->maxlat = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_MAXLAT, 1); } static int -cardbus_attach_card(device_t dev) +cardbus_attach_card(device_t cbdev) { - device_t bdev = device_get_parent(dev); + device_t brdev = device_get_parent(cbdev); int cardattached = 0; static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */ int bus, slot, func; - cardbus_detach_card(dev, DETACH_NOWARN); /* detach existing cards */ + DEVPRINTF((cbdev, "cardbus_attach_card\n")); + cardbus_detach_card(cbdev, DETACH_NOWARN); /* detach existing cards */ - POWER_ENABLE_SOCKET(bdev, dev); - bus = pcib_get_bus(dev); + POWER_ENABLE_SOCKET(brdev, cbdev); + bus = pcib_get_bus(cbdev); if (bus == 0) { /* * XXX EVILE BAD XXX @@ -202,58 +151,60 @@ * works. */ bus = curr_bus_number; - pci_write_config (bdev, PCIR_SECBUS_2, curr_bus_number, 1); - pci_write_config (bdev, PCIR_SUBBUS_2, curr_bus_number+2, 1); + pci_write_config (brdev, PCIR_SECBUS_2, curr_bus_number, 1); + pci_write_config (brdev, PCIR_SUBBUS_2, curr_bus_number+2, 1); curr_bus_number += 3; } + /* For each function, set it up and try to attach a driver to it */ for (slot = 0; slot <= CARDBUS_SLOTMAX; slot++) { int cardbusfunchigh = 0; for (func = 0; func <= cardbusfunchigh; func++) { struct cardbus_devinfo *dinfo = - cardbus_read_device(bdev, bus, slot, func); + cardbus_read_device(brdev, bus, slot, func); if (dinfo == NULL) continue; if (dinfo->cfg.mfdev) cardbusfunchigh = CARDBUS_FUNCMAX; - device_setup_regs(bdev, bus, slot, func, &dinfo->cfg); + device_setup_regs(brdev, bus, slot, func, &dinfo->cfg); cardbus_print_verbose(dinfo); - dinfo->cfg.dev = device_add_child(dev, NULL, -1); + dinfo->cfg.dev = device_add_child(cbdev, NULL, -1); if (!dinfo->cfg.dev) { - DEVPRINTF((dev, "Cannot add child!\n")); + DEVPRINTF((cbdev, "Cannot add child!\n")); cardbus_freecfg(dinfo); continue; } resource_list_init(&dinfo->resources); + SLIST_INIT(&dinfo->intrlist); device_set_ivars(dinfo->cfg.dev, dinfo); - cardbus_add_resources(dinfo->cfg.dev, &dinfo->cfg); - cardbus_do_cis(dev, dinfo->cfg.dev); + cardbus_do_cis(cbdev, dinfo->cfg.dev); if (device_probe_and_attach(dinfo->cfg.dev) != 0) { - cardbus_release_all_resources(dinfo->cfg.dev, - &dinfo->resources); + /* when fail, release all resources */ + cardbus_release_all_resources(cbdev, + dinfo); } else cardattached++; } } if (cardattached > 0) return 0; - POWER_DISABLE_SOCKET(bdev, dev); + POWER_DISABLE_SOCKET(brdev, cbdev); return ENOENT; } static int -cardbus_detach_card(device_t dev, int flags) +cardbus_detach_card(device_t cbdev, int flags) { int numdevs; device_t *devlist; int tmp; int err=0; - device_get_children(dev, &devlist, &numdevs); + device_get_children(cbdev, &devlist, &numdevs); if (numdevs == 0) { if (!(flags & DETACH_NOWARN)) { - DEVPRINTF((dev, "Detaching card: no cards to detach!\n")); - POWER_DISABLE_SOCKET(device_get_parent(dev), dev); + DEVPRINTF((cbdev,"detach_card: no card to detach!\n")); + POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev); } free(devlist, M_TEMP); return ENOENT; @@ -266,59 +217,66 @@ if (status == DS_ATTACHED || status == DS_BUSY) { if (device_detach(dinfo->cfg.dev) == 0 || flags & DETACH_FORCE){ - cardbus_release_all_resources(dinfo->cfg.dev, - &dinfo->resources); - device_delete_child(dev, devlist[tmp]); + cardbus_release_all_resources(cbdev, + dinfo); + device_delete_child(cbdev, devlist[tmp]); } else { err++; } cardbus_freecfg(dinfo); } else { - device_delete_child(dev, devlist[tmp]); + cardbus_release_all_resources(cbdev, + dinfo); + device_delete_child(cbdev, devlist[tmp]); + cardbus_freecfg(dinfo); } } if (err == 0) - POWER_DISABLE_SOCKET(device_get_parent(dev), dev); + POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev); free(devlist, M_TEMP); return err; } static void -cardbus_driver_added(device_t dev, driver_t *driver) +cardbus_driver_added(device_t cbdev, driver_t *driver) { + /* XXX check if 16-bit or cardbus! */ int numdevs; device_t *devlist; - device_t bdev = device_get_parent(dev); int tmp, cardattached; - device_get_children(dev, &devlist, &numdevs); + device_get_children(cbdev, &devlist, &numdevs); cardattached = 0; for (tmp = 0; tmp < numdevs; tmp++) { if (device_get_state(devlist[tmp]) != DS_NOTPRESENT) cardattached++; } + + free(devlist, M_TEMP); + + if (cardattached == 0) { + CARD_REPROBE_CARD(device_get_parent(cbdev), cbdev); + return; + } - if (cardattached == 0) - POWER_ENABLE_SOCKET(bdev, dev); - DEVICE_IDENTIFY(driver, dev); + DEVICE_IDENTIFY(driver, cbdev); for (tmp = 0; tmp < numdevs; tmp++) { if (device_get_state(devlist[tmp]) == DS_NOTPRESENT){ struct cardbus_devinfo *dinfo; dinfo = device_get_ivars(devlist[tmp]); + cardbus_release_all_resources(cbdev, + dinfo); resource_list_init(&dinfo->resources); - cardbus_add_resources(dinfo->cfg.dev, &dinfo->cfg); - cardbus_do_cis(dev, dinfo->cfg.dev); + cardbus_do_cis(cbdev, dinfo->cfg.dev); if (device_probe_and_attach(dinfo->cfg.dev) != 0) { - cardbus_release_all_resources(dinfo->cfg.dev, - &dinfo->resources); + cardbus_release_all_resources(cbdev, + dinfo); } else cardattached++; } } - if (cardattached == 0) - POWER_DISABLE_SOCKET(bdev, dev); free(devlist, M_TEMP); } @@ -328,16 +286,92 @@ /* read configuration header into pcicfgrect structure */ +static void +cardbus_read_extcap(device_t cbdev, pcicfgregs *cfg) +{ +#define REG(n, w) PCIB_READ_CONFIG(cbdev, cfg->bus, cfg->slot, cfg->func, n, w) + int ptr, nextptr, ptrptr; + + switch (cfg->hdrtype) { + case 0: + ptrptr = 0x34; + break; + case 2: + ptrptr = 0x14; + break; + default: + return; /* no extended capabilities support */ + } + nextptr = REG(ptrptr, 1); /* sanity check? */ + + /* + * Read capability entries. + */ + while (nextptr != 0) { + /* Sanity check */ + if (nextptr > 255) { + printf("illegal PCI extended capability offset %d\n", + nextptr); + return; + } + /* Find the next entry */ + ptr = nextptr; + nextptr = REG(ptr + 1, 1); + + /* Process this entry */ + switch (REG(ptr, 1)) { + case 0x01: /* PCI power management */ + if (cfg->pp_cap == 0) { + cfg->pp_cap = REG(ptr + PCIR_POWER_CAP, 2); + cfg->pp_status = ptr + PCIR_POWER_STATUS; + cfg->pp_pmcsr = ptr + PCIR_POWER_PMCSR; + if ((nextptr - ptr) > PCIR_POWER_DATA) + cfg->pp_data = ptr + PCIR_POWER_DATA; + } + break; + default: + break; + } + } +#undef REG +} + +/* extract header type specific config data */ + +static void +cardbus_hdrtypedata(device_t brdev, int b, int s, int f, pcicfgregs *cfg) +{ +#define REG(n, w) PCIB_READ_CONFIG(brdev, b, s, f, n, w) + switch (cfg->hdrtype) { + case 0: + cfg->subvendor = REG(PCIR_SUBVEND_0, 2); + cfg->subdevice = REG(PCIR_SUBDEV_0, 2); + cfg->nummaps = PCI_MAXMAPS_0; + break; + case 1: + cfg->subvendor = REG(PCIR_SUBVEND_1, 2); + cfg->subdevice = REG(PCIR_SUBDEV_1, 2); + cfg->nummaps = PCI_MAXMAPS_1; + break; + case 2: + cfg->subvendor = REG(PCIR_SUBVEND_2, 2); + cfg->subdevice = REG(PCIR_SUBDEV_2, 2); + cfg->nummaps = PCI_MAXMAPS_2; + break; + } +#undef REG +} + static struct cardbus_devinfo * -cardbus_read_device(device_t pcib, int b, int s, int f) +cardbus_read_device(device_t brdev, int b, int s, int f) { -#define REG(n, w) PCIB_READ_CONFIG(pcib, b, s, f, n, w) +#define REG(n, w) PCIB_READ_CONFIG(brdev, b, s, f, n, w) pcicfgregs *cfg = NULL; struct cardbus_devinfo *devlist_entry = NULL; - if (PCIB_READ_CONFIG(pcib, b, s, f, PCIR_DEVVENDOR, 4) != -1) { + if (PCIB_READ_CONFIG(brdev, b, s, f, PCIR_DEVVENDOR, 4) != -1) { devlist_entry = malloc(sizeof(struct cardbus_devinfo), - M_DEVBUF, M_WAITOK | M_ZERO); + M_DEVBUF, M_WAITOK | M_ZERO); if (devlist_entry == NULL) return (NULL); @@ -396,8 +430,11 @@ cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0; cfg->hdrtype &= ~PCIM_MFDEV; + + cardbus_hdrtypedata(brdev, b, s, f, cfg); - cardbus_hdrtypedata(pcib, b, s, f, cfg); + if (REG(PCIR_STATUS, 2) & PCIM_STATUS_CAPPRESENT) + cardbus_read_extcap(brdev, cfg); devlist_entry->conf.pc_sel.pc_bus = cfg->bus; devlist_entry->conf.pc_sel.pc_dev = cfg->slot; @@ -418,32 +455,6 @@ #undef REG } -/* extract header type specific config data */ - -static void -cardbus_hdrtypedata(device_t pcib, int b, int s, int f, pcicfgregs *cfg) -{ -#define REG(n, w) PCIB_READ_CONFIG(pcib, b, s, f, n, w) - switch (cfg->hdrtype) { - case 0: - cfg->subvendor = REG(PCIR_SUBVEND_0, 2); - cfg->subdevice = REG(PCIR_SUBDEV_0, 2); - cfg->nummaps = PCI_MAXMAPS_0; - break; - case 1: - cfg->subvendor = REG(PCIR_SUBVEND_1, 2); - cfg->subdevice = REG(PCIR_SUBDEV_1, 2); - cfg->nummaps = PCI_MAXMAPS_1; - break; - case 2: - cfg->subvendor = REG(PCIR_SUBVEND_2, 2); - cfg->subdevice = REG(PCIR_SUBDEV_2, 2); - cfg->nummaps = PCI_MAXMAPS_2; - break; - } -#undef REG -} - /* free pcicfgregs structure and all depending data structures */ static int @@ -457,23 +468,30 @@ static void cardbus_print_verbose(struct cardbus_devinfo *dinfo) { - if (bootverbose) { +#ifndef CARDBUS_DEBUG + if (bootverbose) +#endif /* CARDBUS_DEBUG */ + { pcicfgregs *cfg = &dinfo->cfg; printf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n", - cfg->vendor, cfg->device, cfg->revid); + cfg->vendor, cfg->device, cfg->revid); printf("\tclass=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n", - cfg->baseclass, cfg->subclass, cfg->progif, - cfg->hdrtype, cfg->mfdev); + cfg->baseclass, cfg->subclass, cfg->progif, + cfg->hdrtype, cfg->mfdev); #ifdef CARDBUS_DEBUG - printf("\tcmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n", - cfg->cmdreg, cfg->statreg, cfg->cachelnsz); - printf("\tlattimer=0x%02x (%d ns), mingnt=0x%02x (%d ns), maxlat=0x%02x (%d ns)\n", - cfg->lattimer, cfg->lattimer * 30, - cfg->mingnt, cfg->mingnt * 250, cfg->maxlat, cfg->maxlat * 250); + printf("\tcmdreg=0x%04x, statreg=0x%04x, " + "cachelnsz=%d (dwords)\n", + cfg->cmdreg, cfg->statreg, cfg->cachelnsz); + printf("\tlattimer=0x%02x (%d ns), mingnt=0x%02x (%d ns), " + "maxlat=0x%02x (%d ns)\n", + cfg->lattimer, cfg->lattimer * 30, + cfg->mingnt, cfg->mingnt * 250, cfg->maxlat, + cfg->maxlat * 250); #endif /* CARDBUS_DEBUG */ if (cfg->intpin > 0) - printf("\tintpin=%c, irq=%d\n", cfg->intpin +'a' -1, cfg->intline); + printf("\tintpin=%c, irq=%d\n", + cfg->intpin +'a' -1, cfg->intline); } } @@ -482,24 +500,62 @@ /************************************************************************/ static int -cardbus_set_resource(device_t dev, device_t child, int type, int rid, - u_long start, u_long count) +cardbus_set_resource(device_t cbdev, device_t child, int type, int rid, + u_long start, u_long count, struct resource *res) { - struct cardbus_devinfo *dinfo = device_get_ivars(child); - struct resource_list *rl = &dinfo->resources; - resource_list_add(rl, type, rid, start, start + count - 1, count); - if (device_get_parent(child) == dev) + struct cardbus_devinfo *dinfo; + struct resource_list *rl; + struct resource_list_entry *rle; + + if (device_get_parent(child) != cbdev) + return ENOENT; + + dinfo = device_get_ivars(child); + rl = &dinfo->resources; + rle = resource_list_find(rl, type, rid); + if (rle == NULL) { + resource_list_add(rl, type, rid, start, start+count-1, count); + if (res != NULL) { + rle = resource_list_find(rl, type, rid); + rle->res = res; + } + } else { + if (rle->res == NULL) { + } else if (rle->res->r_dev == cbdev && + (!(rman_get_flags(rle->res) & RF_ACTIVE))) { + int f; + f = rman_get_flags(rle->res); + bus_release_resource(cbdev, type, rid, res); + rle->res = bus_alloc_resource(cbdev, type, &rid, + start, start+count-1, + count, f); + } else { + device_printf(cbdev, "set_resource: resource busy\n"); + return EBUSY; + } + rle->start = start; + rle->end = start + count - 1; + rle->count = count; + if (res != NULL) rle->res = res; + } + if (device_get_parent(child) == cbdev) pci_write_config(child, rid, start, 4); return 0; } static int -cardbus_get_resource(device_t dev, device_t child, int type, int rid, - u_long *startp, u_long *countp) +cardbus_get_resource(device_t cbdev, device_t child, int type, int rid, + u_long *startp, u_long *countp) { - struct cardbus_devinfo *dinfo = device_get_ivars(child); - struct resource_list *rl = &dinfo->resources; + struct cardbus_devinfo *dinfo; + struct resource_list *rl; struct resource_list_entry *rle; + + if (device_get_parent(child) != cbdev) + return ENOENT; + + dinfo = device_get_ivars(child); + rl = &dinfo->resources; rle = resource_list_find(rl, type, rid); if (!rle) return ENOENT; @@ -511,216 +567,165 @@ } static void -cardbus_delete_resource(device_t dev, device_t child, int type, int rid) +cardbus_delete_resource(device_t cbdev, device_t child, int type, int rid) { - struct cardbus_devinfo *dinfo = device_get_ivars(child); - struct resource_list *rl = &dinfo->resources; + struct cardbus_devinfo *dinfo; + struct resource_list *rl; struct resource_list_entry *rle; + + if (device_get_parent(child) != cbdev) + return; + + dinfo = device_get_ivars(child); + rl = &dinfo->resources; rle = resource_list_find(rl, type, rid); if (rle) { - if (rle->res) - bus_generic_release_resource(dev, child, type, rid, - rle->res); + if (rle->res) { + if (rle->res->r_dev != cbdev || + rman_get_flags(rle->res) & RF_ACTIVE) { + device_printf(cbdev, "delete_resource: " + "Resource still owned by child, oops. " + "(type=%d, rid=%d, addr=%lx)\n", + rle->type, rle->rid, + rman_get_start(rle->res)); + return; + } + bus_release_resource(cbdev, type, rid, rle->res); + } resource_list_delete(rl, type, rid); } - if (device_get_parent(child) == dev) + if (device_get_parent(child) == cbdev) pci_write_config(child, rid, 0, 4); } static int -cardbus_set_resource_method(device_t dev, device_t child, int type, int rid, - u_long start, u_long count) +cardbus_set_resource_method(device_t cbdev, device_t child, int type, int rid, + u_long start, u_long count) { int ret; - ret = cardbus_set_resource(dev, child, type, rid, start, count); + ret = cardbus_set_resource(cbdev, child, type, rid, start, count, NULL); if (ret != 0) return ret; - return BUS_SET_RESOURCE(device_get_parent(dev), child, type, rid, - start, count); + return BUS_SET_RESOURCE(device_get_parent(cbdev), child, type, rid, + start, count); } static int -cardbus_get_resource_method(device_t dev, device_t child, int type, int rid, - u_long *startp, u_long *countp) +cardbus_get_resource_method(device_t cbdev, device_t child, int type, int rid, + u_long *startp, u_long *countp) { int ret; - ret = cardbus_get_resource(dev, child, type, rid, startp, countp); + ret = cardbus_get_resource(cbdev, child, type, rid, startp, countp); if (ret != 0) return ret; - return BUS_GET_RESOURCE(device_get_parent(dev), child, type, rid, - startp, countp); + return BUS_GET_RESOURCE(device_get_parent(cbdev), child, type, rid, + startp, countp); } static void -cardbus_delete_resource_method(device_t dev, device_t child, - int type, int rid) +cardbus_delete_resource_method(device_t cbdev, device_t child, + int type, int rid) { - cardbus_delete_resource(dev, child, type, rid); - BUS_DELETE_RESOURCE(device_get_parent(dev), child, type, rid); + cardbus_delete_resource(cbdev, child, type, rid); + BUS_DELETE_RESOURCE(device_get_parent(cbdev), child, type, rid); } -static int -cardbus_add_map(device_t cbdev, device_t dev, pcicfgregs *cfg, int reg) -{ - struct cardbus_devinfo *dinfo = device_get_ivars(dev); - struct resource_list *rl = &dinfo->resources; - struct resource_list_entry *rle; - struct resource *res; - device_t bdev = device_get_parent(cbdev); - u_int32_t size; - u_int32_t testval; - int type; - - if (reg == CARDBUS_ROM_REG) - testval = CARDBUS_ROM_ADDRMASK; - else - testval = ~0; - - PCIB_WRITE_CONFIG(bdev, cfg->bus, cfg->slot, cfg->func, - reg, testval, 4); - - testval = PCIB_READ_CONFIG(bdev, cfg->bus, cfg->slot, cfg->func, - reg, 4); - if (testval == ~0 || testval == 0) - return 0; - - if ((testval&1) == 0) - type = SYS_RES_MEMORY; - else - type = SYS_RES_IOPORT; - - size = CARDBUS_MAPREG_MEM_SIZE(testval); - res = bus_generic_alloc_resource(cbdev, dev, type, ®, 0, ~0, size, - rman_make_alignment_flags(size)); - if (res) { - u_int32_t start = rman_get_start(res); - u_int32_t end = rman_get_end(res); - cardbus_set_resource(cbdev, dev, type, reg, start,end-start+1); - rle = resource_list_find(rl, type, reg); - rle->res = res; - } else { - device_printf(dev, "Unable to add map %02x\n", reg); - type = 0; - } - return type; -} - static void -cardbus_add_resources(device_t dev, pcicfgregs* cfg) +cardbus_release_all_resources(device_t cbdev, struct cardbus_devinfo *dinfo) { - device_t cbdev = device_get_parent(dev); - device_t bdev = device_get_parent(cbdev); - struct cardbus_devinfo *dinfo = device_get_ivars(dev); - struct resource_list *rl = &dinfo->resources; - struct cardbus_quirk *q; struct resource_list_entry *rle; - struct resource *res; - int rid; - u_int command; - int type; - int types; - int i; - - types = 0; - for (i = 0; i < cfg->nummaps; i++) { - type = cardbus_add_map(cbdev, dev, cfg, PCIR_MAPS + i*4); - types |= 0x1 << type; - } - type = cardbus_add_map(cbdev, dev, cfg, CARDBUS_ROM_REG); - types |= 0x1 << type; - - for (q = &cardbus_quirks[0]; q->devid; q++) { - if (q->devid == ((cfg->device << 16) | cfg->vendor) - && q->type == CARDBUS_QUIRK_MAP_REG) { - type = cardbus_add_map(cbdev, dev, cfg, q->arg1); - types |= 0x1 << type; - } - } - - command = PCIB_READ_CONFIG(bdev, cfg->bus, cfg->slot, - cfg->func, PCIR_COMMAND, 2); - if ((types & (0x1 << SYS_RES_MEMORY)) != 0) - command |= PCIM_CMD_MEMEN; - if ((types & (0x1 << SYS_RES_IOPORT)) != 0) - command |= PCIM_CMD_PORTEN; - command |= PCIM_CMD_BUSMASTEREN; - PCIB_WRITE_CONFIG(bdev, cfg->bus, cfg->slot, cfg->func, - PCIR_COMMAND, command, 2); - - rid = 0; - res = bus_generic_alloc_resource(cbdev, dev, SYS_RES_IRQ, - &rid, 0, ~0, 1, RF_SHAREABLE); - - if (res == NULL) - panic("Cannot allocate IRQ for card\n"); - - resource_list_add(rl, SYS_RES_IRQ, rid, - rman_get_start(res), rman_get_start(res), 1); - rle = resource_list_find(rl, SYS_RES_IRQ, rid); - rle->res = res; -} + struct cardbus_intrlist *ile; -static void -cardbus_release_all_resources(device_t dev, struct resource_list *rl) -{ - struct resource_list_entry *rle; + /* Remove any interrupt handlers */ + while (NULL != (ile = SLIST_FIRST(&dinfo->intrlist))) { + device_printf(cbdev, "release_all_resource: " + "intr handler still active, removing.\n"); + bus_teardown_intr(ile->dev, ile->irq, ile->cookie); + SLIST_REMOVE_HEAD(&dinfo->intrlist, link); + free(ile, M_DEVBUF); + } - SLIST_FOREACH(rle, rl, link) { + /* Free all allocated resources */ + SLIST_FOREACH(rle, &dinfo->resources, link) { if (rle->res) { - bus_generic_release_resource(device_get_parent(dev), - dev, rle->type, rle->rid, - rle->res); + if (rle->res->r_dev != cbdev) + device_printf(cbdev, "release_all_resource: " + "Resource still owned by child, oops. " + "(type=%d, rid=%d, addr=%lx)\n", + rle->type, rle->rid, + rman_get_start(rle->res)); + BUS_RELEASE_RESOURCE(device_get_parent(cbdev), + rle->res->r_dev, + rle->type, rle->rid, + rle->res); + rle->res = NULL; + /* + * zero out config so the card won't acknowledge + * access to the space anymore + */ + pci_write_config(dinfo->cfg.dev, rle->rid, 0, 4); } } + resource_list_free(&dinfo->resources); } static struct resource* -cardbus_alloc_resource(device_t self, device_t child, int type, - int* rid, u_long start, u_long end, - u_long count, u_int flags) +cardbus_alloc_resource(device_t cbdev, device_t child, int type, + int* rid, u_long start, u_long end, u_long count, u_int flags) { - struct cardbus_devinfo *dinfo = device_get_ivars(child); - struct resource_list *rl = &dinfo->resources; - struct resource_list_entry *rle = NULL; - struct resource *res; + struct cardbus_devinfo *dinfo; + struct resource_list_entry *rle = 0; + int passthrough = (device_get_parent(child) != cbdev); - if (device_get_parent(child) == self || child == self) - rle = resource_list_find(rl, type, *rid); - if (rle) { - if (flags & RF_ACTIVE) { - if (bus_activate_resource(child, rle->type, *rid, - rle->res)) { - return NULL; - } - if (*rid == CARDBUS_ROM_REG) { - uint32_t rom_reg; + if (passthrough) { + return (BUS_ALLOC_RESOURCE(device_get_parent(cbdev), child, + type, rid, start, end, count, flags)); + } - rom_reg = pci_read_config(child, *rid, 4); - rom_reg |= CARDBUS_ROM_ENABLE; - pci_write_config(child, *rid, rom_reg, 4); - } - } - return rle->res; /* XXX: check if range within start/end */ + dinfo = device_get_ivars(child); + rle = resource_list_find(&dinfo->resources, type, *rid); + + if (!rle) + return NULL; /* no resource of that type/rid */ + + if (!rle->res) { + device_printf(cbdev, "WARNING: Resource not reserved by bus\n"); + return NULL; } else { - res = bus_generic_alloc_resource(self, child, type, rid, - start, end, count, flags); - if (res) { - start = rman_get_start(res); - end = rman_get_end(res); - cardbus_set_resource(self, child, type, *rid, start, - end-start+1); - rle = resource_list_find(rl, type, *rid); - rle->res = res; - return res; - } else { - device_printf(self, "Resource Allocation Failed!\n"); - return NULL; + /* Release the cardbus hold on the resource */ + if (rle->res->r_dev != cbdev) return NULL; + bus_release_resource(cbdev, type, *rid, rle->res); + rle->res = NULL; + switch(type) { + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + if (!(flags & RF_ALIGNMENT_MASK)) + flags |= rman_make_alignment_flags(rle->count); + break; + case SYS_RES_IRQ: + flags |= RF_SHAREABLE; + break; } + /* Allocate the resource to the child */ + return resource_list_alloc(&dinfo->resources, cbdev, child, + type, rid, rle->start, rle->end, rle->count, flags); } } static int -cardbus_release_resource(device_t dev, device_t child, int type, int rid, - struct resource *r) +cardbus_release_resource(device_t cbdev, device_t child, int type, int rid, + struct resource *r) { + struct cardbus_devinfo *dinfo; + int passthrough = (device_get_parent(child) != cbdev); + struct resource_list_entry *rle = 0; + int flags; + int ret; + + if (passthrough) { + return BUS_RELEASE_RESOURCE(device_get_parent(cbdev), child, + type, rid, r); + } + + dinfo = device_get_ivars(child); /* * According to the PCI 2.2 spec, devices may share an address * decoder between memory mapped ROM access and memory @@ -734,17 +739,104 @@ rom_reg &= ~CARDBUS_ROM_ENABLE; pci_write_config(child, rid, rom_reg, 4); } + + rle = resource_list_find(&dinfo->resources, type, rid); + + if (!rle) { + device_printf(cbdev, "Allocated resource not found\n"); + return ENOENT; + } + if (!rle->res) { + device_printf(cbdev, "Allocated resource not recorded\n"); + return ENOENT; + } + + ret = BUS_RELEASE_RESOURCE(device_get_parent(cbdev), child, + type, rid, r); + switch(type) { + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + flags = rman_make_alignment_flags(rle->count); + break; + case SYS_RES_IRQ: + flags = RF_SHAREABLE; + break; + default: + flags = 0; + } + /* Restore cardbus hold on the resource */ + rle->res = bus_alloc_resource(cbdev, type, &rid, + rle->start, rle->end, rle->count, flags); + if (rle->res == NULL) + device_printf(cbdev, "release_resource: " + "unable to reacquire resource\n"); + return ret; +} + +static int +cardbus_setup_intr(device_t cbdev, device_t child, struct resource *irq, + int flags, driver_intr_t *intr, void *arg, void **cookiep) +{ + int ret; + struct cardbus_intrlist *ile; + device_t cdev; + struct cardbus_devinfo *dinfo; + + ret = bus_generic_setup_intr(cbdev, child, irq, flags, intr, arg, + cookiep); + if (ret != 0) return ret; + + for (cdev = child; cbdev != device_get_parent(cdev); + cdev = device_get_parent(cdev)); + dinfo = device_get_ivars(cdev); + + /* record interrupt handler */ + ile = malloc(sizeof(struct cardbus_intrlist), M_DEVBUF, M_NOWAIT); + ile->dev = child; + ile->irq = irq; + ile->cookie = *cookiep; + + SLIST_INSERT_HEAD(&dinfo->intrlist, ile, link); + return 0; +} + +static int +cardbus_teardown_intr(device_t cbdev, device_t child, struct resource *irq, + void *cookie) +{ + int ret; + struct cardbus_intrlist *ile; + device_t cdev; + struct cardbus_devinfo *dinfo; + + ret = bus_generic_teardown_intr(cbdev, child, irq, cookie); + if (ret != 0) return ret; - return bus_deactivate_resource(child, type, rid, r); + for (cdev = child; cbdev != device_get_parent(cdev); + cdev = device_get_parent(cdev)); + dinfo = device_get_ivars(cdev); + + /* remove interrupt handler from record */ + SLIST_FOREACH(ile, &dinfo->intrlist, link) { + if (ile->irq == irq && ile->cookie == cookie) { + SLIST_REMOVE(&dinfo->intrlist, ile, cardbus_intrlist, + link); + free(ile, M_DEVBUF); + return 0; + } + } + device_printf(cbdev, "teardown_intr: intr handler not recorded.\n"); + return ENOENT; } + /************************************************************************/ /* Other Bus Methods */ /************************************************************************/ static int cardbus_print_resources(struct resource_list *rl, const char *name, - int type, const char *format) + int type, const char *format) { struct resource_list_entry *rle; int printed, retval; @@ -763,7 +855,7 @@ if (rle->count > 1) { retval += printf("-"); retval += printf(format, rle->start + - rle->count - 1); + rle->count - 1); } } } @@ -771,7 +863,7 @@ } static int -cardbus_print_child(device_t dev, device_t child) +cardbus_print_child(device_t cbdev, device_t child) { struct cardbus_devinfo *dinfo; struct resource_list *rl; @@ -782,29 +874,29 @@ cfg = &dinfo->cfg; rl = &dinfo->resources; - retval += bus_print_child_header(dev, child); + retval += bus_print_child_header(cbdev, child); retval += cardbus_print_resources(rl, "port", SYS_RES_IOPORT, "%#lx"); retval += cardbus_print_resources(rl, "mem", SYS_RES_MEMORY, "%#lx"); retval += cardbus_print_resources(rl, "irq", SYS_RES_IRQ, "%ld"); - if (device_get_flags(dev)) - retval += printf(" flags %#x", device_get_flags(dev)); + if (device_get_flags(cbdev)) + retval += printf(" flags %#x", device_get_flags(cbdev)); retval += printf(" at device %d.%d", pci_get_slot(child), - pci_get_function(child)); + pci_get_function(child)); - retval += bus_print_child_footer(dev, child); + retval += bus_print_child_footer(cbdev, child); return (retval); } -static void cardbus_probe_nomatch(device_t dev, device_t child) { +static void cardbus_probe_nomatch(device_t cbdev, device_t child) { struct cardbus_devinfo *dinfo; pcicfgregs *cfg; dinfo = device_get_ivars(child); cfg = &dinfo->cfg; - device_printf(dev, ""); + device_printf(cbdev, ""); printf(" (vendor=0x%04x, dev=0x%04x)", cfg->vendor, cfg->device); printf(" at %d.%d", pci_get_slot(child), pci_get_function(child)); if (cfg->intpin > 0 && cfg->intline != 255) { @@ -816,7 +908,7 @@ } static int -cardbus_read_ivar(device_t dev, device_t child, int which, u_long *result) +cardbus_read_ivar(device_t cbdev, device_t child, int which, u_long *result) { struct cardbus_devinfo *dinfo; pcicfgregs *cfg; @@ -874,7 +966,7 @@ } static int -cardbus_write_ivar(device_t dev, device_t child, int which, uintptr_t value) +cardbus_write_ivar(device_t cbdev, device_t child, int which, uintptr_t value) { struct cardbus_devinfo *dinfo; pcicfgregs *cfg; @@ -908,27 +1000,165 @@ /* Compatibility with PCI bus (XXX: Do we need this?) */ /************************************************************************/ +/* + * PCI power manangement + */ +static int +cardbus_set_powerstate_method(device_t cbdev, device_t child, int state) +{ + struct cardbus_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->cfg; + u_int16_t status; + int result; + + if (cfg->pp_cap != 0) { + status = PCI_READ_CONFIG(cbdev, child, cfg->pp_status, 2) + & ~PCIM_PSTAT_DMASK; + result = 0; + switch (state) { + case PCI_POWERSTATE_D0: + status |= PCIM_PSTAT_D0; + break; + case PCI_POWERSTATE_D1: + if (cfg->pp_cap & PCIM_PCAP_D1SUPP) { + status |= PCIM_PSTAT_D1; + } else { + result = EOPNOTSUPP; + } + break; + case PCI_POWERSTATE_D2: + if (cfg->pp_cap & PCIM_PCAP_D2SUPP) { + status |= PCIM_PSTAT_D2; + } else { + result = EOPNOTSUPP; + } + break; + case PCI_POWERSTATE_D3: + status |= PCIM_PSTAT_D3; + break; + default: + result = EINVAL; + } + if (result == 0) + PCI_WRITE_CONFIG(cbdev, child, cfg->pp_status, + status, 2); + } else { + result = ENXIO; + } + return(result); +} + +static int +cardbus_get_powerstate_method(device_t cbdev, device_t child) +{ + struct cardbus_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->cfg; + u_int16_t status; + int result; + + if (cfg->pp_cap != 0) { + status = PCI_READ_CONFIG(cbdev, child, cfg->pp_status, 2); + switch (status & PCIM_PSTAT_DMASK) { + case PCIM_PSTAT_D0: + result = PCI_POWERSTATE_D0; + break; + case PCIM_PSTAT_D1: + result = PCI_POWERSTATE_D1; + break; + case PCIM_PSTAT_D2: + result = PCI_POWERSTATE_D2; + break; + case PCIM_PSTAT_D3: + result = PCI_POWERSTATE_D3; + break; + default: + result = PCI_POWERSTATE_UNKNOWN; + break; + } + } else { + /* No support, device is always at D0 */ + result = PCI_POWERSTATE_D0; + } + return(result); +} + static u_int32_t -cardbus_read_config_method(device_t dev, device_t child, int reg, int width) +cardbus_read_config_method(device_t cbdev, device_t child, int reg, int width) { struct cardbus_devinfo *dinfo = device_get_ivars(child); pcicfgregs *cfg = &dinfo->cfg; - return PCIB_READ_CONFIG(device_get_parent(dev), - cfg->bus, cfg->slot, cfg->func, - reg, width); + return PCIB_READ_CONFIG(device_get_parent(cbdev), + cfg->bus, cfg->slot, cfg->func, reg, width); } static void -cardbus_write_config_method(device_t dev, device_t child, int reg, - u_int32_t val, int width) +cardbus_write_config_method(device_t cbdev, device_t child, int reg, + u_int32_t val, int width) { struct cardbus_devinfo *dinfo = device_get_ivars(child); pcicfgregs *cfg = &dinfo->cfg; + + PCIB_WRITE_CONFIG(device_get_parent(cbdev), + cfg->bus, cfg->slot, cfg->func, reg, val, width); +} + +static __inline void +cardbus_set_command_bit(device_t cbdev, device_t child, u_int16_t bit) +{ + u_int16_t command; + + command = PCI_READ_CONFIG(cbdev, child, PCIR_COMMAND, 2); + command |= bit; + PCI_WRITE_CONFIG(cbdev, child, PCIR_COMMAND, command, 2); +} + +static __inline void +cardbus_clear_command_bit(device_t cbdev, device_t child, u_int16_t bit) +{ + u_int16_t command; - PCIB_WRITE_CONFIG(device_get_parent(dev), - cfg->bus, cfg->slot, cfg->func, - reg, val, width); + command = PCI_READ_CONFIG(cbdev, child, PCIR_COMMAND, 2); + command &= ~bit; + PCI_WRITE_CONFIG(cbdev, child, PCIR_COMMAND, command, 2); +} + +static void +cardbus_enable_busmaster_method(device_t cbdev, device_t child) +{ + cardbus_set_command_bit(cbdev, child, PCIM_CMD_BUSMASTEREN); +} + +static void +cardbus_disable_busmaster_method(device_t cbdev, device_t child) +{ + cardbus_clear_command_bit(cbdev, child, PCIM_CMD_BUSMASTEREN); +} + +static void +cardbus_enable_io_method(device_t cbdev, device_t child, int space) +{ + switch(space) { + case SYS_RES_IOPORT: + cardbus_set_command_bit(cbdev, child, PCIM_CMD_PORTEN); + break; + case SYS_RES_MEMORY: + cardbus_set_command_bit(cbdev, child, PCIM_CMD_MEMEN); + break; + } +} + +static void +cardbus_disable_io_method(device_t cbdev, device_t child, int space) +{ + switch(space) { + case SYS_RES_IOPORT: + cardbus_clear_command_bit(cbdev, child, PCIM_CMD_PORTEN); + break; + case SYS_RES_MEMORY: + cardbus_clear_command_bit(cbdev, child, PCIM_CMD_MEMEN); + break; + } } static device_method_t cardbus_methods[] = { @@ -950,9 +1180,8 @@ DEVMETHOD(bus_release_resource, cardbus_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - DEVMETHOD(bus_driver_added, bus_generic_driver_added), + DEVMETHOD(bus_setup_intr, cardbus_setup_intr), + DEVMETHOD(bus_teardown_intr, cardbus_teardown_intr), DEVMETHOD(bus_set_resource, cardbus_set_resource_method), DEVMETHOD(bus_get_resource, cardbus_get_resource_method), @@ -967,6 +1196,12 @@ /* Cardbus/PCI interface */ DEVMETHOD(pci_read_config, cardbus_read_config_method), DEVMETHOD(pci_write_config, cardbus_write_config_method), + DEVMETHOD(pci_enable_busmaster, cardbus_enable_busmaster_method), + DEVMETHOD(pci_disable_busmaster, cardbus_disable_busmaster_method), + DEVMETHOD(pci_enable_io, cardbus_enable_io_method), + DEVMETHOD(pci_disable_io, cardbus_disable_io_method), + DEVMETHOD(pci_get_powerstate, cardbus_get_powerstate_method), + DEVMETHOD(pci_set_powerstate, cardbus_set_powerstate_method), {0,0} }; Index: sys/dev/cardbus/cardbus_cis.c =================================================================== RCS file: /export/ncvs/src/sys/dev/cardbus/cardbus_cis.c,v retrieving revision 1.9 diff -u -u -r1.9 cardbus_cis.c --- sys/dev/cardbus/cardbus_cis.c 2001/06/05 23:42:51 1.9 +++ sys/dev/cardbus/cardbus_cis.c 2001/07/15 19:37:10 @@ -44,51 +44,49 @@ #include #include -#include +#include +#include +#include #include +#include #include #include "card_if.h" #if defined CARDBUS_DEBUG -#define STATIC #define DPRINTF(a) printf a #define DEVPRINTF(x) device_printf x #else -#define STATIC static #define DPRINTF(a) #define DEVPRINTF(x) #endif #if !defined(lint) static const char rcsid[] = - "$FreeBSD: src/sys/dev/cardbus/cardbus_cis.c,v 1.9 2001/06/05 23:42:51 imp Exp $"; +"$FreeBSD: src/sys/dev/cardbus/cardbus_cis.c,v 1.9 2001/06/05 23:42:51 imp Exp $"; #endif struct tuple_callbacks; static int cardbus_read_tuple_conf(device_t dev, device_t child, - u_int32_t *start, u_int32_t *off, - int *tupleid, int *len, u_int8_t *tupledata); -static int cardbus_read_tuple_exrom(device_t dev, struct resource *mem, - u_int32_t *start, u_int32_t *off, - int *tupleid, int *len, u_int8_t *tupledata); -static int cardbus_read_tuple_mem(device_t dev, device_t child, u_int32_t *start, - u_int32_t *off, int *tupleid, int *len, - u_int8_t *tupledata); -static int cardbus_read_tuple(device_t dev, device_t child, u_int32_t *start, - u_int32_t *off, int *tupleid, int *len, - u_int8_t *tupledata); + u_int32_t start, u_int32_t *off, int *tupleid, int *len, + u_int8_t *tupledata); +static int cardbus_read_tuple_mem(device_t dev, struct resource *res, + u_int32_t start, u_int32_t *off, int *tupleid, int *len, + u_int8_t *tupledata); +static int cardbus_read_tuple(device_t dev, device_t child, + struct resource *res, u_int32_t start, u_int32_t *off, int *tupleid, + int *len, u_int8_t *tupledata); static int decode_tuple(device_t dev, device_t child, int tupleid, int len, - u_int8_t *tupledata, u_int32_t *start, u_int32_t *off, - struct tuple_callbacks *callbacks); + u_int8_t *tupledata, u_int32_t start, u_int32_t *off, + struct tuple_callbacks *callbacks); static int cardbus_parse_cis(device_t dev, device_t child, - struct tuple_callbacks *callbacks); + struct tuple_callbacks *callbacks); #define DECODE_PARAMS \ (device_t dev, device_t child, int id, int len, \ - u_int8_t *tupledata, u_int32_t *start, u_int32_t *off, \ + u_int8_t *tupledata, u_int32_t start, u_int32_t *off, \ struct tuple_callbacks *info) #define DECODE_PROTOTYPE(NAME) static int decode_tuple_ ## NAME DECODE_PARAMS DECODE_PROTOTYPE(generic); @@ -123,9 +121,25 @@ "Security" }; +struct cardbus_quirk { + u_int32_t devid; /* Vendor/device of the card */ + int type; +#define CARDBUS_QUIRK_MAP_REG 1 /* PCI map register in weird place */ + int arg1; + int arg2; +}; + +struct cardbus_quirk cardbus_quirks[] = { + { 0 } +}; + static struct cis_tupleinfo* cisread_buf; static int ncisread_buf; +/* + * Handler functions for various CIS tuples + */ + DECODE_PROTOTYPE(generic) { #ifdef CARDBUS_DEBUG @@ -156,10 +170,10 @@ struct cis_tupleinfo* tmpbuf; tmpbuf = malloc(sizeof(struct cis_tupleinfo)*(ncisread_buf+1), - M_DEVBUF, M_WAITOK); + M_DEVBUF, M_WAITOK); if (ncisread_buf > 0) { memcpy(tmpbuf, cisread_buf, - sizeof(struct cis_tupleinfo)*ncisread_buf); + sizeof(struct cis_tupleinfo)*ncisread_buf); free(cisread_buf, M_DEVBUF); } cisread_buf = tmpbuf; @@ -190,7 +204,7 @@ tupledata[2] != 'S') { printf("Invalid data for CIS Link Target!\n"); decode_tuple_generic(dev, child, id, len, tupledata, - start, off, info); + start, off, info); return EINVAL; } return 0; @@ -256,11 +270,10 @@ printf ("*** ERROR *** BAR length not 6 (%d)\n", len); return EINVAL; } else { + struct cardbus_devinfo *dinfo = device_get_ivars(child); int type; int reg; u_int32_t bar; - u_int32_t len; - struct resource *res; reg = *(u_int16_t*)tupledata; len = *(u_int32_t*)(tupledata+2); @@ -270,19 +283,32 @@ type = SYS_RES_MEMORY; } bar = (reg & TPL_BAR_REG_ASI_MASK) - 1; - if (bar < 0 || bar > 5 || (type == SYS_RES_IOPORT && bar == 5)) { + if (bar < 0 || bar > 5 || (type == SYS_RES_IOPORT && bar==5)) { device_printf(dev, "Invalid BAR number: %02x(%02x)\n", - reg, bar); + reg, bar); return 0; } bar = CARDBUS_BASE0_REG + bar * 4; - DEVPRINTF((dev, "Opening BAR: type=%s, bar=%02x, len=%04x\n", - (type==SYS_RES_MEMORY)?"MEM":"IO", bar, len)); - res = bus_generic_alloc_resource(child, child, type, &bar, 0, - ~0, len, rman_make_alignment_flags(len) | RF_ACTIVE); - if (res == NULL) { - device_printf(dev, "Cannot allocate BAR %02x\n", bar); + if (type == SYS_RES_MEMORY) { + if (bar & TPL_BAR_REG_PREFETCHABLE) + dinfo->mprefetchable |= BARBIT(bar); + if (bar & TPL_BAR_REG_BELOW1MB) + dinfo->mbelow1mb |= BARBIT(bar); + } else if (type == SYS_RES_IOPORT) { + if (bar & TPL_BAR_REG_BELOW1MB) + dinfo->ibelow1mb |= BARBIT(bar); } + DEVPRINTF((dev, "Opening BAR: type=%s, bar=%02x, " + "len=%04x%s%s\n", + (type==SYS_RES_MEMORY)?"MEM":"IO", bar, len, + (type==SYS_RES_MEMORY&&dinfo->mprefetchable&BARBIT(bar))? + " (Prefetchable)":"", + type==SYS_RES_MEMORY? + ((dinfo->mbelow1mb&BARBIT(bar))?" (Below 1Mb)":"") + :(dinfo->ibelow1mb&BARBIT(bar))?" (Below 1Mb)":"" + )); + + resource_list_add(&dinfo->resources, type, bar, 0UL, ~0UL, len); } return 0; } @@ -299,16 +325,19 @@ return 0; } +/* + * Functions to read the a tuple from the card + */ + static int -cardbus_read_tuple_conf(device_t dev, device_t child, u_int32_t *start, - u_int32_t *off, int *tupleid, int *len, - u_int8_t *tupledata) +cardbus_read_tuple_conf(device_t dev, device_t child, u_int32_t start, + u_int32_t *off, int *tupleid, int *len, u_int8_t *tupledata) { int i, j; u_int32_t e; u_int32_t loc; - loc = CARDBUS_CIS_ADDR(*start) + *off; + loc = start + *off; e = pci_read_config(child, loc - loc%4, 4); for (j = loc % 4; j>0; j--) @@ -329,111 +358,34 @@ return 0; } - static int -cardbus_read_tuple_exrom(device_t dev, struct resource *mem, u_int32_t *start, - u_int32_t *off, int *tupleid, int *len, - u_int8_t *tupledata) -{ -#define READROM(rom, type, offset) \ - (*((u_int ## type ##_t *)(((unsigned char*)rom) + offset))) - - int romnum = 0; - unsigned char *data; - u_int32_t imagesize; - unsigned char *image; - int imagenum; - - image = (unsigned char*)rman_get_virtual(mem); - imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start); - do { - if (READROM(image, 16, CARDBUS_EXROM_SIGNATURE) != 0xaa55) { - device_printf (dev, "Bad header in rom %d: %04x\n", - romnum, *(u_int16_t*)(image + - CARDBUS_EXROM_SIGNATURE)); - return ENXIO; - } - data = image + READROM(image, 16, CARDBUS_EXROM_DATA_PTR); - imagesize = READROM(data, 16, CARDBUS_EXROM_DATA_IMAGE_LENGTH); - - if (imagesize == 0) { - /* - * XXX some ROMs seem to have this as zero, - * can we assume this means 1 block? - */ - imagesize = 1; - } - imagesize <<= 9; - - if (imagenum == romnum) { - image += CARDBUS_CIS_ADDR(*start) + *off; - *tupleid = image[0]; - *len = image[1]; - memcpy(tupledata, image+2, *len); - *off += *len+2; - return 0; - } - image += imagesize; - romnum++; - } while ((READROM(data, 8, CARDBUS_EXROM_DATA_INDICATOR) & 0x80) == 0); - device_printf(dev, "Cannot read CIS: Not enough images of rom\n"); - return ENOENT; -#undef READROM -} - -static int -cardbus_read_tuple_mem(device_t dev, device_t child, u_int32_t *start, - u_int32_t *off, int *tupleid, int *len, - u_int8_t *tupledata) +cardbus_read_tuple_mem(device_t dev, struct resource *res, u_int32_t start, + u_int32_t *off, int *tupleid, int *len, u_int8_t *tupledata) { - struct resource *mem; bus_space_tag_t bt; bus_space_handle_t bh; - int rid; int ret; - - if (CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) { - rid = CARDBUS_ROM_REG; - } else { - rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4; - } - mem = bus_alloc_resource(child, SYS_RES_MEMORY, &rid, 0, ~0, - 1, RF_ACTIVE); - bt = rman_get_bustag(mem); - bh = rman_get_bushandle(mem); - if (mem == NULL) { - device_printf(dev, "Failed to get memory for CIS reading\n"); - return ENOMEM; - } + bt = rman_get_bustag(res); + bh = rman_get_bushandle(res); - if(CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) { - ret = cardbus_read_tuple_exrom(dev, mem, start, off, tupleid, - len, tupledata); - } else { - *tupleid = bus_space_read_1(bt, bh, - CARDBUS_CIS_ADDR(*start) + *off); - *len = bus_space_read_1(bt, bh, - CARDBUS_CIS_ADDR(*start) + *off + 1); - bus_space_read_multi_1(rman_get_bustag(mem), - rman_get_bushandle(mem), - *off + CARDBUS_CIS_ADDR(*start), tupledata, *len); - ret = 0; - *off += *len+2; - } - bus_release_resource(child, SYS_RES_MEMORY, rid, mem); + *tupleid = bus_space_read_1(bt, bh, start + *off); + *len = bus_space_read_1(bt, bh, start + *off + 1); + bus_space_read_multi_1(bt, bh, *off + start, tupledata, *len); + ret = 0; + *off += *len+2; return ret; } static int -cardbus_read_tuple(device_t dev, device_t child, u_int32_t *start, - u_int32_t *off, int *tupleid, int *len, - u_int8_t *tupledata) +cardbus_read_tuple(device_t dev, device_t child, struct resource *res, + u_int32_t start, u_int32_t *off, int *tupleid, int *len, + u_int8_t *tupledata) { - switch(CARDBUS_CIS_SPACE(*start)) { + switch(CARDBUS_CIS_SPACE(start)) { case CARDBUS_CIS_ASI_TUPLE: return cardbus_read_tuple_conf(dev, child, start, off, - tupleid, len, tupledata); + tupleid, len, tupledata); case CARDBUS_CIS_ASI_BAR0: case CARDBUS_CIS_ASI_BAR1: case CARDBUS_CIS_ASI_BAR2: @@ -441,72 +393,503 @@ case CARDBUS_CIS_ASI_BAR4: case CARDBUS_CIS_ASI_BAR5: case CARDBUS_CIS_ASI_ROM: - return cardbus_read_tuple_mem(dev, child, start, off, - tupleid, len, tupledata); + return cardbus_read_tuple_mem(dev, res, start, off, + tupleid, len, tupledata); default: device_printf(dev, "Unable to read CIS: Unknown space: %d\n", - CARDBUS_CIS_SPACE(*start)); + start); return EINVAL; } } +static void +cardbus_read_tuple_finish(device_t dev, device_t child, int rid, + struct resource *res) { + if (res != (struct resource*)~0UL) { + bus_release_resource(child, SYS_RES_MEMORY, rid, res); + pci_write_config(child, rid, 0, 4); + } +} + +static struct resource* +cardbus_read_tuple_init(device_t dev, device_t child, u_int32_t *start, + int *rid) { + u_int32_t testval; + u_int32_t size; + struct resource *res; + + switch(CARDBUS_CIS_SPACE(*start)) { + case CARDBUS_CIS_ASI_TUPLE: + /* CIS in tuple space need no initialization */ + return (struct resource*)~0UL; + case CARDBUS_CIS_ASI_BAR0: + case CARDBUS_CIS_ASI_BAR1: + case CARDBUS_CIS_ASI_BAR2: + case CARDBUS_CIS_ASI_BAR3: + case CARDBUS_CIS_ASI_BAR4: + case CARDBUS_CIS_ASI_BAR5: + *rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4; + pci_write_config(child, *rid, ~0UL, 4); + break; + case CARDBUS_CIS_ASI_ROM: + *rid = CARDBUS_ROM_REG; + pci_read_config(child, *rid, CARDBUS_ROM_ADDRMASK); + break; + default: + device_printf(dev, "Unable to read CIS: Unknown space: %d\n", + CARDBUS_CIS_SPACE(*start)); + return NULL; + } + + /* figure out how much space we need */ + testval = pci_read_config(child, *rid, 4); + if (testval&1) { + device_printf(dev, "CIS Space is IO, expecting memory.\n"); + return NULL; + } + size = CARDBUS_MAPREG_MEM_SIZE(testval); + if (size < 4096) size = 4096; + /* allocate the memory space to read CIS */ + res = bus_alloc_resource(child, SYS_RES_MEMORY, rid, 0, ~0, size, + rman_make_alignment_flags(size)|RF_ACTIVE); + pci_write_config(child, *rid, + rman_get_start(res) | ((*rid == CARDBUS_ROM_REG)? + CARDBUS_ROM_ENABLE:0), + 4); + + /* Flip to the right ROM image if CIS is in ROM */ + if (CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) { + bus_space_tag_t bt; + bus_space_handle_t bh; + int imagenum; + u_int32_t imagesize; + int mystart = CARDBUS_CIS_ADDR(*start); + int romnum = 0; + + bt = rman_get_bustag(res); + bh = rman_get_bushandle(res); + + imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start); + for (romnum = 0; romnum < imagenum; romnum++) { + if (bus_space_read_2(bt, bh, + mystart+CARDBUS_EXROM_SIGNATURE) != 0xaa55) { + device_printf (dev, "Bad header in rom %d: " + "%04x\n", romnum, + bus_space_read_2(bt, bh, + mystart+CARDBUS_EXROM_SIGNATURE)); + bus_release_resource(child, SYS_RES_MEMORY, + *rid, res); + *rid = 0; + return NULL; + } + mystart += bus_space_read_2(bt, bh, + mystart+CARDBUS_EXROM_DATA_PTR); + imagesize = bus_space_read_2(bt,bh, + mystart+CARDBUS_EXROM_DATA_IMAGE_LENGTH); + + if (imagesize == 0) { + /* + * XXX some ROMs seem to have this as zero, + * can we assume this means 1 block? + */ + imagesize = 1; + } + imagesize <<= 9; + + if ((bus_space_read_1(bt, bh, + CARDBUS_EXROM_DATA_INDICATOR) & 0x80) == 0) { + device_printf(dev, "Cannot read CIS: " + "Not enough images of rom\n"); + return NULL; + } + + mystart += imagesize; + } + *start = mystart; + } else { + *start = CARDBUS_CIS_SPACE(*start); + } + return res; +} + +/* + * Dispatch the right handler function per tuple + */ + static int decode_tuple(device_t dev, device_t child, int tupleid, int len, - u_int8_t *tupledata, u_int32_t *start, u_int32_t *off, - struct tuple_callbacks *callbacks) + u_int8_t *tupledata, u_int32_t start, u_int32_t *off, + struct tuple_callbacks *callbacks) { int i; for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) { if (tupleid == callbacks[i].id) return callbacks[i].func(dev, child, tupleid, len, - tupledata, start, off, - &callbacks[i]); + tupledata, start, off, &callbacks[i]); } if (tupleid < CISTPL_CUSTOMSTART) { - device_printf(dev, "Undefined tuple encountered, CIS parsing terminated\n"); + device_printf(dev, "Undefined tuple encountered, " + "CIS parsing terminated\n"); return EINVAL; } return callbacks[i].func(dev, child, tupleid, len, - tupledata, start, off, - NULL); + tupledata, start, off, NULL); } static int cardbus_parse_cis(device_t dev, device_t child, - struct tuple_callbacks *callbacks) + struct tuple_callbacks *callbacks) { u_int8_t tupledata[MAXTUPLESIZE]; int tupleid; int len; int expect_linktarget; u_int32_t start, off; + struct resource *res; + int rid; bzero(tupledata, MAXTUPLESIZE); expect_linktarget = TRUE; start = pci_read_config(child, CARDBUS_CIS_REG, 4); off = 0; + res = cardbus_read_tuple_init(dev, child, &start, &rid); + if (res == NULL) + return ENXIO; do { - cardbus_read_tuple(dev, child, &start, &off, &tupleid, &len, - tupledata); + if (0 != cardbus_read_tuple(dev, child, res, start, &off, + &tupleid, &len, tupledata)) { + device_printf(dev, "Failed to read CIS.\n"); + cardbus_read_tuple_finish(dev, child, rid, res); + return ENXIO; + } if (expect_linktarget && tupleid != CISTPL_LINKTARGET) { device_printf(dev, "Expecting link target, got 0x%x\n", - tupleid); + tupleid); + cardbus_read_tuple_finish(dev, child, rid, res); return EINVAL; } expect_linktarget = decode_tuple(dev, child, tupleid, len, - tupledata, &start, &off, - callbacks); - if (expect_linktarget != 0) + tupledata, start, &off, callbacks); + if (expect_linktarget != 0) { + cardbus_read_tuple_finish(dev, child, rid, res); return expect_linktarget; + } } while (tupleid != CISTPL_END); + cardbus_read_tuple_finish(dev, child, rid, res); + return 0; +} + +static int +barsort(const void* a, const void* b) +{ + return (*(const struct resource_list_entry **)b)->count - + (*(const struct resource_list_entry **)a)->count; +} + +static int +cardbus_alloc_resources(device_t dev, device_t child) +{ + struct cardbus_devinfo *dinfo = device_get_ivars(child); + int count; + struct resource_list_entry *rle; + struct resource_list_entry **barlist; + int tmp; + u_int32_t mem_psize = 0, mem_nsize = 0, io_size = 0; + struct resource *res; + u_int32_t start,end; + int rid, flags; + + count = 0; + SLIST_FOREACH(rle, &dinfo->resources, link) { + count++; + } + if (count == 0) return 0; + barlist = malloc(sizeof(struct resource_list_entry*)*count, M_DEVBUF, + M_WAITOK); + count = 0; + SLIST_FOREACH(rle, &dinfo->resources, link) { + barlist[count] = rle; + if (rle->type == SYS_RES_IOPORT) { + io_size += rle->count; + } else if (rle->type == SYS_RES_MEMORY) { + if (dinfo->mprefetchable & BARBIT(rle->rid)) + mem_psize += rle->count; + else + mem_nsize += rle->count; + } + count++; + } + + /* + * We want to allocate the largest resource first, so that our + * allocated memory is packed. + */ + qsort(barlist, count, sizeof(struct resource_list_entry*), barsort); + + /* Allocate prefetchable memory */ + flags = 0; + for (tmp = 0; tmp < count; tmp++) { + if (barlist[tmp]->res == NULL && + barlist[tmp]->type == SYS_RES_MEMORY && + dinfo->mprefetchable & BARBIT(barlist[tmp]->rid)) { + flags = rman_make_alignment_flags(barlist[tmp]->count); + break; + } + } + if (flags > 0) { /* If any prefetchable memory is requested... */ + /* + * First we allocate one big space for all resources of this + * type. We do this because our parent, pccbb, needs to open + * a window to forward all addresses within the window, and + * it would be best if nobody else has resources allocated + * within the window. + * (XXX: Perhaps there might be a better way to do this?) + */ + rid = 0; + res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, + (dinfo->mprefetchable & dinfo->mbelow1mb)?0xFFFFF:~0UL, + mem_psize, flags); + start = rman_get_start(res); + end = rman_get_end(res); + DEVPRINTF((dev, "Prefetchable memory at %x-%x\n", start, end)); + /* + * Now that we know the region is free, release it and hand it + * out piece by piece. + */ + bus_release_resource(dev, SYS_RES_MEMORY, rid, res); + for (tmp = 0; tmp < count; tmp++) { + if (barlist[tmp]->res == NULL && + barlist[tmp]->type == SYS_RES_MEMORY && + dinfo->mprefetchable & BARBIT(barlist[tmp]->rid)) { + barlist[tmp]->res = bus_alloc_resource(dev, + barlist[tmp]->type, + &barlist[tmp]->rid, start, end, + barlist[tmp]->count, + rman_make_alignment_flags( + barlist[tmp]->count)); + if (barlist[tmp]->res == NULL) { + mem_nsize += barlist[tmp]->count; + dinfo->mprefetchable &= + ~BARBIT(barlist[tmp]->rid); + DEVPRINTF((dev, "Cannot pre-allocate " + "prefetchable memory, will try as " + "non-prefetchable.\n")); + } else { + barlist[tmp]->start = + rman_get_start(barlist[tmp]->res); + barlist[tmp]->end = + rman_get_end(barlist[tmp]->res); + pci_write_config(child, + barlist[tmp]->rid, + barlist[tmp]->start, 4); + DEVPRINTF((dev, "Prefetchable memory " + "rid=%x at %lx-%lx\n", + barlist[tmp]->rid, + barlist[tmp]->start, + barlist[tmp]->end)); + } + } + } + } + + /* Allocate non-prefetchable memory */ + flags = 0; + for (tmp = 0; tmp < count; tmp++) { + if (barlist[tmp]->res == NULL && + barlist[tmp]->type == SYS_RES_MEMORY) { + flags = rman_make_alignment_flags(barlist[tmp]->count); + break; + } + } + if (flags > 0) { /* If any non-prefetchable memory is requested... */ + /* + * First we allocate one big space for all resources of this + * type. We do this because our parent, pccbb, needs to open + * a window to forward all addresses within the window, and + * it would be best if nobody else has resources allocated + * within the window. + * (XXX: Perhaps there might be a better way to do this?) + */ + rid = 0; + res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, + ((~dinfo->mprefetchable) & dinfo->mbelow1mb)?0xFFFFF:~0UL, + mem_nsize, flags); + start = rman_get_start(res); + end = rman_get_end(res); + DEVPRINTF((dev, "Non-prefetchable memory at %x-%x\n", + start, end)); + /* + * Now that we know the region is free, release it and hand it + * out piece by piece. + */ + bus_release_resource(dev, SYS_RES_MEMORY, rid, res); + for (tmp = 0; tmp < count; tmp++) { + if (barlist[tmp]->res == NULL && + barlist[tmp]->type == SYS_RES_MEMORY) { + barlist[tmp]->res = bus_alloc_resource(dev, + barlist[tmp]->type, &barlist[tmp]->rid, + start, end, barlist[tmp]->count, + rman_make_alignment_flags( + barlist[tmp]->count)); + if (barlist[tmp]->res == NULL) { + DEVPRINTF((dev, "Cannot pre-allocate " + "memory for cardbus device\n")); + return ENOMEM; + } + barlist[tmp]->start = + rman_get_start(barlist[tmp]->res); + barlist[tmp]->end = rman_get_end( + barlist[tmp]->res); + pci_write_config(child, barlist[tmp]->rid, + barlist[tmp]->start, 4); + DEVPRINTF((dev, "Non-prefetchable memory " + "rid=%x at %lx-%lx (%lx)\n", + barlist[tmp]->rid, barlist[tmp]->start, + barlist[tmp]->end, barlist[tmp]->count)); + } + } + } + + /* Allocate IO ports */ + flags = 0; + for (tmp = 0; tmp < count; tmp++) { + if (barlist[tmp]->res == NULL && + barlist[tmp]->type == SYS_RES_IOPORT) { + flags = rman_make_alignment_flags(barlist[tmp]->count); + break; + } + } + if (flags > 0) { /* If any IO port is requested... */ + /* + * First we allocate one big space for all resources of this + * type. We do this because our parent, pccbb, needs to open + * a window to forward all addresses within the window, and + * it would be best if nobody else has resources allocated + * within the window. + * (XXX: Perhaps there might be a better way to do this?) + */ + rid = 0; + res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, + (dinfo->ibelow1mb)?0xFFFFF:~0UL, io_size, flags); + start = rman_get_start(res); + end = rman_get_end(res); + DEVPRINTF((dev, "IO port at %x-%x\n", start, end)); + /* + * Now that we know the region is free, release it and hand it + * out piece by piece. + */ + bus_release_resource(dev, SYS_RES_IOPORT, rid, res); + for (tmp = 0; tmp < count; tmp++) { + if (barlist[tmp]->res == NULL && + barlist[tmp]->type == SYS_RES_IOPORT) { + barlist[tmp]->res = bus_alloc_resource(dev, + barlist[tmp]->type, &barlist[tmp]->rid, + start, end, barlist[tmp]->count, + rman_make_alignment_flags( + barlist[tmp]->count)); + if (barlist[tmp]->res == NULL) { + DEVPRINTF((dev, "Cannot pre-allocate " + "IO port for cardbus device\n")); + return ENOMEM; + } + barlist[tmp]->start = + rman_get_start(barlist[tmp]->res); + barlist[tmp]->end = + rman_get_end(barlist[tmp]->res); + pci_write_config(child, barlist[tmp]->rid, + barlist[tmp]->start, 4); + DEVPRINTF((dev, "IO port rid=%x at %lx-%lx\n", + barlist[tmp]->rid, barlist[tmp]->start, + barlist[tmp]->end)); + } + } + } + + /* Allocate IRQ */ + /* XXX: Search CIS for IRQ description */ + rid = 0; + res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0UL, 1, + RF_SHAREABLE); + resource_list_add(&dinfo->resources, SYS_RES_IRQ, rid, + rman_get_start(res), rman_get_end(res), 1); + rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, rid); + rle->res = res; + dinfo->cfg.intline = rman_get_start(res); + pci_write_config(child, PCIR_INTLINE, rman_get_start(res), 1); + return 0; } +/* + * Adding a memory/io resource (sans CIS) + */ + +static void +cardbus_add_map(device_t dev, device_t child, int reg) +{ + struct cardbus_devinfo *dinfo = device_get_ivars(child); + struct resource_list_entry *rle; + u_int32_t size; + u_int32_t testval; + int type; + + SLIST_FOREACH(rle, &dinfo->resources, link) { + if (rle->rid == reg) return; + } + + if (reg == CARDBUS_ROM_REG) + testval = CARDBUS_ROM_ADDRMASK; + else + testval = ~0; + + pci_write_config(child, reg, testval, 4); + testval = pci_read_config(child, reg, 4); + + if (testval == ~0 || testval == 0) + return; + + if ((testval&1) == 0) + type = SYS_RES_MEMORY; + else + type = SYS_RES_IOPORT; + + size = CARDBUS_MAPREG_MEM_SIZE(testval); + device_printf(dev, "Resource not specified in CIS: id=%x, size=%x\n", + reg, size); + resource_list_add(&dinfo->resources, type, reg, 0UL, ~0UL, size); +} + + + +static void +cardbus_pickup_maps(device_t dev, device_t child) { + struct cardbus_devinfo *dinfo = device_get_ivars(child); + struct cardbus_quirk *q; + int reg; + + /* + * Try to pick up any resources that was not specified in CIS. + * Some devices (eg, 3c656) does not list all resources required by + * the driver in its CIS. + * XXX: should we do this or use quirks? + */ + for (reg = 0; reg < dinfo->cfg.nummaps; reg++) { + cardbus_add_map(dev, child, PCIR_MAPS + reg*4); + } + + for (q = &cardbus_quirks[0]; q->devid; q++) { + if (q->devid == ((dinfo->cfg.device << 16) | dinfo->cfg.vendor) + && q->type == CARDBUS_QUIRK_MAP_REG) { + cardbus_add_map(dev, child, q->arg1); + } + } +} + int cardbus_cis_read(device_t dev, device_t child, u_int8_t id, - struct cis_tupleinfo** buff, int* nret) + struct cis_tupleinfo** buff, int* nret) { struct tuple_callbacks cisread_callbacks[] = { MAKETUPLE(NULL, nothing), @@ -578,6 +961,7 @@ int cardbus_do_cis(device_t dev, device_t child) { + int ret; struct tuple_callbacks init_callbacks[] = { MAKETUPLE(NULL, generic), MAKETUPLE(DEVICE, generic), @@ -619,5 +1003,9 @@ MAKETUPLE(END, end), MAKETUPLE(GENERIC, generic), }; - return cardbus_parse_cis(dev, child, init_callbacks); + + ret = cardbus_parse_cis(dev, child, init_callbacks); + if (ret < 0) return ret; + cardbus_pickup_maps(dev, child); + return cardbus_alloc_resources(dev, child); } Index: sys/dev/cardbus/cardbus_cis.h =================================================================== RCS file: /export/ncvs/src/sys/dev/cardbus/cardbus_cis.h,v retrieving revision 1.4 diff -u -u -r1.4 cardbus_cis.h --- sys/dev/cardbus/cardbus_cis.h 2001/01/06 18:04:50 1.4 +++ sys/dev/cardbus/cardbus_cis.h 2001/07/13 12:13:15 @@ -88,6 +88,10 @@ /* BAR */ #define TPL_BAR_REG_ASI_MASK 0x07 #define TPL_BAR_REG_AS 0x10 +#define TPL_BAR_REG_PREFETCHABLE_ONLY 0x20 +#define TPL_BAR_REG_PREFETCHABLE_CACHEABLE 0x40 +#define TPL_BAR_REG_PREFETCHABLE 0x60 +#define TPL_BAR_REG_BELOW1MB 0x80 /* CISTPL_FUNC */ #define TPL_FUNC_MF 0 /* multi function tuple */ Index: sys/dev/cardbus/cardbusvar.h =================================================================== RCS file: /export/ncvs/src/sys/dev/cardbus/cardbusvar.h,v retrieving revision 1.2 diff -u -u -r1.2 cardbusvar.h --- sys/dev/cardbus/cardbusvar.h 2000/10/18 03:21:48 1.2 +++ sys/dev/cardbus/cardbusvar.h 2001/07/13 12:13:15 @@ -32,8 +32,20 @@ * Structure definitions for the Cardbus Bus driver */ +struct cardbus_intrlist { + SLIST_ENTRY(cardbus_intrlist) link; + device_t dev; + struct resource *irq; + void *cookie; +}; + struct cardbus_devinfo { struct resource_list resources; pcicfgregs cfg; struct pci_conf conf; + u_int8_t mprefetchable; /* bit mask of prefetchable BARs */ + u_int8_t mbelow1mb; /* bit mask of BARs which require below 1Mb */ + u_int8_t ibelow1mb; /* bit mask of BARs which require below 1Mb */ +#define BARBIT(RID) (1<<((RID)-CARDBUS_BASE0_REG)/4) + SLIST_HEAD(, cardbus_intrlist) intrlist; }; Index: sys/dev/pccard/card_if.m =================================================================== RCS file: /export/ncvs/src/sys/dev/pccard/card_if.m,v retrieving revision 1.13 diff -u -u -r1.13 card_if.m --- sys/dev/pccard/card_if.m 2001/03/22 06:00:07 1.13 +++ sys/dev/pccard/card_if.m 2001/07/14 10:52:25 @@ -92,6 +92,15 @@ int flags; } +# +# pccard/cardbus buses call this to request a reprobe of the bus. +# reprobe only initiated if the child bus is the same type the card inserted. +# +METHOD int reprobe_card { + device_t dev; + device_t child; +} + HEADER { #define DETACH_FORCE 0x01 #define DETACH_NOWARN 0x02 Index: sys/dev/pccard/pccard.c =================================================================== RCS file: /export/ncvs/src/sys/dev/pccard/pccard.c,v retrieving revision 1.41 diff -u -u -r1.41 pccard.c --- sys/dev/pccard/pccard.c 2001/05/10 06:55:39 1.41 +++ sys/dev/pccard/pccard.c 2001/07/15 19:40:35 @@ -70,16 +70,20 @@ int pccard_verbose = 0; #endif -int pccard_print(void *, const char *); +static int pccard_detach_card(device_t dev, int flags); +static void pccard_function_init(struct pccard_function *pf); +static void pccard_function_free(struct pccard_function *pf); +static int pccard_function_enable(struct pccard_function *pf); +static void pccard_function_disable(struct pccard_function *pf); -int +static int pccard_ccr_read(struct pccard_function *pf, int ccr) { return (bus_space_read_1(pf->pf_ccrt, pf->pf_ccrh, pf->pf_ccr_offset + ccr)); } -void +static void pccard_ccr_write(struct pccard_function *pf, int ccr, int val) { if ((pf->ccr_mask) & (1 << (ccr / 2))) { @@ -95,9 +99,7 @@ struct pccard_function *pf; struct pccard_ivar *ivar; device_t child; - int attached; - sc->intr_handler_count = 0; /* * this is here so that when socket_enable calls gettype, trt happens */ @@ -129,8 +131,6 @@ if (1) pccard_print_cis(dev); - attached = 0; - DEVPRINTF((dev, "functions scanning\n")); STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { if (STAILQ_EMPTY(&pf->cfe_head)) @@ -140,10 +140,7 @@ pf->cfe = NULL; pf->dev = NULL; } -#if 0 - DEVPRINTF((dev, "chip_socket_disable\n")); - POWER_DISABLE_SOCKET(device_get_parent(dev), dev); -#endif + STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { if (STAILQ_EMPTY(&pf->cfe_head)) continue; @@ -173,9 +170,10 @@ * XXX addresses illegal or broken). */ pccard_function_init(pf); + if (sc->sc_enabled_count == 0) + POWER_ENABLE_SOCKET(device_get_parent(dev), dev); if (pccard_function_enable(pf) == 0 && device_probe_and_attach(child) == 0) { - attached++; DEVPRINTF((sc->dev, "function %d CCR at %d " "offset %x: %x %x %x %x, %x %x %x %x, %x\n", @@ -186,9 +184,11 @@ pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); } else { - device_delete_child(dev, child); + pccard_function_disable(pf); } } + if (sc->sc_enabled_count == 0) + pccard_detach_card(dev, 0); return (0); } @@ -197,24 +197,33 @@ { struct pccard_softc *sc = PCCARD_SOFTC(dev); struct pccard_function *pf; + struct pccard_config_entry *cfe; /* * We are running on either the PCCARD socket's event thread * or in user context detaching a device by user request. */ STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { - if (STAILQ_FIRST(&pf->cfe_head) == NULL) - continue; + int state = device_get_state(pf->dev); + if (state == DS_ATTACHED || state == DS_BUSY) + device_detach(pf->dev); pccard_function_disable(pf); - /* - * XXX must also actually delete resources created by - * pccard_function_init(). If pccard_function_init - * keeps things allocated it is a bug. - */ + pccard_function_free(pf); if (pf->dev != NULL) device_delete_child(dev, pf->dev); } + if (sc->sc_enabled_count == 0) + POWER_DISABLE_SOCKET(device_get_parent(dev), dev); + + while (NULL != (pf = STAILQ_FIRST(&sc->card.pf_head))) { + while (NULL != (cfe = STAILQ_FIRST(&pf->cfe_head))) { + STAILQ_REMOVE_HEAD(&pf->cfe_head, cfe_list); + free(cfe, M_DEVBUF); + } + STAILQ_REMOVE_HEAD(&sc->card.pf_head, pf_list); + free(pf, M_DEVBUF); + } return (0); } @@ -297,7 +306,7 @@ * Initialize a PCCARD function. May be called as long as the function is * disabled. */ -void +static void pccard_function_init(struct pccard_function *pf) { struct pccard_config_entry *cfe; @@ -369,7 +378,7 @@ if (cfe->iores[i] != NULL) { bus_release_resource(bus, SYS_RES_IOPORT, cfe->iorid[i], cfe->iores[i]); - rle = resource_list_find(rl, SYS_RES_IOPORT, + rle = resource_list_find(rl, SYS_RES_IOPORT, cfe->iorid[i]); rle->res = NULL; resource_list_delete(rl, SYS_RES_IOPORT, @@ -389,8 +398,39 @@ } } +/* + * Free resources allocated by pccard_function_init(), May be called as long + * as the function is disabled. + */ +static void +pccard_function_free(struct pccard_function *pf) +{ + struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); + struct resource_list_entry *rle; + + if (pf->pf_flags & PFF_ENABLED) { + printf("pccard_function_init: function is enabled"); + return; + } + + SLIST_FOREACH(rle, &devi->resources, link) { + if (rle->res) { + if (rle->res->r_dev != pf->sc->dev) + device_printf(pf->sc->dev, + "function_free: Resource still owned by child, oops. (type=%d, rid=%d, addr=%lx)\n", + rle->type, rle->rid, rman_get_start(rle->res)); + BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev), + rle->res->r_dev, + rle->type, rle->rid, + rle->res); + rle->res = NULL; + } + } + resource_list_free(&devi->resources); +} + /* Enable a PCCARD function */ -int +static int pccard_function_enable(struct pccard_function *pf) { struct pccard_function *tmp; @@ -406,9 +446,7 @@ * Increase the reference count on the socket, enabling power, if * necessary. */ - if (pf->sc->sc_enabled_count++ == 0) - POWER_ENABLE_SOCKET(device_get_parent(dev), dev); - DEVPRINTF((dev, "++enabled_count = %d\n", pf->sc->sc_enabled_count)); + pf->sc->sc_enabled_count++; if (pf->pf_flags & PFF_ENABLED) { /* @@ -530,15 +568,14 @@ * Decrement the reference count, and power down the socket, if * necessary. */ - if (--pf->sc->sc_enabled_count == 0) - POWER_DISABLE_SOCKET(device_get_parent(dev), dev); + pf->sc->sc_enabled_count--; DEVPRINTF((dev, "bad --enabled_count = %d\n", pf->sc->sc_enabled_count)); return (1); } /* Disable PCCARD function. */ -void +static void pccard_function_disable(struct pccard_function *pf) { struct pccard_function *tmp; @@ -555,26 +592,10 @@ } if (pf->intr_handler != NULL) { - pf->intr_handler = NULL; - pf->intr_handler_arg = NULL; - pf->intr_handler_cookie = NULL; - pccard_ccr_write(pf, PCCARD_CCR_OPTION, - pccard_ccr_read(pf, PCCARD_CCR_OPTION) & - ~PCCARD_CCR_OPTION_IREQ_ENABLE); - - if (pf->sc->intr_handler_count == 1) { - struct pccard_ivar *ivar = PCCARD_IVAR(pf->dev); - struct resource_list_entry *rle = NULL; - - pf->sc->intr_handler_count--; - rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, - 0); - if (rle == NULL) - panic("No IRQ for pccard?"); - - bus_teardown_intr(dev, rle->res, - &pf->sc->intr_handler_count); - } + struct pccard_ivar *devi = PCCARD_IVAR(pf->dev); + struct resource_list_entry *rle = + resource_list_find(&devi->resources, SYS_RES_IRQ, 0); + BUS_TEARDOWN_INTR(dev, pf->dev, rle->res, pf->intr_handler_cookie); } /* @@ -603,9 +624,7 @@ * Decrement the reference count, and power down the socket, if * necessary. */ - if (--pf->sc->sc_enabled_count == 0) - POWER_DISABLE_SOCKET(device_get_parent(dev), dev); - DEVPRINTF((dev, "--enabled_count = %d\n", pf->sc->sc_enabled_count)); + pf->sc->sc_enabled_count--; } #if 0 @@ -723,6 +742,13 @@ return (bus_generic_attach(dev)); } +static int +pccard_detach(device_t dev) +{ + pccard_detach_card(dev, 0); + return 0; +} + static void pccard_print_resources(struct resource_list *rl, const char *name, int type, int count, const char *format) @@ -802,8 +828,12 @@ return (EINVAL); resource_list_add(rl, type, rid, start, start + count - 1, count); - - return (0); + if (NULL != resource_list_alloc(rl, device_get_parent(dev), dev, + type, &rid, + start, start + count - 1, count, 0)) + return 0; + else + return ENOMEM; } static int @@ -899,123 +929,152 @@ static void pccard_driver_added(device_t dev, driver_t *driver) { - /* - * XXX eventually we need to attach stuff when we know we - * XXX have kids. For now we do nothing because we normally - * XXX add children ourselves. We don't want to necessarily - * XXX force a reprobe. - */ + struct pccard_softc *sc = PCCARD_SOFTC(dev); + struct pccard_function *pf; + device_t child; + + if (sc->sc_enabled_count == 0) { + CARD_REPROBE_CARD(device_get_parent(dev), dev); + return; + } + + STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { + if (STAILQ_EMPTY(&pf->cfe_head)) + continue; + child = pf->dev; + if (device_get_state(child) != DS_NOTPRESENT) + continue; + if (pccard_function_enable(pf) == 0 && + device_probe_and_attach(child) == 0) { + + DEVPRINTF((sc->dev, "function %d CCR at %d " + "offset %x: %x %x %x %x, %x %x %x %x, %x\n", + pf->number, pf->pf_ccr_window, pf->pf_ccr_offset, + pccard_ccr_read(pf, 0x00), + pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04), + pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A), + pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E), + pccard_ccr_read(pf, 0x10), pccard_ccr_read(pf, 0x12))); + } else { + pccard_function_disable(pf); + } + } + return; } static struct resource * pccard_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { - struct resource_list_entry *rle = NULL; - - /* XXX: This is an ugly way to fudge the resources. */ - - if (device_get_parent(child) == dev) { - struct pccard_ivar *devi = PCCARD_IVAR(child); - struct resource_list *rl = &devi->resources; - - rle = resource_list_find(rl, type, *rid); - } - - if (rle != NULL) { - if (flags & RF_ACTIVE) - bus_activate_resource(dev, type, rle->rid, rle->res); - return (rle->res); + struct pccard_ivar *dinfo; + struct resource_list_entry *rle = 0; + int passthrough = (device_get_parent(child) != dev); + + if (passthrough) { + return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, + type, rid, start, end, count, flags)); + } + + dinfo = device_get_ivars(child); + rle = resource_list_find(&dinfo->resources, type, *rid); + + if (!rle) + return NULL; /* no resource of that type/rid */ + + if (!rle->res) { + device_printf(dev, "WARNING: Resource not reserved by pccard bus\n"); + return NULL; + } else { + if (rle->res->r_dev != dev) return NULL; + bus_release_resource(dev, type, *rid, rle->res); + rle->res = NULL; + switch(type) { + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + if (!(flags & RF_ALIGNMENT_MASK)) + flags |= rman_make_alignment_flags(rle->count); + break; + case SYS_RES_IRQ: + flags |= RF_SHAREABLE; + break; + } + return resource_list_alloc(&dinfo->resources, dev, child, type, rid, + rle->start, rle->end, rle->count, flags); } - return (bus_generic_alloc_resource(dev, child, type, rid, start, - end, count, flags)); } static int pccard_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { - struct resource_list_entry *rle = NULL; + struct pccard_ivar *dinfo; + int passthrough = (device_get_parent(child) != dev); + struct resource_list_entry *rle = 0; + int ret; + int flags; - if (device_get_parent(child) == dev) { - struct pccard_ivar *devi = PCCARD_IVAR(child); - struct resource_list *rl = &devi->resources; - - rle = resource_list_find(rl, type, rid); - } - - if (rle != NULL) { - return (bus_deactivate_resource(dev, type, rle->rid, rle->res)); + if (passthrough) { + return BUS_RELEASE_RESOURCE(device_get_parent(dev), child, + type, rid, r); } - - return (bus_generic_release_resource(dev, child, type, rid, r)); -} - -static int -pccard_activate_resource(device_t dev, device_t child, int type, int rid, - struct resource *r) -{ - /* XXX need to write to the COR to activate this for mf cards */ - struct resource_list_entry *rle = NULL; - if (device_get_parent(child) == dev) { - struct pccard_ivar *devi = PCCARD_IVAR(child); - struct resource_list *rl = &devi->resources; + dinfo = device_get_ivars(child); - rle = resource_list_find(rl, type, rid); - } + rle = resource_list_find(&dinfo->resources, type, rid); - if (rle != NULL) { - return (bus_activate_resource(dev, type, rle->rid, rle->res)); + if (!rle) { + device_printf(dev, "Allocated resource not found, %d %x %lx %lx\n", + type, rid, rman_get_start(r), rman_get_size(r)); + return ENOENT; } - - return (bus_generic_activate_resource(dev, child, type, rid, r)); -} - -static int -pccard_deactivate_resource(device_t dev, device_t child, int type, int rid, - struct resource *r) -{ - /* XXX need to write to the COR to deactivate this for mf cards */ - struct resource_list_entry *rle = NULL; - - if (device_get_parent(child) == dev) { - struct pccard_ivar *devi = PCCARD_IVAR(child); - struct resource_list *rl = &devi->resources; - - rle = resource_list_find(rl, type, rid); + if (!rle->res) { + device_printf(dev, "Allocated resource not recorded\n"); + return ENOENT; } - if (rle != NULL) { - return (bus_deactivate_resource(dev, type, rle->rid, rle->res)); + ret = BUS_RELEASE_RESOURCE(device_get_parent(dev), child, + type, rid, r); + switch(type) { + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + flags = rman_make_alignment_flags(rle->count); + break; + case SYS_RES_IRQ: + flags = RF_SHAREABLE; + break; + default: + flags = 0; } - - return (bus_generic_deactivate_resource(dev, child, type, rid, r)); + rle->res = bus_alloc_resource(dev, type, &rid, + rle->start, rle->end, rle->count, flags); + if (rle->res == NULL) + device_printf(dev, "release_resource: unable to reaquire resource\n"); + return ret; } static void pccard_child_detached(device_t parent, device_t dev) { struct pccard_ivar *ivar = PCCARD_IVAR(dev); + struct pccard_function *pf = ivar->fcn; - if (parent == device_get_parent(dev)) - free(ivar, M_DEVBUF); + pccard_function_disable(pf); } static void pccard_intr(void *arg) { - struct pccard_softc *sc = (struct pccard_softc *) arg; - struct pccard_function *pf; - STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) { - if (pf->intr_handler != NULL) { - int reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); - if (reg & PCCARD_CCR_STATUS_INTR) { - pccard_ccr_write(pf, PCCARD_CCR_STATUS, - reg & ~PCCARD_CCR_STATUS_INTR); - pf->intr_handler(pf->intr_handler_arg); - } - } + struct pccard_function *pf = (struct pccard_function*) arg; + int reg; + + if (pf->intr_handler == NULL) + panic("Null interrupt handler?\n"); + + reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); + if (reg & PCCARD_CCR_STATUS_INTR) { + pccard_ccr_write(pf, PCCARD_CCR_STATUS, + reg & ~PCCARD_CCR_STATUS_INTR); + pf->intr_handler(pf->intr_handler_arg); } } @@ -1025,31 +1084,19 @@ { struct pccard_ivar *ivar = PCCARD_IVAR(child); struct pccard_function *func = ivar->fcn; - struct resource_list_entry *rle = NULL; - struct pccard_softc *sc = device_get_softc(dev); if (func->intr_handler != NULL) panic("Only one interrupt handler per function allowed\n"); - rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 0); - if (rle == NULL || rle->res != irq) - panic("irq in setup_intr does not match allocated irq\n"); - func->intr_handler = intr; func->intr_handler_arg = arg; - func->intr_handler_cookie = *cookiep = func; + func->intr_handler_cookie = *cookiep; pccard_ccr_write(func, PCCARD_CCR_OPTION, - pccard_ccr_read(func, PCCARD_CCR_OPTION) | + pccard_ccr_read(func, PCCARD_CCR_OPTION) | PCCARD_CCR_OPTION_IREQ_ENABLE); - if (sc->intr_handler_count++ == 0) { - rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 0); - if (rle == NULL) - panic("No IRQ for pccard?"); - - bus_setup_intr(dev, rle->res, INTR_TYPE_TTY/* | INTR_FAST*/, - pccard_intr, sc, (void*)&sc->intr_handler_count); - } + bus_setup_intr(dev, irq, INTR_TYPE_TTY/* | INTR_FAST*/, + pccard_intr, func, cookiep); return (0); } @@ -1059,35 +1106,27 @@ { struct pccard_ivar *ivar = PCCARD_IVAR(child); struct pccard_function *func = ivar->fcn; - struct pccard_softc *sc = device_get_softc(dev); + int ret; - if (func->intr_handler_cookie != cookie) - panic("pccard teardown of unknown interrupt handler\n"); - - func->intr_handler = NULL; - func->intr_handler_arg = NULL; - func->intr_handler_cookie = NULL; pccard_ccr_write(func, PCCARD_CCR_OPTION, pccard_ccr_read(func, PCCARD_CCR_OPTION) & ~PCCARD_CCR_OPTION_IREQ_ENABLE); - - if (--sc->intr_handler_count == 0) { - struct resource_list_entry *rle = NULL; - rle = resource_list_find(&ivar->resources, SYS_RES_IRQ, 0); - if (rle == NULL) - panic("No IRQ for pccard?"); - - bus_teardown_intr(dev, rle->res, &sc->intr_handler_count); + ret = bus_teardown_intr(dev, r, cookie); + if (ret == 0) { + func->intr_handler = NULL; + func->intr_handler_arg = NULL; + func->intr_handler_cookie = NULL; } - return (0); + + return (ret); } static device_method_t pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, pccard_probe), DEVMETHOD(device_attach, pccard_attach), - DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_detach, pccard_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), @@ -1098,8 +1137,8 @@ DEVMETHOD(bus_child_detached, pccard_child_detached), DEVMETHOD(bus_alloc_resource, pccard_alloc_resource), DEVMETHOD(bus_release_resource, pccard_release_resource), - DEVMETHOD(bus_activate_resource, pccard_activate_resource), - DEVMETHOD(bus_deactivate_resource, pccard_deactivate_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, pccard_setup_intr), DEVMETHOD(bus_teardown_intr, pccard_teardown_intr), DEVMETHOD(bus_set_resource, pccard_set_resource), Index: sys/dev/pccard/pccardvar.h =================================================================== RCS file: /export/ncvs/src/sys/dev/pccard/pccardvar.h,v retrieving revision 1.25 diff -u -u -r1.25 pccardvar.h --- sys/dev/pccard/pccardvar.h 2001/05/08 23:56:47 1.25 +++ sys/dev/pccard/pccardvar.h 2001/07/13 12:13:15 @@ -185,7 +185,6 @@ /* this stuff is for the card */ struct pccard_card card; int sc_enabled_count; /* num functions enabled */ - int intr_handler_count; }; void @@ -261,17 +260,8 @@ #define PCCARD_SPACE_MEMORY 1 #define PCCARD_SPACE_IO 2 -int pccard_ccr_read(struct pccard_function *, int); -void pccard_ccr_write(struct pccard_function *, int, int); - #define pccard_mfc(sc) (STAILQ_FIRST(&(sc)->card.pf_head) && \ STAILQ_NEXT(STAILQ_FIRST(&(sc)->card.pf_head),pf_list)) - -/* The following is the vestages of the NetBSD driver api */ - -void pccard_function_init(struct pccard_function *); -int pccard_function_enable(struct pccard_function *); -void pccard_function_disable(struct pccard_function *); #define pccard_io_alloc(pf, start, size, align, pciop) \ (pccard_chip_io_alloc((pf)->sc->pct, pf->sc->pch, (start), \