diff options
Diffstat (limited to 'drivers/pci/pcie/aer/aerdrv.c')
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 14081f807e50..b69dbdc36817 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c | |||
@@ -72,6 +72,113 @@ void pci_no_aer(void) | |||
72 | pcie_aer_disable = 1; /* has priority over 'forceload' */ | 72 | pcie_aer_disable = 1; /* has priority over 'forceload' */ |
73 | } | 73 | } |
74 | 74 | ||
75 | static int set_device_error_reporting(struct pci_dev *dev, void *data) | ||
76 | { | ||
77 | bool enable = *((bool *)data); | ||
78 | |||
79 | if ((dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) || | ||
80 | (dev->pcie_type == PCI_EXP_TYPE_UPSTREAM) || | ||
81 | (dev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)) { | ||
82 | if (enable) | ||
83 | pci_enable_pcie_error_reporting(dev); | ||
84 | else | ||
85 | pci_disable_pcie_error_reporting(dev); | ||
86 | } | ||
87 | |||
88 | if (enable) | ||
89 | pcie_set_ecrc_checking(dev); | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * set_downstream_devices_error_reporting - enable/disable the error reporting bits on the root port and its downstream ports. | ||
96 | * @dev: pointer to root port's pci_dev data structure | ||
97 | * @enable: true = enable error reporting, false = disable error reporting. | ||
98 | */ | ||
99 | static void set_downstream_devices_error_reporting(struct pci_dev *dev, | ||
100 | bool enable) | ||
101 | { | ||
102 | set_device_error_reporting(dev, &enable); | ||
103 | |||
104 | if (!dev->subordinate) | ||
105 | return; | ||
106 | pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable); | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * aer_enable_rootport - enable Root Port's interrupts when receiving messages | ||
111 | * @rpc: pointer to a Root Port data structure | ||
112 | * | ||
113 | * Invoked when PCIe bus loads AER service driver. | ||
114 | */ | ||
115 | static void aer_enable_rootport(struct aer_rpc *rpc) | ||
116 | { | ||
117 | struct pci_dev *pdev = rpc->rpd->port; | ||
118 | int pos, aer_pos; | ||
119 | u16 reg16; | ||
120 | u32 reg32; | ||
121 | |||
122 | pos = pci_pcie_cap(pdev); | ||
123 | /* Clear PCIe Capability's Device Status */ | ||
124 | pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, ®16); | ||
125 | pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16); | ||
126 | |||
127 | /* Disable system error generation in response to error messages */ | ||
128 | pci_read_config_word(pdev, pos + PCI_EXP_RTCTL, ®16); | ||
129 | reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK); | ||
130 | pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16); | ||
131 | |||
132 | aer_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); | ||
133 | /* Clear error status */ | ||
134 | pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, ®32); | ||
135 | pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32); | ||
136 | pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, ®32); | ||
137 | pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32); | ||
138 | pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, ®32); | ||
139 | pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32); | ||
140 | |||
141 | /* | ||
142 | * Enable error reporting for the root port device and downstream port | ||
143 | * devices. | ||
144 | */ | ||
145 | set_downstream_devices_error_reporting(pdev, true); | ||
146 | |||
147 | /* Enable Root Port's interrupt in response to error messages */ | ||
148 | pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, ®32); | ||
149 | reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; | ||
150 | pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, reg32); | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * aer_disable_rootport - disable Root Port's interrupts when receiving messages | ||
155 | * @rpc: pointer to a Root Port data structure | ||
156 | * | ||
157 | * Invoked when PCIe bus unloads AER service driver. | ||
158 | */ | ||
159 | static void aer_disable_rootport(struct aer_rpc *rpc) | ||
160 | { | ||
161 | struct pci_dev *pdev = rpc->rpd->port; | ||
162 | u32 reg32; | ||
163 | int pos; | ||
164 | |||
165 | /* | ||
166 | * Disable error reporting for the root port device and downstream port | ||
167 | * devices. | ||
168 | */ | ||
169 | set_downstream_devices_error_reporting(pdev, false); | ||
170 | |||
171 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); | ||
172 | /* Disable Root's interrupt in response to error messages */ | ||
173 | pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, ®32); | ||
174 | reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; | ||
175 | pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, reg32); | ||
176 | |||
177 | /* Clear Root's error status reg */ | ||
178 | pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, ®32); | ||
179 | pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32); | ||
180 | } | ||
181 | |||
75 | /** | 182 | /** |
76 | * aer_irq - Root Port's ISR | 183 | * aer_irq - Root Port's ISR |
77 | * @irq: IRQ assigned to Root Port | 184 | * @irq: IRQ assigned to Root Port |