PCI/AER: Use cached AER Capability offset
[muen/linux.git] / drivers / pci / pcie / aer / ecrc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *    Enables/disables PCIe ECRC checking.
4  *
5  *    (C) Copyright 2009 Hewlett-Packard Development Company, L.P.
6  *    Andrew Patterson <andrew.patterson@hp.com>
7  */
8
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/moduleparam.h>
12 #include <linux/pci.h>
13 #include <linux/pci_regs.h>
14 #include <linux/errno.h>
15 #include "../../pci.h"
16
17 #define ECRC_POLICY_DEFAULT 0           /* ECRC set by BIOS */
18 #define ECRC_POLICY_OFF     1           /* ECRC off for performance */
19 #define ECRC_POLICY_ON      2           /* ECRC on for data integrity */
20
21 static int ecrc_policy = ECRC_POLICY_DEFAULT;
22
23 static const char *ecrc_policy_str[] = {
24         [ECRC_POLICY_DEFAULT] = "bios",
25         [ECRC_POLICY_OFF] = "off",
26         [ECRC_POLICY_ON] = "on"
27 };
28
29 /**
30  * enable_ercr_checking - enable PCIe ECRC checking for a device
31  * @dev: the PCI device
32  *
33  * Returns 0 on success, or negative on failure.
34  */
35 static int enable_ecrc_checking(struct pci_dev *dev)
36 {
37         int pos;
38         u32 reg32;
39
40         if (!pci_is_pcie(dev))
41                 return -ENODEV;
42
43         pos = dev->aer_cap;
44         if (!pos)
45                 return -ENODEV;
46
47         pci_read_config_dword(dev, pos + PCI_ERR_CAP, &reg32);
48         if (reg32 & PCI_ERR_CAP_ECRC_GENC)
49                 reg32 |= PCI_ERR_CAP_ECRC_GENE;
50         if (reg32 & PCI_ERR_CAP_ECRC_CHKC)
51                 reg32 |= PCI_ERR_CAP_ECRC_CHKE;
52         pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
53
54         return 0;
55 }
56
57 /**
58  * disable_ercr_checking - disables PCIe ECRC checking for a device
59  * @dev: the PCI device
60  *
61  * Returns 0 on success, or negative on failure.
62  */
63 static int disable_ecrc_checking(struct pci_dev *dev)
64 {
65         int pos;
66         u32 reg32;
67
68         if (!pci_is_pcie(dev))
69                 return -ENODEV;
70
71         pos = dev->aer_cap;
72         if (!pos)
73                 return -ENODEV;
74
75         pci_read_config_dword(dev, pos + PCI_ERR_CAP, &reg32);
76         reg32 &= ~(PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE);
77         pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
78
79         return 0;
80 }
81
82 /**
83  * pcie_set_ecrc_checking - set/unset PCIe ECRC checking for a device based on global policy
84  * @dev: the PCI device
85  */
86 void pcie_set_ecrc_checking(struct pci_dev *dev)
87 {
88         switch (ecrc_policy) {
89         case ECRC_POLICY_DEFAULT:
90                 return;
91         case ECRC_POLICY_OFF:
92                 disable_ecrc_checking(dev);
93                 break;
94         case ECRC_POLICY_ON:
95                 enable_ecrc_checking(dev);
96                 break;
97         default:
98                 return;
99         }
100 }
101
102 /**
103  * pcie_ecrc_get_policy - parse kernel command-line ecrc option
104  */
105 void pcie_ecrc_get_policy(char *str)
106 {
107         int i;
108
109         for (i = 0; i < ARRAY_SIZE(ecrc_policy_str); i++)
110                 if (!strncmp(str, ecrc_policy_str[i],
111                              strlen(ecrc_policy_str[i])))
112                         break;
113         if (i >= ARRAY_SIZE(ecrc_policy_str))
114                 return;
115
116         ecrc_policy = i;
117 }