aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2008-12-07 16:02:58 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-01-07 14:12:40 -0500
commit63f4898ace2788a89ed685672aab092e1c3e50e6 (patch)
treeed57eeeb486466697c3d97feaf34396dd2a2b992 /drivers
parent894886e5d3de0bde2eded8a39bf7e76023fbd791 (diff)
PCI: handle PCI state saving with interrupts disabled
Since interrupts will soon be disabled at PCI resume time, we need to pre-allocate memory to save/restore PCI config space (or use GFP_ATOMIC, but this is safer). Reported-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: "Rafael J. Wysocki" <rjw@sisk.pl> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/pci.c73
-rw-r--r--drivers/pci/pci.h1
-rw-r--r--drivers/pci/probe.c3
3 files changed, 55 insertions, 22 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 47663dc0daf7..3222f9022707 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -640,19 +640,14 @@ static int pci_save_pcie_state(struct pci_dev *dev)
640 int pos, i = 0; 640 int pos, i = 0;
641 struct pci_cap_saved_state *save_state; 641 struct pci_cap_saved_state *save_state;
642 u16 *cap; 642 u16 *cap;
643 int found = 0;
644 643
645 pos = pci_find_capability(dev, PCI_CAP_ID_EXP); 644 pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
646 if (pos <= 0) 645 if (pos <= 0)
647 return 0; 646 return 0;
648 647
649 save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); 648 save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
650 if (!save_state)
651 save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL);
652 else
653 found = 1;
654 if (!save_state) { 649 if (!save_state) {
655 dev_err(&dev->dev, "out of memory in pci_save_pcie_state\n"); 650 dev_err(&dev->dev, "buffer not found in %s\n", __FUNCTION__);
656 return -ENOMEM; 651 return -ENOMEM;
657 } 652 }
658 cap = (u16 *)&save_state->data[0]; 653 cap = (u16 *)&save_state->data[0];
@@ -661,9 +656,7 @@ static int pci_save_pcie_state(struct pci_dev *dev)
661 pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]); 656 pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]);
662 pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]); 657 pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
663 pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]); 658 pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
664 save_state->cap_nr = PCI_CAP_ID_EXP; 659
665 if (!found)
666 pci_add_saved_cap(dev, save_state);
667 return 0; 660 return 0;
668} 661}
669 662
@@ -688,30 +681,21 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
688 681
689static int pci_save_pcix_state(struct pci_dev *dev) 682static int pci_save_pcix_state(struct pci_dev *dev)
690{ 683{
691 int pos, i = 0; 684 int pos;
692 struct pci_cap_saved_state *save_state; 685 struct pci_cap_saved_state *save_state;
693 u16 *cap;
694 int found = 0;
695 686
696 pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); 687 pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
697 if (pos <= 0) 688 if (pos <= 0)
698 return 0; 689 return 0;
699 690
700 save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX); 691 save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
701 if (!save_state)
702 save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL);
703 else
704 found = 1;
705 if (!save_state) { 692 if (!save_state) {
706 dev_err(&dev->dev, "out of memory in pci_save_pcie_state\n"); 693 dev_err(&dev->dev, "buffer not found in %s\n", __FUNCTION__);
707 return -ENOMEM; 694 return -ENOMEM;
708 } 695 }
709 cap = (u16 *)&save_state->data[0];
710 696
711 pci_read_config_word(dev, pos + PCI_X_CMD, &cap[i++]); 697 pci_read_config_word(dev, pos + PCI_X_CMD, (u16 *)save_state->data);
712 save_state->cap_nr = PCI_CAP_ID_PCIX; 698
713 if (!found)
714 pci_add_saved_cap(dev, save_state);
715 return 0; 699 return 0;
716} 700}
717 701
@@ -1301,6 +1285,51 @@ void pci_pm_init(struct pci_dev *dev)
1301} 1285}
1302 1286
1303/** 1287/**
1288 * pci_add_save_buffer - allocate buffer for saving given capability registers
1289 * @dev: the PCI device
1290 * @cap: the capability to allocate the buffer for
1291 * @size: requested size of the buffer
1292 */
1293static int pci_add_cap_save_buffer(
1294 struct pci_dev *dev, char cap, unsigned int size)
1295{
1296 int pos;
1297 struct pci_cap_saved_state *save_state;
1298
1299 pos = pci_find_capability(dev, cap);
1300 if (pos <= 0)
1301 return 0;
1302
1303 save_state = kzalloc(sizeof(*save_state) + size, GFP_KERNEL);
1304 if (!save_state)
1305 return -ENOMEM;
1306
1307 save_state->cap_nr = cap;
1308 pci_add_saved_cap(dev, save_state);
1309
1310 return 0;
1311}
1312
1313/**
1314 * pci_allocate_cap_save_buffers - allocate buffers for saving capabilities
1315 * @dev: the PCI device
1316 */
1317void pci_allocate_cap_save_buffers(struct pci_dev *dev)
1318{
1319 int error;
1320
1321 error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_EXP, 4 * sizeof(u16));
1322 if (error)
1323 dev_err(&dev->dev,
1324 "unable to preallocate PCI Express save buffer\n");
1325
1326 error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_PCIX, sizeof(u16));
1327 if (error)
1328 dev_err(&dev->dev,
1329 "unable to preallocate PCI-X save buffer\n");
1330}
1331
1332/**
1304 * pci_enable_ari - enable ARI forwarding if hardware support it 1333 * pci_enable_ari - enable ARI forwarding if hardware support it
1305 * @dev: the PCI device 1334 * @dev: the PCI device
1306 */ 1335 */
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 9162e242b99e..7242b511a93f 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -45,6 +45,7 @@ struct pci_platform_pm_ops {
45 45
46extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops); 46extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
47extern void pci_pm_init(struct pci_dev *dev); 47extern void pci_pm_init(struct pci_dev *dev);
48extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
48 49
49extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); 50extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
50extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); 51extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index eb2b985beb48..5dcf2b65e3f9 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -958,6 +958,9 @@ static void pci_init_capabilities(struct pci_dev *dev)
958 /* MSI/MSI-X list */ 958 /* MSI/MSI-X list */
959 pci_msi_init_pci_dev(dev); 959 pci_msi_init_pci_dev(dev);
960 960
961 /* Buffers for saving PCIe and PCI-X capabilities */
962 pci_allocate_cap_save_buffers(dev);
963
961 /* Power Management */ 964 /* Power Management */
962 pci_pm_init(dev); 965 pci_pm_init(dev);
963 966