* [PATCH 1/4] aic7xxx: Add suspend/resume support
@ 2007-10-19 8:32 Hannes Reinecke
2007-10-19 8:44 ` Christoph Hellwig
0 siblings, 1 reply; 5+ messages in thread
From: Hannes Reinecke @ 2007-10-19 8:32 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi
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>
---
drivers/scsi/aic7xxx/aic7770.c | 16 ----------
drivers/scsi/aic7xxx/aic79xx.h | 11 +++++++
drivers/scsi/aic7xxx/aic79xx_core.c | 7 +----
drivers/scsi/aic7xxx/aic79xx_osm_pci.c | 50 ++++++++++++++++++++++++++++++++
drivers/scsi/aic7xxx/aic79xx_pci.c | 27 +++++++++++++++++
drivers/scsi/aic7xxx/aic7xxx.h | 11 +------
drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 46 +++++++++++++++++++++++++++++
drivers/scsi/aic7xxx/aic7xxx_pci.c | 16 +---------
8 files changed, 137 insertions(+), 47 deletions(-)
diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c
index c4d1723..6d86a9b 100644
--- a/drivers/scsi/aic7xxx/aic7770.c
+++ b/drivers/scsi/aic7xxx/aic7770.c
@@ -60,8 +60,6 @@
#define ID_OLV_274xD 0x04907783 /* Olivetti OEM (Differential) */
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 ahc_device_setup_t ahc_aic7770_VL_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);
ahc->bus_chip_init = aic7770_chip_init;
- ahc->bus_suspend = aic7770_suspend;
- ahc->bus_resume = aic7770_resume;
error = ahc_reset(ahc, /*reinit*/FALSE);
if (error != 0)
@@ -272,18 +268,6 @@ aic7770_chip_init(struct ahc_softc *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.
*/
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index 27adbb2..ce638aa 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -1003,8 +1003,15 @@ struct ahd_suspend_channel_state {
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_channel_state channel[2];
+ struct ahd_suspend_pci_state pci_state;
uint8_t optionmode;
uint8_t dscommand0;
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 *,
struct ahd_pci_identity *);
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 **********************/
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 *);
void ahd_controller_info(struct ahd_softc *ahd, char *buf);
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_parse_vpddata(struct ahd_softc *ahd,
struct vpd_config *vpd);
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 05f692b..a7dd8cd 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -7175,7 +7175,6 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
ahd->flags &= ~AHD_ALL_INTERRUPTS;
}
-#if 0
int
ahd_suspend(struct ahd_softc *ahd)
{
@@ -7189,19 +7188,15 @@ ahd_suspend(struct ahd_softc *ahd)
ahd_shutdown(ahd);
return (0);
}
-#endif /* 0 */
-#if 0
-int
+void
ahd_resume(struct ahd_softc *ahd)
{
ahd_reset(ahd, /*reinit*/TRUE);
ahd_intr_enable(ahd, TRUE);
ahd_restart(ahd);
- return (0);
}
-#endif /* 0 */
/************************** Busy Target Table *********************************/
/*
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index c62ce41..66f0259 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -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,
u_long *bus_addr,
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);
/* 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 = {
.name = "aic79xx",
.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,
.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
ahd_linux_pci_dev_remove(struct pci_dev *pdev)
{
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 0bada00..7a203a9 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -389,6 +389,33 @@ ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
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
* our registers are invalidly mapped.
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index e1bd57b..3d4e42d 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -962,16 +962,6 @@ struct ahc_softc {
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.
* Targets that are not enabled will have null entries.
* As an initiator, we keep one target entry for our initiator
@@ -1153,6 +1143,7 @@ struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t);
int ahc_pci_config(struct ahc_softc *,
struct ahc_pci_identity *);
int ahc_pci_test_register_access(struct ahc_softc *);
+void ahc_pci_resume(struct ahc_softc *ahc);
/*************************** EISA/VL Front End ********************************/
struct aic7770_identity *aic7770_find_device(uint32_t);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index ea5687d..4488946 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -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,
u_long *bus_addr,
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);
/* 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 = {
.name = "aic7xxx",
.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,
.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
ahc_linux_pci_dev_remove(struct pci_dev *pdev)
{
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index 09c8172..ae35937 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -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 void ahc_pci_intr(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
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_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 */
if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
@@ -2024,18 +2020,9 @@ ahc_pci_chip_init(struct ahc_softc *ahc)
return (ahc_chip_init(ahc));
}
-static int
-ahc_pci_suspend(struct ahc_softc *ahc)
-{
- return (ahc_suspend(ahc));
-}
-
-static int
+void
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
* mappings, etc. Just update the config space registers
@@ -2063,7 +2050,6 @@ ahc_pci_resume(struct ahc_softc *ahc)
&sxfrctl1);
ahc_release_seeprom(&sd);
}
- return (ahc_resume(ahc));
}
static int
--
1.5.2.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/4] aic7xxx: Add suspend/resume support
2007-10-19 8:32 [PATCH 1/4] aic7xxx: Add suspend/resume support Hannes Reinecke
@ 2007-10-19 8:44 ` Christoph Hellwig
2007-10-19 12:35 ` Hannes Reinecke
0 siblings, 1 reply; 5+ messages in thread
From: Christoph Hellwig @ 2007-10-19 8:44 UTC (permalink / raw)
To: Hannes Reinecke; +Cc: James Bottomley, linux-scsi
I think this needs a little restructuring. ahd_pci_suspend/ahd_pci_resume
should be merged into their callers and use the normal Linux pci accessors,
and ahd_suspend/ahd_resume are tiny enough to merged into the caller aswell.
> +#ifdef CONFIG_PM
> + .suspend = ahd_linux_pci_dev_suspend,
> + .resume = ahd_linux_pci_dev_resume,
> +#endif
> .remove = ahd_linux_pci_dev_remove,
> .id_table = ahd_linux_pci_id_table
> };
>
> +static int
> +ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
I think this needsa #ifdef CONFIG_PM aswell. Also any chance you
could implement functions before their use so we can avoid forward
declarations.
> +{
> + struct ahd_softc *ahd = pci_get_drvdata(pdev);
> + int rc;
> +
> + if ((rc = ahd_suspend(ahd)))
> + return rc;
rc = ahd_suspend(ahd)
if (rc)
return rc;
but as I mentioned above better just inline the content of ahd_suspend
into this function. That would also catch that ahd_suspend returns
positive errno values and we'd have to invert them here.
Same comments apply to the aic7xxx portion.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/4] aic7xxx: Add suspend/resume support
2007-10-19 8:44 ` Christoph Hellwig
@ 2007-10-19 12:35 ` Hannes Reinecke
2007-10-19 13:02 ` Christoph Hellwig
0 siblings, 1 reply; 5+ messages in thread
From: Hannes Reinecke @ 2007-10-19 12:35 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: James Bottomley, linux-scsi
[-- Attachment #1: Type: text/plain, Size: 1687 bytes --]
Christoph Hellwig wrote:
> I think this needs a little restructuring. ahd_pci_suspend/ahd_pci_resume
> should be merged into their callers and use the normal Linux pci accessors,
> and ahd_suspend/ahd_resume are tiny enough to merged into the caller aswell.
>
Yes, partially. ahc_pci_resume() has to stay there as it uses quite some
functions from aic7xxx_pci.c. And I'd rather keep the overall structure
(ie split between linux-specific and generic pci access) for now.
In the long run it should be restructured as we don't do cross-compilation
with ***BSD anymore.
>> +#ifdef CONFIG_PM
>> + .suspend = ahd_linux_pci_dev_suspend,
>> + .resume = ahd_linux_pci_dev_resume,
>> +#endif
>> .remove = ahd_linux_pci_dev_remove,
>> .id_table = ahd_linux_pci_id_table
>> };
>>
>> +static int
>> +ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
>
> I think this needsa #ifdef CONFIG_PM aswell. Also any chance you
> could implement functions before their use so we can avoid forward
> declarations.
>
Yes, no problem.
>> +{
>> + struct ahd_softc *ahd = pci_get_drvdata(pdev);
>> + int rc;
>> +
>> + if ((rc = ahd_suspend(ahd)))
>> + return rc;
>
> rc = ahd_suspend(ahd)
> if (rc)
> return rc;
>
> but as I mentioned above better just inline the content of ahd_suspend
> into this function. That would also catch that ahd_suspend returns
> positive errno values and we'd have to invert them here.
>
Ok. Done.
Updated patch attached.
More to your liking?
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Markus Rex, HRB 16746 (AG Nürnberg)
[-- Attachment #2: 0001-aic7xxx-Add-suspend-resume-support.patch --]
[-- Type: text/x-patch, Size: 19837 bytes --]
>From 2dc1cdee053846fafc98a819bdad1533ac7c2f04 Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <hare@suse.de>
Date: Fri, 19 Oct 2007 09:13:17 +0200
Subject: [PATCH 1/4] 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>
---
drivers/scsi/aic7xxx/aic7770.c | 16 -----
drivers/scsi/aic7xxx/aic79xx.h | 9 +++
drivers/scsi/aic7xxx/aic79xx_core.c | 33 +---------
drivers/scsi/aic7xxx/aic79xx_osm_pci.c | 109 ++++++++++++++++++++++++++------
drivers/scsi/aic7xxx/aic79xx_pci.c | 24 -------
drivers/scsi/aic7xxx/aic79xx_pci.h | 25 +++++++
drivers/scsi/aic7xxx/aic7xxx.h | 18 +-----
drivers/scsi/aic7xxx/aic7xxx_core.c | 41 +------------
drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 88 +++++++++++++++++++++-----
drivers/scsi/aic7xxx/aic7xxx_pci.c | 16 +-----
10 files changed, 204 insertions(+), 175 deletions(-)
diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c
index c4d1723..6d86a9b 100644
--- a/drivers/scsi/aic7xxx/aic7770.c
+++ b/drivers/scsi/aic7xxx/aic7770.c
@@ -60,8 +60,6 @@
#define ID_OLV_274xD 0x04907783 /* Olivetti OEM (Differential) */
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 ahc_device_setup_t ahc_aic7770_VL_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);
ahc->bus_chip_init = aic7770_chip_init;
- ahc->bus_suspend = aic7770_suspend;
- ahc->bus_resume = aic7770_resume;
error = ahc_reset(ahc, /*reinit*/FALSE);
if (error != 0)
@@ -272,18 +268,6 @@ aic7770_chip_init(struct ahc_softc *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.
*/
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index 27adbb2..a96a2ff 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -1003,8 +1003,15 @@ struct ahd_suspend_channel_state {
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_channel_state channel[2];
+ struct ahd_suspend_pci_state pci_state;
uint8_t optionmode;
uint8_t dscommand0;
uint8_t dspcistatus;
@@ -1343,6 +1350,8 @@ struct ahd_softc *ahd_alloc(void *platform_arg, char *name);
int ahd_softc_init(struct ahd_softc *);
void ahd_controller_info(struct ahd_softc *ahd, char *buf);
int ahd_init(struct ahd_softc *ahd);
+void ahd_shutdown(void *arg);
+void ahd_restart(struct ahd_softc *ahd);
int ahd_default_config(struct ahd_softc *ahd);
int ahd_parse_vpddata(struct ahd_softc *ahd,
struct vpd_config *vpd);
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 05f692b..91f6f4f 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -255,7 +255,6 @@ static void ahd_freeze_devq(struct ahd_softc *ahd,
static void ahd_handle_scb_status(struct ahd_softc *ahd,
struct scb *scb);
static struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase);
-static void ahd_shutdown(void *arg);
static void ahd_update_coalescing_values(struct ahd_softc *ahd,
u_int timer,
u_int maxcmds,
@@ -357,7 +356,7 @@ ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
/*
* Restart the sequencer program from address zero
*/
-static void
+void
ahd_restart(struct ahd_softc *ahd)
{
@@ -5456,7 +5455,7 @@ ahd_free(struct ahd_softc *ahd)
return;
}
-static void
+void
ahd_shutdown(void *arg)
{
struct ahd_softc *ahd;
@@ -7175,34 +7174,6 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
ahd->flags &= ~AHD_ALL_INTERRUPTS;
}
-#if 0
-int
-ahd_suspend(struct ahd_softc *ahd)
-{
-
- ahd_pause_and_flushwork(ahd);
-
- if (LIST_FIRST(&ahd->pending_scbs) != NULL) {
- ahd_unpause(ahd);
- return (EBUSY);
- }
- ahd_shutdown(ahd);
- return (0);
-}
-#endif /* 0 */
-
-#if 0
-int
-ahd_resume(struct ahd_softc *ahd)
-{
-
- ahd_reset(ahd, /*reinit*/TRUE);
- ahd_intr_enable(ahd, TRUE);
- ahd_restart(ahd);
- return (0);
-}
-#endif /* 0 */
-
/************************** Busy Target Table *********************************/
/*
* Set SCBPTR to the SCB that contains the busy
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index c62ce41..d93d488 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -43,15 +43,6 @@
#include "aic79xx_inline.h"
#include "aic79xx_pci.h"
-static int ahd_linux_pci_dev_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent);
-static int ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd,
- u_long *base, u_long *base2);
-static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
- u_long *bus_addr,
- uint8_t __iomem **maddr);
-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 ID(x) \
@@ -83,12 +74,81 @@ static struct pci_device_id ahd_linux_pci_id_table[] = {
MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table);
-static struct pci_driver aic79xx_pci_driver = {
- .name = "aic79xx",
- .probe = ahd_linux_pci_dev_probe,
- .remove = ahd_linux_pci_dev_remove,
- .id_table = ahd_linux_pci_id_table
-};
+#ifdef CONFIG_PM
+int
+ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ahd_softc *ahd = pci_get_drvdata(pdev);
+
+ /*
+ * Shutdown the HBA
+ */
+ ahd_pause_and_flushwork(ahd);
+
+ if (LIST_FIRST(&ahd->pending_scbs) != NULL) {
+ ahd_unpause(ahd);
+ return -EBUSY;
+ }
+
+ ahd_shutdown(ahd);
+
+ /*
+ * Save chip register configuration data for chip resets
+ * that occur during runtime and resume events.
+ */
+ pci_read_config_dword(ahd->dev_softc, DEVCONFIG,
+ &ahd->suspend_state.pci_state.devconfig);
+ pci_read_config_byte(ahd->dev_softc, PCIR_COMMAND,
+ &ahd->suspend_state.pci_state.command);
+ pci_read_config_byte(ahd->dev_softc, CSIZE_LATTIME,
+ &ahd->suspend_state.pci_state.csize_lattime);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+
+ if (mesg.event == PM_EVENT_SUSPEND)
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return 0;
+}
+
+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);
+
+ /*
+ * Restore additional PCI registers
+ */
+ pci_write_config_dword(ahd->dev_softc, DEVCONFIG,
+ ahd->suspend_state.pci_state.devconfig);
+ pci_write_config_byte(ahd->dev_softc, PCIR_COMMAND,
+ ahd->suspend_state.pci_state.command);
+ pci_write_config_byte(ahd->dev_softc, CSIZE_LATTIME,
+ ahd->suspend_state.pci_state.csize_lattime);
+
+ /*
+ * Restart the HBA
+ */
+ ahd_reset(ahd, /*reinit*/TRUE);
+ ahd_intr_enable(ahd, TRUE);
+ ahd_restart(ahd);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
static void
ahd_linux_pci_dev_remove(struct pci_dev *pdev)
@@ -195,6 +255,17 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return (0);
}
+static struct pci_driver aic79xx_pci_driver = {
+ .name = "aic79xx",
+ .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,
+ .id_table = ahd_linux_pci_id_table
+};
+
int
ahd_linux_pci_init(void)
{
@@ -276,7 +347,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
/*
* If its allowed, we prefer memory mapped access.
*/
- command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, 4);
+ pci_read_config_dword(ahd->dev_softc, PCIR_COMMAND, &command);
command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN);
base = 0;
maddr = NULL;
@@ -287,8 +358,8 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
ahd->bshs[0].maddr = maddr;
ahd->tags[1] = BUS_SPACE_MEMIO;
ahd->bshs[1].maddr = maddr + 0x100;
- ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
- command | PCIM_CMD_MEMEN, 4);
+ pci_write_config_dword(ahd->dev_softc, PCIR_COMMAND,
+ command | PCIM_CMD_MEMEN);
if (ahd_pci_test_register_access(ahd) != 0) {
@@ -332,7 +403,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
base, base2);
}
}
- ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, 4);
+ pci_write_config_dword(ahd->dev_softc, PCIR_COMMAND, command);
return (error);
}
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 0bada00..c8617e0 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -209,12 +209,6 @@ static struct ahd_pci_identity ahd_pci_ident_table [] =
static const u_int ahd_num_pci_devs = ARRAY_SIZE(ahd_pci_ident_table);
-#define DEVCONFIG 0x40
-#define PCIXINITPAT 0x0000E000ul
-#define PCIXINIT_PCI33_66 0x0000E000ul
-#define PCIXINIT_PCIX50_66 0x0000C000ul
-#define PCIXINIT_PCIX66_100 0x0000A000ul
-#define PCIXINIT_PCIX100_133 0x00008000ul
#define PCI_BUS_MODES_INDEX(devconfig) \
(((devconfig) & PCIXINITPAT) >> 13)
static const char *pci_bus_modes[] =
@@ -229,24 +223,6 @@ static const char *pci_bus_modes[] =
"PCI 33 or 66Mhz"
};
-#define TESTMODE 0x00000800ul
-#define IRDY_RST 0x00000200ul
-#define FRAME_RST 0x00000100ul
-#define PCI64BIT 0x00000080ul
-#define MRDCEN 0x00000040ul
-#define ENDIANSEL 0x00000020ul
-#define MIXQWENDIANEN 0x00000008ul
-#define DACEN 0x00000004ul
-#define STPWLEVEL 0x00000002ul
-#define QWENDIANSEL 0x00000001ul
-
-#define DEVCONFIG1 0x44
-#define PREQDIS 0x01
-
-#define CSIZE_LATTIME 0x0c
-#define CACHESIZE 0x000000fful
-#define LATTIME 0x0000ff00ul
-
static int ahd_check_extport(struct ahd_softc *ahd);
static void ahd_configure_termination(struct ahd_softc *ahd,
u_int adapter_control);
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.h b/drivers/scsi/aic7xxx/aic79xx_pci.h
index 16b7c70..67ea5ae 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.h
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.h
@@ -69,4 +69,29 @@
#define ID_AHA_39320D_HP 0x8011900500AC0E11ull
#define ID_AHA_39320D_B_HP 0x801C900500AC0E11ull
+#define DEVCONFIG 0x40
+#define PCIXINITPAT 0x0000E000ul
+#define PCIXINIT_PCI33_66 0x0000E000ul
+#define PCIXINIT_PCIX50_66 0x0000C000ul
+#define PCIXINIT_PCIX66_100 0x0000A000ul
+#define PCIXINIT_PCIX100_133 0x00008000ul
+
+#define TESTMODE 0x00000800ul
+#define IRDY_RST 0x00000200ul
+#define FRAME_RST 0x00000100ul
+#define PCI64BIT 0x00000080ul
+#define MRDCEN 0x00000040ul
+#define ENDIANSEL 0x00000020ul
+#define MIXQWENDIANEN 0x00000008ul
+#define DACEN 0x00000004ul
+#define STPWLEVEL 0x00000002ul
+#define QWENDIANSEL 0x00000001ul
+
+#define DEVCONFIG1 0x44
+#define PREQDIS 0x01
+
+#define CSIZE_LATTIME 0x0c
+#define CACHESIZE 0x000000fful
+#define LATTIME 0x0000ff00ul
+
#endif /* _AIC79XX_PCI_H_ */
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index e1bd57b..80ceeaf 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -899,8 +899,6 @@ union ahc_bus_softc {
typedef void (*ahc_bus_intr_t)(struct ahc_softc *);
typedef int (*ahc_bus_chip_init_t)(struct ahc_softc *);
-typedef int (*ahc_bus_suspend_t)(struct ahc_softc *);
-typedef int (*ahc_bus_resume_t)(struct ahc_softc *);
typedef void ahc_callback_t (void *);
struct ahc_softc {
@@ -962,16 +960,6 @@ struct ahc_softc {
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.
* Targets that are not enabled will have null entries.
* As an initiator, we keep one target entry for our initiator
@@ -1153,6 +1141,7 @@ struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t);
int ahc_pci_config(struct ahc_softc *,
struct ahc_pci_identity *);
int ahc_pci_test_register_access(struct ahc_softc *);
+void ahc_pci_resume(struct ahc_softc *ahc);
/*************************** EISA/VL Front End ********************************/
struct aic7770_identity *aic7770_find_device(uint32_t);
@@ -1179,14 +1168,13 @@ int ahc_chip_init(struct ahc_softc *ahc);
int ahc_init(struct ahc_softc *ahc);
void ahc_intr_enable(struct ahc_softc *ahc, int enable);
void ahc_pause_and_flushwork(struct ahc_softc *ahc);
-int ahc_suspend(struct ahc_softc *ahc);
-int ahc_resume(struct ahc_softc *ahc);
void ahc_set_unit(struct ahc_softc *, int);
void ahc_set_name(struct ahc_softc *, char *);
void ahc_alloc_scbs(struct ahc_softc *ahc);
void ahc_free(struct ahc_softc *ahc);
int ahc_reset(struct ahc_softc *ahc, int reinit);
-void ahc_shutdown(void *arg);
+void ahc_restart(struct ahc_softc *ahc);
+void ahc_shutdown(struct ahc_softc *ahc);
/*************************** Interrupt Services *******************************/
void ahc_clear_intstat(struct ahc_softc *ahc);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index f350b5e..40f7072 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -3984,13 +3984,10 @@ ahc_free(struct ahc_softc *ahc)
}
void
-ahc_shutdown(void *arg)
+ahc_shutdown(struct ahc_softc *ahc)
{
- struct ahc_softc *ahc;
int i;
- ahc = (struct ahc_softc *)arg;
-
/* This will reset most registers to 0, but not all */
ahc_reset(ahc, /*reinit*/FALSE);
ahc_outb(ahc, SCSISEQ, 0);
@@ -5078,42 +5075,6 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
ahc->flags &= ~AHC_ALL_INTERRUPTS;
}
-int
-ahc_suspend(struct ahc_softc *ahc)
-{
-
- ahc_pause_and_flushwork(ahc);
-
- if (LIST_FIRST(&ahc->pending_scbs) != NULL) {
- ahc_unpause(ahc);
- return (EBUSY);
- }
-
-#ifdef AHC_TARGET_MODE
- /*
- * XXX What about ATIOs that have not yet been serviced?
- * Perhaps we should just refuse to be suspended if we
- * are acting in a target role.
- */
- if (ahc->pending_device != NULL) {
- ahc_unpause(ahc);
- return (EBUSY);
- }
-#endif
- ahc_shutdown(ahc);
- return (0);
-}
-
-int
-ahc_resume(struct ahc_softc *ahc)
-{
-
- ahc_reset(ahc, /*reinit*/TRUE);
- ahc_intr_enable(ahc, TRUE);
- ahc_restart(ahc);
- return (0);
-}
-
/************************** Busy Target Table *********************************/
/*
* Return the untagged transaction id for a given target/channel lun.
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index ea5687d..75b3d5a 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -41,15 +41,7 @@
#include "aic7xxx_osm.h"
#include "aic7xxx_pci.h"
-
-static int ahc_linux_pci_dev_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent);
-static int ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc,
- u_long *base);
-static int ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
- u_long *bus_addr,
- uint8_t __iomem **maddr);
-static void ahc_linux_pci_dev_remove(struct pci_dev *pdev);
+#include "aic7xxx_inline.h"
/* Define the macro locally since it's different for different class of chips.
*/
@@ -130,12 +122,67 @@ static struct pci_device_id ahc_linux_pci_id_table[] = {
MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table);
-static struct pci_driver aic7xxx_pci_driver = {
- .name = "aic7xxx",
- .probe = ahc_linux_pci_dev_probe,
- .remove = ahc_linux_pci_dev_remove,
- .id_table = ahc_linux_pci_id_table
-};
+#ifdef CONFIG_PM
+static int
+ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ahc_softc *ahc = pci_get_drvdata(pdev);
+
+ ahc_pause_and_flushwork(ahc);
+
+ if (LIST_FIRST(&ahc->pending_scbs) != NULL) {
+ ahc_unpause(ahc);
+ return -EBUSY;
+ }
+
+#ifdef AHC_TARGET_MODE
+ /*
+ * XXX What about ATIOs that have not yet been serviced?
+ * Perhaps we should just refuse to be suspended if we
+ * are acting in a target role.
+ */
+ if (ahc->pending_device != NULL) {
+ ahc_unpause(ahc);
+ return -EBUSY;
+ }
+#endif
+ ahc_shutdown(ahc);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+
+ if (mesg.event == PM_EVENT_SUSPEND)
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return 0;
+}
+
+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);
+
+ ahc_reset(ahc, /*reinit*/TRUE);
+ ahc_intr_enable(ahc, TRUE);
+ ahc_restart(ahc);
+
+ return rc;
+}
+#endif /* CONFIG_PM */
static void
ahc_linux_pci_dev_remove(struct pci_dev *pdev)
@@ -243,6 +290,17 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return (0);
}
+static struct pci_driver aic7xxx_pci_driver = {
+ .name = "aic7xxx",
+ .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,
+ .id_table = ahc_linux_pci_id_table
+};
+
int
ahc_linux_pci_init(void)
{
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index 09c8172..ae35937 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -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 void ahc_pci_intr(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
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_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 */
if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
@@ -2024,18 +2020,9 @@ ahc_pci_chip_init(struct ahc_softc *ahc)
return (ahc_chip_init(ahc));
}
-static int
-ahc_pci_suspend(struct ahc_softc *ahc)
-{
- return (ahc_suspend(ahc));
-}
-
-static int
+void
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
* mappings, etc. Just update the config space registers
@@ -2063,7 +2050,6 @@ ahc_pci_resume(struct ahc_softc *ahc)
&sxfrctl1);
ahc_release_seeprom(&sd);
}
- return (ahc_resume(ahc));
}
static int
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/4] aic7xxx: Add suspend/resume support
2007-10-19 12:35 ` Hannes Reinecke
@ 2007-10-19 13:02 ` Christoph Hellwig
2007-10-19 13:45 ` Hannes Reinecke
0 siblings, 1 reply; 5+ messages in thread
From: Christoph Hellwig @ 2007-10-19 13:02 UTC (permalink / raw)
To: Hannes Reinecke; +Cc: Christoph Hellwig, James Bottomley, linux-scsi
On Fri, Oct 19, 2007 at 02:35:35PM +0200, Hannes Reinecke wrote:
> Christoph Hellwig wrote:
> > I think this needs a little restructuring. ahd_pci_suspend/ahd_pci_resume
> > should be merged into their callers and use the normal Linux pci accessors,
> > and ahd_suspend/ahd_resume are tiny enough to merged into the caller aswell.
> >
> Yes, partially. ahc_pci_resume() has to stay there as it uses quite some
> functions from aic7xxx_pci.c. And I'd rather keep the overall structure
> (ie split between linux-specific and generic pci access) for now.
> In the long run it should be restructured as we don't do cross-compilation
> with ***BSD anymore.
Ok..
> Ok. Done.
> Updated patch attached.
> More to your liking?
Much better. There's still some if ((rc = fo())) left, but it's probably
not worth to delay the patch further because of that. Just clean it up
in a followon patch.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/4] aic7xxx: Add suspend/resume support
2007-10-19 13:02 ` Christoph Hellwig
@ 2007-10-19 13:45 ` Hannes Reinecke
0 siblings, 0 replies; 5+ messages in thread
From: Hannes Reinecke @ 2007-10-19 13:45 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: James Bottomley, linux-scsi
[-- Attachment #1: Type: text/plain, Size: 590 bytes --]
Christoph Hellwig wrote:
> On Fri, Oct 19, 2007 at 02:35:35PM +0200, Hannes Reinecke wrote:
[ .. ]
>> Ok. Done.
>> Updated patch attached.
>> More to your liking?
>
> Much better. There's still some if ((rc = fo())) left, but it's probably
> not worth to delay the patch further because of that. Just clean it up
> in a followon patch.
>
Might as well do it now. Fixed patch attached.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Markus Rex, HRB 16746 (AG Nürnberg)
[-- Attachment #2: 0001-aic7xxx-Add-suspend-resume-support.patch --]
[-- Type: text/x-patch, Size: 20409 bytes --]
>From 2dc1cdee053846fafc98a819bdad1533ac7c2f04 Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <hare@suse.de>
Date: Fri, 19 Oct 2007 09:13:17 +0200
Subject: [PATCH 1/4] 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>
---
drivers/scsi/aic7xxx/aic7770.c | 16 -----
drivers/scsi/aic7xxx/aic79xx.h | 9 +++
drivers/scsi/aic7xxx/aic79xx_core.c | 33 +---------
drivers/scsi/aic7xxx/aic79xx_osm_pci.c | 112 ++++++++++++++++++++++++++------
drivers/scsi/aic7xxx/aic79xx_pci.c | 24 -------
drivers/scsi/aic7xxx/aic79xx_pci.h | 25 +++++++
drivers/scsi/aic7xxx/aic7xxx.h | 18 +----
drivers/scsi/aic7xxx/aic7xxx_core.c | 41 +-----------
drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 91 +++++++++++++++++++++-----
drivers/scsi/aic7xxx/aic7xxx_pci.c | 16 +----
10 files changed, 208 insertions(+), 177 deletions(-)
diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c
index c4d1723..6d86a9b 100644
--- a/drivers/scsi/aic7xxx/aic7770.c
+++ b/drivers/scsi/aic7xxx/aic7770.c
@@ -60,8 +60,6 @@
#define ID_OLV_274xD 0x04907783 /* Olivetti OEM (Differential) */
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 ahc_device_setup_t ahc_aic7770_VL_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);
ahc->bus_chip_init = aic7770_chip_init;
- ahc->bus_suspend = aic7770_suspend;
- ahc->bus_resume = aic7770_resume;
error = ahc_reset(ahc, /*reinit*/FALSE);
if (error != 0)
@@ -272,18 +268,6 @@ aic7770_chip_init(struct ahc_softc *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.
*/
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index 27adbb2..a96a2ff 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -1003,8 +1003,15 @@ struct ahd_suspend_channel_state {
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_channel_state channel[2];
+ struct ahd_suspend_pci_state pci_state;
uint8_t optionmode;
uint8_t dscommand0;
uint8_t dspcistatus;
@@ -1343,6 +1350,8 @@ struct ahd_softc *ahd_alloc(void *platform_arg, char *name);
int ahd_softc_init(struct ahd_softc *);
void ahd_controller_info(struct ahd_softc *ahd, char *buf);
int ahd_init(struct ahd_softc *ahd);
+void ahd_shutdown(void *arg);
+void ahd_restart(struct ahd_softc *ahd);
int ahd_default_config(struct ahd_softc *ahd);
int ahd_parse_vpddata(struct ahd_softc *ahd,
struct vpd_config *vpd);
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 05f692b..91f6f4f 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -255,7 +255,6 @@ static void ahd_freeze_devq(struct ahd_softc *ahd,
static void ahd_handle_scb_status(struct ahd_softc *ahd,
struct scb *scb);
static struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase);
-static void ahd_shutdown(void *arg);
static void ahd_update_coalescing_values(struct ahd_softc *ahd,
u_int timer,
u_int maxcmds,
@@ -357,7 +356,7 @@ ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
/*
* Restart the sequencer program from address zero
*/
-static void
+void
ahd_restart(struct ahd_softc *ahd)
{
@@ -5456,7 +5455,7 @@ ahd_free(struct ahd_softc *ahd)
return;
}
-static void
+void
ahd_shutdown(void *arg)
{
struct ahd_softc *ahd;
@@ -7175,34 +7174,6 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
ahd->flags &= ~AHD_ALL_INTERRUPTS;
}
-#if 0
-int
-ahd_suspend(struct ahd_softc *ahd)
-{
-
- ahd_pause_and_flushwork(ahd);
-
- if (LIST_FIRST(&ahd->pending_scbs) != NULL) {
- ahd_unpause(ahd);
- return (EBUSY);
- }
- ahd_shutdown(ahd);
- return (0);
-}
-#endif /* 0 */
-
-#if 0
-int
-ahd_resume(struct ahd_softc *ahd)
-{
-
- ahd_reset(ahd, /*reinit*/TRUE);
- ahd_intr_enable(ahd, TRUE);
- ahd_restart(ahd);
- return (0);
-}
-#endif /* 0 */
-
/************************** Busy Target Table *********************************/
/*
* Set SCBPTR to the SCB that contains the busy
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index c62ce41..8aa6302 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -43,15 +43,6 @@
#include "aic79xx_inline.h"
#include "aic79xx_pci.h"
-static int ahd_linux_pci_dev_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent);
-static int ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd,
- u_long *base, u_long *base2);
-static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
- u_long *bus_addr,
- uint8_t __iomem **maddr);
-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 ID(x) \
@@ -83,12 +74,82 @@ static struct pci_device_id ahd_linux_pci_id_table[] = {
MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table);
-static struct pci_driver aic79xx_pci_driver = {
- .name = "aic79xx",
- .probe = ahd_linux_pci_dev_probe,
- .remove = ahd_linux_pci_dev_remove,
- .id_table = ahd_linux_pci_id_table
-};
+#ifdef CONFIG_PM
+int
+ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ahd_softc *ahd = pci_get_drvdata(pdev);
+
+ /*
+ * Shutdown the HBA
+ */
+ ahd_pause_and_flushwork(ahd);
+
+ if (LIST_FIRST(&ahd->pending_scbs) != NULL) {
+ ahd_unpause(ahd);
+ return -EBUSY;
+ }
+
+ ahd_shutdown(ahd);
+
+ /*
+ * Save chip register configuration data for chip resets
+ * that occur during runtime and resume events.
+ */
+ pci_read_config_dword(ahd->dev_softc, DEVCONFIG,
+ &ahd->suspend_state.pci_state.devconfig);
+ pci_read_config_byte(ahd->dev_softc, PCIR_COMMAND,
+ &ahd->suspend_state.pci_state.command);
+ pci_read_config_byte(ahd->dev_softc, CSIZE_LATTIME,
+ &ahd->suspend_state.pci_state.csize_lattime);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+
+ if (mesg.event == PM_EVENT_SUSPEND)
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return 0;
+}
+
+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);
+
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to enable device after resume (%d)\n", rc);
+ return rc;
+ }
+
+ pci_set_master(pdev);
+
+ /*
+ * Restore additional PCI registers
+ */
+ pci_write_config_dword(ahd->dev_softc, DEVCONFIG,
+ ahd->suspend_state.pci_state.devconfig);
+ pci_write_config_byte(ahd->dev_softc, PCIR_COMMAND,
+ ahd->suspend_state.pci_state.command);
+ pci_write_config_byte(ahd->dev_softc, CSIZE_LATTIME,
+ ahd->suspend_state.pci_state.csize_lattime);
+
+ /*
+ * Restart the HBA
+ */
+ ahd_reset(ahd, /*reinit*/TRUE);
+ ahd_intr_enable(ahd, TRUE);
+ ahd_restart(ahd);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
static void
ahd_linux_pci_dev_remove(struct pci_dev *pdev)
@@ -97,7 +158,7 @@ ahd_linux_pci_dev_remove(struct pci_dev *pdev)
u_long s;
if (ahd->platform_data && ahd->platform_data->host)
- scsi_remove_host(ahd->platform_data->host);
+ scsi_remove_host(ahd->platform_data->host);
ahd_lock(ahd, &s);
ahd_intr_enable(ahd, FALSE);
@@ -195,6 +256,17 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return (0);
}
+static struct pci_driver aic79xx_pci_driver = {
+ .name = "aic79xx",
+ .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,
+ .id_table = ahd_linux_pci_id_table
+};
+
int
ahd_linux_pci_init(void)
{
@@ -276,7 +348,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
/*
* If its allowed, we prefer memory mapped access.
*/
- command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, 4);
+ pci_read_config_dword(ahd->dev_softc, PCIR_COMMAND, &command);
command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN);
base = 0;
maddr = NULL;
@@ -287,8 +359,8 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
ahd->bshs[0].maddr = maddr;
ahd->tags[1] = BUS_SPACE_MEMIO;
ahd->bshs[1].maddr = maddr + 0x100;
- ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
- command | PCIM_CMD_MEMEN, 4);
+ pci_write_config_dword(ahd->dev_softc, PCIR_COMMAND,
+ command | PCIM_CMD_MEMEN);
if (ahd_pci_test_register_access(ahd) != 0) {
@@ -332,7 +404,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd)
base, base2);
}
}
- ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, 4);
+ pci_write_config_dword(ahd->dev_softc, PCIR_COMMAND, command);
return (error);
}
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 0bada00..c8617e0 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -209,12 +209,6 @@ static struct ahd_pci_identity ahd_pci_ident_table [] =
static const u_int ahd_num_pci_devs = ARRAY_SIZE(ahd_pci_ident_table);
-#define DEVCONFIG 0x40
-#define PCIXINITPAT 0x0000E000ul
-#define PCIXINIT_PCI33_66 0x0000E000ul
-#define PCIXINIT_PCIX50_66 0x0000C000ul
-#define PCIXINIT_PCIX66_100 0x0000A000ul
-#define PCIXINIT_PCIX100_133 0x00008000ul
#define PCI_BUS_MODES_INDEX(devconfig) \
(((devconfig) & PCIXINITPAT) >> 13)
static const char *pci_bus_modes[] =
@@ -229,24 +223,6 @@ static const char *pci_bus_modes[] =
"PCI 33 or 66Mhz"
};
-#define TESTMODE 0x00000800ul
-#define IRDY_RST 0x00000200ul
-#define FRAME_RST 0x00000100ul
-#define PCI64BIT 0x00000080ul
-#define MRDCEN 0x00000040ul
-#define ENDIANSEL 0x00000020ul
-#define MIXQWENDIANEN 0x00000008ul
-#define DACEN 0x00000004ul
-#define STPWLEVEL 0x00000002ul
-#define QWENDIANSEL 0x00000001ul
-
-#define DEVCONFIG1 0x44
-#define PREQDIS 0x01
-
-#define CSIZE_LATTIME 0x0c
-#define CACHESIZE 0x000000fful
-#define LATTIME 0x0000ff00ul
-
static int ahd_check_extport(struct ahd_softc *ahd);
static void ahd_configure_termination(struct ahd_softc *ahd,
u_int adapter_control);
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.h b/drivers/scsi/aic7xxx/aic79xx_pci.h
index 16b7c70..67ea5ae 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.h
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.h
@@ -69,4 +69,29 @@
#define ID_AHA_39320D_HP 0x8011900500AC0E11ull
#define ID_AHA_39320D_B_HP 0x801C900500AC0E11ull
+#define DEVCONFIG 0x40
+#define PCIXINITPAT 0x0000E000ul
+#define PCIXINIT_PCI33_66 0x0000E000ul
+#define PCIXINIT_PCIX50_66 0x0000C000ul
+#define PCIXINIT_PCIX66_100 0x0000A000ul
+#define PCIXINIT_PCIX100_133 0x00008000ul
+
+#define TESTMODE 0x00000800ul
+#define IRDY_RST 0x00000200ul
+#define FRAME_RST 0x00000100ul
+#define PCI64BIT 0x00000080ul
+#define MRDCEN 0x00000040ul
+#define ENDIANSEL 0x00000020ul
+#define MIXQWENDIANEN 0x00000008ul
+#define DACEN 0x00000004ul
+#define STPWLEVEL 0x00000002ul
+#define QWENDIANSEL 0x00000001ul
+
+#define DEVCONFIG1 0x44
+#define PREQDIS 0x01
+
+#define CSIZE_LATTIME 0x0c
+#define CACHESIZE 0x000000fful
+#define LATTIME 0x0000ff00ul
+
#endif /* _AIC79XX_PCI_H_ */
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index e1bd57b..80ceeaf 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -899,8 +899,6 @@ union ahc_bus_softc {
typedef void (*ahc_bus_intr_t)(struct ahc_softc *);
typedef int (*ahc_bus_chip_init_t)(struct ahc_softc *);
-typedef int (*ahc_bus_suspend_t)(struct ahc_softc *);
-typedef int (*ahc_bus_resume_t)(struct ahc_softc *);
typedef void ahc_callback_t (void *);
struct ahc_softc {
@@ -962,16 +960,6 @@ struct ahc_softc {
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.
* Targets that are not enabled will have null entries.
* As an initiator, we keep one target entry for our initiator
@@ -1153,6 +1141,7 @@ struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t);
int ahc_pci_config(struct ahc_softc *,
struct ahc_pci_identity *);
int ahc_pci_test_register_access(struct ahc_softc *);
+void ahc_pci_resume(struct ahc_softc *ahc);
/*************************** EISA/VL Front End ********************************/
struct aic7770_identity *aic7770_find_device(uint32_t);
@@ -1179,14 +1168,13 @@ int ahc_chip_init(struct ahc_softc *ahc);
int ahc_init(struct ahc_softc *ahc);
void ahc_intr_enable(struct ahc_softc *ahc, int enable);
void ahc_pause_and_flushwork(struct ahc_softc *ahc);
-int ahc_suspend(struct ahc_softc *ahc);
-int ahc_resume(struct ahc_softc *ahc);
void ahc_set_unit(struct ahc_softc *, int);
void ahc_set_name(struct ahc_softc *, char *);
void ahc_alloc_scbs(struct ahc_softc *ahc);
void ahc_free(struct ahc_softc *ahc);
int ahc_reset(struct ahc_softc *ahc, int reinit);
-void ahc_shutdown(void *arg);
+void ahc_restart(struct ahc_softc *ahc);
+void ahc_shutdown(struct ahc_softc *ahc);
/*************************** Interrupt Services *******************************/
void ahc_clear_intstat(struct ahc_softc *ahc);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index f350b5e..40f7072 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -3984,13 +3984,10 @@ ahc_free(struct ahc_softc *ahc)
}
void
-ahc_shutdown(void *arg)
+ahc_shutdown(struct ahc_softc *ahc)
{
- struct ahc_softc *ahc;
int i;
- ahc = (struct ahc_softc *)arg;
-
/* This will reset most registers to 0, but not all */
ahc_reset(ahc, /*reinit*/FALSE);
ahc_outb(ahc, SCSISEQ, 0);
@@ -5078,42 +5075,6 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
ahc->flags &= ~AHC_ALL_INTERRUPTS;
}
-int
-ahc_suspend(struct ahc_softc *ahc)
-{
-
- ahc_pause_and_flushwork(ahc);
-
- if (LIST_FIRST(&ahc->pending_scbs) != NULL) {
- ahc_unpause(ahc);
- return (EBUSY);
- }
-
-#ifdef AHC_TARGET_MODE
- /*
- * XXX What about ATIOs that have not yet been serviced?
- * Perhaps we should just refuse to be suspended if we
- * are acting in a target role.
- */
- if (ahc->pending_device != NULL) {
- ahc_unpause(ahc);
- return (EBUSY);
- }
-#endif
- ahc_shutdown(ahc);
- return (0);
-}
-
-int
-ahc_resume(struct ahc_softc *ahc)
-{
-
- ahc_reset(ahc, /*reinit*/TRUE);
- ahc_intr_enable(ahc, TRUE);
- ahc_restart(ahc);
- return (0);
-}
-
/************************** Busy Target Table *********************************/
/*
* Return the untagged transaction id for a given target/channel lun.
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index ea5687d..847485f 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -41,15 +41,7 @@
#include "aic7xxx_osm.h"
#include "aic7xxx_pci.h"
-
-static int ahc_linux_pci_dev_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent);
-static int ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc,
- u_long *base);
-static int ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
- u_long *bus_addr,
- uint8_t __iomem **maddr);
-static void ahc_linux_pci_dev_remove(struct pci_dev *pdev);
+#include "aic7xxx_inline.h"
/* Define the macro locally since it's different for different class of chips.
*/
@@ -130,12 +122,68 @@ static struct pci_device_id ahc_linux_pci_id_table[] = {
MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table);
-static struct pci_driver aic7xxx_pci_driver = {
- .name = "aic7xxx",
- .probe = ahc_linux_pci_dev_probe,
- .remove = ahc_linux_pci_dev_remove,
- .id_table = ahc_linux_pci_id_table
-};
+#ifdef CONFIG_PM
+static int
+ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ahc_softc *ahc = pci_get_drvdata(pdev);
+
+ ahc_pause_and_flushwork(ahc);
+
+ if (LIST_FIRST(&ahc->pending_scbs) != NULL) {
+ ahc_unpause(ahc);
+ return -EBUSY;
+ }
+
+#ifdef AHC_TARGET_MODE
+ /*
+ * XXX What about ATIOs that have not yet been serviced?
+ * Perhaps we should just refuse to be suspended if we
+ * are acting in a target role.
+ */
+ if (ahc->pending_device != NULL) {
+ ahc_unpause(ahc);
+ return -EBUSY;
+ }
+#endif
+ ahc_shutdown(ahc);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+
+ if (mesg.event == PM_EVENT_SUSPEND)
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return 0;
+}
+
+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);
+
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ 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);
+
+ ahc_reset(ahc, /*reinit*/TRUE);
+ ahc_intr_enable(ahc, TRUE);
+ ahc_restart(ahc);
+
+ return rc;
+}
+#endif /* CONFIG_PM */
static void
ahc_linux_pci_dev_remove(struct pci_dev *pdev)
@@ -144,7 +192,7 @@ ahc_linux_pci_dev_remove(struct pci_dev *pdev)
u_long s;
if (ahc->platform_data && ahc->platform_data->host)
- scsi_remove_host(ahc->platform_data->host);
+ scsi_remove_host(ahc->platform_data->host);
ahc_lock(ahc, &s);
ahc_intr_enable(ahc, FALSE);
@@ -243,6 +291,17 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return (0);
}
+static struct pci_driver aic7xxx_pci_driver = {
+ .name = "aic7xxx",
+ .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,
+ .id_table = ahc_linux_pci_id_table
+};
+
int
ahc_linux_pci_init(void)
{
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index 09c8172..ae35937 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -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 void ahc_pci_intr(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
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_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 */
if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
@@ -2024,18 +2020,9 @@ ahc_pci_chip_init(struct ahc_softc *ahc)
return (ahc_chip_init(ahc));
}
-static int
-ahc_pci_suspend(struct ahc_softc *ahc)
-{
- return (ahc_suspend(ahc));
-}
-
-static int
+void
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
* mappings, etc. Just update the config space registers
@@ -2063,7 +2050,6 @@ ahc_pci_resume(struct ahc_softc *ahc)
&sxfrctl1);
ahc_release_seeprom(&sd);
}
- return (ahc_resume(ahc));
}
static int
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2007-10-19 13:45 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-10-19 8:32 [PATCH 1/4] aic7xxx: Add suspend/resume support Hannes Reinecke
2007-10-19 8:44 ` Christoph Hellwig
2007-10-19 12:35 ` Hannes Reinecke
2007-10-19 13:02 ` Christoph Hellwig
2007-10-19 13:45 ` Hannes Reinecke
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).