Sergey G Nasonov wrote: > to disk. So the basic issue preventing normal suspend/resume > process on modern Lenovo laptops is ata subsystem. Does anyone can > help with this problem? I can test any path or provide additional > info. Hi, All. I wrote patch for AHCI driver and Sergey tested it. So, He reported that now "suspend/resume" works on his laptop. I'll try to describe all changes which my patch makes. 1. Initialization: * Global AHCI reset code moved to ata_ahci_reset_controller() function (it will be reused in ata_ahci_resume). * Detection of implemented ports moved to ata_ahci_allocate() function (i think it isn't needed to detect it on each reset). * From ata_ahci_allocate() function removed all working code, only initialization code is here. 2. Resetting: * ata_ahci_reset() function reorganized and splitted to several functions: ata_ahci_stop_channel() - stop all port activity; ata_ahci_fre_stop() - disable FIS receiving; ata_ahci_fre_start() - setup work areas and enable FIS receiving; ata_ahci_clo_enable() - enable command list override. * working code from ata_ahci_allocate moved to ata_ahci_reset. * CLO shall only be set immediately prior to setting the PxCMD.ST bit to '1' (from AHCI spec). * Software shall not set PxCMD.ST to 1 until it is determined that a functional device is present on the port (from AHCI spec). * removed hack when didn't detect signature asuming disk device (it may broke some systems, but it needs testing). 3. Interrupts handling: * Call ata_sata_phy_check_events() only when PHY changing detected. * Fatal error handling changed. 4. Suspend/resume: * Added new methods to atapci(4) driver * Added suspend/resume implementation for AHCI: + Software must disable interrupts prior to requesting a transition of the HBA to the D3 state. + Reset controller and enable interrupts before resume. So, any comments and suggestions are welcome. -- WBR, Andrey V. Elsukov Index: src/sys/dev/ata/ata-all.h =================================================================== RCS file: /ncvs/src/sys/dev/ata/ata-all.h,v retrieving revision 1.133 diff -u -b -p -r1.133 ata-all.h --- src/sys/dev/ata/ata-all.h 17 Apr 2008 12:29:35 -0000 1.133 +++ src/sys/dev/ata/ata-all.h 21 Jul 2008 09:23:31 -0000 _at_@ -188,6 +188,9 @@ #define ATA_AHCI_P_IX_HBF 0x20000000 #define ATA_AHCI_P_IX_TFE 0x40000000 #define ATA_AHCI_P_IX_CPD 0x80000000 +#define ATA_AHCI_P_IX_FE \ + (ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF |\ + ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF) #define ATA_AHCI_P_CMD 0x118 #define ATA_AHCI_P_CMD_ST 0x00000001 Index: src/sys/dev/ata/ata-chipset.c =================================================================== RCS file: /ncvs/src/sys/dev/ata/ata-chipset.c,v retrieving revision 1.224 diff -u -b -p -r1.224 ata-chipset.c --- src/sys/dev/ata/ata-chipset.c 10 Jul 2008 21:36:53 -0000 1.224 +++ src/sys/dev/ata/ata-chipset.c 21 Jul 2008 09:23:31 -0000 _at__at_ -62,6 +62,9 _at__at_ static int ata_sata_connect(struct ata_c static void ata_sata_setmode(device_t dev, int mode); static int ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis); static int ata_ahci_chipinit(device_t dev); +static int ata_ahci_suspend(device_t dev); +static int ata_ahci_resume(device_t dev); +static int ata_ahci_reset_controller(device_t dev); static int ata_ahci_allocate(device_t dev); static int ata_ahci_status(device_t dev); static int ata_ahci_begin_transaction(struct ata_request *request); _at__at_ -69,6 +72,11 _at__at_ static int ata_ahci_end_transaction(stru static int ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result); static int ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t result); static u_int32_t ata_ahci_softreset(device_t dev, int port); +static void ata_ahci_fre_start(struct ata_channel *ch); +static void ata_ahci_fre_stop(struct ata_channel *ch); +static void ata_ahci_stop_channel(struct ata_channel *ch); +static void ata_ahci_restart_channel(struct ata_channel *ch); +static void ata_ahci_clo_enable(struct ata_channel *ch); static void ata_ahci_reset(device_t dev); static void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static void ata_ahci_dmainit(device_t dev); _at__at_ -582,6 +590,29 _at__at_ ata_ahci_ident(device_t dev) } static int +ata_ahci_reset_controller(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); + + /* enable AHCI mode */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); + + /* reset AHCI controller */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_HR); + DELAY(1000000); + if (ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) { + bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); + device_printf(dev, "AHCI controller reset failure\n"); + return ENXIO; + } + + /* reenable AHCI mode */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); + + return 0; +} + +static int ata_ahci_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); _at__at_ -602,20 +633,8 @@ ata_ahci_chipinit(device_t dev) else device_printf(dev, "AHCI called from vendor specific driver\n"); - /* enable AHCI mode */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); - - /* reset AHCI controller */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_HR); - DELAY(1000000); - if (ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_AHCI_GHC_HR) { - bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); - device_printf(dev, "AHCI controller reset failure\n"); + if (ata_ahci_reset_controller(dev)) return ENXIO; - } - - /* reenable AHCI mode */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); /* get the number of HW channels */ ctlr->channels = _at__at_ -633,6 +652,8 _at__at_ ata_ahci_chipinit(device_t dev) ctlr->dmainit = ata_ahci_dmainit; ctlr->allocate = ata_ahci_allocate; ctlr->setmode = ata_sata_setmode; + ctlr->resume = ata_ahci_resume; + ctlr->suspend = ata_ahci_suspend; /* enable PCI interrupt */ pci_write_config(dev, PCIR_COMMAND, _at__at_ -655,9 +676,13 _at__at_ ata_ahci_allocate(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); - u_int64_t work; int offset = ch->unit << 7; + if (!(ATA_INL(ctlr->r_res2, ATA_AHCI_PI) & (1 << ch->unit))) { + device_printf(dev, "port not implemented\n"); + return ENXIO; + } + /* set the SATA resources */ ch->r_io[ATA_SSTATUS].res = ctlr->r_res2; ch->r_io[ATA_SSTATUS].offset = ATA_AHCI_P_SSTS + offset; _at__at_ -676,30 +701,45 _at__at_ ata_ahci_allocate(device_t dev) ch->hw.pm_read = ata_ahci_pm_read; ch->hw.pm_write = ata_ahci_pm_write; - /* setup work areas */ - work = ch->dma.work_bus + ATA_AHCI_CL_OFFSET; - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLB + offset, work & 0xffffffff); - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLBU + offset, work >> 32); + return 0; +} - work = ch->dma.work_bus + ATA_AHCI_FB_OFFSET; - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FB + offset, work & 0xffffffff); - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBU + offset, work >> 32); +static int +ata_ahci_suspend(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); - /* enable wanted port interrupts */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, - (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF | - ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF | - ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | ATA_AHCI_P_IX_DP | - ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS | - ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)); + /* XXX: PxCMD.ST must be cleared to '0' before entry into the + * D3 power state. + */ - /* enable FIS based switching */ - //ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBS + offset, 0x00000003); + /* Software must disable interrupts (GHC.IE must be cleared to 0) + * prior to requesting a transition of the HBA to the D3 state. + */ - /* start operations on this channel */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, - (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE | - ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST)); + ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, + ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & (~ATA_AHCI_GHC_IE)); + + return 0; +} + +static int +ata_ahci_resume(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); + + /* reset controller */ + if (ata_ahci_reset_controller(dev)) + return ENXIO; /* XXX */ + + /* clear interrupts */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, ATA_INL(ctlr->r_res2, ATA_AHCI_IS)); + + /* enable AHCI interrupts */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, + ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE); + + /* next part will be done by ata_resume */ return 0; } _at__at_ -716,38 +756,24 _at__at_ ata_ahci_status(device_t dev) u_int32_t cstatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset); /* clear interrupt(s) */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, action & (1 << ch->unit)); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, istatus); + ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, action & (1 << ch->unit)); /* do we have any PHY events ? */ - /* XXX SOS check istatus phy bits */ + if (istatus & (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC)) ata_sata_phy_check_events(dev); /* do we have a potentially hanging engine to take care of? */ /* XXX SOS what todo on NCQ */ - if ((istatus & 0x78400050) && (cstatus & 1)) { - - u_int32_t cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); - int timeout = 0; - - /* kill off all activity on this channel */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, - cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST)); - - /* XXX SOS this is not entirely wrong */ - do { - DELAY(1000); - if (timeout++ > 1000) { - device_printf(dev, "stopping AHCI engine failed\n"); - break; - } - } while (ATA_INL(ctlr->r_res2, - ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR); - - /* start operations on this channel */ - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, - cmd | (ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST)); - + if ((istatus & ATA_AHCI_P_IX_FE) && (cstatus & 1)) { + if (bootverbose) + device_printf(dev, "PHY fatal error: PxIS = 0x%08x\n", + istatus); + /* To recover fatal errors, the port must be restarted; + * the port is restarted by clearing PxCMD.ST to '0' and + * then setting PxCMD.ST to '1'. + */ + ata_ahci_restart_channel(ch); return 1; } else _at__at_ -998,46 +1024,107 @@ ata_ahci_pm_write(device_t dev, int port return (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) >> 8) & 0xff; } +/* CLO shall only be set immediately prior to setting + * the PxCMD.ST bit to '1' from a previous value of '0' + */ static void -ata_ahci_restart(device_t dev) +ata_ahci_clo_enable(struct ata_channel *ch) { - struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); - struct ata_channel *ch = device_get_softc(dev); - u_int32_t cmd; + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(ch->dev)); int offset = ch->unit << 7; - int timeout; + int timeout = 0; + u_int32_t cmd; - /* kill off all activity on this channel */ + if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_CLO) { cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, - cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST)); - - /* XXX SOS this is not entirely wrong */ - timeout = 0; + cmd | ATA_AHCI_P_CMD_CLO); do { DELAY(1000); if (timeout++ > 1000) { - device_printf(dev, "stopping AHCI engine failed\n"); + device_printf(ch->dev, "executing CLO failed\n"); break; } + } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) + & ATA_AHCI_P_CMD_CLO); } - while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR); +} + +/* When PxCMD.FR and PxCMD.FRE are both cleared to '0', software may update + * the values of PxFB and PxFBU. Prior to setting PxCMD.FRE to '1', software + * shall ensure that PxFB and PxFBU are set to valid values. Software shall + * not write PxFB and PxFBU while PxCMD.FRE is set to '1'. + */ +static void +ata_ahci_fre_start(struct ata_channel *ch) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(ch->dev)); + u_int32_t offset = ch->unit << 7; + u_int64_t work; + + /* setup work areas */ + work = ch->dma.work_bus + ATA_AHCI_CL_OFFSET; + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLB + offset, work & 0xffffffff); + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLBU + offset, work >> 32); + + work = ch->dma.work_bus + ATA_AHCI_FB_OFFSET; + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FB + offset, work & 0xffffffff); + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBU + offset, work >> 32); + + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, + ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) | ATA_AHCI_P_CMD_FRE); +} + +static void +ata_ahci_fre_stop(struct ata_channel *ch) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(ch->dev)); + u_int32_t offset = ch->unit << 7; + int timeout = 0; + + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, + ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & (~ATA_AHCI_P_CMD_FRE)); - /* issue Command List Override if supported */ - if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_CLO) { - cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); - cmd |= ATA_AHCI_P_CMD_CLO; - ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd); - timeout = 0; do { DELAY(1000); if (timeout++ > 1000) { - device_printf(dev, "executing CLO failed\n"); + device_printf(ch->dev, "ata_ahci_fre_stop failed\n"); break; } + } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_FR); +} + +static void +ata_ahci_stop_channel(struct ata_channel *ch) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(ch->dev)); + u_int32_t cmd, offset = ch->unit << 7; + int timeout = 0; + + cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); + if ((cmd & (ATA_AHCI_P_CMD_ST | ATA_AHCI_P_CMD_CR)) == 0) + return; + + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, + cmd & (~ATA_AHCI_P_CMD_ST)); + do { + DELAY(1000); + if (timeout++ > 1000) { + device_printf(ch->dev, "ata_ahci_stop_channel failed\n"); + break; } - while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD+offset)&ATA_AHCI_P_CMD_CLO); - } + } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR); +} + + +static void +ata_ahci_restart_channel(struct ata_channel *ch) +{ + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(ch->dev)); + int offset = ch->unit << 7; + + /* kill off all activity on this channel */ + ata_ahci_stop_channel(ch); /* clear SATA error register */ ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); _at__at_ -1046,11 +1133,12 @@ ata_ahci_restart(device_t dev) ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); + /* issue Command List Override if supported */ + ata_ahci_clo_enable(ch); + /* start operations on this channel */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, - (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_FRE | - ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD | ATA_AHCI_P_CMD_ST) - | (ch->devices & ATA_PORTMULTIPLIER ? ATA_AHCI_P_CMD_PMA : 0)); + ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) | ATA_AHCI_P_CMD_ST); } static u_int32_t _at__at_ -1065,7 +1153,7 _at_@ ata_ahci_softreset(device_t dev, int por (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); /* kick controller into sane state if needed */ - ata_ahci_restart(dev); + ata_ahci_restart_channel(ch); /* pull reset active */ bzero(ctp->cfis, 64); _at__at_ -1094,7 +1182,7 _at__at_ ata_ahci_softreset(device_t dev, int por #endif do { DELAY(1000); - if (timeout++ > 1000) { + if (timeout++ > 5000) { device_printf(dev, "still BUSY after softreset\n"); break; } _at__at_ -1110,19 +1198,35 _at_@ ata_ahci_reset(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); - u_int32_t signature; + u_int32_t signature, offset = ch->unit << 7; + ch->devices = 0; - if (!(ATA_INL(ctlr->r_res2, ATA_AHCI_PI) & (1 << ch->unit))) { - device_printf(dev, "port not implemented\n"); - return; - } + /* kill off all activity on this channel */ + ata_ahci_stop_channel(ch); + ata_ahci_fre_stop(ch); + + /* setup work areas and enable FIS receiving */ + ata_ahci_fre_start(ch); + + /* clear SATA error register */ + ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); + + /* clear port interrupts */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, + ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); + ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, (1 << ch->unit)); - ata_ahci_restart(dev); + /* enable wanted port interrupts */ + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, + (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF | + ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF | + ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | ATA_AHCI_P_IX_DP | + ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS | + ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)); if (!ata_sata_phy_reset(dev)) { if (bootverbose) device_printf(dev, "phy reset found no device\n"); - ch->devices = 0; return; } _at__at_ -1146,13 +1250,24 _at__at_ ata_ahci_reset(device_t dev) case 0xeb140101: ch->devices = ATA_ATAPI_MASTER; break; - default: /* SOS XXX */ + default: if (bootverbose) device_printf(dev, "No signature, asuming disk device\n"); - ch->devices = ATA_ATA_MASTER; } if (bootverbose) device_printf(dev, "ahci_reset devices=%08x\n", ch->devices); + + /* Software shall not set PxCMD.ST to 1 until it is determined + * that a functional device is present on the port. + */ + if (ch->devices) { + /* issue Command List Override if supported */ + ata_ahci_clo_enable(ch); + ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, + ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) | ATA_AHCI_P_CMD_SUD | + ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_ST | + (ch->devices & ATA_PORTMULTIPLIER ? ATA_AHCI_P_CMD_PMA : 0)); + } } static void Index: src/sys/dev/ata/ata-pci.c =================================================================== RCS file: /ncvs/src/sys/dev/ata/ata-pci.c,v retrieving revision 1.128 diff -u -b -p -r1.128 ata-pci.c --- src/sys/dev/ata/ata-pci.c 11 Jun 2008 06:44:58 -0000 1.128 +++ src/sys/dev/ata/ata-pci.c 21 Jul 2008 09:23:31 -0000 _at__at_ -262,6 +262,32 _at__at_ ata_pci_detach(device_t dev) return 0; } +int +ata_pci_suspend(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); + int error = 0; + + bus_generic_suspend(dev); + if (ctlr->suspend) + error = ctlr->suspend(dev); + + return error; +} + +int +ata_pci_resume(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); + int error = 0; + + if (ctlr->resume) + error = ctlr->resume(dev); + bus_generic_resume(dev); + + return error; +} + struct resource * ata_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) _at__at_ -556,8 +582,8 _at__at_ static device_method_t ata_pci_methods[] DEVMETHOD(device_attach, ata_pci_attach), DEVMETHOD(device_detach, ata_pci_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_suspend, ata_pci_suspend), + DEVMETHOD(device_resume, ata_pci_resume), /* bus methods */ DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), Index: src/sys/dev/ata/ata-pci.h =================================================================== RCS file: /ncvs/src/sys/dev/ata/ata-pci.h,v retrieving revision 1.89 diff -u -b -p -r1.89 ata-pci.h --- src/sys/dev/ata/ata-pci.h 10 Jul 2008 21:36:53 -0000 1.89 +++ src/sys/dev/ata/ata-pci.h 21 Jul 2008 09:23:31 -0000 _at__at_ -55,6 +55,8 @@ struct ata_pci_controller { void (*reset)(device_t); void (*dmainit)(device_t); void (*setmode)(device_t, int); + int (*suspend)(device_t); + int (*resume)(device_t); struct { void (*function)(void *); void *argument; _at__at_ -460,6 +462,8 @@ struct ata_connect_task { int ata_pci_probe(device_t dev); int ata_pci_attach(device_t dev); int ata_pci_detach(device_t dev); +int ata_pci_suspend(device_t dev); +int ata_pci_resume(device_t dev); struct resource * ata_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); int ata_pci_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r); int ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_filter_t *filter, driver_intr_t *function, void *argument, void **cookiep);Received on Mon Jul 21 2008 - 08:49:34 UTC
This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:39:33 UTC