From: Adam Belay <abelay@novell.com>
To: Greg KH <greg@kroah.com>, Andrew Morton <akpm@osdl.org>
Cc: linux-kernel@vger.kernel.org, linux-pci@atrey.karlin.mff.cuni.cz
Subject: [PATCH 4/9] PCI PM: save and restore configuration state correctly
Date: Mon, 05 Jun 2006 04:46:05 -0400 [thread overview]
Message-ID: <1149497166.7831.158.camel@localhost.localdomain> (raw)
This patch updates pci_save_state() and pci_restore_state() to be more
in line with the PCI PM specification. Specifically, read-only
registers are no longer saved, BIST is never touched, and the command
register is handled more carefully. A new data structure "struct
pci_dev_config" is created to store any context that might need to be
saved before entering a higher power state.
The configuration space cache is now obsolete and no longer needed for
PCI PM. However, this patch does not remove it as it is still
referenced by the PCI configuration space access restriction code. As
an unexpected bonus, this patch also fixes a possible memory leak;
drivers/pci/access.c wasn't expecting the MSI code in pci_save_state().
Signed-off-by: Adam Belay <abelay@novell.com>
---
drivers/pci/access.c | 17 ++++++++++-------
drivers/pci/pm.c | 29 +++++++++++++++++++++++------
include/linux/pci.h | 12 +++++++++++-
3 files changed, 44 insertions(+), 14 deletions(-)
diff -urN a/drivers/pci/access.c b/drivers/pci/access.c
--- a/drivers/pci/access.c 2006-06-03 16:21:16.000000000 -0400
+++ b/drivers/pci/access.c 2006-06-02 00:40:28.000000000 -0400
@@ -67,8 +67,8 @@
{
u32 data;
- data = dev->saved_config_space[pos/sizeof(dev->saved_config_space[0])];
- data >>= (pos % sizeof(dev->saved_config_space[0])) * 8;
+ data = dev->cached_config_space[pos/sizeof(dev->cached_config_space[0])];
+ data >>= (pos % sizeof(dev->cached_config_space[0])) * 8;
return data;
}
@@ -84,7 +84,7 @@
if (likely(!dev->block_ucfg_access)) \
ret = dev->bus->ops->read(dev->bus, dev->devfn, \
pos, sizeof(type), &data); \
- else if (pos < sizeof(dev->saved_config_space)) \
+ else if (pos < sizeof(dev->cached_config_space)) \
data = pci_user_cached_config(dev, pos); \
spin_unlock_irqrestore(&pci_lock, flags); \
*val = (type)data; \
@@ -118,15 +118,18 @@
* @dev: pci device struct
*
* This function blocks any userspace PCI config accesses from occurring.
- * When blocked, any writes will be bit bucketed and reads will return the
- * data saved using pci_save_state for the first 64 bytes of config
- * space and return 0xff for all other config reads.
+ * When blocked, any writes will be bit bucketed and reads will return cached
+ * data for the first 64 bytes of config space and return 0xff for all other
+ * config reads.
**/
void pci_block_user_cfg_access(struct pci_dev *dev)
{
unsigned long flags;
+ int i;
- pci_save_state(dev);
+ /* NOTE: 100% dword access ok here? */
+ for (i = 0; i < 16; i++)
+ pci_read_config_dword(dev, i * 4, &dev->cached_config_space[i]);
/* spinlock to synchronize with anyone reading config space now */
spin_lock_irqsave(&pci_lock, flags);
diff -urN a/drivers/pci/pm.c b/drivers/pci/pm.c
--- a/drivers/pci/pm.c 2006-06-03 16:21:16.000000000 -0400
+++ b/drivers/pci/pm.c 2006-06-03 16:46:08.000000000 -0400
@@ -58,13 +58,19 @@
int pci_save_state(struct pci_dev *dev)
{
int i;
- /* XXX: 100% dword access ok here? */
- for (i = 0; i < 16; i++)
- pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]);
+ struct pci_dev_config * conf = &dev->saved_config;
+
+ pci_read_config_word(dev, PCI_COMMAND, &conf->command);
+ pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &conf->cacheline_size);
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &conf->latency_timer);
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &conf->interrupt_pin);
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &conf->interrupt_line);
+
if ((i = pci_save_msi_state(dev)) != 0)
return i;
if ((i = pci_save_msix_state(dev)) != 0)
return i;
+
return 0;
}
@@ -76,12 +82,23 @@
*/
int pci_restore_state(struct pci_dev *dev)
{
- int i;
+ u16 command;
+ struct pci_dev_config * conf = &dev->saved_config;
+
+ command = conf->command & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER);
+
+ pci_write_config_word(dev, PCI_COMMAND, command);
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, conf->cacheline_size);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, conf->latency_timer);
+ pci_write_config_byte(dev, PCI_INTERRUPT_PIN, conf->interrupt_pin);
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, conf->interrupt_line);
+
+ pci_restore_bars(dev);
- for (i = 0; i < 16; i++)
- pci_write_config_dword(dev,i * 4, dev->saved_config_space[i]);
pci_restore_msi_state(dev);
pci_restore_msix_state(dev);
+
return 0;
}
diff -urN a/include/linux/pci.h b/include/linux/pci.h
--- a/include/linux/pci.h 2006-06-03 16:21:16.000000000 -0400
+++ b/include/linux/pci.h 2006-06-03 16:27:45.000000000 -0400
@@ -68,6 +68,14 @@
#define DEVICE_COUNT_COMPATIBLE 4
#define DEVICE_COUNT_RESOURCE 12
+struct pci_dev_config {
+ unsigned short command;
+ unsigned char cacheline_size;
+ unsigned char latency_timer;
+ unsigned char interrupt_pin;
+ unsigned char interrupt_line;
+};
+
struct pci_dev_pm {
unsigned int pm_offset; /* the PCI PM capability offset */
@@ -183,7 +191,9 @@
unsigned int no_msi:1; /* device may not use msi */
unsigned int block_ucfg_access:1; /* userspace config space access is blocked */
- u32 saved_config_space[16]; /* config space saved at suspend time */
+ u32 cached_config_space[16]; /* config space saved at suspend time */
+ struct pci_dev_config saved_config; /* config space saved for power management */
+
struct hlist_head saved_cap_space;
struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */
int rom_attr_enabled; /* has display of the rom attribute been enabled? */
next reply other threads:[~2006-06-05 8:35 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-06-05 8:46 Adam Belay [this message]
2006-06-10 13:34 ` [PATCH 4/9] PCI PM: save and restore configuration state correctly Pavel Machek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1149497166.7831.158.camel@localhost.localdomain \
--to=abelay@novell.com \
--cc=akpm@osdl.org \
--cc=greg@kroah.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@atrey.karlin.mff.cuni.cz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox