aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
authorGavin Shan <shangw@linux.vnet.ibm.com>2012-09-11 15:16:18 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-09-18 01:32:33 -0400
commitea81245cf4dab5ef5428102a4a00281ed6e890a6 (patch)
treeeb75479f80d1f24014f8b6f624e35f9e89d59067 /arch/powerpc/platforms
parent20ee6a970858a0f5711ea32cb7f855a81704cb53 (diff)
powerpc/eeh: Global mutex to protect PE tree
We have missed lots of situations where the PE hierarchy tree need protection through the EEH global mutex. The patch fixes that for those public APIs implemented in eeh_pe.c. The only exception is eeh_pe_restore_bars() because it calls eeh_pe_dev_traverse(), which has been protected by the mutex. Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pe.c39
1 files changed, 32 insertions, 7 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh_pe.c b/arch/powerpc/platforms/pseries/eeh_pe.c
index 30b8d96ed54d..9d35543736ed 100644
--- a/arch/powerpc/platforms/pseries/eeh_pe.c
+++ b/arch/powerpc/platforms/pseries/eeh_pe.c
@@ -99,8 +99,6 @@ static struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb)
99{ 99{
100 struct eeh_pe *pe; 100 struct eeh_pe *pe;
101 101
102 eeh_lock();
103
104 list_for_each_entry(pe, &eeh_phb_pe, child) { 102 list_for_each_entry(pe, &eeh_phb_pe, child) {
105 /* 103 /*
106 * Actually, we needn't check the type since 104 * Actually, we needn't check the type since
@@ -114,8 +112,6 @@ static struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb)
114 } 112 }
115 } 113 }
116 114
117 eeh_unlock();
118
119 return NULL; 115 return NULL;
120} 116}
121 117
@@ -192,14 +188,21 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root,
192 return NULL; 188 return NULL;
193 } 189 }
194 190
191 eeh_lock();
192
195 /* Traverse root PE */ 193 /* Traverse root PE */
196 for (pe = root; pe; pe = eeh_pe_next(pe, root)) { 194 for (pe = root; pe; pe = eeh_pe_next(pe, root)) {
197 eeh_pe_for_each_dev(pe, edev) { 195 eeh_pe_for_each_dev(pe, edev) {
198 ret = fn(edev, flag); 196 ret = fn(edev, flag);
199 if (ret) return ret; 197 if (ret) {
198 eeh_unlock();
199 return ret;
200 }
200 } 201 }
201 } 202 }
202 203
204 eeh_unlock();
205
203 return NULL; 206 return NULL;
204} 207}
205 208
@@ -251,9 +254,7 @@ static struct eeh_pe *eeh_pe_get(struct eeh_dev *edev)
251 struct eeh_pe *root = eeh_phb_pe_get(edev->phb); 254 struct eeh_pe *root = eeh_phb_pe_get(edev->phb);
252 struct eeh_pe *pe; 255 struct eeh_pe *pe;
253 256
254 eeh_lock();
255 pe = eeh_pe_traverse(root, __eeh_pe_get, edev); 257 pe = eeh_pe_traverse(root, __eeh_pe_get, edev);
256 eeh_unlock();
257 258
258 return pe; 259 return pe;
259} 260}
@@ -307,6 +308,8 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
307{ 308{
308 struct eeh_pe *pe, *parent; 309 struct eeh_pe *pe, *parent;
309 310
311 eeh_lock();
312
310 /* 313 /*
311 * Search the PE has been existing or not according 314 * Search the PE has been existing or not according
312 * to the PE address. If that has been existing, the 315 * to the PE address. If that has been existing, the
@@ -316,6 +319,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
316 pe = eeh_pe_get(edev); 319 pe = eeh_pe_get(edev);
317 if (pe && !(pe->type & EEH_PE_INVALID)) { 320 if (pe && !(pe->type & EEH_PE_INVALID)) {
318 if (!edev->pe_config_addr) { 321 if (!edev->pe_config_addr) {
322 eeh_unlock();
319 pr_err("%s: PE with addr 0x%x already exists\n", 323 pr_err("%s: PE with addr 0x%x already exists\n",
320 __func__, edev->config_addr); 324 __func__, edev->config_addr);
321 return -EEXIST; 325 return -EEXIST;
@@ -327,6 +331,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
327 331
328 /* Put the edev to PE */ 332 /* Put the edev to PE */
329 list_add_tail(&edev->list, &pe->edevs); 333 list_add_tail(&edev->list, &pe->edevs);
334 eeh_unlock();
330 pr_debug("EEH: Add %s to Bus PE#%x\n", 335 pr_debug("EEH: Add %s to Bus PE#%x\n",
331 edev->dn->full_name, pe->addr); 336 edev->dn->full_name, pe->addr);
332 337
@@ -345,6 +350,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
345 parent->type &= ~EEH_PE_INVALID; 350 parent->type &= ~EEH_PE_INVALID;
346 parent = parent->parent; 351 parent = parent->parent;
347 } 352 }
353 eeh_unlock();
348 pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n", 354 pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n",
349 edev->dn->full_name, pe->addr, pe->parent->addr); 355 edev->dn->full_name, pe->addr, pe->parent->addr);
350 356
@@ -354,6 +360,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
354 /* Create a new EEH PE */ 360 /* Create a new EEH PE */
355 pe = eeh_pe_alloc(edev->phb, EEH_PE_DEVICE); 361 pe = eeh_pe_alloc(edev->phb, EEH_PE_DEVICE);
356 if (!pe) { 362 if (!pe) {
363 eeh_unlock();
357 pr_err("%s: out of memory!\n", __func__); 364 pr_err("%s: out of memory!\n", __func__);
358 return -ENOMEM; 365 return -ENOMEM;
359 } 366 }
@@ -370,6 +377,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
370 if (!parent) { 377 if (!parent) {
371 parent = eeh_phb_pe_get(edev->phb); 378 parent = eeh_phb_pe_get(edev->phb);
372 if (!parent) { 379 if (!parent) {
380 eeh_unlock();
373 pr_err("%s: No PHB PE is found (PHB Domain=%d)\n", 381 pr_err("%s: No PHB PE is found (PHB Domain=%d)\n",
374 __func__, edev->phb->global_number); 382 __func__, edev->phb->global_number);
375 edev->pe = NULL; 383 edev->pe = NULL;
@@ -386,6 +394,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
386 list_add_tail(&pe->child, &parent->child_list); 394 list_add_tail(&pe->child, &parent->child_list);
387 list_add_tail(&edev->list, &pe->edevs); 395 list_add_tail(&edev->list, &pe->edevs);
388 edev->pe = pe; 396 edev->pe = pe;
397 eeh_unlock();
389 pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n", 398 pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n",
390 edev->dn->full_name, pe->addr, pe->parent->addr); 399 edev->dn->full_name, pe->addr, pe->parent->addr);
391 400
@@ -413,6 +422,8 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe)
413 return -EEXIST; 422 return -EEXIST;
414 } 423 }
415 424
425 eeh_lock();
426
416 /* Remove the EEH device */ 427 /* Remove the EEH device */
417 pe = edev->pe; 428 pe = edev->pe;
418 edev->pe = NULL; 429 edev->pe = NULL;
@@ -457,6 +468,8 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe)
457 pe = parent; 468 pe = parent;
458 } 469 }
459 470
471 eeh_unlock();
472
460 return 0; 473 return 0;
461} 474}
462 475
@@ -502,7 +515,9 @@ static void *__eeh_pe_state_mark(void *data, void *flag)
502 */ 515 */
503void eeh_pe_state_mark(struct eeh_pe *pe, int state) 516void eeh_pe_state_mark(struct eeh_pe *pe, int state)
504{ 517{
518 eeh_lock();
505 eeh_pe_traverse(pe, __eeh_pe_state_mark, &state); 519 eeh_pe_traverse(pe, __eeh_pe_state_mark, &state);
520 eeh_unlock();
506} 521}
507 522
508/** 523/**
@@ -536,7 +551,9 @@ static void *__eeh_pe_state_clear(void *data, void *flag)
536 */ 551 */
537void eeh_pe_state_clear(struct eeh_pe *pe, int state) 552void eeh_pe_state_clear(struct eeh_pe *pe, int state)
538{ 553{
554 eeh_lock();
539 eeh_pe_traverse(pe, __eeh_pe_state_clear, &state); 555 eeh_pe_traverse(pe, __eeh_pe_state_clear, &state);
556 eeh_unlock();
540} 557}
541 558
542/** 559/**
@@ -598,6 +615,10 @@ static void *eeh_restore_one_device_bars(void *data, void *flag)
598 */ 615 */
599void eeh_pe_restore_bars(struct eeh_pe *pe) 616void eeh_pe_restore_bars(struct eeh_pe *pe)
600{ 617{
618 /*
619 * We needn't take the EEH lock since eeh_pe_dev_traverse()
620 * will take that.
621 */
601 eeh_pe_dev_traverse(pe, eeh_restore_one_device_bars, NULL); 622 eeh_pe_dev_traverse(pe, eeh_restore_one_device_bars, NULL);
602} 623}
603 624
@@ -617,6 +638,8 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe)
617 struct eeh_dev *edev; 638 struct eeh_dev *edev;
618 struct pci_dev *pdev; 639 struct pci_dev *pdev;
619 640
641 eeh_lock();
642
620 if (pe->type & EEH_PE_PHB) { 643 if (pe->type & EEH_PE_PHB) {
621 bus = pe->phb->bus; 644 bus = pe->phb->bus;
622 } else if (pe->type & EEH_PE_BUS) { 645 } else if (pe->type & EEH_PE_BUS) {
@@ -626,5 +649,7 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe)
626 bus = pdev->bus; 649 bus = pdev->bus;
627 } 650 }
628 651
652 eeh_unlock();
653
629 return bus; 654 return bus;
630} 655}