From: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
To: Matthew Wilcox <willy@debian.org>,
"Wiedemeier, Jeff" <Jeff.Wiedemeier@hp.com>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>,
Jeff Garzik <jgarzik@pobox.com>,
"David S. Miller" <davem@redhat.com>,
linux-kernel@vger.kernel.org
Subject: [patch 2.5] pci_{save,restore}_extended_state, corrected
Date: Sat, 25 Jan 2003 20:25:13 +0300 [thread overview]
Message-ID: <20030125202513.A1283@localhost.park.msu.ru> (raw)
In-Reply-To: <20030125085248.A4882@parcelfarce.linux.theplanet.co.uk>; from willy@debian.org on Sat, Jan 25, 2003 at 08:52:48AM +0000
On Sat, Jan 25, 2003 at 08:52:48AM +0000, Matthew Wilcox wrote:
> PCI-X is 8 bytes -- ID, Next capability, 2-byte `Command', 4-byte `Status'
Thanks, corrected.
> Except PCI-X bridges, which are 16-bytes long. And I didn't write down the
> definition for those.
We can ignore them for now as a special case. I've yet to see the ppb
spec update.
> Hotswap uses only 3 bytes, but the 4th byte is `reserved' so better save
> 4 bytes rather than 3.
Fine.
Here's the corrected patch:
- fixed PCI_X_SIZEOF;
- Jeff's "pci_using_msi" patch is included, with some additions:
- check whether the dev->irq is configured;
- add "broken_msi" bit to struct pci_dev, for quirks.
I believe the MSI hardware will become quite popular even on
desktop PCs in a year or two, because it's *very* simple and
elegant way to awoid "4 pins per slot" limitation and to get
rid of those ugly IRQ routers. On the other hand, MSI is just
peer-to-peer DMA, which is horribly broken on a lot of PCs.
So let's be prepared.
Ivan.
--- 2.5.59/drivers/pci/pci.c Tue Dec 10 09:07:10 2002
+++ linux/drivers/pci/pci.c Sat Jan 25 19:19:41 2003
@@ -67,6 +67,29 @@ pci_max_busnr(void)
return max;
}
+static u8
+get_cap_pos(struct pci_dev *dev)
+{
+ u8 pos;
+ u16 status;
+
+ pci_read_config_word(dev, PCI_STATUS, &status);
+ if (!(status & PCI_STATUS_CAP_LIST))
+ return 0;
+ switch (dev->hdr_type) {
+ case PCI_HEADER_TYPE_NORMAL:
+ case PCI_HEADER_TYPE_BRIDGE:
+ pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &pos);
+ break;
+ case PCI_HEADER_TYPE_CARDBUS:
+ pci_read_config_byte(dev, PCI_CB_CAPABILITY_LIST, &pos);
+ break;
+ default:
+ return 0;
+ }
+ return pos;
+}
+
/**
* pci_find_capability - query for devices' capabilities
* @dev: PCI device to query
@@ -94,24 +117,10 @@ pci_max_busnr(void)
int
pci_find_capability(struct pci_dev *dev, int cap)
{
- u16 status;
u8 pos, id;
int ttl = 48;
- pci_read_config_word(dev, PCI_STATUS, &status);
- if (!(status & PCI_STATUS_CAP_LIST))
- return 0;
- switch (dev->hdr_type) {
- case PCI_HEADER_TYPE_NORMAL:
- case PCI_HEADER_TYPE_BRIDGE:
- pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &pos);
- break;
- case PCI_HEADER_TYPE_CARDBUS:
- pci_read_config_byte(dev, PCI_CB_CAPABILITY_LIST, &pos);
- break;
- default:
- return 0;
- }
+ pos = get_cap_pos(dev);
while (ttl-- && pos >= 0x40) {
pos &= ~3;
pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &id);
@@ -327,6 +336,116 @@ pci_restore_state(struct pci_dev *dev, u
return 0;
}
+static int
+get_cap_size(u32 cap)
+{
+ switch (cap & 0xff) {
+ case PCI_CAP_ID_PM:
+ return PCI_PM_SIZEOF;
+ case PCI_CAP_ID_AGP:
+ return PCI_AGP_SIZEOF;
+ case PCI_CAP_ID_VPD:
+ return PCI_VPD_SIZEOF;
+ case PCI_CAP_ID_SLOTID:
+ return PCI_SID_SIZEOF;
+ case PCI_CAP_ID_MSI:
+ return cap & (PCI_MSI_FLAGS_64BIT << 16) ? PCI_MSI64_SIZEOF :
+ PCI_MSI32_SIZEOF;
+ case PCI_CAP_ID_CHSWP:
+ return PCI_CHSWP_SIZEOF;
+ case PCI_CAP_ID_PCIX:
+ return PCI_X_SIZEOF;
+ default:
+ return PCI_CAP_SIZEOF;
+ }
+}
+
+/**
+ * pci_alloc_extended_state - allocates buffer large enough to hold
+ * standard PCI 2.1 configuration registers (first 64 bytes of configuration
+ * header) plus space for extended configuration registers defined by
+ * Capabilities List (if present)
+ * @dev: - PCI device that we're dealing with
+ */
+u32 *
+pci_alloc_extended_state(struct pci_dev *dev)
+{
+ u8 pos;
+ u32 cap;
+ int ttl = 48, size = 64;
+
+ pos = get_cap_pos(dev) & ~3;
+ while (ttl-- && pos >= 0x40) {
+ pci_read_config_dword(dev, pos, &cap);
+ size += (get_cap_size(cap) + 3) & ~3; /* round up to dword */
+ pos = (cap >> 8) & 0xfc;
+ }
+ return kmalloc(size, GFP_KERNEL);
+}
+
+/**
+ * pci_save_extended_state - save the PCI configuration space of a device
+ * before suspending, including extended configuration registers defined by
+ * Capabilities List
+ * @dev: - PCI device that we're dealing with
+ * @buffer: - buffer to hold config space context
+ *
+ * @buffer must be allocated by pci_alloc_extended_state
+ * (>= 64 bytes).
+ */
+int
+pci_save_extended_state(struct pci_dev *dev, u32 *buf)
+{
+ u32 *ptr = buf + 16;
+ u8 pos, next_pos;
+ int ttl = 48, i, cap_size;
+
+ if (!buf)
+ return 0;
+ pci_save_state(dev, buf);
+ pos = get_cap_pos(dev) & ~3;
+ while (ttl-- && pos >= 0x40) {
+ pci_read_config_dword(dev, pos, ptr);
+ next_pos = (*ptr >> 8) & 0xfc;
+ cap_size = get_cap_size(*ptr++);
+ for (i = 4; i < cap_size; i += 4, ptr++)
+ pci_read_config_dword(dev, pos + i, ptr);
+ pos = next_pos;
+ }
+ return 0;
+}
+
+/**
+ * pci_restore_extended_state - restore the saved state of a PCI device,
+ * including extended configuration registers defined by Capabilities List
+ * @dev: - PCI device that we're dealing with
+ * @buffer: - saved PCI config space
+ */
+int
+pci_restore_extended_state(struct pci_dev *dev, u32 *buf)
+{
+ u32 *ptr = buf + 16;
+ u8 pos, next_pos;
+ int i, cap_size;
+
+ pci_restore_state(dev, buf);
+ if (!buf)
+ return 0;
+ pos = get_cap_pos(dev) & ~3;
+ while (pos >= 0x40) {
+ u8 cap_id = *ptr & 0xff;
+
+ cap_size = get_cap_size(*ptr);
+ next_pos = (*ptr >> 8) & 0xfc;
+ for (i = 0; i < cap_size; i += 4, ptr++)
+ /* Don't restore PM state! */
+ if (cap_id != PCI_CAP_ID_PM)
+ pci_write_config_dword(dev, pos + i, *ptr);
+ pos = next_pos;
+ }
+ return 0;
+}
+
/**
* pci_enable_device_bars - Initialize some of a device for use
* @dev: PCI device to be initialized
@@ -679,6 +798,27 @@ pci_clear_mwi(struct pci_dev *dev)
}
}
+/**
+ * pci_using_msi - is this PCI device configured to use MSI?
+ * @dev: PCI device structure of device being queried
+ *
+ * Tells whether or not a PCI device is configured to use Message Signalled
+ * Interrupts. Returns non-zero if configured for MSI, else 0.
+ */
+int
+pci_using_msi(struct pci_dev *dev)
+{
+ int msi = pci_find_capability(dev, PCI_CAP_ID_MSI);
+ u8 flags;
+
+ if (!msi || !dev->irq || dev->broken_msi)
+ return 0;
+
+ pci_read_config_byte(dev, msi + PCI_MSI_FLAGS, &flags);
+
+ return (flags & PCI_MSI_FLAGS_ENABLE);
+}
+
int
pci_set_dma_mask(struct pci_dev *dev, u64 mask)
{
@@ -749,6 +889,7 @@ EXPORT_SYMBOL(pci_request_region);
EXPORT_SYMBOL(pci_set_master);
EXPORT_SYMBOL(pci_set_mwi);
EXPORT_SYMBOL(pci_clear_mwi);
+EXPORT_SYMBOL(pci_using_msi);
EXPORT_SYMBOL(pci_set_dma_mask);
EXPORT_SYMBOL(pci_dac_set_dma_mask);
EXPORT_SYMBOL(pci_assign_resource);
@@ -757,6 +898,9 @@ EXPORT_SYMBOL(pci_find_parent_resource);
EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_save_state);
EXPORT_SYMBOL(pci_restore_state);
+EXPORT_SYMBOL(pci_alloc_extended_state);
+EXPORT_SYMBOL(pci_save_extended_state);
+EXPORT_SYMBOL(pci_restore_extended_state);
EXPORT_SYMBOL(pci_enable_wake);
/* Quirk info */
--- 2.5.59/include/linux/pci.h Fri Jan 3 14:53:32 2003
+++ linux/include/linux/pci.h Sat Jan 25 19:13:50 2003
@@ -258,6 +258,7 @@
#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */
#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */
#define PCI_VPD_DATA 4 /* 32-bits of data returned here */
+#define PCI_VPD_SIZEOF 8
/* Slot Identification */
@@ -265,6 +266,7 @@
#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */
#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */
#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */
+#define PCI_SID_SIZEOF 4
/* Message Signalled Interrupts registers */
@@ -278,6 +280,8 @@
#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */
#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
+#define PCI_MSI32_SIZEOF 10
+#define PCI_MSI64_SIZEOF 14
/* CompactPCI Hotswap Register */
@@ -289,6 +293,7 @@
#define PCI_CHSWP_PI 0x30 /* Programming Interface */
#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */
#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */
+#define PCI_CHSWP_SIZEOF 4
/* PCI-X registers */
@@ -309,6 +314,7 @@
#define PCI_X_STATUS_MAX_SPLIT 0x0380 /* Design Max Outstanding Split Trans */
#define PCI_X_STATUS_MAX_CUM 0x1c00 /* Designed Max Cumulative Read Size */
#define PCI_X_STATUS_SPL_ERR 0x2000 /* Rcvd Split Completion Error Msg */
+#define PCI_X_SIZEOF 8
/* Include the ID list */
@@ -412,7 +418,10 @@ struct pci_dev {
char slot_name[8]; /* slot name */
/* These fields are used by common fixups */
- unsigned int transparent:1; /* Transparent PCI bridge */
+ unsigned int transparent:1, /* Transparent PCI bridge */
+ broken_msi:1; /* The device claims MSI capabability,
+ but MSI doesn't work for whatever
+ reason */
};
#define pci_dev_g(n) list_entry(n, struct pci_dev, global_list)
@@ -622,6 +631,7 @@ void pci_set_master(struct pci_dev *dev)
#define HAVE_PCI_SET_MWI
int pci_set_mwi(struct pci_dev *dev);
void pci_clear_mwi(struct pci_dev *dev);
+int pci_using_msi(struct pci_dev *dev);
int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask);
int pci_assign_resource(struct pci_dev *dev, int i);
@@ -629,6 +639,9 @@ int pci_assign_resource(struct pci_dev *
/* Power management related routines */
int pci_save_state(struct pci_dev *dev, u32 *buffer);
int pci_restore_state(struct pci_dev *dev, u32 *buffer);
+u32 *pci_alloc_extended_state(struct pci_dev *dev);
+int pci_save_extended_state(struct pci_dev *dev, u32 *buffer);
+int pci_restore_extended_state(struct pci_dev *dev, u32 *buffer);
int pci_set_power_state(struct pci_dev *dev, int state);
int pci_enable_wake(struct pci_dev *dev, u32 state, int enable);
prev parent reply other threads:[~2003-01-25 17:18 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-01-24 18:24 [patch 2.5] pci_{save,restore}_extended_state Ivan Kokshaysky
2003-01-24 23:07 ` Jeff Garzik
2003-01-25 8:52 ` Matthew Wilcox
2003-01-25 17:25 ` Ivan Kokshaysky [this message]
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=20030125202513.A1283@localhost.park.msu.ru \
--to=ink@jurassic.park.msu.ru \
--cc=Jeff.Wiedemeier@hp.com \
--cc=davem@redhat.com \
--cc=jgarzik@pobox.com \
--cc=linux-kernel@vger.kernel.org \
--cc=willy@debian.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.