summaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2007-04-12 21:50:03 +0400
committerPaul Mackerras <paulus@samba.org>2007-04-12 21:50:03 +0400
commite049d1ca3094f3d1d94617f456a9961202f96e3a (patch)
treea30397ad22f2fbea268bd28fa69c60aad9dfa62a /drivers/pci
parentedfac96a92b88d3b0b53e3f8231b74beee9ecd1d (diff)
parent80584ff3b99c36ead7e130e453b3a48b18072d18 (diff)
downloadlinux-e049d1ca3094f3d1d94617f456a9961202f96e3a.tar.xz
Merge branch 'linux-2.6' into for-2.6.22
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/msi.c151
-rw-r--r--drivers/pci/pci.c29
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c6
-rw-r--r--drivers/pci/pcie/portdrv_pci.c8
-rw-r--r--drivers/pci/quirks.c18
-rw-r--r--drivers/pci/search.c2
7 files changed, 55 insertions, 161 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 01869b1782e4..435c1958a7b7 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -94,12 +94,14 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
writel(flag, entry->mask_base + offset);
+ readl(entry->mask_base + offset);
break;
}
default:
BUG();
break;
}
+ entry->msi_attrib.masked = !!flag;
}
void read_msi_msg(unsigned int irq, struct msi_msg *msg)
@@ -179,6 +181,7 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg)
default:
BUG();
}
+ entry->msg = *msg;
}
void mask_msi_irq(unsigned int irq)
@@ -225,164 +228,60 @@ static struct msi_desc* alloc_msi_entry(void)
}
#ifdef CONFIG_PM
-static int __pci_save_msi_state(struct pci_dev *dev)
-{
- int pos, i = 0;
- u16 control;
- struct pci_cap_saved_state *save_state;
- u32 *cap;
-
- if (!dev->msi_enabled)
- return 0;
-
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (pos <= 0)
- return 0;
-
- save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u32) * 5,
- GFP_KERNEL);
- if (!save_state) {
- printk(KERN_ERR "Out of memory in pci_save_msi_state\n");
- return -ENOMEM;
- }
- cap = &save_state->data[0];
-
- pci_read_config_dword(dev, pos, &cap[i++]);
- control = cap[0] >> 16;
- pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, &cap[i++]);
- if (control & PCI_MSI_FLAGS_64BIT) {
- pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, &cap[i++]);
- pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, &cap[i++]);
- } else
- pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]);
- if (control & PCI_MSI_FLAGS_MASKBIT)
- pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]);
- save_state->cap_nr = PCI_CAP_ID_MSI;
- pci_add_saved_cap(dev, save_state);
- return 0;
-}
-
static void __pci_restore_msi_state(struct pci_dev *dev)
{
- int i = 0, pos;
+ int pos;
u16 control;
- struct pci_cap_saved_state *save_state;
- u32 *cap;
+ struct msi_desc *entry;
if (!dev->msi_enabled)
return;
- save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSI);
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (!save_state || pos <= 0)
- return;
- cap = &save_state->data[0];
+ entry = get_irq_msi(dev->irq);
+ pos = entry->msi_attrib.pos;
pci_intx(dev, 0); /* disable intx */
- control = cap[i++] >> 16;
msi_set_enable(dev, 0);
- pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, cap[i++]);
- if (control & PCI_MSI_FLAGS_64BIT) {
- pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, cap[i++]);
- pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, cap[i++]);
- } else
- pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, cap[i++]);
- if (control & PCI_MSI_FLAGS_MASKBIT)
- pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, cap[i++]);
+ write_msi_msg(dev->irq, &entry->msg);
+ if (entry->msi_attrib.maskbit)
+ msi_set_mask_bit(dev->irq, entry->msi_attrib.masked);
+
+ pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
+ control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
+ if (entry->msi_attrib.maskbit || !entry->msi_attrib.masked)
+ control |= PCI_MSI_FLAGS_ENABLE;
pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
- pci_remove_saved_cap(save_state);
- kfree(save_state);
-}
-
-static int __pci_save_msix_state(struct pci_dev *dev)
-{
- int pos;
- int irq, head, tail = 0;
- u16 control;
- struct pci_cap_saved_state *save_state;
-
- if (!dev->msix_enabled)
- return 0;
-
- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos <= 0)
- return 0;
-
- /* save the capability */
- pci_read_config_word(dev, msi_control_reg(pos), &control);
- save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u16),
- GFP_KERNEL);
- if (!save_state) {
- printk(KERN_ERR "Out of memory in pci_save_msix_state\n");
- return -ENOMEM;
- }
- *((u16 *)&save_state->data[0]) = control;
-
- /* save the table */
- irq = head = dev->first_msi_irq;
- while (head != tail) {
- struct msi_desc *entry;
-
- entry = get_irq_msi(irq);
- read_msi_msg(irq, &entry->msg_save);
-
- tail = entry->link.tail;
- irq = tail;
- }
-
- save_state->cap_nr = PCI_CAP_ID_MSIX;
- pci_add_saved_cap(dev, save_state);
- return 0;
-}
-
-int pci_save_msi_state(struct pci_dev *dev)
-{
- int rc;
-
- rc = __pci_save_msi_state(dev);
- if (rc)
- return rc;
-
- rc = __pci_save_msix_state(dev);
-
- return rc;
}
static void __pci_restore_msix_state(struct pci_dev *dev)
{
- u16 save;
int pos;
int irq, head, tail = 0;
struct msi_desc *entry;
- struct pci_cap_saved_state *save_state;
+ u16 control;
if (!dev->msix_enabled)
return;
- save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX);
- if (!save_state)
- return;
- save = *((u16 *)&save_state->data[0]);
- pci_remove_saved_cap(save_state);
- kfree(save_state);
-
- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos <= 0)
- return;
-
/* route the table */
pci_intx(dev, 0); /* disable intx */
msix_set_enable(dev, 0);
irq = head = dev->first_msi_irq;
+ entry = get_irq_msi(irq);
+ pos = entry->msi_attrib.pos;
while (head != tail) {
entry = get_irq_msi(irq);
- write_msi_msg(irq, &entry->msg_save);
+ write_msi_msg(irq, &entry->msg);
+ msi_set_mask_bit(irq, entry->msi_attrib.masked);
tail = entry->link.tail;
irq = tail;
}
- pci_write_config_word(dev, msi_control_reg(pos), save);
+ pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
+ control &= ~PCI_MSIX_FLAGS_MASKALL;
+ control |= PCI_MSIX_FLAGS_ENABLE;
+ pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
}
void pci_restore_msi_state(struct pci_dev *dev)
@@ -420,6 +319,7 @@ static int msi_capability_init(struct pci_dev *dev)
entry->msi_attrib.is_64 = is_64bit_address(control);
entry->msi_attrib.entry_nr = 0;
entry->msi_attrib.maskbit = is_mask_bit_support(control);
+ entry->msi_attrib.masked = 1;
entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
entry->msi_attrib.pos = pos;
if (is_mask_bit_support(control)) {
@@ -507,6 +407,7 @@ static int msix_capability_init(struct pci_dev *dev,
entry->msi_attrib.is_64 = 1;
entry->msi_attrib.entry_nr = j;
entry->msi_attrib.maskbit = 1;
+ entry->msi_attrib.masked = 1;
entry->msi_attrib.default_irq = dev->irq;
entry->msi_attrib.pos = pos;
entry->dev = dev;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index df495300ce3d..d3eab057b2d3 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -551,7 +551,9 @@ static int pci_save_pcie_state(struct pci_dev *dev)
if (pos <= 0)
return 0;
- save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL);
+ save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
+ if (!save_state)
+ save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL);
if (!save_state) {
dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
return -ENOMEM;
@@ -582,8 +584,6 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]);
pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]);
pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]);
- pci_remove_saved_cap(save_state);
- kfree(save_state);
}
@@ -597,7 +597,9 @@ static int pci_save_pcix_state(struct pci_dev *dev)
if (pos <= 0)
return 0;
- save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL);
+ save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
+ if (!save_state)
+ save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL);
if (!save_state) {
dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
return -ENOMEM;
@@ -622,8 +624,6 @@ static void pci_restore_pcix_state(struct pci_dev *dev)
cap = (u16 *)&save_state->data[0];
pci_write_config_word(dev, pos + PCI_X_CMD, cap[i++]);
- pci_remove_saved_cap(save_state);
- kfree(save_state);
}
@@ -638,8 +638,6 @@ pci_save_state(struct pci_dev *dev)
/* XXX: 100% dword access ok here? */
for (i = 0; i < 16; i++)
pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]);
- if ((i = pci_save_msi_state(dev)) != 0)
- return i;
if ((i = pci_save_pcie_state(dev)) != 0)
return i;
if ((i = pci_save_pcix_state(dev)) != 0)
@@ -757,7 +755,8 @@ int pci_enable_device(struct pci_dev *dev)
* when a device is enabled using managed PCI device enable interface.
*/
struct pci_devres {
- unsigned int disable:1;
+ unsigned int enabled:1;
+ unsigned int pinned:1;
unsigned int orig_intx:1;
unsigned int restore_intx:1;
u32 region_mask;
@@ -781,7 +780,7 @@ static void pcim_release(struct device *gendev, void *res)
if (this->restore_intx)
pci_intx(dev, this->orig_intx);
- if (this->disable)
+ if (this->enabled && !this->pinned)
pci_disable_device(dev);
}
@@ -820,12 +819,12 @@ int pcim_enable_device(struct pci_dev *pdev)
dr = get_pci_dr(pdev);
if (unlikely(!dr))
return -ENOMEM;
- WARN_ON(!!dr->disable);
+ WARN_ON(!!dr->enabled);
rc = pci_enable_device(pdev);
if (!rc) {
pdev->is_managed = 1;
- dr->disable = 1;
+ dr->enabled = 1;
}
return rc;
}
@@ -843,9 +842,9 @@ void pcim_pin_device(struct pci_dev *pdev)
struct pci_devres *dr;
dr = find_pci_dr(pdev);
- WARN_ON(!dr || !dr->disable);
+ WARN_ON(!dr || !dr->enabled);
if (dr)
- dr->disable = 0;
+ dr->pinned = 1;
}
/**
@@ -876,7 +875,7 @@ pci_disable_device(struct pci_dev *dev)
dr = find_pci_dr(dev);
if (dr)
- dr->disable = 0;
+ dr->enabled = 0;
if (atomic_sub_return(1, &dev->enable_cnt) != 0)
return;
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index ae7a975995a5..62ea04c8af64 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -52,10 +52,8 @@ static inline void pci_no_msi(void) { }
#endif
#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
-int pci_save_msi_state(struct pci_dev *dev);
void pci_restore_msi_state(struct pci_dev *dev);
#else
-static inline int pci_save_msi_state(struct pci_dev *dev) { return 0; }
static inline void pci_restore_msi_state(struct pci_dev *dev) {}
#endif
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index b164de050d4f..db6ad8e763ac 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -66,7 +66,7 @@ static struct pci_error_handlers aer_error_handlers = {
.resume = aer_error_resume,
};
-static struct pcie_port_service_driver aerdrv = {
+static struct pcie_port_service_driver aerdriver = {
.name = "aer",
.id_table = &aer_id[0],
@@ -328,7 +328,7 @@ static void aer_error_resume(struct pci_dev *dev)
**/
static int __init aer_service_init(void)
{
- return pcie_port_service_register(&aerdrv);
+ return pcie_port_service_register(&aerdriver);
}
/**
@@ -338,7 +338,7 @@ static int __init aer_service_init(void)
**/
static void __exit aer_service_exit(void)
{
- pcie_port_service_unregister(&aerdrv);
+ pcie_port_service_unregister(&aerdriver);
}
module_init(aer_service_init);
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index f17e7ed2b2a5..df383645e366 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -93,7 +93,7 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
if (!dev->irq && dev->pin) {
printk(KERN_WARNING
"%s->Dev[%04x:%04x] has invalid IRQ. Check vendor BIOS\n",
- __FUNCTION__, dev->device, dev->vendor);
+ __FUNCTION__, dev->vendor, dev->device);
}
if (pcie_port_device_register(dev)) {
pci_disable_device(dev);
@@ -276,7 +276,7 @@ static struct pci_error_handlers pcie_portdrv_err_handler = {
.resume = pcie_portdrv_err_resume,
};
-static struct pci_driver pcie_portdrv = {
+static struct pci_driver pcie_portdriver = {
.name = (char *)device_name,
.id_table = &port_pci_ids[0],
@@ -298,7 +298,7 @@ static int __init pcie_portdrv_init(void)
printk(KERN_WARNING "PCIE: bus_register error: %d\n", retval);
goto out;
}
- retval = pci_register_driver(&pcie_portdrv);
+ retval = pci_register_driver(&pcie_portdriver);
if (retval)
pcie_port_bus_unregister();
out:
@@ -307,7 +307,7 @@ static int __init pcie_portdrv_init(void)
static void __exit pcie_portdrv_exit(void)
{
- pci_unregister_driver(&pcie_portdrv);
+ pci_unregister_driver(&pcie_portdriver);
pcie_port_bus_unregister();
}
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 7f94fc098cd3..65d6f23ead41 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -963,6 +963,13 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_ho
* bridge. Unfortunately, this device has no subvendor/subdevice ID. So it
* becomes necessary to do this tweak in two steps -- I've chosen the Host
* bridge as trigger.
+ *
+ * Note that we used to unhide the SMBus that way on Toshiba laptops
+ * (Satellite A40 and Tecra M2) but then found that the thermal management
+ * was done by SMM code, which could cause unsynchronized concurrent
+ * accesses to the SMBus registers, with potentially bad effects. Thus you
+ * should be very careful when adding new entries: if SMM is accessing the
+ * Intel SMBus, this is a very good reason to leave it hidden.
*/
static int asus_hides_smbus;
@@ -1040,17 +1047,6 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
case 0x099c: /* HP Compaq nx6110 */
asus_hides_smbus = 1;
}
- } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) {
- if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
- switch(dev->subsystem_device) {
- case 0x0001: /* Toshiba Satellite A40 */
- asus_hides_smbus = 1;
- }
- else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
- switch(dev->subsystem_device) {
- case 0x0001: /* Toshiba Tecra M2 */
- asus_hides_smbus = 1;
- }
} else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG)) {
if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
switch(dev->subsystem_device) {
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index ff98eaddaa73..2dd8681d6b31 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -15,7 +15,7 @@
DECLARE_RWSEM(pci_bus_sem);
-static struct pci_bus * __devinit
+static struct pci_bus *
pci_do_find_bus(struct pci_bus* bus, unsigned char busnr)
{
struct pci_bus* child;