Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 330289
b: refs/heads/master
c: 9e6d2cf
h: refs/heads/master
i:
  330287: 365de8c
v: v3
  • Loading branch information
Gavin Shan authored and Benjamin Herrenschmidt committed Sep 9, 2012
1 parent 9a1d8be commit dec4649
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 81 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 371a395d2f1fe296c89735547672d70f4dcc2949
refs/heads/master: 9e6d2cf65e3dbaf783917c92c15d31d419b0d648
3 changes: 3 additions & 0 deletions trunk/arch/powerpc/include/asm/eeh.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ typedef void *(*eeh_traverse_func)(void *data, void *flag);
int __devinit eeh_phb_pe_create(struct pci_controller *phb);
int eeh_add_to_parent_pe(struct eeh_dev *edev);
int eeh_rmv_from_parent_pe(struct eeh_dev *edev);
void *eeh_pe_dev_traverse(struct eeh_pe *root,
eeh_traverse_func fn, void *flag);
void eeh_pe_restore_bars(struct eeh_pe *pe);

void * __devinit eeh_dev_init(struct device_node *dn, void *data);
void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb);
Expand Down
1 change: 0 additions & 1 deletion trunk/arch/powerpc/include/asm/ppc-pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ struct pci_dev *pci_addr_cache_get_device(unsigned long addr);
void eeh_slot_error_detail(struct eeh_dev *edev, int severity);
int eeh_pci_enable(struct eeh_dev *edev, int function);
int eeh_reset_pe(struct eeh_dev *);
void eeh_restore_bars(struct eeh_dev *);
int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
int rtas_read_config(struct pci_dn *, int where, int size, u32 *val);
void eeh_pe_state_mark(struct eeh_pe *pe, int state);
Expand Down
79 changes: 0 additions & 79 deletions trunk/arch/powerpc/platforms/pseries/eeh.c
Original file line number Diff line number Diff line change
Expand Up @@ -610,85 +610,6 @@ int eeh_reset_pe(struct eeh_dev *edev)
return -1;
}

/** Save and restore of PCI BARs
*
* Although firmware will set up BARs during boot, it doesn't
* set up device BAR's after a device reset, although it will,
* if requested, set up bridge configuration. Thus, we need to
* configure the PCI devices ourselves.
*/

/**
* eeh_restore_one_device_bars - Restore the Base Address Registers for one device
* @edev: PCI device associated EEH device
*
* Loads the PCI configuration space base address registers,
* the expansion ROM base address, the latency timer, and etc.
* from the saved values in the device node.
*/
static inline void eeh_restore_one_device_bars(struct eeh_dev *edev)
{
int i;
u32 cmd;
struct device_node *dn = eeh_dev_to_of_node(edev);

if (!edev->phb)
return;

for (i=4; i<10; i++) {
eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]);
}

/* 12 == Expansion ROM Address */
eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]);

#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)])

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

eeh_ops->write_config(dn, 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]);

/* Restore PERR & SERR bits, some devices require it,
* don't touch the other command bits
*/
eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd);
if (edev->config_space[1] & PCI_COMMAND_PARITY)
cmd |= PCI_COMMAND_PARITY;
else
cmd &= ~PCI_COMMAND_PARITY;
if (edev->config_space[1] & PCI_COMMAND_SERR)
cmd |= PCI_COMMAND_SERR;
else
cmd &= ~PCI_COMMAND_SERR;
eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd);
}

/**
* eeh_restore_bars - Restore the PCI config space info
* @edev: EEH device
*
* This routine performs a recursive walk to the children
* of this device as well.
*/
void eeh_restore_bars(struct eeh_dev *edev)
{
struct device_node *dn;
if (!edev)
return;

if ((edev->mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(edev->class_code))
eeh_restore_one_device_bars(edev);

for_each_child_of_node(eeh_dev_to_of_node(edev), dn)
eeh_restore_bars(of_node_to_eeh_dev(dn));
}

/**
* eeh_save_bars - Save device bars
* @edev: PCI device associated EEH device
Expand Down
94 changes: 94 additions & 0 deletions trunk/arch/powerpc/platforms/pseries/eeh_pe.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,38 @@ static void *eeh_pe_traverse(struct eeh_pe *root,
return NULL;
}

/**
* eeh_pe_dev_traverse - Traverse the devices from the PE
* @root: EEH PE
* @fn: function callback
* @flag: extra parameter to callback
*
* The function is used to traverse the devices of the specified
* PE and its child PEs.
*/
void *eeh_pe_dev_traverse(struct eeh_pe *root,
eeh_traverse_func fn, void *flag)
{
struct eeh_pe *pe;
struct eeh_dev *edev;
void *ret;

if (!root) {
pr_warning("%s: Invalid PE %p\n", __func__, root);
return NULL;
}

/* 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;
}
}

return NULL;
}

/**
* __eeh_pe_get - Check the PE address
* @data: EEH PE
Expand Down Expand Up @@ -467,3 +499,65 @@ void eeh_pe_state_clear(struct eeh_pe *pe, int state)
{
eeh_pe_traverse(pe, __eeh_pe_state_clear, &state);
}

/**
* eeh_restore_one_device_bars - Restore the Base Address Registers for one device
* @data: EEH device
* @flag: Unused
*
* Loads the PCI configuration space base address registers,
* the expansion ROM base address, the latency timer, and etc.
* from the saved values in the device node.
*/
static void *eeh_restore_one_device_bars(void *data, void *flag)
{
int i;
u32 cmd;
struct eeh_dev *edev = (struct eeh_dev *)data;
struct device_node *dn = eeh_dev_to_of_node(edev);

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

#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)])

eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1,
SAVED_BYTE(PCI_CACHE_LINE_SIZE));
eeh_ops->write_config(dn, 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]);

/*
* Restore PERR & SERR bits, some devices require it,
* don't touch the other command bits
*/
eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd);
if (edev->config_space[1] & PCI_COMMAND_PARITY)
cmd |= PCI_COMMAND_PARITY;
else
cmd &= ~PCI_COMMAND_PARITY;
if (edev->config_space[1] & PCI_COMMAND_SERR)
cmd |= PCI_COMMAND_SERR;
else
cmd &= ~PCI_COMMAND_SERR;
eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd);

return NULL;
}

/**
* eeh_pe_restore_bars - Restore the PCI config space info
* @pe: EEH PE
*
* This routine performs a recursive walk to the children
* of this device as well.
*/
void eeh_pe_restore_bars(struct eeh_pe *pe)
{
eeh_pe_dev_traverse(pe, eeh_restore_one_device_bars, NULL);
}

0 comments on commit dec4649

Please sign in to comment.