aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pcie/aer/aerdrv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pcie/aer/aerdrv.c')
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c179
1 files changed, 133 insertions, 46 deletions
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 7a711ee314b7..484cc55194b8 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -72,13 +72,120 @@ 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
75static 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 */
99static 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 */
115static 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, &reg16);
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, &reg16);
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, &reg32);
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, &reg32);
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, &reg32);
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, &reg32);
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 */
159static 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, &reg32);
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, &reg32);
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
78 * @context: pointer to Root Port data structure 185 * @context: pointer to Root Port data structure
79 * 186 *
80 * Invoked when Root Port detects AER messages. 187 * Invoked when Root Port detects AER messages.
81 **/ 188 */
82irqreturn_t aer_irq(int irq, void *context) 189irqreturn_t aer_irq(int irq, void *context)
83{ 190{
84 unsigned int status, id; 191 unsigned int status, id;
@@ -97,13 +204,13 @@ irqreturn_t aer_irq(int irq, void *context)
97 204
98 /* Read error status */ 205 /* Read error status */
99 pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status); 206 pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status);
100 if (!(status & ROOT_ERR_STATUS_MASKS)) { 207 if (!(status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV))) {
101 spin_unlock_irqrestore(&rpc->e_lock, flags); 208 spin_unlock_irqrestore(&rpc->e_lock, flags);
102 return IRQ_NONE; 209 return IRQ_NONE;
103 } 210 }
104 211
105 /* Read error source and clear error status */ 212 /* Read error source and clear error status */
106 pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_COR_SRC, &id); 213 pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_ERR_SRC, &id);
107 pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status); 214 pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status);
108 215
109 /* Store error source for later DPC handler */ 216 /* Store error source for later DPC handler */
@@ -135,7 +242,7 @@ EXPORT_SYMBOL_GPL(aer_irq);
135 * @dev: pointer to the pcie_dev data structure 242 * @dev: pointer to the pcie_dev data structure
136 * 243 *
137 * Invoked when Root Port's AER service is loaded. 244 * Invoked when Root Port's AER service is loaded.
138 **/ 245 */
139static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) 246static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
140{ 247{
141 struct aer_rpc *rpc; 248 struct aer_rpc *rpc;
@@ -144,15 +251,11 @@ static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
144 if (!rpc) 251 if (!rpc)
145 return NULL; 252 return NULL;
146 253
147 /* 254 /* Initialize Root lock access, e_lock, to Root Error Status Reg */
148 * Initialize Root lock access, e_lock, to Root Error Status Reg,
149 * Root Error ID Reg, and Root error producer/consumer index.
150 */
151 spin_lock_init(&rpc->e_lock); 255 spin_lock_init(&rpc->e_lock);
152 256
153 rpc->rpd = dev; 257 rpc->rpd = dev;
154 INIT_WORK(&rpc->dpc_handler, aer_isr); 258 INIT_WORK(&rpc->dpc_handler, aer_isr);
155 rpc->prod_idx = rpc->cons_idx = 0;
156 mutex_init(&rpc->rpc_mutex); 259 mutex_init(&rpc->rpc_mutex);
157 init_waitqueue_head(&rpc->wait_release); 260 init_waitqueue_head(&rpc->wait_release);
158 261
@@ -167,7 +270,7 @@ static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
167 * @dev: pointer to the pcie_dev data structure 270 * @dev: pointer to the pcie_dev data structure
168 * 271 *
169 * Invoked when PCI Express bus unloads or AER probe fails. 272 * Invoked when PCI Express bus unloads or AER probe fails.
170 **/ 273 */
171static void aer_remove(struct pcie_device *dev) 274static void aer_remove(struct pcie_device *dev)
172{ 275{
173 struct aer_rpc *rpc = get_service_data(dev); 276 struct aer_rpc *rpc = get_service_data(dev);
@@ -179,7 +282,8 @@ static void aer_remove(struct pcie_device *dev)
179 282
180 wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx); 283 wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx);
181 284
182 aer_delete_rootport(rpc); 285 aer_disable_rootport(rpc);
286 kfree(rpc);
183 set_service_data(dev, NULL); 287 set_service_data(dev, NULL);
184 } 288 }
185} 289}
@@ -190,7 +294,7 @@ static void aer_remove(struct pcie_device *dev)
190 * @id: pointer to the service id data structure 294 * @id: pointer to the service id data structure
191 * 295 *
192 * Invoked when PCI Express bus loads AER service driver. 296 * Invoked when PCI Express bus loads AER service driver.
193 **/ 297 */
194static int __devinit aer_probe(struct pcie_device *dev) 298static int __devinit aer_probe(struct pcie_device *dev)
195{ 299{
196 int status; 300 int status;
@@ -230,47 +334,30 @@ static int __devinit aer_probe(struct pcie_device *dev)
230 * @dev: pointer to Root Port's pci_dev data structure 334 * @dev: pointer to Root Port's pci_dev data structure
231 * 335 *
232 * Invoked by Port Bus driver when performing link reset at Root Port. 336 * Invoked by Port Bus driver when performing link reset at Root Port.
233 **/ 337 */
234static pci_ers_result_t aer_root_reset(struct pci_dev *dev) 338static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
235{ 339{
236 u16 p2p_ctrl; 340 u32 reg32;
237 u32 status;
238 int pos; 341 int pos;
239 342
240 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); 343 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
241 344
242 /* Disable Root's interrupt in response to error messages */ 345 /* Disable Root's interrupt in response to error messages */
243 pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, 0); 346 pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
244 347 reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
245 /* Assert Secondary Bus Reset */ 348 pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
246 pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
247 p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
248 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
249
250 /*
251 * we should send hot reset message for 2ms to allow it time to
252 * propogate to all downstream ports
253 */
254 msleep(2);
255
256 /* De-assert Secondary Bus Reset */
257 p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
258 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
259 349
260 /* 350 aer_do_secondary_bus_reset(dev);
261 * System software must wait for at least 100ms from the end
262 * of a reset of one or more device before it is permitted
263 * to issue Configuration Requests to those devices.
264 */
265 msleep(200);
266 dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n"); 351 dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n");
267 352
353 /* Clear Root Error Status */
354 pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32);
355 pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, reg32);
356
268 /* Enable Root Port's interrupt in response to error messages */ 357 /* Enable Root Port's interrupt in response to error messages */
269 pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status); 358 pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
270 pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status); 359 reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
271 pci_write_config_dword(dev, 360 pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
272 pos + PCI_ERR_ROOT_COMMAND,
273 ROOT_PORT_INTR_ON_MESG_MASK);
274 361
275 return PCI_ERS_RESULT_RECOVERED; 362 return PCI_ERS_RESULT_RECOVERED;
276} 363}
@@ -281,7 +368,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
281 * @error: error severity being notified by port bus 368 * @error: error severity being notified by port bus
282 * 369 *
283 * Invoked by Port Bus driver during error recovery. 370 * Invoked by Port Bus driver during error recovery.
284 **/ 371 */
285static pci_ers_result_t aer_error_detected(struct pci_dev *dev, 372static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
286 enum pci_channel_state error) 373 enum pci_channel_state error)
287{ 374{
@@ -294,7 +381,7 @@ static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
294 * @dev: pointer to Root Port's pci_dev data structure 381 * @dev: pointer to Root Port's pci_dev data structure
295 * 382 *
296 * Invoked by Port Bus driver during nonfatal recovery. 383 * Invoked by Port Bus driver during nonfatal recovery.
297 **/ 384 */
298static void aer_error_resume(struct pci_dev *dev) 385static void aer_error_resume(struct pci_dev *dev)
299{ 386{
300 int pos; 387 int pos;
@@ -321,7 +408,7 @@ static void aer_error_resume(struct pci_dev *dev)
321 * aer_service_init - register AER root service driver 408 * aer_service_init - register AER root service driver
322 * 409 *
323 * Invoked when AER root service driver is loaded. 410 * Invoked when AER root service driver is loaded.
324 **/ 411 */
325static int __init aer_service_init(void) 412static int __init aer_service_init(void)
326{ 413{
327 if (pcie_aer_disable) 414 if (pcie_aer_disable)
@@ -335,7 +422,7 @@ static int __init aer_service_init(void)
335 * aer_service_exit - unregister AER root service driver 422 * aer_service_exit - unregister AER root service driver
336 * 423 *
337 * Invoked when AER root service driver is unloaded. 424 * Invoked when AER root service driver is unloaded.
338 **/ 425 */
339static void __exit aer_service_exit(void) 426static void __exit aer_service_exit(void)
340{ 427{
341 pcie_port_service_unregister(&aerdriver); 428 pcie_port_service_unregister(&aerdriver);