[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:
parent
eb7a1698d2
commit
b5720729f5
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 *********************************/
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue