[SCSI] aic7xxx: Add suspend/resume support

The aic7xxx driver already contains fragments for suspend/resume
support. So we only need to update them to the current interface
and have full PCI suspend/resume.

Signed-off-by: Hannes Reinecke <hare@suse.de>
Tested-by: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
Hannes Reinecke 2007-10-19 10:32:21 +02:00 committed by James Bottomley
parent eb7a1698d2
commit b5720729f5
8 changed files with 137 additions and 47 deletions

View File

@ -60,8 +60,6 @@
#define ID_OLV_274xD 0x04907783 /* Olivetti OEM (Differential) */ #define ID_OLV_274xD 0x04907783 /* Olivetti OEM (Differential) */
static int aic7770_chip_init(struct ahc_softc *ahc); static int aic7770_chip_init(struct ahc_softc *ahc);
static int aic7770_suspend(struct ahc_softc *ahc);
static int aic7770_resume(struct ahc_softc *ahc);
static int aha2840_load_seeprom(struct ahc_softc *ahc); static int aha2840_load_seeprom(struct ahc_softc *ahc);
static ahc_device_setup_t ahc_aic7770_VL_setup; static ahc_device_setup_t ahc_aic7770_VL_setup;
static ahc_device_setup_t ahc_aic7770_EISA_setup; static ahc_device_setup_t ahc_aic7770_EISA_setup;
@ -155,8 +153,6 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
return (error); return (error);
ahc->bus_chip_init = aic7770_chip_init; ahc->bus_chip_init = aic7770_chip_init;
ahc->bus_suspend = aic7770_suspend;
ahc->bus_resume = aic7770_resume;
error = ahc_reset(ahc, /*reinit*/FALSE); error = ahc_reset(ahc, /*reinit*/FALSE);
if (error != 0) if (error != 0)
@ -272,18 +268,6 @@ aic7770_chip_init(struct ahc_softc *ahc)
return (ahc_chip_init(ahc)); return (ahc_chip_init(ahc));
} }
static int
aic7770_suspend(struct ahc_softc *ahc)
{
return (ahc_suspend(ahc));
}
static int
aic7770_resume(struct ahc_softc *ahc)
{
return (ahc_resume(ahc));
}
/* /*
* Read the 284x SEEPROM. * Read the 284x SEEPROM.
*/ */

View File

@ -1003,8 +1003,15 @@ struct ahd_suspend_channel_state {
uint8_t seqctl; uint8_t seqctl;
}; };
struct ahd_suspend_pci_state {
uint32_t devconfig;
uint8_t command;
uint8_t csize_lattime;
};
struct ahd_suspend_state { struct ahd_suspend_state {
struct ahd_suspend_channel_state channel[2]; struct ahd_suspend_channel_state channel[2];
struct ahd_suspend_pci_state pci_state;
uint8_t optionmode; uint8_t optionmode;
uint8_t dscommand0; uint8_t dscommand0;
uint8_t dspcistatus; uint8_t dspcistatus;
@ -1333,6 +1340,8 @@ struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t);
int ahd_pci_config(struct ahd_softc *, int ahd_pci_config(struct ahd_softc *,
struct ahd_pci_identity *); struct ahd_pci_identity *);
int ahd_pci_test_register_access(struct ahd_softc *); int ahd_pci_test_register_access(struct ahd_softc *);
void ahd_pci_suspend(struct ahd_softc *);
void ahd_pci_resume(struct ahd_softc *);
/************************** SCB and SCB queue management **********************/ /************************** SCB and SCB queue management **********************/
void ahd_qinfifo_requeue_tail(struct ahd_softc *ahd, void ahd_qinfifo_requeue_tail(struct ahd_softc *ahd,
@ -1343,6 +1352,8 @@ struct ahd_softc *ahd_alloc(void *platform_arg, char *name);
int ahd_softc_init(struct ahd_softc *); int ahd_softc_init(struct ahd_softc *);
void ahd_controller_info(struct ahd_softc *ahd, char *buf); void ahd_controller_info(struct ahd_softc *ahd, char *buf);
int ahd_init(struct ahd_softc *ahd); int ahd_init(struct ahd_softc *ahd);
int ahd_suspend(struct ahd_softc *ahd);
void ahd_resume(struct ahd_softc *ahd);
int ahd_default_config(struct ahd_softc *ahd); int ahd_default_config(struct ahd_softc *ahd);
int ahd_parse_vpddata(struct ahd_softc *ahd, int ahd_parse_vpddata(struct ahd_softc *ahd,
struct vpd_config *vpd); struct vpd_config *vpd);

View File

@ -7175,7 +7175,6 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
ahd->flags &= ~AHD_ALL_INTERRUPTS; ahd->flags &= ~AHD_ALL_INTERRUPTS;
} }
#if 0
int int
ahd_suspend(struct ahd_softc *ahd) ahd_suspend(struct ahd_softc *ahd)
{ {
@ -7189,19 +7188,15 @@ ahd_suspend(struct ahd_softc *ahd)
ahd_shutdown(ahd); ahd_shutdown(ahd);
return (0); return (0);
} }
#endif /* 0 */
#if 0 void
int
ahd_resume(struct ahd_softc *ahd) ahd_resume(struct ahd_softc *ahd)
{ {
ahd_reset(ahd, /*reinit*/TRUE); ahd_reset(ahd, /*reinit*/TRUE);
ahd_intr_enable(ahd, TRUE); ahd_intr_enable(ahd, TRUE);
ahd_restart(ahd); ahd_restart(ahd);
return (0);
} }
#endif /* 0 */
/************************** Busy Target Table *********************************/ /************************** Busy Target Table *********************************/
/* /*

View File

@ -50,6 +50,8 @@ static int ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd,
static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd, static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
u_long *bus_addr, u_long *bus_addr,
uint8_t __iomem **maddr); uint8_t __iomem **maddr);
static int ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg);
static int ahd_linux_pci_dev_resume(struct pci_dev *pdev);
static void ahd_linux_pci_dev_remove(struct pci_dev *pdev); static void ahd_linux_pci_dev_remove(struct pci_dev *pdev);
/* Define the macro locally since it's different for different class of chips. /* Define the macro locally since it's different for different class of chips.
@ -86,10 +88,58 @@ MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table);
static struct pci_driver aic79xx_pci_driver = { static struct pci_driver aic79xx_pci_driver = {
.name = "aic79xx", .name = "aic79xx",
.probe = ahd_linux_pci_dev_probe, .probe = ahd_linux_pci_dev_probe,
#ifdef CONFIG_PM
.suspend = ahd_linux_pci_dev_suspend,
.resume = ahd_linux_pci_dev_resume,
#endif
.remove = ahd_linux_pci_dev_remove, .remove = ahd_linux_pci_dev_remove,
.id_table = ahd_linux_pci_id_table .id_table = ahd_linux_pci_id_table
}; };
static int
ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
struct ahd_softc *ahd = pci_get_drvdata(pdev);
int rc;
if ((rc = ahd_suspend(ahd)))
return rc;
ahd_pci_suspend(ahd);
pci_save_state(pdev);
pci_disable_device(pdev);
if (mesg.event == PM_EVENT_SUSPEND)
pci_set_power_state(pdev, PCI_D3hot);
return rc;
}
static int
ahd_linux_pci_dev_resume(struct pci_dev *pdev)
{
struct ahd_softc *ahd = pci_get_drvdata(pdev);
int rc;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
if ((rc = pci_enable_device(pdev))) {
dev_printk(KERN_ERR, &pdev->dev,
"failed to enable device after resume (%d)\n", rc);
return rc;
}
pci_set_master(pdev);
ahd_pci_resume(ahd);
ahd_resume(ahd);
return rc;
}
static void static void
ahd_linux_pci_dev_remove(struct pci_dev *pdev) ahd_linux_pci_dev_remove(struct pci_dev *pdev)
{ {

View File

@ -389,6 +389,33 @@ ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
return error; return error;
} }
void
ahd_pci_suspend(struct ahd_softc *ahd)
{
/*
* Save chip register configuration data for chip resets
* that occur during runtime and resume events.
*/
ahd->suspend_state.pci_state.devconfig =
ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4);
ahd->suspend_state.pci_state.command =
ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/1);
ahd->suspend_state.pci_state.csize_lattime =
ahd_pci_read_config(ahd->dev_softc, CSIZE_LATTIME, /*bytes*/1);
}
void
ahd_pci_resume(struct ahd_softc *ahd)
{
ahd_pci_write_config(ahd->dev_softc, DEVCONFIG,
ahd->suspend_state.pci_state.devconfig, /*bytes*/4);
ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
ahd->suspend_state.pci_state.command, /*bytes*/1);
ahd_pci_write_config(ahd->dev_softc, CSIZE_LATTIME,
ahd->suspend_state.pci_state.csize_lattime, /*bytes*/1);
}
/* /*
* Perform some simple tests that should catch situations where * Perform some simple tests that should catch situations where
* our registers are invalidly mapped. * our registers are invalidly mapped.

View File

@ -961,16 +961,6 @@ struct ahc_softc {
*/ */
ahc_bus_chip_init_t bus_chip_init; ahc_bus_chip_init_t bus_chip_init;
/*
* Bus specific suspend routine.
*/
ahc_bus_suspend_t bus_suspend;
/*
* Bus specific resume routine.
*/
ahc_bus_resume_t bus_resume;
/* /*
* Target mode related state kept on a per enabled lun basis. * Target mode related state kept on a per enabled lun basis.
* Targets that are not enabled will have null entries. * Targets that are not enabled will have null entries.
@ -1153,6 +1143,7 @@ struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t);
int ahc_pci_config(struct ahc_softc *, int ahc_pci_config(struct ahc_softc *,
struct ahc_pci_identity *); struct ahc_pci_identity *);
int ahc_pci_test_register_access(struct ahc_softc *); int ahc_pci_test_register_access(struct ahc_softc *);
void ahc_pci_resume(struct ahc_softc *ahc);
/*************************** EISA/VL Front End ********************************/ /*************************** EISA/VL Front End ********************************/
struct aic7770_identity *aic7770_find_device(uint32_t); struct aic7770_identity *aic7770_find_device(uint32_t);

View File

@ -49,6 +49,8 @@ static int ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc,
static int ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc, static int ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
u_long *bus_addr, u_long *bus_addr,
uint8_t __iomem **maddr); uint8_t __iomem **maddr);
static int ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg);
static int ahc_linux_pci_dev_resume(struct pci_dev *pdev);
static void ahc_linux_pci_dev_remove(struct pci_dev *pdev); static void ahc_linux_pci_dev_remove(struct pci_dev *pdev);
/* Define the macro locally since it's different for different class of chips. /* Define the macro locally since it's different for different class of chips.
@ -133,10 +135,54 @@ MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table);
static struct pci_driver aic7xxx_pci_driver = { static struct pci_driver aic7xxx_pci_driver = {
.name = "aic7xxx", .name = "aic7xxx",
.probe = ahc_linux_pci_dev_probe, .probe = ahc_linux_pci_dev_probe,
#ifdef CONFIG_PM
.suspend = ahc_linux_pci_dev_suspend,
.resume = ahc_linux_pci_dev_resume,
#endif
.remove = ahc_linux_pci_dev_remove, .remove = ahc_linux_pci_dev_remove,
.id_table = ahc_linux_pci_id_table .id_table = ahc_linux_pci_id_table
}; };
static int
ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
struct ahc_softc *ahc = pci_get_drvdata(pdev);
int rc;
if ((rc = ahc_suspend(ahc)))
return rc;
pci_save_state(pdev);
pci_disable_device(pdev);
if (mesg.event == PM_EVENT_SUSPEND)
pci_set_power_state(pdev, PCI_D3hot);
return rc;
}
static int
ahc_linux_pci_dev_resume(struct pci_dev *pdev)
{
struct ahc_softc *ahc = pci_get_drvdata(pdev);
int rc;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
if ((rc = pci_enable_device(pdev))) {
dev_printk(KERN_ERR, &pdev->dev,
"failed to enable device after resume (%d)\n", rc);
return rc;
}
pci_set_master(pdev);
ahc_pci_resume(ahc);
return (ahc_resume(ahc));
}
static void static void
ahc_linux_pci_dev_remove(struct pci_dev *pdev) ahc_linux_pci_dev_remove(struct pci_dev *pdev)
{ {

View File

@ -633,8 +633,6 @@ static void write_brdctl(struct ahc_softc *ahc, uint8_t value);
static uint8_t read_brdctl(struct ahc_softc *ahc); static uint8_t read_brdctl(struct ahc_softc *ahc);
static void ahc_pci_intr(struct ahc_softc *ahc); static void ahc_pci_intr(struct ahc_softc *ahc);
static int ahc_pci_chip_init(struct ahc_softc *ahc); static int ahc_pci_chip_init(struct ahc_softc *ahc);
static int ahc_pci_suspend(struct ahc_softc *ahc);
static int ahc_pci_resume(struct ahc_softc *ahc);
static int static int
ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor, ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor,
@ -791,8 +789,6 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
ahc->bus_intr = ahc_pci_intr; ahc->bus_intr = ahc_pci_intr;
ahc->bus_chip_init = ahc_pci_chip_init; ahc->bus_chip_init = ahc_pci_chip_init;
ahc->bus_suspend = ahc_pci_suspend;
ahc->bus_resume = ahc_pci_resume;
/* Remeber how the card was setup in case there is no SEEPROM */ /* Remeber how the card was setup in case there is no SEEPROM */
if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) { if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
@ -2024,18 +2020,9 @@ ahc_pci_chip_init(struct ahc_softc *ahc)
return (ahc_chip_init(ahc)); return (ahc_chip_init(ahc));
} }
static int void
ahc_pci_suspend(struct ahc_softc *ahc)
{
return (ahc_suspend(ahc));
}
static int
ahc_pci_resume(struct ahc_softc *ahc) ahc_pci_resume(struct ahc_softc *ahc)
{ {
pci_set_power_state(ahc->dev_softc, AHC_POWER_STATE_D0);
/* /*
* We assume that the OS has restored our register * We assume that the OS has restored our register
* mappings, etc. Just update the config space registers * mappings, etc. Just update the config space registers
@ -2063,7 +2050,6 @@ ahc_pci_resume(struct ahc_softc *ahc)
&sxfrctl1); &sxfrctl1);
ahc_release_seeprom(&sd); ahc_release_seeprom(&sd);
} }
return (ahc_resume(ahc));
} }
static int static int