Skip to content

Commit

Permalink
powerpc/eeh: Global mutex to protect PE tree
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Gavin Shan authored and Benjamin Herrenschmidt committed Sep 18, 2012
1 parent 20ee6a9 commit ea81245
Showing 1 changed file with 32 additions and 7 deletions.
39 changes: 32 additions & 7 deletions arch/powerpc/platforms/pseries/eeh_pe.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,6 @@ static struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb)
{
struct eeh_pe *pe;

eeh_lock();

list_for_each_entry(pe, &eeh_phb_pe, child) {
/*
* Actually, we needn't check the type since
Expand All @@ -114,8 +112,6 @@ static struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb)
}
}

eeh_unlock();

return NULL;
}

Expand Down Expand Up @@ -192,14 +188,21 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root,
return NULL;
}

eeh_lock();

/* Traverse root PE */
for (pe = root; pe; pe = eeh_pe_next(pe, root)) {
eeh_pe_for_each_dev(pe, edev) {
ret = fn(edev, flag);
if (ret) return ret;
if (ret) {
eeh_unlock();
return ret;
}
}
}

eeh_unlock();

return NULL;
}

Expand Down Expand Up @@ -251,9 +254,7 @@ static struct eeh_pe *eeh_pe_get(struct eeh_dev *edev)
struct eeh_pe *root = eeh_phb_pe_get(edev->phb);
struct eeh_pe *pe;

eeh_lock();
pe = eeh_pe_traverse(root, __eeh_pe_get, edev);
eeh_unlock();

return pe;
}
Expand Down Expand Up @@ -307,6 +308,8 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
{
struct eeh_pe *pe, *parent;

eeh_lock();

/*
* Search the PE has been existing or not according
* to the PE address. If that has been existing, the
Expand All @@ -316,6 +319,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
pe = eeh_pe_get(edev);
if (pe && !(pe->type & EEH_PE_INVALID)) {
if (!edev->pe_config_addr) {
eeh_unlock();
pr_err("%s: PE with addr 0x%x already exists\n",
__func__, edev->config_addr);
return -EEXIST;
Expand All @@ -327,6 +331,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)

/* Put the edev to PE */
list_add_tail(&edev->list, &pe->edevs);
eeh_unlock();
pr_debug("EEH: Add %s to Bus PE#%x\n",
edev->dn->full_name, pe->addr);

Expand All @@ -345,6 +350,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
parent->type &= ~EEH_PE_INVALID;
parent = parent->parent;
}
eeh_unlock();
pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n",
edev->dn->full_name, pe->addr, pe->parent->addr);

Expand All @@ -354,6 +360,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
/* Create a new EEH PE */
pe = eeh_pe_alloc(edev->phb, EEH_PE_DEVICE);
if (!pe) {
eeh_unlock();
pr_err("%s: out of memory!\n", __func__);
return -ENOMEM;
}
Expand All @@ -370,6 +377,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
if (!parent) {
parent = eeh_phb_pe_get(edev->phb);
if (!parent) {
eeh_unlock();
pr_err("%s: No PHB PE is found (PHB Domain=%d)\n",
__func__, edev->phb->global_number);
edev->pe = NULL;
Expand All @@ -386,6 +394,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
list_add_tail(&pe->child, &parent->child_list);
list_add_tail(&edev->list, &pe->edevs);
edev->pe = pe;
eeh_unlock();
pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n",
edev->dn->full_name, pe->addr, pe->parent->addr);

Expand Down Expand Up @@ -413,6 +422,8 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe)
return -EEXIST;
}

eeh_lock();

/* Remove the EEH device */
pe = edev->pe;
edev->pe = NULL;
Expand Down Expand Up @@ -457,6 +468,8 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe)
pe = parent;
}

eeh_unlock();

return 0;
}

Expand Down Expand Up @@ -502,7 +515,9 @@ static void *__eeh_pe_state_mark(void *data, void *flag)
*/
void eeh_pe_state_mark(struct eeh_pe *pe, int state)
{
eeh_lock();
eeh_pe_traverse(pe, __eeh_pe_state_mark, &state);
eeh_unlock();
}

/**
Expand Down Expand Up @@ -536,7 +551,9 @@ static void *__eeh_pe_state_clear(void *data, void *flag)
*/
void eeh_pe_state_clear(struct eeh_pe *pe, int state)
{
eeh_lock();
eeh_pe_traverse(pe, __eeh_pe_state_clear, &state);
eeh_unlock();
}

/**
Expand Down Expand Up @@ -598,6 +615,10 @@ static void *eeh_restore_one_device_bars(void *data, void *flag)
*/
void eeh_pe_restore_bars(struct eeh_pe *pe)
{
/*
* We needn't take the EEH lock since eeh_pe_dev_traverse()
* will take that.
*/
eeh_pe_dev_traverse(pe, eeh_restore_one_device_bars, NULL);
}

Expand All @@ -617,6 +638,8 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe)
struct eeh_dev *edev;
struct pci_dev *pdev;

eeh_lock();

if (pe->type & EEH_PE_PHB) {
bus = pe->phb->bus;
} else if (pe->type & EEH_PE_BUS) {
Expand All @@ -626,5 +649,7 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe)
bus = pdev->bus;
}

eeh_unlock();

return bus;
}

0 comments on commit ea81245

Please sign in to comment.