diff -druN sys/dev/acpica/acpi_pci.c sys-fiva206/dev/acpica/acpi_pci.c --- sys/dev/acpica/acpi_pci.c Tue Feb 18 06:20:34 2003 +++ sys-fiva206/dev/acpica/acpi_pci.c Thu Jun 12 17:24:14 2003 @@ -79,7 +79,7 @@ DEVMETHOD(device_attach, acpi_pci_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_resume, pci_resume), /* Bus interface */ DEVMETHOD(bus_print_child, pci_print_child), diff -druN sys/dev/ata/ata-all.c sys-fiva206/dev/ata/ata-all.c --- sys/dev/ata/ata-all.c Mon May 19 01:43:08 2003 +++ sys-fiva206/dev/ata/ata-all.c Sun Jun 15 13:10:41 2003 @@ -84,6 +84,7 @@ /* local vars */ static MALLOC_DEFINE(M_ATA, "ATA generic", "ATA driver generic layer"); +static int ata_cold = 1; /* misc defines */ #define DEV_ATAPIALL defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || \ @@ -149,7 +150,7 @@ * when interrupts are enabled by a hook into the boot process. * otherwise attach what the probe has found in ch->devices. */ - if (!ata_delayed_attach) { + if (!ata_cold) { ch->locking(ch, ATA_LF_LOCK); if (ch->devices & ATA_ATA_SLAVE) if (ata_getparam(&ch->device[SLAVE], ATA_C_ATA_IDENTIFY)) @@ -248,6 +249,21 @@ if (!dev || !(ch = device_get_softc(dev))) return ENXIO; +#ifdef DEV_ATADISK + if (ch->devices & ATA_ATA_MASTER && ch->device[MASTER].driver) { + ch->device[MASTER].suspended = 1; + if (ch->device[MASTER].mode >= ATA_DMA) { + ata_waitdmadone(&ch->device[MASTER]); + } + } + if (ch->devices & ATA_ATA_SLAVE && ch->device[SLAVE].driver) { + ch->device[SLAVE].suspended = 1; + if (ch->device[SLAVE].mode >= ATA_DMA) { + ata_waitdmadone(&ch->device[SLAVE]); + } + } +#endif + ch->locking(ch, ATA_LF_LOCK); ATA_SLEEPLOCK_CH(ch, ATA_CONTROL); return 0; @@ -262,6 +278,15 @@ if (!dev || !(ch = device_get_softc(dev))) return ENXIO; +#ifdef DEV_ATADISK + if (ch->devices & ATA_ATA_MASTER && ch->device[MASTER].driver) { + ch->device[MASTER].suspended = 0; + } + if (ch->devices & ATA_ATA_SLAVE && ch->device[SLAVE].driver) { + ch->device[SLAVE].suspended = 0; + } +#endif + ch->locking(ch, ATA_LF_LOCK); error = ata_reinit(ch); ch->locking(ch, ATA_LF_UNLOCK); @@ -558,6 +583,7 @@ #endif ch->locking(ch, ATA_LF_UNLOCK); } + ata_cold = 0; if (ata_delayed_attach) { config_intrhook_disestablish(ata_delayed_attach); free(ata_delayed_attach, M_TEMP); @@ -652,6 +678,20 @@ if (ch->devices & (ATA_ATA_SLAVE) && ch->device[SLAVE].driver) ad_start(&ch->device[SLAVE]); } + if (ch->devices & (ATA_ATA_MASTER) && ch->device[MASTER].driver) { + if (ch->device[MASTER].suspended && ch->device[MASTER].mode >= ATA_DMA) { + printf("%s: going to suspend, ignoring.\n", __func__); + splx(s); + return; + } + } + if (ch->devices & (ATA_ATA_SLAVE) && ch->device[SLAVE].driver) { + if (ch->device[SLAVE].suspended && ch->device[SLAVE].mode >= ATA_DMA) { + printf("%s: going to suspend, ignoring.\n", __func__); + splx(s); + return; + } + } if ((ad_request = TAILQ_FIRST(&ch->ata_queue))) { TAILQ_REMOVE(&ch->ata_queue, ad_request, chain); ch->active = ATA_ACTIVE_ATA; @@ -1454,6 +1494,7 @@ case ATA_SA150: return "SATA150"; default: return "???"; } + ata_cold = 0; } int diff -druN sys/dev/ata/ata-all.h sys-fiva206/dev/ata/ata-all.h --- sys/dev/ata/ata-all.h Sun May 4 18:34:14 2003 +++ sys-fiva206/dev/ata/ata-all.h Sun Jun 15 13:47:29 2003 @@ -189,6 +189,7 @@ void *result; /* misc data */ int mode; /* transfermode */ void (*setmode)(struct ata_device *, int); + int suspended; /* 0 = normal 1 = suspnded */ }; /* structure holding DMA related information */ @@ -288,6 +289,7 @@ void ata_reset(struct ata_channel *); int ata_reinit(struct ata_channel *); int ata_wait(struct ata_device *, u_int8_t); +void ata_waitdmadone(struct ata_device *); int ata_command(struct ata_device *, u_int8_t, u_int64_t, u_int16_t, u_int16_t, int); void ata_enclosure_leds(struct ata_device *, u_int8_t); void ata_enclosure_print(struct ata_device *); diff -druN sys/dev/ata/ata-dma.c sys-fiva206/dev/ata/ata-dma.c --- sys/dev/ata/ata-dma.c Mon Apr 7 23:12:12 2003 +++ sys-fiva206/dev/ata/ata-dma.c Sun Jun 15 14:03:20 2003 @@ -222,8 +222,11 @@ { struct ata_dmasetup_data_cb_args cba; - if (ch->dma->flags & ATA_DMA_ACTIVE) - panic("ata_dmasetup: transfer active on this device!"); + if (ch->dma->flags & ATA_DMA_ACTIVE) { + printf("ata_dmastart: transfer active on this device!\n"); + Debugger("ata_dmastart"); + return -1; + } cba.dmatab = ch->dma->dmatab; bus_dmamap_sync(ch->dma->cdmatag, ch->dma->cdmamap, BUS_DMASYNC_PREWRITE); @@ -249,4 +252,14 @@ bus_dmamap_unload(ch->dma->ddmatag, ch->dma->ddmamap); ch->dma->flags = 0; return 0; +} + +void +ata_waitdmadone(struct ata_device *atadev) +{ + if (atadev->channel->dma->flags & ATA_DMA_ACTIVE) { + printf("%s: waiting for atadev->channel->dma->stop()\n", __func__); + tsleep(atadev->channel->dma->stop, PRIBIO, "atawdma", 10 * hz); + printf("%s: done\n", __func__); + } } diff -druN sys/dev/pccard/pccard.c sys-fiva206/dev/pccard/pccard.c --- sys/dev/pccard/pccard.c Thu Apr 10 13:11:15 2003 +++ sys-fiva206/dev/pccard/pccard.c Thu Jun 12 17:24:23 2003 @@ -1203,12 +1203,15 @@ * interrupt storm from happening. Of course this won't * help in the non-MFC case. */ + reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS); if (pccard_mfc(pf->sc)) { - 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); else + doisr = 0; + } else { + if (reg == 0xff) /* card was removed */ doisr = 0; } if (pf->intr_handler != NULL && doisr) diff -druN sys/dev/pci/pci.c sys-fiva206/dev/pci/pci.c --- sys/dev/pci/pci.c Wed Apr 16 12:15:08 2003 +++ sys-fiva206/dev/pci/pci.c Thu Jun 12 17:24:23 2003 @@ -88,7 +88,7 @@ DEVMETHOD(device_attach, pci_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_resume, pci_resume), /* Bus interface */ DEVMETHOD(bus_print_child, pci_print_child), @@ -784,7 +784,7 @@ pcicfgregs *cfg = &dinfo->cfg; struct resource_list *rl = &dinfo->resources; struct pci_quirk *q; - int b, i, f, s; + int b, i, irq, f, s; b = cfg->bus; s = cfg->slot; @@ -800,14 +800,16 @@ } if (cfg->intpin > 0 && PCI_INTERRUPT_VALID(cfg->intline)) { -#ifdef __ia64__ /* - * Re-route interrupts on ia64 so that we can get the - * I/O SAPIC interrupt numbers (the BIOS leaves legacy - * PIC interrupt numbers in the intline registers). + * Try to re-route interrupts. Sometimes the BIOS or + * firmware may leave bogus values in these registers. + * If the re-route fails, then just stick with what we + * have. */ - cfg->intline = PCIB_ROUTE_INTERRUPT(pcib, dev, cfg->intpin); -#endif + irq = PCIB_ROUTE_INTERRUPT(pcib, dev, cfg->intpin); + if (PCI_INTERRUPT_VALID(irq)) { + cfg->intline = irq; + } resource_list_add(rl, SYS_RES_IRQ, 0, cfg->intline, cfg->intline, 1); } @@ -1495,3 +1497,36 @@ return (0); } + +int +pci_resume(device_t dev) +{ + int numdevs; + int i; + device_t *children; + device_t child; + struct pci_devinfo *dinfo; + pcicfgregs *cfg; + + device_get_children(dev, &children, &numdevs); + + for (i = 0; i < numdevs; i++) { + child = children[i]; + + dinfo = device_get_ivars(child); + cfg = &dinfo->cfg; + if (cfg->intpin > 0 && PCI_INTERRUPT_VALID(cfg->intline)) { + cfg->intline = PCIB_ROUTE_INTERRUPT(device_get_parent(dev), + child, cfg->intpin); + if (PCI_INTERRUPT_VALID(cfg->intline)) { + pci_write_config(child, PCIR_INTLINE, + cfg->intline, 1); + } + } + } + + free(children, M_TEMP); + + return (bus_generic_resume(dev)); +} + diff -druN sys/dev/pci/pci_private.h sys-fiva206/dev/pci/pci_private.h --- sys/dev/pci/pci_private.h Wed Apr 16 12:15:08 2003 +++ sys-fiva206/dev/pci/pci_private.h Thu Jun 12 17:24:23 2003 @@ -68,6 +68,7 @@ size_t size); void pci_print_verbose(struct pci_devinfo *dinfo); int pci_freecfg(struct pci_devinfo *dinfo); +int pci_resume(device_t dev); int pci_child_location_str_method(device_t cbdev, device_t child, char *buf, size_t buflen); int pci_child_pnpinfo_str_method(device_t cbdev, device_t child, diff -druN sys/dev/usb/ohci.c sys-fiva206/dev/usb/ohci.c --- sys/dev/usb/ohci.c Wed Mar 5 22:17:15 2003 +++ sys-fiva206/dev/usb/ohci.c Thu Jun 12 17:24:23 2003 @@ -989,7 +989,6 @@ /* * Shut down the controller when the system is going down. */ -#if defined(__NetBSD__) || defined(__OpenBSD__) void ohci_shutdown(void *v) { @@ -1021,7 +1020,9 @@ s = splhardusb(); switch (why) { case PWR_SUSPEND: +#if 0 case PWR_STANDBY: +#endif sc->sc_bus.use_polling++; ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK; if (sc->sc_control == 0) { @@ -1059,14 +1060,15 @@ sc->sc_control = sc->sc_intre = 0; sc->sc_bus.use_polling--; break; +#if 0 case PWR_SOFTSUSPEND: case PWR_SOFTSTANDBY: case PWR_SOFTRESUME: break; +#endif } splx(s); } -#endif #ifdef USB_DEBUG void diff -druN sys/dev/usb/ohci_pci.c sys-fiva206/dev/usb/ohci_pci.c --- sys/dev/usb/ohci_pci.c Fri Feb 28 22:21:17 2003 +++ sys-fiva206/dev/usb/ohci_pci.c Thu Jun 12 17:36:47 2003 @@ -114,6 +114,48 @@ static int ohci_pci_attach(device_t self); static int ohci_pci_detach(device_t self); +static int ohci_pci_suspend(device_t self); +static int ohci_pci_resume(device_t self); +static int ohci_pci_shutdown(device_t self); + +static int +ohci_pci_suspend(device_t self) +{ + ohci_softc_t *sc = device_get_softc(self); + int err; + + err = bus_generic_suspend(self); + if (err) + return err; + ohci_power(PWR_SUSPEND, sc); + + return 0; +} + +static int +ohci_pci_resume(device_t self) +{ + ohci_softc_t *sc = device_get_softc(self); + + ohci_power(PWR_RESUME, sc); + bus_generic_resume(self); + + return 0; +} + +static int +ohci_pci_shutdown(device_t self) +{ + ohci_softc_t *sc = device_get_softc(self); + int err; + + err = bus_generic_shutdown(self); + if (err) + return err; + ohci_shutdown(sc); + + return 0; +} static const char * ohci_pci_match(device_t self) @@ -295,9 +337,11 @@ static device_method_t ohci_methods[] = { /* Device interface */ - DEVMETHOD(device_probe, ohci_pci_probe), - DEVMETHOD(device_attach, ohci_pci_attach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_probe, ohci_pci_probe), + DEVMETHOD(device_attach, ohci_pci_attach), + DEVMETHOD(device_suspend, ohci_pci_suspend), + DEVMETHOD(device_resume, ohci_pci_resume), + DEVMETHOD(device_shutdown, ohci_pci_shutdown), /* Bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), diff -druN sys/dev/usb/ohcivar.h sys-fiva206/dev/usb/ohcivar.h --- sys/dev/usb/ohcivar.h Tue Oct 1 02:50:16 2002 +++ sys-fiva206/dev/usb/ohcivar.h Thu Jun 12 17:24:23 2003 @@ -160,4 +160,9 @@ int ohci_activate(device_ptr_t, enum devact); #endif +#if defined(__FreeBSD__) +void ohci_power(int state, void *); +void ohci_shutdown(void *); +#endif + #define MS_TO_TICKS(ms) ((ms) * hz / 1000) diff -druN sys/i386/bios/apm.c sys-fiva206/i386/bios/apm.c --- sys/i386/bios/apm.c Tue Mar 25 14:19:18 2003 +++ sys-fiva206/i386/bios/apm.c Thu Jun 12 17:23:34 2003 @@ -292,12 +292,161 @@ return (sc->bios.r.ebx & 0xffff); } + +#ifndef KLD_MODULE +#include +#if __FreeBSD_version >= 500001 +#include +#endif +#define APM_FIVA_HACK +#endif + +#ifdef APM_FIVA_HACK +/* + * CASSIOPEIA FIVA suspend/resume hack by iwasaki@FreeBSD.org + * The following hack was done by the translation from the FIVA + * ACPI data blocks (_PTS and _WAK) into C code. + */ + +/* FIVA _PTS (Prepare To Sleep) */ +static void +apm_fiva_pts(void) +{ + u_int8_t *bdatap, bdata; +#if __FreeBSD_version < 500001 + pcicfgregs cfg; +#endif + + /* + * Store(0x85, \_SB_.PCI0.ISA_.BCMD) + * [aml_region_write(0, 0, 0x85, 0x6ffff2c, 0x0, 0x8)] + */ + pmap_kenter((vm_offset_t)ptvmmap, (0x6ffff2c) & ~PAGE_MASK); + bdatap = (u_int8_t *) &ptvmmap[0x6ffff2c & PAGE_MASK]; + *bdatap = 0x85; + + /* + * Store(0x0, \_SB_.PCI0.ISA_.SMIC) + * [aml_region_write(1, 0, 0x0, 0x8038, 0x0, 0x8)] + */ + outb(0x8038, 0x0); + + /* + * Store(0x81, \_SB_.PCI0.ISA_.BCMD) + * [aml_region_write(0, 0, 0x81, 0x6ffff2c, 0x0, 0x8)] + */ + *bdatap = 0x81; + + /* + * Store(0x0, \_SB_.PCI0.ISA_.SMIC) + * [aml_region_write(1, 0, 0x0, 0x8038, 0x0, 0x8)] + */ + outb(0x8038, 0x0); + + /* + * Store(0x0, \_SB_.PCI0.PM__.PPCM) + * [aml_region_write(2, 1, 0x0, 0x0, 0x454, 0x1)] + * Note: pciconf -v -l gives us the following; + * chip1@pci0:17:0: + * class=0x068000 card=0x00000000 chip=0x710110b9 rev=0x00 hdr=0x00 + * vendor = 'Acer Labs Inc.' + * device = 'M7101 Power Management Controller' + * class = bridge + * subclass = PCI-unknown + */ +#if __FreeBSD_version >= 500001 + if (!pci_cfgregopen()) + return; + bdata = pci_cfgregread(0, 17, 0, 0x8a, 1); + bdata &= ~(1 << 4); + if (!pci_cfgregopen()) + return; + pci_cfgregwrite(0, 17, 0, 0x8a, bdata, 1); +#else + cfg.bus = 0; cfg.slot = 17; cfg.func = 0; + bdata = (u_int8_t)pci_cfgread(&cfg, 0x8a, 1); + bdata &= ~(1 << 4); + pci_cfgwrite(&cfg, 0x8a, (u_int32_t)bdata, 1); +#endif + + /* + * Store(0x0, \_SB_.PCI0.PM__.PVGA) + * [aml_region_write(2, 1, 0x0, 0x0, 0x455, 0x1)] + */ +#if __FreeBSD_version >= 500001 + if (!pci_cfgregopen()) + return; + bdata = pci_cfgregread(0, 17, 0, 0x8a, 1); + bdata &= ~(1 << 5); + if (!pci_cfgregopen()) + return; + pci_cfgregwrite(0, 17, 0, 0x8a, bdata, 1); +#else + bdata = (u_int8_t)pci_cfgread(&cfg, 0x8a, 1); + bdata &= ~(1 << 5); + pci_cfgwrite(&cfg, 0x8a, (u_int32_t)bdata, 1); +#endif + + pmap_kremove((vm_offset_t)ptvmmap); +} + +/* FIVA _WAK (Wakeup) */ +static void +apm_fiva_wak(void) +{ + u_int8_t bdata; +#if __FreeBSD_version < 500001 + pcicfgregs cfg; +#endif + + /* + * Store(0x1, \_SB_.PCI0.PM__.PPCM) + * [aml_region_write(2, 1, 0x1, 0x0, 0x454, 0x1)] + */ +#if __FreeBSD_version >= 500001 + if (!pci_cfgregopen()) + return; + bdata = pci_cfgregread(0, 17, 0, 0x8a, 1); + bdata |= (1 << 4); + if (!pci_cfgregopen()) + return; + pci_cfgregwrite(0, 17, 0, 0x8a, bdata, 1); +#else + cfg.bus = 0; cfg.slot = 17; cfg.func = 0; + bdata = (u_int8_t)pci_cfgread(&cfg, 0x8a, 1); + bdata |= (1 << 4); + pci_cfgwrite(&cfg, 0x8a, (u_int32_t)bdata, 1); +#endif + + /* + * Store(0x1, \_SB_.PCI0.PM__.PVGA) + * [aml_region_write(2, 1, 0x1, 0x0, 0x455, 0x1)] + */ +#if __FreeBSD_version >= 500001 + if (!pci_cfgregopen()) + return; + bdata = pci_cfgregread(0, 17, 0, 0x8a, 1); + bdata |= (1 << 5); + if (!pci_cfgregopen()) + return; + pci_cfgregwrite(0, 17, 0, 0x8a, bdata, 1); +#else + bdata = (u_int8_t)pci_cfgread(&cfg, 0x8a, 1); + bdata |= (1 << 5); + pci_cfgwrite(&cfg, 0x8a, (u_int32_t)bdata, 1); +#endif +} +#endif + /* suspend entire system */ static int apm_suspend_system(int state) { struct apm_softc *sc = &apm_softc; +#ifdef APM_FIVA_HACK + apm_fiva_pts(); +#endif sc->bios.r.eax = (APM_BIOS << 8) | APM_SETPWSTATE; sc->bios.r.ebx = PMDV_ALLDEV; sc->bios.r.ecx = state; @@ -598,6 +747,9 @@ return; sc->suspending = 0; +#ifdef APM_FIVA_HACK + apm_fiva_wak(); +#endif if (sc->initialized) { apm_execute_hook(hook[APM_HOOK_RESUME]); DEVICE_RESUME(root_bus);