powerpc/powernv: Use dev-node in PCI config accessors

Currently, we're using the combo (PCI bus + devfn) in the PCI
config accessors and PCI config accessors in EEH depends on them.
However, it's not safe to refer the PCI bus which might have been
removed during hotplug. So we're using device node in the PCI
config accessors and the corresponding backends just reuse them.

The patch also fix one potential risk: We possiblly have frozen
PE during the early PCI probe time, but we haven't setup the PE
mapping yet. So the errors should be counted to PE#0.

Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
Gavin Shan 2013-06-27 13:46:48 +08:00 committed by Benjamin Herrenschmidt
parent eeb6361fdd
commit 9bf41be673
3 changed files with 79 additions and 89 deletions

View file

@ -314,46 +314,6 @@ static int powernv_eeh_configure_bridge(struct eeh_pe *pe)
return ret;
}
/**
* powernv_eeh_read_config - Read PCI config space
* @dn: device node
* @where: PCI address
* @size: size to read
* @val: return value
*
* Read config space from the speicifed device
*/
static int powernv_eeh_read_config(struct device_node *dn, int where,
int size, u32 *val)
{
struct eeh_dev *edev = of_node_to_eeh_dev(dn);
struct pci_dev *dev = eeh_dev_to_pci_dev(edev);
struct pci_controller *hose = edev->phb;
return hose->ops->read(dev->bus, dev->devfn, where, size, val);
}
/**
* powernv_eeh_write_config - Write PCI config space
* @dn: device node
* @where: PCI address
* @size: size to write
* @val: value to be written
*
* Write config space to the specified device
*/
static int powernv_eeh_write_config(struct device_node *dn, int where,
int size, u32 val)
{
struct eeh_dev *edev = of_node_to_eeh_dev(dn);
struct pci_dev *dev = eeh_dev_to_pci_dev(edev);
struct pci_controller *hose = edev->phb;
hose = pci_bus_to_host(dev->bus);
return hose->ops->write(dev->bus, dev->devfn, where, size, val);
}
/**
* powernv_eeh_next_error - Retrieve next EEH error to handle
* @pe: Affected PE
@ -389,8 +349,8 @@ static struct eeh_ops powernv_eeh_ops = {
.wait_state = powernv_eeh_wait_state,
.get_log = powernv_eeh_get_log,
.configure_bridge = powernv_eeh_configure_bridge,
.read_config = powernv_eeh_read_config,
.write_config = powernv_eeh_write_config,
.read_config = pnv_pci_cfg_read,
.write_config = pnv_pci_cfg_write,
.next_error = powernv_eeh_next_error
};

View file

@ -231,47 +231,50 @@ static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no)
spin_unlock_irqrestore(&phb->lock, flags);
}
static void pnv_pci_config_check_eeh(struct pnv_phb *phb, struct pci_bus *bus,
u32 bdfn)
static void pnv_pci_config_check_eeh(struct pnv_phb *phb,
struct device_node *dn)
{
s64 rc;
u8 fstate;
u16 pcierr;
u32 pe_no;
/* Get PE# if we support IODA */
pe_no = phb->bdfn_to_pe ? phb->bdfn_to_pe(phb, bus, bdfn & 0xff) : 0;
/*
* Get the PE#. During the PCI probe stage, we might not
* setup that yet. So all ER errors should be mapped to
* PE#0
*/
pe_no = PCI_DN(dn)->pe_number;
if (pe_no == IODA_INVALID_PE)
pe_no = 0;
/* Read freeze status */
rc = opal_pci_eeh_freeze_status(phb->opal_id, pe_no, &fstate, &pcierr,
NULL);
if (rc) {
pr_warning("PCI %d: Failed to read EEH status for PE#%d,"
" err %lld\n", phb->hose->global_number, pe_no, rc);
pr_warning("%s: Can't read EEH status (PE#%d) for "
"%s, err %lld\n",
__func__, pe_no, dn->full_name, rc);
return;
}
cfg_dbg(" -> EEH check, bdfn=%04x PE%d fstate=%x\n",
bdfn, pe_no, fstate);
cfg_dbg(" -> EEH check, bdfn=%04x PE#%d fstate=%x\n",
(PCI_DN(dn)->busno << 8) | (PCI_DN(dn)->devfn),
pe_no, fstate);
if (fstate != 0)
pnv_pci_handle_eeh_config(phb, pe_no);
}
static int pnv_pci_read_config(struct pci_bus *bus,
unsigned int devfn,
int where, int size, u32 *val)
int pnv_pci_cfg_read(struct device_node *dn,
int where, int size, u32 *val)
{
struct pci_controller *hose = pci_bus_to_host(bus);
struct pnv_phb *phb = hose->private_data;
struct pci_dn *pdn = PCI_DN(dn);
struct pnv_phb *phb = pdn->phb->private_data;
u32 bdfn = (pdn->busno << 8) | pdn->devfn;
#ifdef CONFIG_EEH
struct device_node *busdn, *dn;
struct eeh_pe *phb_pe = NULL;
#endif
u32 bdfn = (((uint64_t)bus->number) << 8) | devfn;
s64 rc;
if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
switch (size) {
case 1: {
u8 v8;
@ -295,8 +298,8 @@ static int pnv_pci_read_config(struct pci_bus *bus,
default:
return PCIBIOS_FUNC_NOT_SUPPORTED;
}
cfg_dbg("pnv_pci_read_config bus: %x devfn: %x +%x/%x -> %08x\n",
bus->number, devfn, where, size, *val);
cfg_dbg("%s: bus: %x devfn: %x +%x/%x -> %08x\n",
__func__, pdn->busno, pdn->devfn, where, size, *val);
/*
* Check if the specified PE has been put into frozen
@ -305,44 +308,33 @@ static int pnv_pci_read_config(struct pci_bus *bus,
* PHB-fatal errors.
*/
#ifdef CONFIG_EEH
phb_pe = eeh_phb_pe_get(hose);
phb_pe = eeh_phb_pe_get(pdn->phb);
if (phb_pe && (phb_pe->state & EEH_PE_ISOLATED))
return PCIBIOS_SUCCESSFUL;
if (phb->eeh_state & PNV_EEH_STATE_ENABLED) {
if (*val == EEH_IO_ERROR_VALUE(size)) {
busdn = pci_bus_to_OF_node(bus);
for (dn = busdn->child; dn; dn = dn->sibling) {
struct pci_dn *pdn = PCI_DN(dn);
if (pdn && pdn->devfn == devfn &&
eeh_dev_check_failure(of_node_to_eeh_dev(dn)))
return PCIBIOS_DEVICE_NOT_FOUND;
}
}
if (*val == EEH_IO_ERROR_VALUE(size) &&
eeh_dev_check_failure(of_node_to_eeh_dev(dn)))
return PCIBIOS_DEVICE_NOT_FOUND;
} else {
pnv_pci_config_check_eeh(phb, bus, bdfn);
pnv_pci_config_check_eeh(phb, dn);
}
#else
pnv_pci_config_check_eeh(phb, bus, bdfn);
pnv_pci_config_check_eeh(phb, dn);
#endif
return PCIBIOS_SUCCESSFUL;
}
static int pnv_pci_write_config(struct pci_bus *bus,
unsigned int devfn,
int where, int size, u32 val)
int pnv_pci_cfg_write(struct device_node *dn,
int where, int size, u32 val)
{
struct pci_controller *hose = pci_bus_to_host(bus);
struct pnv_phb *phb = hose->private_data;
u32 bdfn = (((uint64_t)bus->number) << 8) | devfn;
struct pci_dn *pdn = PCI_DN(dn);
struct pnv_phb *phb = pdn->phb->private_data;
u32 bdfn = (pdn->busno << 8) | pdn->devfn;
if (hose == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
cfg_dbg("pnv_pci_write_config bus: %x devfn: %x +%x/%x -> %08x\n",
bus->number, devfn, where, size, val);
cfg_dbg("%s: bus: %x devfn: %x +%x/%x -> %08x\n",
pdn->busno, pdn->devfn, where, size, val);
switch (size) {
case 1:
opal_pci_config_write_byte(phb->opal_id, bdfn, where, val);
@ -360,16 +352,50 @@ static int pnv_pci_write_config(struct pci_bus *bus,
/* Check if the PHB got frozen due to an error (no response) */
#ifdef CONFIG_EEH
if (!(phb->eeh_state & PNV_EEH_STATE_ENABLED))
pnv_pci_config_check_eeh(phb, bus, bdfn);
pnv_pci_config_check_eeh(phb, dn);
#else
pnv_pci_config_check_eeh(phb, bus, bdfn);
pnv_pci_config_check_eeh(phb, dn);
#endif
return PCIBIOS_SUCCESSFUL;
}
static int pnv_pci_read_config(struct pci_bus *bus,
unsigned int devfn,
int where, int size, u32 *val)
{
struct device_node *dn, *busdn = pci_bus_to_OF_node(bus);
struct pci_dn *pdn;
for (dn = busdn->child; dn; dn = dn->sibling) {
pdn = PCI_DN(dn);
if (pdn && pdn->devfn == devfn)
return pnv_pci_cfg_read(dn, where, size, val);
}
*val = 0xFFFFFFFF;
return PCIBIOS_DEVICE_NOT_FOUND;
}
static int pnv_pci_write_config(struct pci_bus *bus,
unsigned int devfn,
int where, int size, u32 val)
{
struct device_node *dn, *busdn = pci_bus_to_OF_node(bus);
struct pci_dn *pdn;
for (dn = busdn->child; dn; dn = dn->sibling) {
pdn = PCI_DN(dn);
if (pdn && pdn->devfn == devfn)
return pnv_pci_cfg_write(dn, where, size, val);
}
return PCIBIOS_DEVICE_NOT_FOUND;
}
struct pci_ops pnv_pci_ops = {
.read = pnv_pci_read_config,
.read = pnv_pci_read_config,
.write = pnv_pci_write_config,
};

View file

@ -182,6 +182,10 @@ extern struct pci_ops pnv_pci_ops;
extern struct pnv_eeh_ops ioda_eeh_ops;
#endif
int pnv_pci_cfg_read(struct device_node *dn,
int where, int size, u32 *val);
int pnv_pci_cfg_write(struct device_node *dn,
int where, int size, u32 val);
extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
void *tce_mem, u64 tce_size,
u64 dma_offset);