aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Patterson <andrew.patterson@hp.com>2009-04-22 18:52:09 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-06-11 15:04:21 -0400
commit43c16408842b0eeb367c23a6fa540ce69f99e347 (patch)
tree25be054b280b430b8bb00ff5f9c1f422bc21a3a0
parentf62795f1e892ca9269849fa83de97621da7e02c0 (diff)
PCI: Add support for turning PCIe ECRC on or off
Adds support for PCI Express transaction layer end-to-end CRC checking (ECRC). This patch will enable/disable ECRC checking by setting/clearing the ECRC Check Enable and/or ECRC Generation Enable bits for devices that support ECRC. The ECRC setting is controlled by the "pci=ecrc=<policy>" command-line option. If this option is not set or is set to 'bios", the enable and generation bits are left in whatever state that firmware/BIOS set them to. The "off" setting turns them off, and the "on" option turns them on (if the device supports it). Turning ECRC on or off can be a data integrity versus performance tradeoff. In theory, turning it on will catch more data errors, turning it off means possibly better performance since CRC does not need to be calculated by the PCIe hardware and packet sizes are reduced. Signed-off-by: Andrew Patterson <andrew.patterson@hp.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-rw-r--r--Documentation/kernel-parameters.txt6
-rw-r--r--drivers/pci/pci.c2
-rw-r--r--drivers/pci/pcie/aer/Kconfig13
-rw-r--r--drivers/pci/pcie/aer/Makefile2
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c16
-rw-r--r--drivers/pci/pcie/aer/ecrc.c131
-rw-r--r--include/linux/pci.h11
7 files changed, 174 insertions, 7 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 7bdaf5080408..395d1a013ebb 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1824,6 +1824,12 @@ and is between 256 and 4096 characters. It is defined in the file
1824 PAGE_SIZE is used as alignment. 1824 PAGE_SIZE is used as alignment.
1825 PCI-PCI bridge can be specified, if resource 1825 PCI-PCI bridge can be specified, if resource
1826 windows need to be expanded. 1826 windows need to be expanded.
1827 ecrc= Enable/disable PCIe ECRC (transaction layer
1828 end-to-end CRC checking).
1829 bios: Use BIOS/firmware settings. This is the
1830 the default.
1831 off: Turn ECRC off
1832 on: Turn ECRC on.
1827 1833
1828 pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power 1834 pcie_aspm= [PCIE] Forcibly enable or disable PCIe Active State Power
1829 Management. 1835 Management.
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 761557688b18..56fb18d2cb52 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2588,6 +2588,8 @@ static int __init pci_setup(char *str)
2588 } else if (!strncmp(str, "resource_alignment=", 19)) { 2588 } else if (!strncmp(str, "resource_alignment=", 19)) {
2589 pci_set_resource_alignment_param(str + 19, 2589 pci_set_resource_alignment_param(str + 19,
2590 strlen(str + 19)); 2590 strlen(str + 19));
2591 } else if (!strncmp(str, "ecrc=", 5)) {
2592 pcie_ecrc_get_policy(str + 5);
2591 } else { 2593 } else {
2592 printk(KERN_ERR "PCI: Unknown option `%s'\n", 2594 printk(KERN_ERR "PCI: Unknown option `%s'\n",
2593 str); 2595 str);
diff --git a/drivers/pci/pcie/aer/Kconfig b/drivers/pci/pcie/aer/Kconfig
index c3bde588aa13..db4cb950933a 100644
--- a/drivers/pci/pcie/aer/Kconfig
+++ b/drivers/pci/pcie/aer/Kconfig
@@ -10,3 +10,16 @@ config PCIEAER
10 This enables PCI Express Root Port Advanced Error Reporting 10 This enables PCI Express Root Port Advanced Error Reporting
11 (AER) driver support. Error reporting messages sent to Root 11 (AER) driver support. Error reporting messages sent to Root
12 Port will be handled by PCI Express AER driver. 12 Port will be handled by PCI Express AER driver.
13
14
15#
16# PCI Express ECRC
17#
18config PCIE_ECRC
19 bool "PCI Express ECRC settings control"
20 depends on PCIEAER
21 help
22 Used to override firmware/bios settings for PCI Express ECRC
23 (transaction layer end-to-end CRC checking).
24
25 When in doubt, say N.
diff --git a/drivers/pci/pcie/aer/Makefile b/drivers/pci/pcie/aer/Makefile
index 8da3bd8455a8..7f93411c56e5 100644
--- a/drivers/pci/pcie/aer/Makefile
+++ b/drivers/pci/pcie/aer/Makefile
@@ -4,6 +4,8 @@
4 4
5obj-$(CONFIG_PCIEAER) += aerdriver.o 5obj-$(CONFIG_PCIEAER) += aerdriver.o
6 6
7obj-$(CONFIG_PCIE_ECRC) += ecrc.o
8
7aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o 9aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o
8aerdriver-$(CONFIG_ACPI) += aerdrv_acpi.o 10aerdriver-$(CONFIG_ACPI) += aerdrv_acpi.o
9 11
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index 307452f30035..dd3829e68e3f 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -113,15 +113,17 @@ static void set_device_error_reporting(struct pci_dev *dev, void *data)
113{ 113{
114 bool enable = *((bool *)data); 114 bool enable = *((bool *)data);
115 115
116 if (dev->pcie_type != PCIE_RC_PORT && 116 if (dev->pcie_type == PCIE_RC_PORT ||
117 dev->pcie_type != PCIE_SW_UPSTREAM_PORT && 117 dev->pcie_type == PCIE_SW_UPSTREAM_PORT ||
118 dev->pcie_type != PCIE_SW_DOWNSTREAM_PORT) 118 dev->pcie_type == PCIE_SW_DOWNSTREAM_PORT) {
119 return; 119 if (enable)
120 pci_enable_pcie_error_reporting(dev);
121 else
122 pci_disable_pcie_error_reporting(dev);
123 }
120 124
121 if (enable) 125 if (enable)
122 pci_enable_pcie_error_reporting(dev); 126 pcie_set_ecrc_checking(dev);
123 else
124 pci_disable_pcie_error_reporting(dev);
125} 127}
126 128
127/** 129/**
diff --git a/drivers/pci/pcie/aer/ecrc.c b/drivers/pci/pcie/aer/ecrc.c
new file mode 100644
index 000000000000..ece97df4df6d
--- /dev/null
+++ b/drivers/pci/pcie/aer/ecrc.c
@@ -0,0 +1,131 @@
1/*
2 * Enables/disables PCIe ECRC checking.
3 *
4 * (C) Copyright 2009 Hewlett-Packard Development Company, L.P.
5 * Andrew Patterson <andrew.patterson@hp.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307, USA.
20 *
21 */
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/moduleparam.h>
26#include <linux/pci.h>
27#include <linux/pci_regs.h>
28#include <linux/errno.h>
29#include "../../pci.h"
30
31#define ECRC_POLICY_DEFAULT 0 /* ECRC set by BIOS */
32#define ECRC_POLICY_OFF 1 /* ECRC off for performance */
33#define ECRC_POLICY_ON 2 /* ECRC on for data integrity */
34
35static int ecrc_policy = ECRC_POLICY_DEFAULT;
36
37static const char *ecrc_policy_str[] = {
38 [ECRC_POLICY_DEFAULT] = "bios",
39 [ECRC_POLICY_OFF] = "off",
40 [ECRC_POLICY_ON] = "on"
41};
42
43/**
44 * enable_ercr_checking - enable PCIe ECRC checking for a device
45 * @dev: the PCI device
46 *
47 * Returns 0 on success, or negative on failure.
48 */
49static int enable_ecrc_checking(struct pci_dev *dev)
50{
51 int pos;
52 u32 reg32;
53
54 if (!dev->is_pcie)
55 return -ENODEV;
56
57 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
58 if (!pos)
59 return -ENODEV;
60
61 pci_read_config_dword(dev, pos + PCI_ERR_CAP, &reg32);
62 if (reg32 & PCI_ERR_CAP_ECRC_GENC)
63 reg32 |= PCI_ERR_CAP_ECRC_GENE;
64 if (reg32 & PCI_ERR_CAP_ECRC_CHKC)
65 reg32 |= PCI_ERR_CAP_ECRC_CHKE;
66 pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
67
68 return 0;
69}
70
71/**
72 * disable_ercr_checking - disables PCIe ECRC checking for a device
73 * @dev: the PCI device
74 *
75 * Returns 0 on success, or negative on failure.
76 */
77static int disable_ecrc_checking(struct pci_dev *dev)
78{
79 int pos;
80 u32 reg32;
81
82 if (!dev->is_pcie)
83 return -ENODEV;
84
85 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
86 if (!pos)
87 return -ENODEV;
88
89 pci_read_config_dword(dev, pos + PCI_ERR_CAP, &reg32);
90 reg32 &= ~(PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
91 pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
92
93 return 0;
94}
95
96/**
97 * pcie_set_ecrc_checking - set/unset PCIe ECRC checking for a device based on global policy
98 * @dev: the PCI device
99 */
100void pcie_set_ecrc_checking(struct pci_dev *dev)
101{
102 switch (ecrc_policy) {
103 case ECRC_POLICY_DEFAULT:
104 return;
105 case ECRC_POLICY_OFF:
106 disable_ecrc_checking(dev);
107 break;
108 case ECRC_POLICY_ON:
109 enable_ecrc_checking(dev);;
110 break;
111 default:
112 return;
113 }
114}
115
116/**
117 * pcie_ecrc_get_policy - parse kernel command-line ecrc option
118 */
119void pcie_ecrc_get_policy(char *str)
120{
121 int i;
122
123 for (i = 0; i < ARRAY_SIZE(ecrc_policy_str); i++)
124 if (!strncmp(str, ecrc_policy_str[i],
125 strlen(ecrc_policy_str[i])))
126 break;
127 if (i >= ARRAY_SIZE(ecrc_policy_str))
128 return;
129
130 ecrc_policy = i;
131}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 19ee92c53ef7..ec03b90d3510 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -878,6 +878,17 @@ static inline int pcie_aspm_enabled(void)
878extern int pcie_aspm_enabled(void); 878extern int pcie_aspm_enabled(void);
879#endif 879#endif
880 880
881#ifndef CONFIG_PCIE_ECRC
882static inline void pcie_set_ecrc_checking(struct pci_dev *dev)
883{
884 return;
885}
886static inline void pcie_ecrc_get_policy(char *str) {};
887#else
888extern void pcie_set_ecrc_checking(struct pci_dev *dev);
889extern void pcie_ecrc_get_policy(char *str);
890#endif
891
881#define pci_enable_msi(pdev) pci_enable_msi_block(pdev, 1) 892#define pci_enable_msi(pdev) pci_enable_msi_block(pdev, 1)
882 893
883#ifdef CONFIG_HT_IRQ 894#ifdef CONFIG_HT_IRQ