Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 292525
b: refs/heads/master
c: eb740b5
h: refs/heads/master
i:
  292523: bebb691
v: v3
  • Loading branch information
Gavin Shan authored and Benjamin Herrenschmidt committed Mar 9, 2012
1 parent f290525 commit 88561de
Show file tree
Hide file tree
Showing 11 changed files with 191 additions and 11 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: def9d83da4f8587dbad5ea57c57d91e53a51006a
refs/heads/master: eb740b5f3e6559a8f1c22e2505914d07f9632881
3 changes: 3 additions & 0 deletions trunk/arch/powerpc/include/asm/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ struct dev_archdata {
#ifdef CONFIG_SWIOTLB
dma_addr_t max_direct_dma_addr;
#endif
#ifdef CONFIG_EEH
struct eeh_dev *edev;
#endif
};

struct pdev_archdata {
Expand Down
57 changes: 50 additions & 7 deletions trunk/arch/powerpc/include/asm/eeh.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,43 @@ struct device_node;

#ifdef CONFIG_EEH

/*
* The struct is used to trace EEH state for the associated
* PCI device node or PCI device. In future, it might
* represent PE as well so that the EEH device to form
* another tree except the currently existing tree of PCI
* buses and PCI devices
*/
#define EEH_MODE_SUPPORTED (1<<0) /* EEH supported on the device */
#define EEH_MODE_NOCHECK (1<<1) /* EEH check should be skipped */
#define EEH_MODE_ISOLATED (1<<2) /* The device has been isolated */
#define EEH_MODE_RECOVERING (1<<3) /* Recovering the device */
#define EEH_MODE_IRQ_DISABLED (1<<4) /* Interrupt disabled */

struct eeh_dev {
int mode; /* EEH mode */
int class_code; /* Class code of the device */
int config_addr; /* Config address */
int pe_config_addr; /* PE config address */
int check_count; /* Times of ignored error */
int freeze_count; /* Times of froze up */
int false_positives; /* Times of reported #ff's */
u32 config_space[16]; /* Saved PCI config space */
struct pci_controller *phb; /* Associated PHB */
struct device_node *dn; /* Associated device node */
struct pci_dev *pdev; /* Associated PCI device */
};

static inline struct device_node *eeh_dev_to_of_node(struct eeh_dev *edev)
{
return edev->dn;
}

static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev)
{
return edev->pdev;
}

/*
* The struct is used to trace the registered EEH operation
* callback functions. Actually, those operation callback
Expand Down Expand Up @@ -70,19 +107,15 @@ struct eeh_ops {
extern struct eeh_ops *eeh_ops;
extern int eeh_subsystem_enabled;

/* Values for eeh_mode bits in device_node */
#define EEH_MODE_SUPPORTED (1<<0)
#define EEH_MODE_NOCHECK (1<<1)
#define EEH_MODE_ISOLATED (1<<2)
#define EEH_MODE_RECOVERING (1<<3)
#define EEH_MODE_IRQ_DISABLED (1<<4)

/*
* Max number of EEH freezes allowed before we consider the device
* to be permanently disabled.
*/
#define EEH_MAX_ALLOWED_FREEZES 5

void * __devinit eeh_dev_init(struct device_node *dn, void *data);
void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb);
void __init eeh_dev_phb_init(void);
void __init eeh_init(void);
#ifdef CONFIG_PPC_PSERIES
int __init eeh_pseries_init(void);
Expand Down Expand Up @@ -113,6 +146,16 @@ void eeh_remove_bus_device(struct pci_dev *);
#define EEH_IO_ERROR_VALUE(size) (~0U >> ((4 - (size)) * 8))

#else /* !CONFIG_EEH */

static inline void *eeh_dev_init(struct device_node *dn, void *data)
{
return NULL;
}

static inline void eeh_dev_phb_init_dynamic(struct pci_controller *phb) { }

static inline void eeh_dev_phb_init(void) { }

static inline void eeh_init(void) { }

#ifdef CONFIG_PPC_PSERIES
Expand Down
6 changes: 5 additions & 1 deletion trunk/arch/powerpc/kernel/of_platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/atomic.h>

#include <asm/errno.h>
#include <asm/topology.h>
#include <asm/pci-bridge.h>
#include <asm/ppc-pci.h>
#include <linux/atomic.h>
#include <asm/eeh.h>

#ifdef CONFIG_PPC_OF_PLATFORM_PCI

Expand Down Expand Up @@ -66,6 +67,9 @@ static int __devinit of_pci_phb_probe(struct platform_device *dev)
/* Init pci_dn data structures */
pci_devs_phb_init_dynamic(phb);

/* Create EEH devices for the PHB */
eeh_dev_phb_init_dynamic(phb);

/* Register devices with EEH */
#ifdef CONFIG_EEH
if (dev->dev.of_node->child)
Expand Down
3 changes: 3 additions & 0 deletions trunk/arch/powerpc/kernel/rtas_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,9 @@ void __init find_and_init_phbs(void)
of_node_put(root);
pci_devs_phb_init();

/* Create EEH devices for all PHBs */
eeh_dev_phb_init();

/*
* pci_probe_only and pci_assign_all_buses can be set via properties
* in chosen.
Expand Down
3 changes: 2 additions & 1 deletion trunk/arch/powerpc/platforms/pseries/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \
firmware.o power.o dlpar.o mobility.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SCANLOG) += scanlog.o
obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o eeh_pseries.o
obj-$(CONFIG_EEH) += eeh.o eeh_dev.o eeh_cache.o eeh_driver.o \
eeh_event.o eeh_sysfs.o eeh_pseries.o
obj-$(CONFIG_KEXEC) += kexec.o
obj-$(CONFIG_PCI) += pci.o pci_dlpar.o
obj-$(CONFIG_PSERIES_MSI) += msi.o
Expand Down
102 changes: 102 additions & 0 deletions trunk/arch/powerpc/platforms/pseries/eeh_dev.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* The file intends to implement dynamic creation of EEH device, which will
* be bound with OF node and PCI device simutaneously. The EEH devices would
* be foundamental information for EEH core components to work proerly. Besides,
* We have to support multiple situations where dynamic creation of EEH device
* is required:
*
* 1) Before PCI emunation starts, we need create EEH devices according to the
* PCI sensitive OF nodes.
* 2) When PCI emunation is done, we need do the binding between PCI device and
* the associated EEH device.
* 3) DR (Dynamic Reconfiguration) would create PCI sensitive OF node. EEH device
* will be created while PCI sensitive OF node is detected from DR.
* 4) PCI hotplug needs redoing the binding between PCI device and EEH device. If
* PHB is newly inserted, we also need create EEH devices accordingly.
*
* Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2012.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <linux/export.h>
#include <linux/gfp.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/string.h>

#include <asm/pci-bridge.h>
#include <asm/ppc-pci.h>

/**
* eeh_dev_init - Create EEH device according to OF node
* @dn: device node
* @data: PHB
*
* It will create EEH device according to the given OF node. The function
* might be called by PCI emunation, DR, PHB hotplug.
*/
void * __devinit eeh_dev_init(struct device_node *dn, void *data)
{
struct pci_controller *phb = data;
struct eeh_dev *edev;

/* Allocate EEH device */
edev = zalloc_maybe_bootmem(sizeof(*edev), GFP_KERNEL);
if (!edev) {
pr_warning("%s: out of memory\n", __func__);
return NULL;
}

/* Associate EEH device with OF node */
dn->edev = edev;
edev->dn = dn;
edev->phb = phb;

return NULL;
}

/**
* eeh_dev_phb_init_dynamic - Create EEH devices for devices included in PHB
* @phb: PHB
*
* Scan the PHB OF node and its child association, then create the
* EEH devices accordingly
*/
void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb)
{
struct device_node *dn = phb->dn;

/* EEH device for PHB */
eeh_dev_init(dn, phb);

/* EEH devices for children OF nodes */
traverse_pci_devices(dn, eeh_dev_init, phb);
}

/**
* eeh_dev_phb_init - Create EEH devices for devices included in existing PHBs
*
* Scan all the existing PHBs and create EEH devices for their OF
* nodes and their children OF nodes
*/
void __init eeh_dev_phb_init(void)
{
struct pci_controller *phb, *tmp;

list_for_each_entry_safe(phb, tmp, &hose_list, list_node)
eeh_dev_phb_init_dynamic(phb);
}
3 changes: 3 additions & 0 deletions trunk/arch/powerpc/platforms/pseries/pci_dlpar.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)

pci_devs_phb_init_dynamic(phb);

/* Create EEH devices for the PHB */
eeh_dev_phb_init_dynamic(phb);

if (dn->child)
eeh_add_device_tree_early(dn);

Expand Down
6 changes: 5 additions & 1 deletion trunk/arch/powerpc/platforms/pseries/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,12 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act
switch (action) {
case PSERIES_RECONFIG_ADD:
pci = np->parent->data;
if (pci)
if (pci) {
update_dn_pci_info(np, pci->phb);

/* Create EEH device for the OF node */
eeh_dev_init(np, pci->phb);
}
break;
default:
err = NOTIFY_DONE;
Expand Down
10 changes: 10 additions & 0 deletions trunk/include/linux/of.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ struct device_node {
struct kref kref;
unsigned long _flags;
void *data;
#if defined(CONFIG_EEH)
struct eeh_dev *edev;
#endif
#if defined(CONFIG_SPARC)
char *path_component_name;
unsigned int unique_id;
Expand All @@ -72,6 +75,13 @@ struct of_phandle_args {
uint32_t args[MAX_PHANDLE_ARGS];
};

#if defined(CONFIG_EEH)
static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn)
{
return dn->edev;
}
#endif

#if defined(CONFIG_SPARC) || !defined(CONFIG_OF)
/* Dummy ref counting routines - to be implemented later */
static inline struct device_node *of_node_get(struct device_node *node)
Expand Down
7 changes: 7 additions & 0 deletions trunk/include/linux/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -1647,6 +1647,13 @@ static inline void pci_set_bus_of_node(struct pci_bus *bus) { }
static inline void pci_release_bus_of_node(struct pci_bus *bus) { }
#endif /* CONFIG_OF */

#ifdef CONFIG_EEH
static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev)
{
return pdev->dev.archdata.edev;
}
#endif

/**
* pci_find_upstream_pcie_bridge - find upstream PCIe-to-PCI bridge of a device
* @pdev: the PCI device
Expand Down

0 comments on commit 88561de

Please sign in to comment.