Skip to content

Commit

Permalink
powerpc/eeh: Replace device_node with pci_dn in eeh_ops
Browse files Browse the repository at this point in the history
There are 3 EEH operations whose arguments contain device_node:
read_config(), write_config() and restore_config(). The patch
replaces device_node with pci_dn.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
  • Loading branch information
Gavin Shan authored and Benjamin Herrenschmidt committed Mar 24, 2015
1 parent ff57b45 commit 0bd7858
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 97 deletions.
6 changes: 3 additions & 3 deletions arch/powerpc/include/asm/eeh.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,10 @@ struct eeh_ops {
int (*configure_bridge)(struct eeh_pe *pe);
int (*err_inject)(struct eeh_pe *pe, int type, int func,
unsigned long addr, unsigned long mask);
int (*read_config)(struct device_node *dn, int where, int size, u32 *val);
int (*write_config)(struct device_node *dn, int where, int size, u32 val);
int (*read_config)(struct pci_dn *pdn, int where, int size, u32 *val);
int (*write_config)(struct pci_dn *pdn, int where, int size, u32 val);
int (*next_error)(struct eeh_pe **pe);
int (*restore_config)(struct device_node *dn);
int (*restore_config)(struct pci_dn *pdn);
};

extern int eeh_subsystem_flags;
Expand Down
40 changes: 22 additions & 18 deletions arch/powerpc/kernel/eeh.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,42 +164,46 @@ __setup("eeh=", eeh_setup);
*/
static size_t eeh_dump_dev_log(struct eeh_dev *edev, char *buf, size_t len)
{
struct device_node *dn = eeh_dev_to_of_node(edev);
struct pci_dn *pdn = eeh_dev_to_pdn(edev);
u32 cfg;
int cap, i;
int n = 0, l = 0;
char buffer[128];

n += scnprintf(buf+n, len-n, "%s\n", dn->full_name);
pr_warn("EEH: of node=%s\n", dn->full_name);
n += scnprintf(buf+n, len-n, "%04x:%02x:%02x:%01x\n",
edev->phb->global_number, pdn->busno,
PCI_SLOT(pdn->devfn), PCI_FUNC(pdn->devfn));
pr_warn("EEH: of node=%04x:%02x:%02x:%01x\n",
edev->phb->global_number, pdn->busno,
PCI_SLOT(pdn->devfn), PCI_FUNC(pdn->devfn));

eeh_ops->read_config(dn, PCI_VENDOR_ID, 4, &cfg);
eeh_ops->read_config(pdn, PCI_VENDOR_ID, 4, &cfg);
n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg);
pr_warn("EEH: PCI device/vendor: %08x\n", cfg);

eeh_ops->read_config(dn, PCI_COMMAND, 4, &cfg);
eeh_ops->read_config(pdn, PCI_COMMAND, 4, &cfg);
n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg);
pr_warn("EEH: PCI cmd/status register: %08x\n", cfg);

/* Gather bridge-specific registers */
if (edev->mode & EEH_DEV_BRIDGE) {
eeh_ops->read_config(dn, PCI_SEC_STATUS, 2, &cfg);
eeh_ops->read_config(pdn, PCI_SEC_STATUS, 2, &cfg);
n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg);
pr_warn("EEH: Bridge secondary status: %04x\n", cfg);

eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &cfg);
eeh_ops->read_config(pdn, PCI_BRIDGE_CONTROL, 2, &cfg);
n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg);
pr_warn("EEH: Bridge control: %04x\n", cfg);
}

/* Dump out the PCI-X command and status regs */
cap = edev->pcix_cap;
if (cap) {
eeh_ops->read_config(dn, cap, 4, &cfg);
eeh_ops->read_config(pdn, cap, 4, &cfg);
n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg);
pr_warn("EEH: PCI-X cmd: %08x\n", cfg);

eeh_ops->read_config(dn, cap+4, 4, &cfg);
eeh_ops->read_config(pdn, cap+4, 4, &cfg);
n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg);
pr_warn("EEH: PCI-X status: %08x\n", cfg);
}
Expand All @@ -211,7 +215,7 @@ static size_t eeh_dump_dev_log(struct eeh_dev *edev, char *buf, size_t len)
pr_warn("EEH: PCI-E capabilities and status follow:\n");

for (i=0; i<=8; i++) {
eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
eeh_ops->read_config(pdn, cap+4*i, 4, &cfg);
n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);

if ((i % 4) == 0) {
Expand All @@ -238,7 +242,7 @@ static size_t eeh_dump_dev_log(struct eeh_dev *edev, char *buf, size_t len)
pr_warn("EEH: PCI-E AER capability register set follows:\n");

for (i=0; i<=13; i++) {
eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
eeh_ops->read_config(pdn, cap+4*i, 4, &cfg);
n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);

if ((i % 4) == 0) {
Expand Down Expand Up @@ -698,16 +702,16 @@ static void *eeh_disable_and_save_dev_state(void *data, void *userdata)
static void *eeh_restore_dev_state(void *data, void *userdata)
{
struct eeh_dev *edev = data;
struct device_node *dn = eeh_dev_to_of_node(edev);
struct pci_dn *pdn = eeh_dev_to_pdn(edev);
struct pci_dev *pdev = eeh_dev_to_pci_dev(edev);
struct pci_dev *dev = userdata;

if (!pdev)
return NULL;

/* Apply customization from firmware */
if (dn && eeh_ops->restore_config)
eeh_ops->restore_config(dn);
if (pdn && eeh_ops->restore_config)
eeh_ops->restore_config(pdn);

/* The caller should restore state for the specified device */
if (pdev != dev)
Expand Down Expand Up @@ -870,15 +874,15 @@ int eeh_reset_pe(struct eeh_pe *pe)
*/
void eeh_save_bars(struct eeh_dev *edev)
{
struct pci_dn *pdn;
int i;
struct device_node *dn;

if (!edev)
pdn = eeh_dev_to_pdn(edev);
if (!pdn)
return;
dn = eeh_dev_to_of_node(edev);

for (i = 0; i < 16; i++)
eeh_ops->read_config(dn, i * 4, 4, &edev->config_space[i]);
eeh_ops->read_config(pdn, i * 4, 4, &edev->config_space[i]);

/*
* For PCI bridges including root port, we need enable bus
Expand Down
82 changes: 40 additions & 42 deletions arch/powerpc/kernel/eeh_pe.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,27 +291,25 @@ struct eeh_pe *eeh_pe_get(struct eeh_dev *edev)
*/
static struct eeh_pe *eeh_pe_get_parent(struct eeh_dev *edev)
{
struct device_node *dn;
struct eeh_dev *parent;
struct pci_dn *pdn = eeh_dev_to_pdn(edev);

/*
* It might have the case for the indirect parent
* EEH device already having associated PE, but
* the direct parent EEH device doesn't have yet.
*/
dn = edev->dn->parent;
while (dn) {
pdn = pdn ? pdn->parent : NULL;
while (pdn) {
/* We're poking out of PCI territory */
if (!PCI_DN(dn)) return NULL;

parent = of_node_to_eeh_dev(dn);
/* We're poking out of PCI territory */
if (!parent) return NULL;
parent = pdn_to_eeh_dev(pdn);
if (!parent)
return NULL;

if (parent->pe)
return parent->pe;

dn = dn->parent;
pdn = pdn->parent;
}

return NULL;
Expand Down Expand Up @@ -653,9 +651,9 @@ void eeh_pe_state_clear(struct eeh_pe *pe, int state)
* blocked on normal path during the stage. So we need utilize
* eeh operations, which is always permitted.
*/
static void eeh_bridge_check_link(struct eeh_dev *edev,
struct device_node *dn)
static void eeh_bridge_check_link(struct eeh_dev *edev)
{
struct pci_dn *pdn = eeh_dev_to_pdn(edev);
int cap;
uint32_t val;
int timeout = 0;
Expand All @@ -675,32 +673,32 @@ static void eeh_bridge_check_link(struct eeh_dev *edev,

/* Check slot status */
cap = edev->pcie_cap;
eeh_ops->read_config(dn, cap + PCI_EXP_SLTSTA, 2, &val);
eeh_ops->read_config(pdn, cap + PCI_EXP_SLTSTA, 2, &val);
if (!(val & PCI_EXP_SLTSTA_PDS)) {
pr_debug(" No card in the slot (0x%04x) !\n", val);
return;
}

/* Check power status if we have the capability */
eeh_ops->read_config(dn, cap + PCI_EXP_SLTCAP, 2, &val);
eeh_ops->read_config(pdn, cap + PCI_EXP_SLTCAP, 2, &val);
if (val & PCI_EXP_SLTCAP_PCP) {
eeh_ops->read_config(dn, cap + PCI_EXP_SLTCTL, 2, &val);
eeh_ops->read_config(pdn, cap + PCI_EXP_SLTCTL, 2, &val);
if (val & PCI_EXP_SLTCTL_PCC) {
pr_debug(" In power-off state, power it on ...\n");
val &= ~(PCI_EXP_SLTCTL_PCC | PCI_EXP_SLTCTL_PIC);
val |= (0x0100 & PCI_EXP_SLTCTL_PIC);
eeh_ops->write_config(dn, cap + PCI_EXP_SLTCTL, 2, val);
eeh_ops->write_config(pdn, cap + PCI_EXP_SLTCTL, 2, val);
msleep(2 * 1000);
}
}

/* Enable link */
eeh_ops->read_config(dn, cap + PCI_EXP_LNKCTL, 2, &val);
eeh_ops->read_config(pdn, cap + PCI_EXP_LNKCTL, 2, &val);
val &= ~PCI_EXP_LNKCTL_LD;
eeh_ops->write_config(dn, cap + PCI_EXP_LNKCTL, 2, val);
eeh_ops->write_config(pdn, cap + PCI_EXP_LNKCTL, 2, val);

/* Check link */
eeh_ops->read_config(dn, cap + PCI_EXP_LNKCAP, 4, &val);
eeh_ops->read_config(pdn, cap + PCI_EXP_LNKCAP, 4, &val);
if (!(val & PCI_EXP_LNKCAP_DLLLARC)) {
pr_debug(" No link reporting capability (0x%08x) \n", val);
msleep(1000);
Expand All @@ -713,7 +711,7 @@ static void eeh_bridge_check_link(struct eeh_dev *edev,
msleep(20);
timeout += 20;

eeh_ops->read_config(dn, cap + PCI_EXP_LNKSTA, 2, &val);
eeh_ops->read_config(pdn, cap + PCI_EXP_LNKSTA, 2, &val);
if (val & PCI_EXP_LNKSTA_DLLLA)
break;
}
Expand All @@ -728,59 +726,59 @@ static void eeh_bridge_check_link(struct eeh_dev *edev,
#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)])

static void eeh_restore_bridge_bars(struct eeh_dev *edev,
struct device_node *dn)
static void eeh_restore_bridge_bars(struct eeh_dev *edev)
{
struct pci_dn *pdn = eeh_dev_to_pdn(edev);
int i;

/*
* Device BARs: 0x10 - 0x18
* Bus numbers and windows: 0x18 - 0x30
*/
for (i = 4; i < 13; i++)
eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]);
eeh_ops->write_config(pdn, i*4, 4, edev->config_space[i]);
/* Rom: 0x38 */
eeh_ops->write_config(dn, 14*4, 4, edev->config_space[14]);
eeh_ops->write_config(pdn, 14*4, 4, edev->config_space[14]);

/* Cache line & Latency timer: 0xC 0xD */
eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1,
eeh_ops->write_config(pdn, PCI_CACHE_LINE_SIZE, 1,
SAVED_BYTE(PCI_CACHE_LINE_SIZE));
eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1,
eeh_ops->write_config(pdn, PCI_LATENCY_TIMER, 1,
SAVED_BYTE(PCI_LATENCY_TIMER));
/* Max latency, min grant, interrupt ping and line: 0x3C */
eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]);
eeh_ops->write_config(pdn, 15*4, 4, edev->config_space[15]);

/* PCI Command: 0x4 */
eeh_ops->write_config(dn, PCI_COMMAND, 4, edev->config_space[1]);
eeh_ops->write_config(pdn, PCI_COMMAND, 4, edev->config_space[1]);

/* Check the PCIe link is ready */
eeh_bridge_check_link(edev, dn);
eeh_bridge_check_link(edev);
}

static void eeh_restore_device_bars(struct eeh_dev *edev,
struct device_node *dn)
static void eeh_restore_device_bars(struct eeh_dev *edev)
{
struct pci_dn *pdn = eeh_dev_to_pdn(edev);
int i;
u32 cmd;

for (i = 4; i < 10; i++)
eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]);
eeh_ops->write_config(pdn, i*4, 4, edev->config_space[i]);
/* 12 == Expansion ROM Address */
eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]);
eeh_ops->write_config(pdn, 12*4, 4, edev->config_space[12]);

eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1,
eeh_ops->write_config(pdn, PCI_CACHE_LINE_SIZE, 1,
SAVED_BYTE(PCI_CACHE_LINE_SIZE));
eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1,
eeh_ops->write_config(pdn, PCI_LATENCY_TIMER, 1,
SAVED_BYTE(PCI_LATENCY_TIMER));

/* max latency, min grant, interrupt pin and line */
eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]);
eeh_ops->write_config(pdn, 15*4, 4, edev->config_space[15]);

/*
* Restore PERR & SERR bits, some devices require it,
* don't touch the other command bits
*/
eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd);
eeh_ops->read_config(pdn, PCI_COMMAND, 4, &cmd);
if (edev->config_space[1] & PCI_COMMAND_PARITY)
cmd |= PCI_COMMAND_PARITY;
else
Expand All @@ -789,7 +787,7 @@ static void eeh_restore_device_bars(struct eeh_dev *edev,
cmd |= PCI_COMMAND_SERR;
else
cmd &= ~PCI_COMMAND_SERR;
eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd);
eeh_ops->write_config(pdn, PCI_COMMAND, 4, cmd);
}

/**
Expand All @@ -804,16 +802,16 @@ static void eeh_restore_device_bars(struct eeh_dev *edev,
static void *eeh_restore_one_device_bars(void *data, void *flag)
{
struct eeh_dev *edev = (struct eeh_dev *)data;
struct device_node *dn = eeh_dev_to_of_node(edev);
struct pci_dn *pdn = eeh_dev_to_pdn(edev);

/* Do special restore for bridges */
if (edev->mode & EEH_DEV_BRIDGE)
eeh_restore_bridge_bars(edev, dn);
eeh_restore_bridge_bars(edev);
else
eeh_restore_device_bars(edev, dn);
eeh_restore_device_bars(edev);

if (eeh_ops->restore_config)
eeh_ops->restore_config(dn);
if (eeh_ops->restore_config && pdn)
eeh_ops->restore_config(pdn);

return NULL;
}
Expand Down
Loading

0 comments on commit 0bd7858

Please sign in to comment.