diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/eeh_pe.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_pe.c | 39 |
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 | */ |
503 | void eeh_pe_state_mark(struct eeh_pe *pe, int state) | 516 | void 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 | */ |
537 | void eeh_pe_state_clear(struct eeh_pe *pe, int state) | 552 | void 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 | */ |
599 | void eeh_pe_restore_bars(struct eeh_pe *pe) | 616 | void 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 | } |