diff -ur src/sys/dev/acpica/acpi.c power/src/sys/dev/acpica/acpi.c --- src/sys/dev/acpica/acpi.c Tue Dec 30 13:54:26 2003 +++ power/src/sys/dev/acpica/acpi.c Thu Jan 1 13:10:00 2004 @@ -1501,6 +1501,16 @@ } /* + * Get a specified device's power state. + */ +ACPI_STATUS +acpi_GetPowerState(ACPI_HANDLE handle, int *state) +{ + + return (acpi_EvaluateInteger(handle, "_PSC", state)); +} + +/* * Set the system sleep state * * Currently we support S1-S5 but S4 is only S4BIOS diff -ur src/sys/dev/acpica/acpi_pci.c power/src/sys/dev/acpica/acpi_pci.c --- src/sys/dev/acpica/acpi_pci.c Fri Sep 19 10:07:51 2003 +++ power/src/sys/dev/acpica/acpi_pci.c Thu Jan 1 09:54:50 2004 @@ -65,11 +65,8 @@ static int acpi_pci_attach(device_t dev); static int acpi_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result); -#if 0 static int acpi_pci_set_powerstate_method(device_t dev, device_t child, int state); -static int acpi_pci_get_powerstate_method(device_t dev, device_t child); -#endif static ACPI_STATUS acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 level, void *context, void **status); @@ -78,7 +75,7 @@ DEVMETHOD(device_probe, acpi_pci_probe), DEVMETHOD(device_attach, acpi_pci_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_suspend, pci_suspend), DEVMETHOD(device_resume, pci_resume), /* Bus interface */ @@ -108,9 +105,8 @@ DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method), DEVMETHOD(pci_enable_io, pci_enable_io_method), DEVMETHOD(pci_disable_io, pci_disable_io_method), - /* XXX: We should override these two. */ DEVMETHOD(pci_get_powerstate, pci_get_powerstate_method), - DEVMETHOD(pci_set_powerstate, pci_set_powerstate_method), + DEVMETHOD(pci_set_powerstate, acpi_pci_set_powerstate_method), DEVMETHOD(pci_assign_interrupt, pci_assign_interrupt_method), { 0, 0 } @@ -140,24 +136,58 @@ return(pci_read_ivar(dev, child, which, result)); } -#if 0 /* * PCI power manangement */ static int acpi_pci_set_powerstate_method(device_t dev, device_t child, int state) { - /* XXX: TODO */ - return (ENXIO); -} + ACPI_STATUS status; + int acpi_state, old_state, error; -static int -acpi_pci_get_powerstate_method(device_t dev, device_t child) -{ - /* XXX: TODO */ - return (ENXIO); + switch (state) { + case PCI_POWERSTATE_D0: + acpi_state = ACPI_STATE_D0; + break; + case PCI_POWERSTATE_D1: + acpi_state = ACPI_STATE_D1; + break; + case PCI_POWERSTATE_D2: + acpi_state = ACPI_STATE_D2; + break; + case PCI_POWERSTATE_D3: + acpi_state = ACPI_STATE_D3; + break; + default: + return (EINVAL); + } + + /* + * We set the state using PCI Power Management outside of setting + * the ACPI state. This means that when powering down a device, we + * first shut it down using PCI, and then using ACPI, which lets ACPI + * try to power down any Power Resources that are now no longer used. + * When powering up a device, we let ACPI set the state first so that + * it can enable any needed Power Resources before changing the PCI + * power state. + */ + old_state = pci_get_powerstate(child); + if (old_state < state) { + error = pci_set_powerstate_method(dev, child, state); + if (error) + return (error); + } + status = acpi_pwr_switch_consumer(acpi_get_handle(child), acpi_state); + if (ACPI_FAILURE(status)) + device_printf(dev, + "Failed to set ACPI power state D%d on %s: %s\n", + acpi_state, device_get_nameunit(child), + AcpiFormatException(status)); + if (state > old_state) + return (pci_set_powerstate_method(dev, child, state)); + else + return (0); } -#endif static ACPI_STATUS acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 level, void *context, diff -ur src/sys/dev/acpica/acpivar.h power/src/sys/dev/acpica/acpivar.h --- src/sys/dev/acpica/acpivar.h Tue Dec 30 13:54:27 2003 +++ power/src/sys/dev/acpica/acpivar.h Thu Jan 1 13:10:02 2004 @@ -174,6 +174,7 @@ extern BOOLEAN acpi_MatchHid(device_t dev, char *hid); extern ACPI_STATUS acpi_GetHandleInScope(ACPI_HANDLE parent, char *path, ACPI_HANDLE *result); +extern ACPI_STATUS acpi_GetPowerState(ACPI_HANDLE handle, int *state); extern ACPI_BUFFER *acpi_AllocBuffer(int size); extern ACPI_STATUS acpi_EvaluateInteger(ACPI_HANDLE handle, char *path, int *number); Only in src/sys/dev: ccd diff -ur src/sys/dev/firewire/fwohci_pci.c power/src/sys/dev/firewire/fwohci_pci.c --- src/sys/dev/firewire/fwohci_pci.c Tue Jan 6 04:48:03 2004 +++ power/src/sys/dev/firewire/fwohci_pci.c Tue Jan 6 05:11:39 2004 @@ -418,11 +418,6 @@ { fwohci_softc_t *sc = device_get_softc(dev); -#ifndef BURN_BRIDGES - device_printf(dev, "fwohci_pci_resume: power_state = 0x%08x\n", - pci_get_powerstate(dev)); - pci_set_powerstate(dev, PCI_POWERSTATE_D0); -#endif fwohci_pci_init(dev); fwohci_resume(sc, dev); return 0; diff -ur src/sys/dev/fxp/if_fxp.c power/src/sys/dev/fxp/if_fxp.c --- src/sys/dev/fxp/if_fxp.c Mon Dec 1 21:17:25 2003 +++ power/src/sys/dev/fxp/if_fxp.c Sat Jan 3 11:29:17 2004 @@ -211,9 +211,6 @@ static void fxp_init(void *xsc); static void fxp_init_body(struct fxp_softc *sc); static void fxp_tick(void *xsc); -#ifndef BURN_BRIDGES -static void fxp_powerstate_d0(device_t dev); -#endif static void fxp_start(struct ifnet *ifp); static void fxp_start_body(struct ifnet *ifp); static void fxp_stop(struct fxp_softc *sc); @@ -358,34 +355,6 @@ return (ENXIO); } -#ifndef BURN_BRIDGES -static void -fxp_powerstate_d0(device_t dev) -{ -#if __FreeBSD_version >= 430002 - u_int32_t iobase, membase, irq; - - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - /* Save important PCI config data. */ - iobase = pci_read_config(dev, FXP_PCI_IOBA, 4); - membase = pci_read_config(dev, FXP_PCI_MMBA, 4); - irq = pci_read_config(dev, PCIR_INTLINE, 4); - - /* Reset the power state. */ - device_printf(dev, "chip is in D%d power mode " - "-- setting to D0\n", pci_get_powerstate(dev)); - - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - - /* Restore PCI config data. */ - pci_write_config(dev, FXP_PCI_IOBA, iobase, 4); - pci_write_config(dev, FXP_PCI_MMBA, membase, 4); - pci_write_config(dev, PCIR_INTLINE, irq, 4); - } -#endif -} -#endif - static void fxp_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) { @@ -426,9 +395,7 @@ */ pci_enable_busmaster(dev); val = pci_read_config(dev, PCIR_COMMAND, 2); -#ifndef BURN_BRIDGES - fxp_powerstate_d0(dev); -#endif + /* * Figure out which we should try first - memory mapping or i/o mapping? * We default to memory mapping. Then we accept an override from the @@ -1021,9 +988,7 @@ FXP_LOCK(sc); s = splimp(); -#ifndef BURN_BRIDGES - fxp_powerstate_d0(dev); -#endif + /* better way to do this? */ for (i = 0; i < 5; i++) pci_write_config(dev, PCIR_BAR(i), sc->saved_maps[i], 4); @@ -1553,6 +1518,9 @@ struct fxp_softc *sc = xsc; struct ifnet *ifp = &sc->sc_if; u_int8_t statack; + + if (sc->gone) + return; FXP_LOCK(sc); if (sc->suspended) { diff -ur src/sys/dev/fxp/if_fxpvar.h power/src/sys/dev/fxp/if_fxpvar.h --- src/sys/dev/fxp/if_fxpvar.h Thu Oct 30 17:36:14 2003 +++ power/src/sys/dev/fxp/if_fxpvar.h Sat Jan 3 11:29:17 2004 @@ -189,6 +189,7 @@ int cu_resume_bug; int revision; int flags; + int gone; u_int32_t saved_maps[5]; /* pci data */ u_int32_t saved_biosaddr; u_int8_t saved_intline; diff -ur src/sys/dev/lge/if_lge.c power/src/sys/dev/lge/if_lge.c --- src/sys/dev/lge/if_lge.c Fri Dec 12 01:13:25 2003 +++ power/src/sys/dev/lge/if_lge.c Sat Jan 3 11:29:18 2004 @@ -498,30 +498,7 @@ sc = device_get_softc(dev); unit = device_get_unit(dev); bzero(sc, sizeof(struct lge_softc)); -#ifndef BURN_BRIDGES - /* - * Handle power management nonsense. - */ - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - u_int32_t iobase, membase, irq; - /* Save important PCI config data. */ - iobase = pci_read_config(dev, LGE_PCI_LOIO, 4); - membase = pci_read_config(dev, LGE_PCI_LOMEM, 4); - irq = pci_read_config(dev, LGE_PCI_INTLINE, 4); - - /* Reset the power state. */ - printf("lge%d: chip is in D%d power mode " - "-- setting to D0\n", unit, - pci_get_powerstate(dev)); - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - - /* Restore PCI config data. */ - pci_write_config(dev, LGE_PCI_LOIO, iobase, 4); - pci_write_config(dev, LGE_PCI_LOMEM, membase, 4); - pci_write_config(dev, LGE_PCI_INTLINE, irq, 4); - } -#endif /* * Map control/status registers. */ diff -ur src/sys/dev/nge/if_nge.c power/src/sys/dev/nge/if_nge.c --- src/sys/dev/nge/if_nge.c Fri Dec 12 01:13:27 2003 +++ power/src/sys/dev/nge/if_nge.c Sat Jan 3 11:29:19 2004 @@ -832,30 +832,7 @@ mtx_init(&sc->nge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); -#ifndef BURN_BRIDGES - /* - * Handle power management nonsense. - */ - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - u_int32_t iobase, membase, irq; - /* Save important PCI config data. */ - iobase = pci_read_config(dev, NGE_PCI_LOIO, 4); - membase = pci_read_config(dev, NGE_PCI_LOMEM, 4); - irq = pci_read_config(dev, NGE_PCI_INTLINE, 4); - - /* Reset the power state. */ - printf("nge%d: chip is in D%d power mode " - "-- setting to D0\n", unit, - pci_get_powerstate(dev)); - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - - /* Restore PCI config data. */ - pci_write_config(dev, NGE_PCI_LOIO, iobase, 4); - pci_write_config(dev, NGE_PCI_LOMEM, membase, 4); - pci_write_config(dev, NGE_PCI_INTLINE, irq, 4); - } -#endif /* * Map control/status registers. */ diff -ur src/sys/dev/pccbb/pccbb.c power/src/sys/dev/pccbb/pccbb.c --- src/sys/dev/pccbb/pccbb.c Sat Jan 3 03:53:35 2004 +++ power/src/sys/dev/pccbb/pccbb.c Sat Jan 3 11:29:21 2004 @@ -640,6 +640,10 @@ } #ifndef BURN_BRIDGES +/* + * Still need this because the pci code only does power for type 0 + * header devices. + */ static void cbb_powerstate_d0(device_t dev) { @@ -683,8 +687,9 @@ static int cbb_attach(device_t brdev) { + static int curr_bus_number = 1; /* XXX EVILE BAD (see below) */ struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev); - int rid; + int rid, bus; mtx_init(&sc->mtx, device_get_nameunit(brdev), "cbb", MTX_DEF); cv_init(&sc->cv, "cbb cv"); @@ -698,55 +703,16 @@ STAILQ_INIT(&sc->intr_handlers); #ifndef BURN_BRIDGES cbb_powerstate_d0(brdev); - - /* - * The PCI bus code should assign us memory in the absense - * of the BIOS doing so. However, 'should' isn't 'is,' so we kludge - * up something here until the PCI/acpi code properly assigns the - * resource. - */ #endif + rid = CBBR_SOCKBASE; sc->base_res = bus_alloc_resource(brdev, SYS_RES_MEMORY, &rid, 0, ~0, 1, RF_ACTIVE); if (!sc->base_res) { -#ifdef BURN_BRIDGES device_printf(brdev, "Could not map register memory\n"); mtx_destroy(&sc->mtx); cv_destroy(&sc->cv); return (ENOMEM); -#else - uint32_t sockbase; - /* - * Generally, the BIOS will assign this memory for us. - * However, newer BIOSes do not because the MS design - * documents have mandated that this is for the OS - * to assign rather than the BIOS. This driver shouldn't - * be doing this, but until the pci bus code (or acpi) - * does this, we allow CardBus bridges to work on more - * machines. - */ - pci_write_config(brdev, rid, 0xfffffffful, 4); - sockbase = pci_read_config(brdev, rid, 4); - sockbase = (sockbase & 0xfffffff0ul) & - -(sockbase & 0xfffffff0ul); - sc->base_res = bus_generic_alloc_resource( - device_get_parent(brdev), brdev, SYS_RES_MEMORY, - &rid, cbb_start_mem, ~0, sockbase, - RF_ACTIVE | rman_make_alignment_flags(sockbase)); - if (!sc->base_res) { - device_printf(brdev, - "Could not grab register memory\n"); - mtx_destroy(&sc->mtx); - cv_destroy(&sc->cv); - return (ENOMEM); - } - sc->flags |= CBB_KLUDGE_ALLOC; - pci_write_config(brdev, CBBR_SOCKBASE, - rman_get_start(sc->base_res), 4); - DEVPRINTF((brdev, "PCI Memory allocated: %08lx\n", - rman_get_start(sc->base_res))); -#endif } else { DEVPRINTF((brdev, "Found memory at %08lx\n", rman_get_start(sc->base_res))); @@ -759,6 +725,25 @@ sc->exca.chipset = EXCA_CARDBUS; cbb_chipinit(sc); + /* + * This is a gross hack. We should be scanning the entire pci + * tree, assigning bus numbers in a way such that we (1) can + * reserve 1 extra bus just in case and (2) all sub busses + * are in an appropriate range. + */ + bus = pci_read_config(brdev, PCIR_SECBUS_2, 1); + DEVPRINTF((brdev, "Secondary bus is %d\n", bus)); + if (bus == 0) { + bus = curr_bus_number; + DEVPRINTF((brdev, "Secondary bus set to %d subbus %d\n", bus, + bus + 1)); + sc->secbus = bus; + sc->subbus = bus + 1; + pci_write_config(brdev, PCIR_SECBUS_2, bus, 1); + pci_write_config(brdev, PCIR_SUBBUS_2, bus + 1, 1); + curr_bus_number += 2; + } + /* attach children */ sc->cbdev = device_add_child(brdev, "cardbus", -1); if (sc->cbdev == NULL) @@ -812,19 +797,13 @@ device_printf(brdev, "unable to create event thread.\n"); panic("cbb_create_event_thread"); } - return (0); err: if (sc->irq_res) bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res); if (sc->base_res) { - if (sc->flags & CBB_KLUDGE_ALLOC) - bus_generic_release_resource(device_get_parent(brdev), - brdev, SYS_RES_MEMORY, CBBR_SOCKBASE, - sc->base_res); - else - bus_release_resource(brdev, SYS_RES_MEMORY, - CBBR_SOCKBASE, sc->base_res); + bus_release_resource(brdev, SYS_RES_MEMORY, CBBR_SOCKBASE, + sc->base_res); } mtx_destroy(&sc->mtx); cv_destroy(&sc->cv); @@ -863,12 +842,8 @@ mtx_unlock(&sc->mtx); bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res); - if (sc->flags & CBB_KLUDGE_ALLOC) - bus_generic_release_resource(device_get_parent(brdev), - brdev, SYS_RES_MEMORY, CBBR_SOCKBASE, sc->base_res); - else - bus_release_resource(brdev, SYS_RES_MEMORY, - CBBR_SOCKBASE, sc->base_res); + bus_release_resource(brdev, SYS_RES_MEMORY, CBBR_SOCKBASE, + sc->base_res); mtx_destroy(&sc->mtx); cv_destroy(&sc->cv); return (0); @@ -1124,7 +1099,6 @@ */ sockevent = cbb_get(sc, CBB_SOCKET_EVENT); if (sockevent != 0) { - DPRINTF(("CBB EVENT 0x%x\n", sockevent)); /* ack the interrupt */ cbb_setb(sc, CBB_SOCKET_EVENT, sockevent); @@ -1146,7 +1120,6 @@ cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD); sc->flags &= ~CBB_CARD_OK; cbb_disable_func_intr(sc); - DPRINTF(("Waking up thread\n")); cv_signal(&sc->cv); mtx_unlock(&sc->mtx); } @@ -1340,13 +1313,17 @@ * detect the voltage for the card, and set it. Since the power * used is the square of the voltage, lower voltages is a big win * and what Windows does (and what Microsoft prefers). The MS paper - * also talks about preferring the CIS entry as well. + * also talks about preferring the CIS entry as well. In addition, + * we power up with OE disabled. We'll set it later in the power + * up sequence. */ static int cbb_do_power(device_t brdev) { + struct cbb_softc *sc = device_get_softc(brdev); int voltage; + exca_clrb(&sc->exca, EXCA_PWRCTL, EXCA_PWRCTL_OE); /* Prefer lowest voltage supported */ voltage = cbb_detect_voltage(brdev); cbb_power(brdev, CARD_OFF); @@ -1632,6 +1609,7 @@ start = cbb_start_mem; if (end < start) end = start; + /* This is now suspect: */ if (RF_ALIGNMENT(flags) < CBB_MEMALIGN_BITS) flags = (flags & ~RF_ALIGNMENT_MASK) | rman_make_alignment_flags(CBB_MEMALIGN); @@ -1956,11 +1934,14 @@ static uint32_t cbb_read_config(device_t brdev, int b, int s, int f, int reg, int width) { + uint32_t rv; + /* * Pass through to the next ppb up the chain (i.e. our grandparent). */ - return (PCIB_READ_CONFIG(device_get_parent(device_get_parent(brdev)), - b, s, f, reg, width)); + rv = PCIB_READ_CONFIG(device_get_parent(device_get_parent(brdev)), + b, s, f, reg, width); + return (rv); } static void diff -ur src/sys/dev/pccbb/pccbbvar.h power/src/sys/dev/pccbb/pccbbvar.h --- src/sys/dev/pccbb/pccbbvar.h Sat Jun 14 11:44:11 2003 +++ power/src/sys/dev/pccbb/pccbbvar.h Thu Jan 1 13:41:51 2004 @@ -67,7 +67,6 @@ struct cv cv; u_int32_t flags; #define CBB_CARD_OK 0x08000000 -#define CBB_KLUDGE_ALLOC 0x10000000 #define CBB_16BIT_CARD 0x20000000 #define CBB_KTHREAD_RUNNING 0x40000000 #define CBB_KTHREAD_DONE 0x80000000 Only in power/src/sys/dev/pccbb: tmp.71124.11~ Only in power/src/sys/dev/pccbb: tmp.71124.2~ Only in power/src/sys/dev/pccbb: tmp.79432.2~ diff -ur src/sys/dev/pci/pci.c power/src/sys/dev/pci/pci.c --- src/sys/dev/pci/pci.c Tue Dec 30 13:54:44 2003 +++ power/src/sys/dev/pci/pci.c Sat Jan 3 11:29:21 2004 @@ -68,7 +68,8 @@ static int pci_porten(device_t pcib, int b, int s, int f); static int pci_memen(device_t pcib, int b, int s, int f); -static int pci_add_map(device_t pcib, int b, int s, int f, int reg, +static int pci_add_map(device_t pcib, device_t bus, device_t dev, + int b, int s, int f, int reg, struct resource_list *rl); static void pci_add_resources(device_t pcib, device_t bus, device_t dev); @@ -82,13 +83,15 @@ static void pci_hdrtypedata(device_t pcib, int b, int s, int f, pcicfgregs *cfg); static void pci_read_extcap(device_t pcib, pcicfgregs *cfg); +static void pci_cfg_restore(device_t, struct pci_devinfo *); +static void pci_cfg_save(device_t, struct pci_devinfo *, int); static device_method_t pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, pci_probe), DEVMETHOD(device_attach, pci_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_suspend, pci_suspend), DEVMETHOD(device_resume, pci_resume), /* Bus interface */ @@ -96,7 +99,7 @@ DEVMETHOD(bus_probe_nomatch, pci_probe_nomatch), DEVMETHOD(bus_read_ivar, pci_read_ivar), DEVMETHOD(bus_write_ivar, pci_write_ivar), - DEVMETHOD(bus_driver_added, bus_generic_driver_added), + DEVMETHOD(bus_driver_added, pci_driver_added), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), @@ -613,6 +616,7 @@ return (EINVAL); } pci_set_command_bit(dev, child, bit); + /* Some devices seem to need a brief stall here, what do to? */ command = PCI_READ_CONFIG(dev, child, PCIR_COMMAND, 2); if (command & bit) return (0); @@ -719,11 +723,12 @@ * register is a 32bit map register or 2 if it is a 64bit register. */ static int -pci_add_map(device_t pcib, int b, int s, int f, int reg, - struct resource_list *rl) +pci_add_map(device_t pcib, device_t bus, device_t dev, + int b, int s, int f, int reg, struct resource_list *rl) { uint32_t map; uint64_t base; + uint64_t start, end, count; uint8_t ln2size; uint8_t ln2range; uint32_t testval; @@ -731,25 +736,34 @@ int type; map = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4); - - if (map == 0 || map == 0xffffffff) - return (1); /* skip invalid entry */ - PCIB_WRITE_CONFIG(pcib, b, s, f, reg, 0xffffffff, 4); testval = PCIB_READ_CONFIG(pcib, b, s, f, reg, 4); PCIB_WRITE_CONFIG(pcib, b, s, f, reg, map, 4); - base = pci_mapbase(map); if (pci_maptype(map) & PCI_MAPMEM) type = SYS_RES_MEMORY; else type = SYS_RES_IOPORT; ln2size = pci_mapsize(testval); ln2range = pci_maprange(testval); - if (ln2range == 64) { + base = pci_mapbase(map); + + /* + * For I/O registers, if bottom bit is set, and the next bit up + * isn't clear, we know we have a BAR that doesn't conform to the + * spec, so ignore it. Also, sanity check the size of the data + * areas to the type of memory involved. + */ + if ((testval & 0x1) == 0x1 && + (testval & 0x2) != 0) + return (1); + if ((type == SYS_RES_MEMORY && ln2size < 5) || + (type == SYS_RES_IOPORT && ln2size < 3)) + return (1); + + if (ln2range == 64) /* Read the other half of a 64bit map register */ base |= (uint64_t) PCIB_READ_CONFIG(pcib, b, s, f, reg + 4, 4) << 32; - } if (bootverbose) { printf("\tmap[%02x]: type %x, range %2d, base %08x, size %2d", @@ -765,9 +779,10 @@ /* * This code theoretically does the right thing, but has - * undesirable side effects in some cases where - * peripherals respond oddly to having these bits - * enabled. Leave them alone by default. + * undesirable side effects in some cases where peripherals + * respond oddly to having these bits enabled. Let the user + * be able to turn them off (since pci_enable_io_modes is 1 by + * default). */ if (pci_enable_io_modes) { /* Turn on resources that have been left off by a lazy BIOS */ @@ -787,9 +802,23 @@ if (type == SYS_RES_MEMORY && !pci_memen(pcib, b, s, f)) return (1); } - resource_list_add(rl, type, reg, base, base + (1 << ln2size) - 1, - (1 << ln2size)); + /* + * If base is 0, then we have problems. It is best to ignore + * such entires for the moment. These will be allocated later if + * the driver specifically requests them. + */ + if (base == 0) + return 1; + start = base; + end = base + (1 << ln2size) - 1; + count = 1 << ln2size; + resource_list_add(rl, type, reg, start, end, count); + /* + * Not quite sure what to do on failure of allocating the resource + * since I can postulate several right answers. + */ + resource_list_alloc(rl, bus, dev, type, ®, start, end, count, 0); return ((ln2range == 64) ? 2 : 1); } @@ -805,14 +834,13 @@ b = cfg->bus; s = cfg->slot; f = cfg->func; - for (i = 0; i < cfg->nummaps;) { - i += pci_add_map(pcib, b, s, f, PCIR_BAR(i), rl); - } + for (i = 0; i < cfg->nummaps;) + i += pci_add_map(pcib, bus, dev, b, s, f, PCIR_BAR(i), rl); for (q = &pci_quirks[0]; q->devid; q++) { if (q->devid == ((cfg->device << 16) | cfg->vendor) && q->type == PCI_QUIRK_MAP_REG) - pci_add_map(pcib, b, s, f, q->arg1, rl); + pci_add_map(pcib, bus, dev, b, s, f, q->arg1, rl); } if (cfg->intpin > 0 && PCI_INTERRUPT_VALID(cfg->intline)) { @@ -873,6 +901,8 @@ pcib = device_get_parent(bus); dinfo->cfg.dev = device_add_child(bus, NULL, -1); device_set_ivars(dinfo->cfg.dev, dinfo); + pci_cfg_save(dinfo->cfg.dev, dinfo, 0); + pci_cfg_restore(dinfo->cfg.dev, dinfo); pci_add_resources(pcib, bus, dinfo->cfg.dev); pci_print_verbose(dinfo); } @@ -907,6 +937,52 @@ return (bus_generic_attach(dev)); } +int +pci_suspend(device_t dev) +{ + int numdevs; + device_t *devlist; + device_t child; + struct pci_devinfo *dinfo; + int i; + + /* + * Save the pci configuration space for each child. We don't need + * to do this, unless the BIOS suspend code powers down the bus and + * the devices on the bus. + */ + device_get_children(dev, &devlist, &numdevs); + for (i = 0; i < numdevs; i++) { + child = devlist[i]; + dinfo = (struct pci_devinfo *) device_get_ivars(child); + pci_cfg_save(child, dinfo, 0); + } + free(devlist, M_TEMP); + return (bus_generic_suspend(dev)); +} + +int +pci_resume(device_t dev) +{ + int numdevs; + device_t *devlist; + device_t child; + struct pci_devinfo *dinfo; + int i; + + /* + * Restore the pci configuration space for each child. + */ + device_get_children(dev, &devlist, &numdevs); + for (i = 0; i < numdevs; i++) { + child = devlist[i]; + dinfo = (struct pci_devinfo *) device_get_ivars(child); + pci_cfg_restore(child, dinfo); + } + free(devlist, M_TEMP); + return (bus_generic_resume(dev)); +} + static void pci_load_vendor_data(void) { @@ -922,6 +998,34 @@ } } +void +pci_driver_added(device_t dev, driver_t *driver) +{ + int numdevs; + device_t *devlist; + device_t child; + struct pci_devinfo *dinfo; + int i; + + device_printf(dev, "driver added\n"); + DEVICE_IDENTIFY(driver, dev); + device_get_children(dev, &devlist, &numdevs); + for (i = 0; i < numdevs; i++) { + child = devlist[i]; + if (device_get_state(child) != DS_NOTPRESENT) + continue; + dinfo = device_get_ivars(child); + pci_print_verbose(dinfo); +/*XXX???*/ /* resource_list_init(&dinfo->cfg.resources); */ + printf("pci%d:%d:%d: reprobing on driver added\n", + dinfo->cfg.bus, dinfo->cfg.slot, dinfo->cfg.func); + pci_cfg_restore(child, dinfo); + if (device_probe_and_attach(child) != 0) + pci_cfg_save(child, dinfo, 1); + } + free(devlist, M_TEMP); +} + int pci_print_child(device_t dev, device_t child) { @@ -1047,6 +1151,7 @@ } printf(" at device %d.%d (no driver attached)\n", pci_get_slot(child), pci_get_function(child)); + pci_cfg_save(child, (struct pci_devinfo *) device_get_ivars(child), 1); return; } @@ -1326,18 +1431,74 @@ } #endif /* DDB */ +/* + * XXX I'm not sure the following is good for 64-bit bars. + */ +static struct resource * +pci_alloc_map(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); + struct resource_list *rl = &dinfo->resources; + struct resource_list_entry *rle; + struct resource *res; + uint32_t map, testval; + + /* + * Weed out the bogons, and figure out how large the BAR/map is. + */ + map = pci_read_config(child, *rid, 4); + if (pci_maptype(map) & PCI_MAPMEM) { + if (type != SYS_RES_MEMORY) { + device_printf(child, "rid %#x says memory, driver wants %d failed.\n", *rid, type); + return (NULL); + } + } else { + if (type != SYS_RES_IOPORT) { + device_printf(child, "rid %#x says ioport, driver wants %d failed.\n", *rid, type); + return (NULL); + } + } + pci_write_config(child, *rid, 0xffffffff, 4); + testval = pci_read_config(child, *rid, 4); + + /* + * Allocate enough resource, and then write back the + * appropriate bar for that resource (this is the part + * I'm not sure is good for 64-bit bars). + */ + count = 1 << pci_mapsize(testval); + res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, type, rid, + start, end, count, flags); + if (res == NULL) { + device_printf(child, "%#lx bytes of rid %#x res %d failed.\n", + count, *rid, type); + pci_write_config(child, *rid, map, 4); + return (NULL); + } + resource_list_add(rl, type, *rid, start, end, count); + rle = resource_list_find(rl, type, *rid); + if (rle == NULL) + panic("pci_alloc_map: unexpedly can't find resource."); + rle->res = res; + device_printf(child, "Lazy allocation of %#lx bytes rid %#x type %d at %#lx\n", + count, *rid, type, rman_get_start(res)); + pci_write_config(child, *rid, rman_get_start(res), 4); + return (res); +} + + struct resource * pci_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 pci_devinfo *dinfo = device_get_ivars(child); struct resource_list *rl = &dinfo->resources; + struct resource_list_entry *rle; pcicfgregs *cfg = &dinfo->cfg; /* * Perform lazy resource allocation - * - * XXX add support here for SYS_RES_IOPORT and SYS_RES_MEMORY */ if (device_get_parent(child) == dev) { switch (type) { @@ -1363,16 +1524,39 @@ if (*rid < PCIR_BAR(cfg->nummaps)) { /* * Enable the I/O mode. We should - * also be allocating resources - * too. XXX + * also be assigning resources too + * when none are present. The + * resource_list_alloc kind of sorta does + * this... */ if (PCI_ENABLE_IO(dev, child, type)) return (NULL); } + rle = resource_list_find(rl, type, *rid); + if (rle == NULL) + return (pci_alloc_map(dev, child, type, rid, + start, end, count, flags)); break; } + /* + * If we've already allocated the resource, then + * return it now. But first we may need to activate + * it, since we don't allocate the resource as active + * above. Normally this would be done down in the + * nexus, but since we short-circuit that path we have + * to do its job here. Not sure if we should free the + * resource if it fails to activate. + */ + rle = resource_list_find(rl, type, *rid); + if (rle != NULL && rle->res != NULL) { + device_printf(child, "Bus reserved %#lx bytes for rid %#x type %d at %#lx\n", rman_get_size(rle->res), *rid, type, rman_get_start(rle->res)); + if ((flags & RF_ACTIVE) && + bus_generic_activate_resource(dev, child, type, + *rid, rle->res) != 0) + return NULL; + return (rle->res); + } } - return (resource_list_alloc(rl, dev, child, type, rid, start, end, count, flags)); } @@ -1416,13 +1600,9 @@ struct resource_list * pci_get_resource_list (device_t dev, device_t child) { - struct pci_devinfo * dinfo = device_get_ivars(child); - struct resource_list * rl = &dinfo->resources; - - if (!rl) - return (NULL); + struct pci_devinfo *dinfo = device_get_ivars(child); - return (rl); + return (&dinfo->resources); } uint32_t @@ -1447,7 +1627,7 @@ } int -pci_child_location_str_method(device_t cbdev, device_t child, char *buf, +pci_child_location_str_method(device_t dev, device_t child, char *buf, size_t buflen) { struct pci_devinfo *dinfo; @@ -1459,7 +1639,7 @@ } int -pci_child_pnpinfo_str_method(device_t cbdev, device_t child, char *buf, +pci_child_pnpinfo_str_method(device_t dev, device_t child, char *buf, size_t buflen) { struct pci_devinfo *dinfo; @@ -1506,34 +1686,86 @@ return (0); } -int -pci_resume(device_t dev) +static void +pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo) { - int numdevs; - int i; - device_t *children; - device_t child; - struct pci_devinfo *dinfo; - pcicfgregs *cfg; + int i; - device_get_children(dev, &children, &numdevs); + /* + * Only do header type 0 devices. Type 1 devices are bridges, which + * we know need special treatment. Type 2 devices are cardbus bridges + * which also require special treatment. Other types are unknown, and + * we err on the side of safety by ignoring them. + */ + if (dinfo->cfg.hdrtype != 0) + return; + printf("pci%d:%d:%d: setting power state D0\n", dinfo->cfg.bus, + dinfo->cfg.slot, dinfo->cfg.func); + pci_set_powerstate(dev, PCI_POWERSTATE_D0); + for (i = 0; i < dinfo->cfg.nummaps; i++) + pci_write_config(dev, PCIR_MAPS + i * 4, dinfo->cfg.bar[i], 4); + pci_write_config(dev, PCIR_BIOS, dinfo->cfg.bios, 4); + pci_write_config(dev, PCIR_COMMAND, dinfo->cfg.cmdreg, 2); + pci_write_config(dev, PCIR_INTLINE, dinfo->cfg.intline, 1); + pci_write_config(dev, PCIR_INTPIN, dinfo->cfg.intpin, 1); + pci_write_config(dev, PCIR_MINGNT, dinfo->cfg.mingnt, 1); + pci_write_config(dev, PCIR_MAXLAT, dinfo->cfg.maxlat, 1); + pci_write_config(dev, PCIR_CACHELNSZ, dinfo->cfg.cachelnsz, 1); + pci_write_config(dev, PCIR_LATTIMER, dinfo->cfg.lattimer, 1); +} - for (i = 0; i < numdevs; i++) { - child = children[i]; +static void +pci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate) +{ + int i; + uint32_t cls; - dinfo = device_get_ivars(child); - cfg = &dinfo->cfg; - if (cfg->intpin > 0 && PCI_INTERRUPT_VALID(cfg->intline)) { - cfg->intline = PCI_ASSIGN_INTERRUPT(dev, child); - if (PCI_INTERRUPT_VALID(cfg->intline)) { - pci_write_config(child, PCIR_INTLINE, - cfg->intline, 1); - } - } - } + /* + * Only do header type 0 devices. Type 1 devices are bridges, which + * we know need special treatment. Type 2 devices are cardbus bridges + * which also require special treatment. Other types are unknown, and + * we err on the side of safety by ignoring them. Powering down + * bridges should not be undertaken lightly. + */ + if (dinfo->cfg.hdrtype != 0) + return; + for (i = 0; i < dinfo->cfg.nummaps; i++) + dinfo->cfg.bar[i] = pci_read_config(dev, PCIR_MAPS + i * 4, 4); + dinfo->cfg.bios = pci_read_config(dev, PCIR_BIOS, 4); - free(children, M_TEMP); + /* + * Some drivers apparently write to these registers w/o + * updating our cahced copy. No harm happens if we update the + * copy, so do so here so we can restore them. The COMMAND + * register is modified by the bus w/o updating the cache. This + * should represent the normally writable portion of the 'defined' + * part of type 0 headers. In theory we also need to save/restore + * the PCI capability structures we know about, but apart from power + * we don't know any that are writable. + */ + dinfo->cfg.cmdreg = pci_read_config(dev, PCIR_COMMAND, 2); + dinfo->cfg.intline = pci_read_config(dev, PCIR_INTLINE, 1); + dinfo->cfg.intpin = pci_read_config(dev, PCIR_INTPIN, 1); + dinfo->cfg.mingnt = pci_read_config(dev, PCIR_MINGNT, 1); + dinfo->cfg.maxlat = pci_read_config(dev, PCIR_MAXLAT, 1); + dinfo->cfg.cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); + dinfo->cfg.lattimer = pci_read_config(dev, PCIR_LATTIMER, 1); - return (bus_generic_resume(dev)); + /* + * don't set the state for display devices and for memory devices + * since bad things happen. we should (a) have drivers that can easily + * detach and (b) use generic drivers for these devices so that some + * device actually attaches. We need to make sure that when we + * implement (a) we don't power the device down on a reattach. + * + * John and Nate also tell me that we should be running the power up + * and power down hooks when we change power state for those nodes + * that have ACPI hooks in the tree. + */ + cls = pci_get_class(dev); + if (setstate && cls != PCIC_DISPLAY && cls != PCIC_MEMORY) { + pci_set_powerstate(dev, PCI_POWERSTATE_D3); + printf("pci%d:%d:%d: setting power state D3\n", dinfo->cfg.bus, + dinfo->cfg.slot, dinfo->cfg.func); + } } - diff -ur src/sys/dev/pci/pci_pci.c power/src/sys/dev/pci/pci_pci.c --- src/sys/dev/pci/pci_pci.c Wed Oct 22 22:43:36 2003 +++ power/src/sys/dev/pci/pci_pci.c Sat Jan 3 11:29:22 2004 @@ -92,18 +92,6 @@ DRIVER_MODULE(pcib, pci, pcib_driver, pcib_devclass, 0, 0); /* - * sysctl and tunable vars - */ -static int pci_allow_unsupported_io_range = 0; -TUNABLE_INT("hw.pci.allow_unsupported_io_range", - (int *)&pci_allow_unsupported_io_range); -SYSCTL_DECL(_hw_pci); -SYSCTL_INT(_hw_pci, OID_AUTO, allow_unsupported_io_range, CTLFLAG_RDTUN, - &pci_allow_unsupported_io_range, 0, - "Allows the PCI Bridge to pass through an unsupported memory range " - "assigned by the BIOS."); - -/* * Generic device interface */ static int @@ -173,7 +161,7 @@ * Quirk handling. */ switch (pci_get_devid(dev)) { - case 0x12258086: /* Intel 82454KX/GX (Orion) */ + case 0x12258086: /* Intel 82454KX/GX (Orion) */ { uint8_t supbus; @@ -182,16 +170,42 @@ sc->secbus = supbus + 1; sc->subbus = supbus + 1; } + break; } + + /* + * The i82380FB mobile docking controller is a PCI-PCI bridge, + * and it is a subtractive bridge. However, the ProgIf is wrong + * so the normal setting of PCIB_SUBTRACTIVE bit doesn't + * happen. There's also a Toshiba bridge that behaves this + * way. + */ + case 0x124b8086: /* Intel 82380FB Mobile */ + case 0x060513d7: /* Toshiba ???? */ + sc->flags |= PCIB_SUBTRACTIVE; break; } + /* + * Intel 815, 845 and other chipsets say they are PCI-PCI bridges, + * but have a ProgIF of 0x80. The 82801 family (AA, AB, BAM/CAM, + * BA/CA/DB and E) PCI bridges are HUB-PCI bridges, in Intelese. + * This means they act as if they were subtractively decoding + * bridges and pass all transactions. Mark them and real ProgIf 1 + * parts as subtractive. + */ + if ((pci_get_devid(dev) & 0xff00ffff) == 0x24008086 || + pci_read_config(dev, PCIR_PROGIF, 1) == 1) + sc->flags |= PCIB_SUBTRACTIVE; + if (bootverbose) { device_printf(dev, " secondary bus %d\n", sc->secbus); device_printf(dev, " subordinate bus %d\n", sc->subbus); device_printf(dev, " I/O decode 0x%x-0x%x\n", sc->iobase, sc->iolimit); device_printf(dev, " memory decode 0x%x-0x%x\n", sc->membase, sc->memlimit); device_printf(dev, " prefetched decode 0x%x-0x%x\n", sc->pmembase, sc->pmemlimit); + if (sc->flags & PCIB_SUBTRACTIVE) + device_printf(dev, " Subtractively decoded bridge.\n"); } /* @@ -252,37 +266,12 @@ } /* - * Is this a decoded ISA I/O port address? Note, we need to do the mask that - * we do below because of the ISA alias addresses. I'm not 100% sure that - * this is correct. Maybe the bridge needs to be subtractive decode for - * this to work? - */ -static int -pcib_is_isa_io(u_long start) -{ - if ((start & 0xfffUL) > 0x3ffUL || start == 0) - return (0); - return (1); -} - -/* - * Is this a decoded ISA memory address? - */ -static int -pcib_is_isa_mem(u_long start) -{ - if (start > 0xfffffUL || start == 0) - return (0); - return (1); -} - -/* * Is the prefetch window open (eg, can we allocate memory in it?) */ static int pcib_is_prefetch_open(struct pcib_softc *sc) { - return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit); + return (sc->pmembase > 0 && sc->pmembase < sc->pmemlimit); } /* @@ -291,7 +280,7 @@ static int pcib_is_nonprefetch_open(struct pcib_softc *sc) { - return (sc->membase > 0 && sc->membase < sc->memlimit); + return (sc->membase > 0 && sc->membase < sc->memlimit); } /* @@ -300,7 +289,7 @@ static int pcib_is_io_open(struct pcib_softc *sc) { - return (sc->iobase > 0 && sc->iobase < sc->iolimit); + return (sc->iobase > 0 && sc->iobase < sc->iolimit); } /* @@ -311,144 +300,122 @@ pcib_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 pcib_softc *sc = device_get_softc(dev); - int ok; + struct pcib_softc *sc = device_get_softc(dev); + int ok; - /* - * If this is a "default" allocation against this rid, we can't work - * out where it's coming from (we should actually never see these) so we - * just have to punt. - */ - if ((start == 0) && (end == ~0)) { - device_printf(dev, "can't decode default resource id %d for %s%d, bypassing\n", - *rid, device_get_name(child), device_get_unit(child)); - } else { /* * Fail the allocation for this range if it's not supported. */ switch (type) { case SYS_RES_IOPORT: - ok = 1; - if (!pcib_is_isa_io(start)) { ok = 0; - if (pcib_is_io_open(sc)) - ok = (start >= sc->iobase && end <= sc->iolimit); - if (!pci_allow_unsupported_io_range) { - if (!ok) { - if (start < sc->iobase) - start = sc->iobase; - if (end > sc->iolimit) - end = sc->iolimit; - } + if (!pcib_is_io_open(sc)) + break; + ok = (start >= sc->iobase && end <= sc->iolimit); + if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { + if (!ok) { + if (start < sc->iobase) + start = sc->iobase; + if (end > sc->iolimit) + end = sc->iolimit; + } } else { - if (start < sc->iobase) - printf("start (%lx) < sc->iobase (%x)\n", start, - sc->iobase); - if (end > sc->iolimit) - printf("end (%lx) > sc->iolimit (%x)\n", - end, sc->iolimit); - if (end < start) - printf("end (%lx) < start (%lx)\n", end, start); + ok = 1; + if (start < sc->iobase && end > sc->iolimit) { + start = sc->iobase; + end = sc->iolimit; + } + } - } - if (end < start) { - start = 0; - end = 0; - ok = 0; - } - if (!ok) { - device_printf(dev, "device %s%d requested unsupported I/O " - "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n", - device_get_name(child), device_get_unit(child), start, end, - sc->iobase, sc->iolimit); - return (NULL); - } - if (bootverbose) - device_printf(sc->dev, "device %s%d requested decoded I/O range 0x%lx-0x%lx\n", - device_get_name(child), device_get_unit(child), start, end); - break; + if (end < start) { + device_printf(dev, "ioport: end (%lx) < start (%lx)\n", end, start); + start = 0; + end = 0; + ok = 0; + } + if (!ok) { + device_printf(dev, "device %s requested unsupported I/O " + "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n", + device_get_nameunit(child), start, end, + sc->iobase, sc->iolimit); + return (NULL); + } + if (bootverbose) + device_printf(dev, "device %s requested decoded I/O range 0x%lx-0x%lx\n", + device_get_nameunit(child), start, end); + break; case SYS_RES_MEMORY: - ok = 1; - if (!pcib_is_isa_mem(start)) { ok = 0; if (pcib_is_nonprefetch_open(sc)) - ok = ok || (start >= sc->membase && end <= sc->memlimit); + ok = ok || (start >= sc->membase && end <= sc->memlimit); if (pcib_is_prefetch_open(sc)) - ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit); - if (!pci_allow_unsupported_io_range) { - if (!ok) { - ok = 1; - if (flags & RF_PREFETCHABLE) { - if (pcib_is_prefetch_open(sc)) { - if (start < sc->pmembase) - start = sc->pmembase; - if (end > sc->pmemlimit) - end = sc->pmemlimit; - } else { - ok = 0; - } - } else { /* non-prefetchable */ - if (pcib_is_nonprefetch_open(sc)) { - if (start < sc->membase) - start = sc->membase; - if (end > sc->memlimit) - end = sc->memlimit; - } else { - ok = 0; - } + ok = ok || (start >= sc->pmembase && end <= sc->pmemlimit); + if ((sc->flags & PCIB_SUBTRACTIVE) == 0) { + if (!ok) { + ok = 1; + if (flags & RF_PREFETCHABLE) { + if (pcib_is_prefetch_open(sc)) { + if (start < sc->pmembase) + start = sc->pmembase; + if (end > sc->pmemlimit) + end = sc->pmemlimit; + } else { + ok = 0; + } + } else { /* non-prefetchable */ + if (pcib_is_nonprefetch_open(sc)) { + if (start < sc->membase) + start = sc->membase; + if (end > sc->memlimit) + end = sc->memlimit; + } else { + ok = 0; + } + } } - } } else if (!ok) { - ok = 1; /* pci_allow_unsupported_ranges -> always ok */ - if (pcib_is_nonprefetch_open(sc)) { - if (start < sc->membase) - printf("start (%lx) < sc->membase (%x)\n", - start, sc->membase); - if (end > sc->memlimit) - printf("end (%lx) > sc->memlimit (%x)\n", - end, sc->memlimit); - } - if (pcib_is_prefetch_open(sc)) { - if (start < sc->pmembase) - printf("start (%lx) < sc->pmembase (%x)\n", - start, sc->pmembase); - if (end > sc->pmemlimit) - printf("end (%lx) > sc->pmemlimit (%x)\n", - end, sc->memlimit); - } - if (end < start) - printf("end (%lx) < start (%lx)\n", end, start); + ok = 1; /* subtractive bridge: always ok */ + if (pcib_is_nonprefetch_open(sc)) { + if (start < sc->membase && end > sc->memlimit) { + start = sc->membase; + end = sc->memlimit; + } + } + if (pcib_is_prefetch_open(sc)) { + if (start < sc->pmembase && end > sc->pmemlimit) { + start = sc->pmembase; + end = sc->pmemlimit; + } + } } - } - if (end < start) { - start = 0; - end = 0; - ok = 0; - } - if (!ok && bootverbose) - device_printf(dev, - "device %s%d requested unsupported memory range " - "0x%lx-0x%lx (decoding 0x%x-0x%x, 0x%x-0x%x)\n", - device_get_name(child), device_get_unit(child), start, - end, sc->membase, sc->memlimit, sc->pmembase, - sc->pmemlimit); - if (!ok) - return (NULL); - if (bootverbose) - device_printf(sc->dev, "device %s%d requested decoded memory range 0x%lx-0x%lx\n", - device_get_name(child), device_get_unit(child), start, end); - break; + if (end < start) { + device_printf(dev, "memory: end (%lx) < start (%lx)\n", end, start); + start = 0; + end = 0; + ok = 0; + } + if (!ok && bootverbose) + device_printf(dev, + "device %s requested unsupported memory range " + "0x%lx-0x%lx (decoding 0x%x-0x%x, 0x%x-0x%x)\n", + device_get_nameunit(child), start, end, + sc->membase, sc->memlimit, sc->pmembase, + sc->pmemlimit); + if (!ok) + return (NULL); + if (bootverbose) + device_printf(dev,"device %s requested decoded memory range 0x%lx-0x%lx\n", + device_get_nameunit(child), start, end); + break; default: - break; + break; } - } - - /* - * Bridge is OK decoding this resource, so pass it up. - */ - return(bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags)); + /* + * Bridge is OK decoding this resource, so pass it up. + */ + return (bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags)); } /* diff -ur src/sys/dev/pci/pci_private.h power/src/sys/dev/pci/pci_private.h --- src/sys/dev/pci/pci_private.h Fri Sep 19 10:07:54 2003 +++ power/src/sys/dev/pci/pci_private.h Thu Jan 1 13:33:43 2004 @@ -41,6 +41,7 @@ void pci_add_children(device_t dev, int busno, size_t dinfo_size); void pci_add_child(device_t bus, struct pci_devinfo *dinfo); +void pci_driver_added(device_t dev, driver_t *driver); int pci_print_child(device_t dev, device_t child); void pci_probe_nomatch(device_t dev, device_t child); int pci_read_ivar(device_t dev, device_t child, int which, @@ -74,4 +75,5 @@ char *buf, size_t buflen); int pci_assign_interrupt_method(device_t dev, device_t child); int pci_resume(device_t dev); +int pci_suspend(device_t dev); #endif /* _PCI_PRIVATE_H_ */ diff -ur src/sys/dev/pci/pci_user.c power/src/sys/dev/pci/pci_user.c --- src/sys/dev/pci/pci_user.c Sun Oct 12 23:05:09 2003 +++ power/src/sys/dev/pci/pci_user.c Thu Jan 1 13:33:43 2004 @@ -429,4 +429,3 @@ return (error); } - diff -ur src/sys/dev/pci/pcib_private.h power/src/sys/dev/pci/pcib_private.h --- src/sys/dev/pci/pcib_private.h Sun Aug 24 23:44:36 2003 +++ power/src/sys/dev/pci/pcib_private.h Sat Jan 3 11:29:22 2004 @@ -44,6 +44,8 @@ struct pcib_softc { device_t dev; + uint32_t flags; /* flags */ +#define PCIB_SUBTRACTIVE 0x1 uint16_t command; /* command register */ uint8_t secbus; /* secondary bus number */ uint8_t subbus; /* subordinate bus number */ diff -ur src/sys/dev/pci/pcivar.h power/src/sys/dev/pci/pcivar.h --- src/sys/dev/pci/pcivar.h Mon Sep 15 09:29:28 2003 +++ power/src/sys/dev/pci/pcivar.h Sat Jan 3 11:29:22 2004 @@ -67,9 +67,11 @@ }; /* config header information common to all header types */ - typedef struct pcicfg { struct device *dev; /* device which owns this */ + + uint32_t bar[PCI_MAXMAPS_0]; /* BARs */ + uint32_t bios; /* BIOS mapping */ uint16_t subvendor; /* card vendor ID */ uint16_t subdevice; /* card device ID, assigned by card vendor */ diff -ur src/sys/dev/txp/if_txp.c power/src/sys/dev/txp/if_txp.c --- src/sys/dev/txp/if_txp.c Fri Oct 31 14:10:06 2003 +++ power/src/sys/dev/txp/if_txp.c Sat Jan 3 11:29:28 2004 @@ -226,29 +226,7 @@ mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); -#ifndef BURN_BRIDGES - /* - * Handle power management nonsense. - */ - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - u_int32_t iobase, membase, irq; - /* Save important PCI config data. */ - iobase = pci_read_config(dev, TXP_PCI_LOIO, 4); - membase = pci_read_config(dev, TXP_PCI_LOMEM, 4); - irq = pci_read_config(dev, TXP_PCI_INTLINE, 4); - - /* Reset the power state. */ - device_printf(dev, "chip is in D%d power mode " - "-- setting to D0\n", pci_get_powerstate(dev)); - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - - /* Restore PCI config data. */ - pci_write_config(dev, TXP_PCI_LOIO, iobase, 4); - pci_write_config(dev, TXP_PCI_LOMEM, membase, 4); - pci_write_config(dev, TXP_PCI_INTLINE, irq, 4); - } -#endif /* * Map control/status registers. */ diff -ur src/sys/pci/if_dc.c power/src/sys/pci/if_dc.c --- src/sys/pci/if_dc.c Sun Dec 7 10:49:34 2003 +++ power/src/sys/pci/if_dc.c Sat Jan 3 11:29:33 2004 @@ -220,9 +220,6 @@ static int dc_detach (device_t); static int dc_suspend (device_t); static int dc_resume (device_t); -#ifndef BURN_BRIDGES -static void dc_acpi (device_t); -#endif static struct dc_type *dc_devtype (device_t); static int dc_newbuf (struct dc_softc *, int, int); static int dc_encap (struct dc_softc *, struct mbuf **); @@ -1644,35 +1641,6 @@ return (ENXIO); } -#ifndef BURN_BRIDGES -static void -dc_acpi(device_t dev) -{ - int unit; - u_int32_t iobase, membase, irq; - - unit = device_get_unit(dev); - - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - /* Save important PCI config data. */ - iobase = pci_read_config(dev, DC_PCI_CFBIO, 4); - membase = pci_read_config(dev, DC_PCI_CFBMA, 4); - irq = pci_read_config(dev, DC_PCI_CFIT, 4); - - /* Reset the power state. */ - printf("dc%d: chip is in D%d power mode " - "-- setting to D0\n", unit, - pci_get_powerstate(dev)); - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - - /* Restore PCI config data. */ - pci_write_config(dev, DC_PCI_CFBIO, iobase, 4); - pci_write_config(dev, DC_PCI_CFBMA, membase, 4); - pci_write_config(dev, DC_PCI_CFIT, irq, 4); - } -} -#endif - static void dc_apply_fixup(struct dc_softc *sc, int media) { @@ -1890,12 +1858,7 @@ mtx_init(&sc->dc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); -#ifndef BURN_BRIDGES - /* - * Handle power management nonsense. - */ - dc_acpi(dev); -#endif + /* * Map control/status registers. */ @@ -3799,13 +3762,6 @@ dc_stop(sc); - for (i = 0; i < 5; i++) - sc->saved_maps[i] = pci_read_config(dev, PCIR_BAR(i), 4); - sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4); - sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1); - sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); - sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1); - sc->suspended = 1; splx(s); @@ -3828,20 +3784,6 @@ sc = device_get_softc(dev); ifp = &sc->arpcom.ac_if; -#ifndef BURN_BRIDGES - dc_acpi(dev); -#endif - /* better way to do this? */ - for (i = 0; i < 5; i++) - pci_write_config(dev, PCIR_BAR(i), sc->saved_maps[i], 4); - pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4); - pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1); - pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1); - pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1); - - /* reenable busmastering */ - pci_enable_busmaster(dev); - pci_enable_io(dev, DC_RES); /* reinitialize interface if necessary */ if (ifp->if_flags & IFF_UP) diff -ur src/sys/pci/if_dcreg.h power/src/sys/pci/if_dcreg.h --- src/sys/pci/if_dcreg.h Sun Dec 7 10:49:35 2003 +++ power/src/sys/pci/if_dcreg.h Sat Jan 3 11:29:33 2004 @@ -756,11 +756,6 @@ int rxcycles; /* ... when polling */ #endif int suspended; /* 0 = normal 1 = suspended */ - u_int32_t saved_maps[5]; /* pci data */ - u_int32_t saved_biosaddr; - u_int8_t saved_intline; - u_int8_t saved_cachelnsz; - u_int8_t saved_lattimer; }; diff -ur src/sys/pci/if_pcn.c power/src/sys/pci/if_pcn.c --- src/sys/pci/if_pcn.c Fri Dec 12 01:13:57 2003 +++ power/src/sys/pci/if_pcn.c Sat Jan 3 11:29:38 2004 @@ -517,30 +517,7 @@ /* Initialize our mutex. */ mtx_init(&sc->pcn_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); -#ifndef BURN_BRIDGES - /* - * Handle power management nonsense. - */ - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - u_int32_t iobase, membase, irq; - /* Save important PCI config data. */ - iobase = pci_read_config(dev, PCN_PCI_LOIO, 4); - membase = pci_read_config(dev, PCN_PCI_LOMEM, 4); - irq = pci_read_config(dev, PCN_PCI_INTLINE, 4); - - /* Reset the power state. */ - printf("pcn%d: chip is in D%d power mode " - "-- setting to D0\n", unit, - pci_get_powerstate(dev)); - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - - /* Restore PCI config data. */ - pci_write_config(dev, PCN_PCI_LOIO, iobase, 4); - pci_write_config(dev, PCN_PCI_LOMEM, membase, 4); - pci_write_config(dev, PCN_PCI_INTLINE, irq, 4); - } -#endif /* * Map control/status registers. */ diff -ur src/sys/pci/if_rl.c power/src/sys/pci/if_rl.c --- src/sys/pci/if_rl.c Sat Jan 3 03:49:42 2004 +++ power/src/sys/pci/if_rl.c Sat Jan 3 11:29:39 2004 @@ -915,32 +915,7 @@ mtx_init(&sc->rl_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); -#ifndef BURN_BRIDGES - /* - * Handle power management nonsense. - */ - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - u_int32_t iobase, membase, irq; - - /* Save important PCI config data. */ - iobase = pci_read_config(dev, RL_PCI_LOIO, 4); - membase = pci_read_config(dev, RL_PCI_LOMEM, 4); - irq = pci_read_config(dev, RL_PCI_INTLINE, 4); - - /* Reset the power state. */ - printf("rl%d: chip is is in D%d power mode " - "-- setting to D0\n", unit, - pci_get_powerstate(dev)); - - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - - /* Restore PCI config data. */ - pci_write_config(dev, RL_PCI_LOIO, iobase, 4); - pci_write_config(dev, RL_PCI_LOMEM, membase, 4); - pci_write_config(dev, RL_PCI_INTLINE, irq, 4); - } -#endif /* * Map control/status registers. */ diff -ur src/sys/pci/if_sf.c power/src/sys/pci/if_sf.c --- src/sys/pci/if_sf.c Fri Dec 12 01:13:58 2003 +++ power/src/sys/pci/if_sf.c Sat Jan 3 11:29:40 2004 @@ -673,30 +673,7 @@ mtx_init(&sc->sf_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); -#ifndef BURN_BRIDGES - /* - * Handle power management nonsense. - */ - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - u_int32_t iobase, membase, irq; - /* Save important PCI config data. */ - iobase = pci_read_config(dev, SF_PCI_LOIO, 4); - membase = pci_read_config(dev, SF_PCI_LOMEM, 4); - irq = pci_read_config(dev, SF_PCI_INTLINE, 4); - - /* Reset the power state. */ - printf("sf%d: chip is in D%d power mode " - "-- setting to D0\n", unit, - pci_get_powerstate(dev)); - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - - /* Restore PCI config data. */ - pci_write_config(dev, SF_PCI_LOIO, iobase, 4); - pci_write_config(dev, SF_PCI_LOMEM, membase, 4); - pci_write_config(dev, SF_PCI_INTLINE, irq, 4); - } -#endif /* * Map control/status registers. */ diff -ur src/sys/pci/if_sis.c power/src/sys/pci/if_sis.c --- src/sys/pci/if_sis.c Tue Dec 30 13:55:39 2003 +++ power/src/sys/pci/if_sis.c Sat Jan 3 11:29:42 2004 @@ -1063,30 +1063,7 @@ sc->sis_type = SIS_TYPE_83815; sc->sis_rev = pci_read_config(dev, PCIR_REVID, 1); -#ifndef BURN_BRIDGES - /* - * Handle power management nonsense. - */ - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - u_int32_t iobase, membase, irq; - /* Save important PCI config data. */ - iobase = pci_read_config(dev, SIS_PCI_LOIO, 4); - membase = pci_read_config(dev, SIS_PCI_LOMEM, 4); - irq = pci_read_config(dev, SIS_PCI_INTLINE, 4); - - /* Reset the power state. */ - printf("sis%d: chip is in D%d power mode " - "-- setting to D0\n", unit, - pci_get_powerstate(dev)); - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - - /* Restore PCI config data. */ - pci_write_config(dev, SIS_PCI_LOIO, iobase, 4); - pci_write_config(dev, SIS_PCI_LOMEM, membase, 4); - pci_write_config(dev, SIS_PCI_INTLINE, irq, 4); - } -#endif /* * Map control/status registers. */ diff -ur src/sys/pci/if_sk.c power/src/sys/pci/if_sk.c --- src/sys/pci/if_sk.c Fri Dec 12 01:14:00 2003 +++ power/src/sys/pci/if_sk.c Sat Jan 3 11:29:43 2004 @@ -1469,30 +1469,7 @@ mtx_init(&sc->sk_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); -#ifndef BURN_BRIDGES - /* - * Handle power management nonsense. - */ - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - u_int32_t iobase, membase, irq; - /* Save important PCI config data. */ - iobase = pci_read_config(dev, SK_PCI_LOIO, 4); - membase = pci_read_config(dev, SK_PCI_LOMEM, 4); - irq = pci_read_config(dev, SK_PCI_INTLINE, 4); - - /* Reset the power state. */ - printf("skc%d: chip is in D%d power mode " - "-- setting to D0\n", unit, - pci_get_powerstate(dev)); - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - - /* Restore PCI config data. */ - pci_write_config(dev, SK_PCI_LOIO, iobase, 4); - pci_write_config(dev, SK_PCI_LOMEM, membase, 4); - pci_write_config(dev, SK_PCI_INTLINE, irq, 4); - } -#endif /* * Map control/status registers. */ diff -ur src/sys/pci/if_ste.c power/src/sys/pci/if_ste.c --- src/sys/pci/if_ste.c Fri Dec 12 01:14:00 2003 +++ power/src/sys/pci/if_ste.c Tue Jan 6 06:00:52 2004 @@ -921,6 +921,9 @@ unit = device_get_unit(dev); sc->ste_dev = dev; + mtx_init(&sc->ste_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, + MTX_DEF | MTX_RECURSE); + /* * Only use one PHY since this chip reports multiple * Note on the DFE-550 the PHY is at 1 on the DFE-580 @@ -933,30 +936,7 @@ mtx_init(&sc->ste_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); -#ifndef BURN_BRIDGES - /* - * Handle power management nonsense. - */ - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - u_int32_t iobase, membase, irq; - - /* Save important PCI config data. */ - iobase = pci_read_config(dev, STE_PCI_LOIO, 4); - membase = pci_read_config(dev, STE_PCI_LOMEM, 4); - irq = pci_read_config(dev, STE_PCI_INTLINE, 4); - - /* Reset the power state. */ - printf("ste%d: chip is in D%d power mode " - "-- setting to D0\n", unit, - pci_get_powerstate(dev)); - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - /* Restore PCI config data. */ - pci_write_config(dev, STE_PCI_LOIO, iobase, 4); - pci_write_config(dev, STE_PCI_LOMEM, membase, 4); - pci_write_config(dev, STE_PCI_INTLINE, irq, 4); - } -#endif /* * Map control/status registers. */ diff -ur src/sys/pci/if_vr.c power/src/sys/pci/if_vr.c --- src/sys/pci/if_vr.c Fri Dec 12 01:14:02 2003 +++ power/src/sys/pci/if_vr.c Sat Jan 3 11:29:48 2004 @@ -742,30 +742,7 @@ mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); -#ifndef BURN_BRIDGES - /* - * Handle power management nonsense. - */ - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - u_int32_t iobase, membase, irq; - /* Save important PCI config data. */ - iobase = pci_read_config(dev, VR_PCI_LOIO, 4); - membase = pci_read_config(dev, VR_PCI_LOMEM, 4); - irq = pci_read_config(dev, VR_PCI_INTLINE, 4); - - /* Reset the power state. */ - printf("vr%d: chip is in D%d power mode " - "-- setting to D0\n", unit, - pci_get_powerstate(dev)); - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - - /* Restore PCI config data. */ - pci_write_config(dev, VR_PCI_LOIO, iobase, 4); - pci_write_config(dev, VR_PCI_LOMEM, membase, 4); - pci_write_config(dev, VR_PCI_INTLINE, irq, 4); - } -#endif /* * Map control/status registers. */ diff -ur src/sys/pci/if_wb.c power/src/sys/pci/if_wb.c --- src/sys/pci/if_wb.c Fri Dec 12 01:14:02 2003 +++ power/src/sys/pci/if_wb.c Sat Jan 3 11:29:49 2004 @@ -827,31 +827,7 @@ mtx_init(&sc->wb_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); -#ifndef BURN_BRIDGES - /* - * Handle power management nonsense. - */ - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - u_int32_t iobase, membase, irq; - - /* Save important PCI config data. */ - iobase = pci_read_config(dev, WB_PCI_LOIO, 4); - membase = pci_read_config(dev, WB_PCI_LOMEM, 4); - irq = pci_read_config(dev, WB_PCI_INTLINE, 4); - - /* Reset the power state. */ - printf("wb%d: chip is in D%d power mode " - "-- setting to D0\n", unit, - pci_get_powerstate(dev)); - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - - /* Restore PCI config data. */ - pci_write_config(dev, WB_PCI_LOIO, iobase, 4); - pci_write_config(dev, WB_PCI_LOMEM, membase, 4); - pci_write_config(dev, WB_PCI_INTLINE, irq, 4); - } -#endif /* * Map control/status registers. */ diff -ur src/sys/pci/if_xl.c power/src/sys/pci/if_xl.c --- src/sys/pci/if_xl.c Fri Dec 12 01:14:04 2003 +++ power/src/sys/pci/if_xl.c Sat Jan 3 11:29:51 2004 @@ -1368,47 +1368,6 @@ break; } -#ifndef BURN_BRIDGES - /* - * If this is a 3c905B, we have to check one extra thing. - * The 905B supports power management and may be placed in - * a low-power mode (D3 mode), typically by certain operating - * systems which shall not be named. The PCI BIOS is supposed - * to reset the NIC and bring it out of low-power mode, but - * some do not. Consequently, we have to see if this chip - * supports power management, and if so, make sure it's not - * in low-power mode. If power management is available, the - * capid byte will be 0x01. - * - * I _think_ that what actually happens is that the chip - * loses its PCI configuration during the transition from - * D3 back to D0; this means that it should be possible for - * us to save the PCI iobase, membase and IRQ, put the chip - * back in the D0 state, then restore the PCI config ourselves. - */ - - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { - u_int32_t iobase, membase, irq; - - /* Save important PCI config data. */ - iobase = pci_read_config(dev, XL_PCI_LOIO, 4); - membase = pci_read_config(dev, XL_PCI_LOMEM, 4); - irq = pci_read_config(dev, XL_PCI_INTLINE, 4); - - /* Reset the power state. */ - printf("xl%d: chip is in D%d power mode " - "-- setting to D0\n", unit, - pci_get_powerstate(dev)); - - pci_set_powerstate(dev, PCI_POWERSTATE_D0); - - /* Restore PCI config data. */ - pci_write_config(dev, XL_PCI_LOIO, iobase, 4); - pci_write_config(dev, XL_PCI_LOMEM, membase, 4); - pci_write_config(dev, XL_PCI_INTLINE, irq, 4); - } -#endif - /* * Map control/status registers. */ diff -ur src/sys/sparc64/pci/ofw_pcibus.c power/src/sys/sparc64/pci/ofw_pcibus.c --- src/sys/sparc64/pci/ofw_pcibus.c Sun Aug 24 23:46:56 2003 +++ power/src/sys/sparc64/pci/ofw_pcibus.c Thu Jan 1 10:11:37 2004 @@ -69,8 +69,8 @@ DEVMETHOD(device_probe, ofw_pcibus_probe), DEVMETHOD(device_attach, ofw_pcibus_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_suspend, pci_suspend), + DEVMETHOD(device_resume, pci_resume), /* Bus interface */ DEVMETHOD(bus_print_child, pci_print_child),