Commit 07bc9dc1 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc

Pull powerpc fixes from Ben Herrenschmidt:
 "Here is a series of powerpc fixes.  It's a bit big, mostly because of
  the series of 11 "EEH" patches from Gavin.  The EEH (Our IBM specific
  PCI/PCIe Enhanced Error Handling) code had been rotting for a while
  and this merge window saw a significant rework & fixing of it by Gavin
  Shan.

  However, that wasn't complete and left some open issues.  There were
  still a few corner cases that didn't work properly, for example in
  relation to hotplug and devices without explicit error handlers.  We
  had some patches but they weren't quite good enough yet so I left them
  off the 3.11 merge window.

  Gavin since then fixed it all up, we ran quite a few rounds of testing
  and it seems fairly solid (at least probably more than it has ever
  been).  This should probably have made -rc1 but both Gavin and I took
  some vacation so it had to wait for -rc2.

  The rest is more bug fixes, mostly to new features recently added, for
  example, we missed the cpu table entry for one of the two models of P8
  (we didn't realize they had different PVR [Processor Version Register]
  values), some module CRC issues, etc..."

* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (23 commits)
  powerpc/perf: BHRB filter configuration should follow the task
  powerpc/perf: Ignore separate BHRB privilege state filter request
  powerpc/powernv: Mark pnv_pci_init_ioda2_phb() as __init
  powerpc/mm: Use the correct SLB(LLP) encoding in tlbie instruction
  powerpc/mm: Fix fallthrough bug in hpte_decode
  powerpc/pseries: Fix a typo in pSeries_lpar_hpte_insert()
  powerpc/eeh: Introdce flag to protect sysfs
  powerpc/eeh: Fix unbalanced enable for IRQ
  powerpc/eeh: Don't use pci_dev during BAR restore
  powerpc/eeh: Use partial hotplug for EEH unaware drivers
  powerpc/pci: Partial tree hotplug support
  powerpc/eeh: Use safe list traversal when walking EEH devices
  powerpc/eeh: Keep PE during hotplug
  powerpc/pci/hotplug: Don't need to remove from EEH cache twice
  powerpc/pci: Override pcibios_release_device()
  powerpc/eeh: Export functions for hotplug
  powerpc/eeh: Remove reference to PCI device
  powerpc: Fix the corrupt r3 error during MCE handling.
  powerpc/perf: Set PPC_FEATURE2_EBB when we register the power8 PMU
  powerpc/pseries: Drop "select HOTPLUG"
  ...
parents b48a97be ff3d79dc
...@@ -55,6 +55,8 @@ struct device_node; ...@@ -55,6 +55,8 @@ struct device_node;
#define EEH_PE_RECOVERING (1 << 1) /* Recovering PE */ #define EEH_PE_RECOVERING (1 << 1) /* Recovering PE */
#define EEH_PE_PHB_DEAD (1 << 2) /* Dead PHB */ #define EEH_PE_PHB_DEAD (1 << 2) /* Dead PHB */
#define EEH_PE_KEEP (1 << 8) /* Keep PE on hotplug */
struct eeh_pe { struct eeh_pe {
int type; /* PE type: PHB/Bus/Device */ int type; /* PE type: PHB/Bus/Device */
int state; /* PE EEH dependent mode */ int state; /* PE EEH dependent mode */
...@@ -72,8 +74,8 @@ struct eeh_pe { ...@@ -72,8 +74,8 @@ struct eeh_pe {
struct list_head child; /* Child PEs */ struct list_head child; /* Child PEs */
}; };
#define eeh_pe_for_each_dev(pe, edev) \ #define eeh_pe_for_each_dev(pe, edev, tmp) \
list_for_each_entry(edev, &pe->edevs, list) list_for_each_entry_safe(edev, tmp, &pe->edevs, list)
/* /*
* The struct is used to trace EEH state for the associated * The struct is used to trace EEH state for the associated
...@@ -82,7 +84,13 @@ struct eeh_pe { ...@@ -82,7 +84,13 @@ struct eeh_pe {
* another tree except the currently existing tree of PCI * another tree except the currently existing tree of PCI
* buses and PCI devices * buses and PCI devices
*/ */
#define EEH_DEV_IRQ_DISABLED (1<<0) /* Interrupt disabled */ #define EEH_DEV_BRIDGE (1 << 0) /* PCI bridge */
#define EEH_DEV_ROOT_PORT (1 << 1) /* PCIe root port */
#define EEH_DEV_DS_PORT (1 << 2) /* Downstream port */
#define EEH_DEV_IRQ_DISABLED (1 << 3) /* Interrupt disabled */
#define EEH_DEV_DISCONNECTED (1 << 4) /* Removing from PE */
#define EEH_DEV_SYSFS (1 << 8) /* Sysfs created */
struct eeh_dev { struct eeh_dev {
int mode; /* EEH mode */ int mode; /* EEH mode */
...@@ -90,11 +98,13 @@ struct eeh_dev { ...@@ -90,11 +98,13 @@ struct eeh_dev {
int config_addr; /* Config address */ int config_addr; /* Config address */
int pe_config_addr; /* PE config address */ int pe_config_addr; /* PE config address */
u32 config_space[16]; /* Saved PCI config space */ u32 config_space[16]; /* Saved PCI config space */
u8 pcie_cap; /* Saved PCIe capability */
struct eeh_pe *pe; /* Associated PE */ struct eeh_pe *pe; /* Associated PE */
struct list_head list; /* Form link list in the PE */ struct list_head list; /* Form link list in the PE */
struct pci_controller *phb; /* Associated PHB */ struct pci_controller *phb; /* Associated PHB */
struct device_node *dn; /* Associated device node */ struct device_node *dn; /* Associated device node */
struct pci_dev *pdev; /* Associated PCI device */ struct pci_dev *pdev; /* Associated PCI device */
struct pci_bus *bus; /* PCI bus for partial hotplug */
}; };
static inline struct device_node *eeh_dev_to_of_node(struct eeh_dev *edev) static inline struct device_node *eeh_dev_to_of_node(struct eeh_dev *edev)
...@@ -193,8 +203,10 @@ int eeh_phb_pe_create(struct pci_controller *phb); ...@@ -193,8 +203,10 @@ int eeh_phb_pe_create(struct pci_controller *phb);
struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb); struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb);
struct eeh_pe *eeh_pe_get(struct eeh_dev *edev); struct eeh_pe *eeh_pe_get(struct eeh_dev *edev);
int eeh_add_to_parent_pe(struct eeh_dev *edev); int eeh_add_to_parent_pe(struct eeh_dev *edev);
int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe); int eeh_rmv_from_parent_pe(struct eeh_dev *edev);
void eeh_pe_update_time_stamp(struct eeh_pe *pe); void eeh_pe_update_time_stamp(struct eeh_pe *pe);
void *eeh_pe_traverse(struct eeh_pe *root,
eeh_traverse_func fn, void *flag);
void *eeh_pe_dev_traverse(struct eeh_pe *root, void *eeh_pe_dev_traverse(struct eeh_pe *root,
eeh_traverse_func fn, void *flag); eeh_traverse_func fn, void *flag);
void eeh_pe_restore_bars(struct eeh_pe *pe); void eeh_pe_restore_bars(struct eeh_pe *pe);
...@@ -209,10 +221,12 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, ...@@ -209,10 +221,12 @@ unsigned long eeh_check_failure(const volatile void __iomem *token,
unsigned long val); unsigned long val);
int eeh_dev_check_failure(struct eeh_dev *edev); int eeh_dev_check_failure(struct eeh_dev *edev);
void eeh_addr_cache_build(void); void eeh_addr_cache_build(void);
void eeh_add_device_early(struct device_node *);
void eeh_add_device_tree_early(struct device_node *); void eeh_add_device_tree_early(struct device_node *);
void eeh_add_device_late(struct pci_dev *);
void eeh_add_device_tree_late(struct pci_bus *); void eeh_add_device_tree_late(struct pci_bus *);
void eeh_add_sysfs_files(struct pci_bus *); void eeh_add_sysfs_files(struct pci_bus *);
void eeh_remove_bus_device(struct pci_dev *, int); void eeh_remove_device(struct pci_dev *);
/** /**
* EEH_POSSIBLE_ERROR() -- test for possible MMIO failure. * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
...@@ -252,13 +266,17 @@ static inline unsigned long eeh_check_failure(const volatile void __iomem *token ...@@ -252,13 +266,17 @@ static inline unsigned long eeh_check_failure(const volatile void __iomem *token
static inline void eeh_addr_cache_build(void) { } static inline void eeh_addr_cache_build(void) { }
static inline void eeh_add_device_early(struct device_node *dn) { }
static inline void eeh_add_device_tree_early(struct device_node *dn) { } static inline void eeh_add_device_tree_early(struct device_node *dn) { }
static inline void eeh_add_device_late(struct pci_dev *dev) { }
static inline void eeh_add_device_tree_late(struct pci_bus *bus) { } static inline void eeh_add_device_tree_late(struct pci_bus *bus) { }
static inline void eeh_add_sysfs_files(struct pci_bus *bus) { } static inline void eeh_add_sysfs_files(struct pci_bus *bus) { }
static inline void eeh_remove_bus_device(struct pci_dev *dev, int purge_pe) { } static inline void eeh_remove_device(struct pci_dev *dev) { }
#define EEH_POSSIBLE_ERROR(val, type) (0) #define EEH_POSSIBLE_ERROR(val, type) (0)
#define EEH_IO_ERROR_VALUE(size) (-1UL) #define EEH_IO_ERROR_VALUE(size) (-1UL)
......
...@@ -96,10 +96,11 @@ static inline bool arch_irqs_disabled(void) ...@@ -96,10 +96,11 @@ static inline bool arch_irqs_disabled(void)
#endif #endif
#define hard_irq_disable() do { \ #define hard_irq_disable() do { \
u8 _was_enabled = get_paca()->soft_enabled; \ u8 _was_enabled; \
__hard_irq_disable(); \ __hard_irq_disable(); \
get_paca()->soft_enabled = 0; \ _was_enabled = local_paca->soft_enabled; \
get_paca()->irq_happened |= PACA_IRQ_HARD_DIS; \ local_paca->soft_enabled = 0; \
local_paca->irq_happened |= PACA_IRQ_HARD_DIS; \
if (_was_enabled) \ if (_was_enabled) \
trace_hardirqs_off(); \ trace_hardirqs_off(); \
} while(0) } while(0)
......
...@@ -82,10 +82,9 @@ struct exception_table_entry; ...@@ -82,10 +82,9 @@ struct exception_table_entry;
void sort_ex_table(struct exception_table_entry *start, void sort_ex_table(struct exception_table_entry *start,
struct exception_table_entry *finish); struct exception_table_entry *finish);
#ifdef CONFIG_MODVERSIONS #if defined(CONFIG_MODVERSIONS) && defined(CONFIG_PPC64)
#define ARCH_RELOCATES_KCRCTAB #define ARCH_RELOCATES_KCRCTAB
#define reloc_start PHYSICAL_START
extern const unsigned long reloc_start[];
#endif #endif
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_MODULE_H */ #endif /* _ASM_POWERPC_MODULE_H */
...@@ -209,7 +209,6 @@ static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn) ...@@ -209,7 +209,6 @@ static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn)
extern struct pci_bus *pcibios_find_pci_bus(struct device_node *dn); extern struct pci_bus *pcibios_find_pci_bus(struct device_node *dn);
/** Remove all of the PCI devices under this bus */ /** Remove all of the PCI devices under this bus */
extern void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe);
extern void pcibios_remove_pci_devices(struct pci_bus *bus); extern void pcibios_remove_pci_devices(struct pci_bus *bus);
/** Discover new pci devices under this bus, and add them */ /** Discover new pci devices under this bus, and add them */
......
...@@ -1088,7 +1088,8 @@ ...@@ -1088,7 +1088,8 @@
#define PVR_970MP 0x0044 #define PVR_970MP 0x0044
#define PVR_970GX 0x0045 #define PVR_970GX 0x0045
#define PVR_POWER7p 0x004A #define PVR_POWER7p 0x004A
#define PVR_POWER8 0x004B #define PVR_POWER8E 0x004B
#define PVR_POWER8 0x004D
#define PVR_BE 0x0070 #define PVR_BE 0x0070
#define PVR_PA6T 0x0090 #define PVR_PA6T 0x0090
......
...@@ -494,9 +494,27 @@ static struct cpu_spec __initdata cpu_specs[] = { ...@@ -494,9 +494,27 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_restore = __restore_cpu_power7, .cpu_restore = __restore_cpu_power7,
.platform = "power7+", .platform = "power7+",
}, },
{ /* Power8 */ { /* Power8E */
.pvr_mask = 0xffff0000, .pvr_mask = 0xffff0000,
.pvr_value = 0x004b0000, .pvr_value = 0x004b0000,
.cpu_name = "POWER8E (raw)",
.cpu_features = CPU_FTRS_POWER8,
.cpu_user_features = COMMON_USER_POWER8,
.cpu_user_features2 = COMMON_USER2_POWER8,
.mmu_features = MMU_FTRS_POWER8,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
.pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/power8",
.oprofile_type = PPC_OPROFILE_INVALID,
.cpu_setup = __setup_cpu_power8,
.cpu_restore = __restore_cpu_power8,
.platform = "power8",
},
{ /* Power8 */
.pvr_mask = 0xffff0000,
.pvr_value = 0x004d0000,
.cpu_name = "POWER8 (raw)", .cpu_name = "POWER8 (raw)",
.cpu_features = CPU_FTRS_POWER8, .cpu_features = CPU_FTRS_POWER8,
.cpu_user_features = COMMON_USER_POWER8, .cpu_user_features = COMMON_USER_POWER8,
......
...@@ -231,7 +231,7 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) ...@@ -231,7 +231,7 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
void eeh_slot_error_detail(struct eeh_pe *pe, int severity) void eeh_slot_error_detail(struct eeh_pe *pe, int severity)
{ {
size_t loglen = 0; size_t loglen = 0;
struct eeh_dev *edev; struct eeh_dev *edev, *tmp;
bool valid_cfg_log = true; bool valid_cfg_log = true;
/* /*
...@@ -251,7 +251,7 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity) ...@@ -251,7 +251,7 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity)
eeh_pe_restore_bars(pe); eeh_pe_restore_bars(pe);
pci_regs_buf[0] = 0; pci_regs_buf[0] = 0;
eeh_pe_for_each_dev(pe, edev) { eeh_pe_for_each_dev(pe, edev, tmp) {
loglen += eeh_gather_pci_data(edev, pci_regs_buf + loglen, loglen += eeh_gather_pci_data(edev, pci_regs_buf + loglen,
EEH_PCI_REGS_LOG_LEN - loglen); EEH_PCI_REGS_LOG_LEN - loglen);
} }
...@@ -499,8 +499,6 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon ...@@ -499,8 +499,6 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon
} }
eeh_dev_check_failure(edev); eeh_dev_check_failure(edev);
pci_dev_put(eeh_dev_to_pci_dev(edev));
return val; return val;
} }
...@@ -838,7 +836,7 @@ core_initcall_sync(eeh_init); ...@@ -838,7 +836,7 @@ core_initcall_sync(eeh_init);
* on the CEC architecture, type of the device, on earlier boot * on the CEC architecture, type of the device, on earlier boot
* command-line arguments & etc. * command-line arguments & etc.
*/ */
static void eeh_add_device_early(struct device_node *dn) void eeh_add_device_early(struct device_node *dn)
{ {
struct pci_controller *phb; struct pci_controller *phb;
...@@ -886,7 +884,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); ...@@ -886,7 +884,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_early);
* This routine must be used to complete EEH initialization for PCI * This routine must be used to complete EEH initialization for PCI
* devices that were added after system boot (e.g. hotplug, dlpar). * devices that were added after system boot (e.g. hotplug, dlpar).
*/ */
static void eeh_add_device_late(struct pci_dev *dev) void eeh_add_device_late(struct pci_dev *dev)
{ {
struct device_node *dn; struct device_node *dn;
struct eeh_dev *edev; struct eeh_dev *edev;
...@@ -902,9 +900,23 @@ static void eeh_add_device_late(struct pci_dev *dev) ...@@ -902,9 +900,23 @@ static void eeh_add_device_late(struct pci_dev *dev)
pr_debug("EEH: Already referenced !\n"); pr_debug("EEH: Already referenced !\n");
return; return;
} }
WARN_ON(edev->pdev);
pci_dev_get(dev); /*
* The EEH cache might not be removed correctly because of
* unbalanced kref to the device during unplug time, which
* relies on pcibios_release_device(). So we have to remove
* that here explicitly.
*/
if (edev->pdev) {
eeh_rmv_from_parent_pe(edev);
eeh_addr_cache_rmv_dev(edev->pdev);
eeh_sysfs_remove_device(edev->pdev);
edev->mode &= ~EEH_DEV_SYSFS;
edev->pdev = NULL;
dev->dev.archdata.edev = NULL;
}
edev->pdev = dev; edev->pdev = dev;
dev->dev.archdata.edev = edev; dev->dev.archdata.edev = edev;
...@@ -967,7 +979,6 @@ EXPORT_SYMBOL_GPL(eeh_add_sysfs_files); ...@@ -967,7 +979,6 @@ EXPORT_SYMBOL_GPL(eeh_add_sysfs_files);
/** /**
* eeh_remove_device - Undo EEH setup for the indicated pci device * eeh_remove_device - Undo EEH setup for the indicated pci device
* @dev: pci device to be removed * @dev: pci device to be removed
* @purge_pe: remove the PE or not
* *
* This routine should be called when a device is removed from * This routine should be called when a device is removed from
* a running system (e.g. by hotplug or dlpar). It unregisters * a running system (e.g. by hotplug or dlpar). It unregisters
...@@ -975,7 +986,7 @@ EXPORT_SYMBOL_GPL(eeh_add_sysfs_files); ...@@ -975,7 +986,7 @@ EXPORT_SYMBOL_GPL(eeh_add_sysfs_files);
* this device will no longer be detected after this call; thus, * this device will no longer be detected after this call; thus,
* i/o errors affecting this slot may leave this device unusable. * i/o errors affecting this slot may leave this device unusable.
*/ */
static void eeh_remove_device(struct pci_dev *dev, int purge_pe) void eeh_remove_device(struct pci_dev *dev)
{ {
struct eeh_dev *edev; struct eeh_dev *edev;
...@@ -986,42 +997,29 @@ static void eeh_remove_device(struct pci_dev *dev, int purge_pe) ...@@ -986,42 +997,29 @@ static void eeh_remove_device(struct pci_dev *dev, int purge_pe)
/* Unregister the device with the EEH/PCI address search system */ /* Unregister the device with the EEH/PCI address search system */
pr_debug("EEH: Removing device %s\n", pci_name(dev)); pr_debug("EEH: Removing device %s\n", pci_name(dev));
if (!edev || !edev->pdev) { if (!edev || !edev->pdev || !edev->pe) {
pr_debug("EEH: Not referenced !\n"); pr_debug("EEH: Not referenced !\n");
return; return;
} }
/*
* During the hotplug for EEH error recovery, we need the EEH
* device attached to the parent PE in order for BAR restore
* a bit later. So we keep it for BAR restore and remove it
* from the parent PE during the BAR resotre.
*/
edev->pdev = NULL; edev->pdev = NULL;
dev->dev.archdata.edev = NULL; dev->dev.archdata.edev = NULL;
pci_dev_put(dev); if (!(edev->pe->state & EEH_PE_KEEP))
eeh_rmv_from_parent_pe(edev);
else
edev->mode |= EEH_DEV_DISCONNECTED;
eeh_rmv_from_parent_pe(edev, purge_pe);
eeh_addr_cache_rmv_dev(dev); eeh_addr_cache_rmv_dev(dev);
eeh_sysfs_remove_device(dev); eeh_sysfs_remove_device(dev);
edev->mode &= ~EEH_DEV_SYSFS;
} }
/**
* eeh_remove_bus_device - Undo EEH setup for the indicated PCI device
* @dev: PCI device
* @purge_pe: remove the corresponding PE or not
*
* This routine must be called when a device is removed from the
* running system through hotplug or dlpar. The corresponding
* PCI address cache will be removed.
*/
void eeh_remove_bus_device(struct pci_dev *dev, int purge_pe)
{
struct pci_bus *bus = dev->subordinate;
struct pci_dev *child, *tmp;
eeh_remove_device(dev, purge_pe);
if (bus && dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
list_for_each_entry_safe(child, tmp, &bus->devices, bus_list)
eeh_remove_bus_device(child, purge_pe);
}
}
EXPORT_SYMBOL_GPL(eeh_remove_bus_device);
static int proc_eeh_show(struct seq_file *m, void *v) static int proc_eeh_show(struct seq_file *m, void *v)
{ {
if (0 == eeh_subsystem_enabled) { if (0 == eeh_subsystem_enabled) {
......
...@@ -68,16 +68,12 @@ static inline struct eeh_dev *__eeh_addr_cache_get_device(unsigned long addr) ...@@ -68,16 +68,12 @@ static inline struct eeh_dev *__eeh_addr_cache_get_device(unsigned long addr)
struct pci_io_addr_range *piar; struct pci_io_addr_range *piar;
piar = rb_entry(n, struct pci_io_addr_range, rb_node); piar = rb_entry(n, struct pci_io_addr_range, rb_node);
if (addr < piar->addr_lo) { if (addr < piar->addr_lo)
n = n->rb_left; n = n->rb_left;
} else { else if (addr > piar->addr_hi)
if (addr > piar->addr_hi) { n = n->rb_right;
n = n->rb_right; else
} else { return piar->edev;
pci_dev_get(piar->pcidev);
return piar->edev;
}
}
} }
return NULL; return NULL;
...@@ -156,7 +152,6 @@ eeh_addr_cache_insert(struct pci_dev *dev, unsigned long alo, ...@@ -156,7 +152,6 @@ eeh_addr_cache_insert(struct pci_dev *dev, unsigned long alo,
if (!piar) if (!piar)
return NULL; return NULL;
pci_dev_get(dev);
piar->addr_lo = alo; piar->addr_lo = alo;
piar->addr_hi = ahi; piar->addr_hi = ahi;
piar->edev = pci_dev_to_eeh_dev(dev); piar->edev = pci_dev_to_eeh_dev(dev);
...@@ -250,7 +245,6 @@ static inline void __eeh_addr_cache_rmv_dev(struct pci_dev *dev) ...@@ -250,7 +245,6 @@ static inline void __eeh_addr_cache_rmv_dev(struct pci_dev *dev)
if (piar->pcidev == dev) { if (piar->pcidev == dev) {
rb_erase(n, &pci_io_addr_cache_root.rb_root); rb_erase(n, &pci_io_addr_cache_root.rb_root);
pci_dev_put(piar->pcidev);
kfree(piar); kfree(piar);
goto restart; goto restart;
} }
...@@ -302,12 +296,10 @@ void eeh_addr_cache_build(void) ...@@ -302,12 +296,10 @@ void eeh_addr_cache_build(void)
if (!edev) if (!edev)
continue; continue;
pci_dev_get(dev); /* matching put is in eeh_remove_device() */
dev->dev.archdata.edev = edev; dev->dev.archdata.edev = edev;
edev->pdev = dev; edev->pdev = dev;
eeh_addr_cache_insert_dev(dev); eeh_addr_cache_insert_dev(dev);
eeh_sysfs_add_device(dev); eeh_sysfs_add_device(dev);
} }
......
...@@ -143,10 +143,14 @@ static void eeh_disable_irq(struct pci_dev *dev) ...@@ -143,10 +143,14 @@ static void eeh_disable_irq(struct pci_dev *dev)
static void eeh_enable_irq(struct pci_dev *dev) static void eeh_enable_irq(struct pci_dev *dev)
{ {
struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); struct eeh_dev *edev = pci_dev_to_eeh_dev(dev);
struct irq_desc *desc;
if ((edev->mode) & EEH_DEV_IRQ_DISABLED) { if ((edev->mode) & EEH_DEV_IRQ_DISABLED) {
edev->mode &= ~EEH_DEV_IRQ_DISABLED; edev->mode &= ~EEH_DEV_IRQ_DISABLED;
enable_irq(dev->irq);
desc = irq_to_desc(dev->irq);
if (desc && desc->depth > 0)
enable_irq(dev->irq);
} }
} }
...@@ -338,6 +342,54 @@ static void *eeh_report_failure(void *data, void *userdata) ...@@ -338,6 +342,54 @@ static void *eeh_report_failure(void *data, void *userdata)
return NULL; return NULL;
} }
static void *eeh_rmv_device(void *data, void *userdata)
{
struct pci_driver *driver;
struct eeh_dev *edev = (struct eeh_dev *)data;
struct pci_dev *dev = eeh_dev_to_pci_dev(edev);
int *removed = (int *)userdata;
/*
* Actually, we should remove the PCI bridges as well.
* However, that's lots of complexity to do that,
* particularly some of devices under the bridge might
* support EEH. So we just care about PCI devices for
* simplicity here.
*/
if (!dev || (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE))
return NULL;
driver = eeh_pcid_get(dev);
if (driver && driver->err_handler)
return NULL;
/* Remove it from PCI subsystem */
pr_debug("EEH: Removing %s without EEH sensitive driver\n",
pci_name(dev));
edev->bus = dev->bus;
edev->mode |= EEH_DEV_DISCONNECTED;
(*removed)++;
pci_stop_and_remove_bus_device(dev);
return NULL;
}
static void *eeh_pe_detach_dev(void *data, void *userdata)
{
struct eeh_pe *pe = (struct eeh_pe *)data;
struct eeh_dev *edev, *tmp;
eeh_pe_for_each_dev(pe, edev, tmp) {
if (!(edev->mode & EEH_DEV_DISCONNECTED))
continue;
edev->mode &= ~(EEH_DEV_DISCONNECTED | EEH_DEV_IRQ_DISABLED);
eeh_rmv_from_parent_pe(edev);
}
return NULL;
}
/** /**
* eeh_reset_device - Perform actual reset of a pci slot * eeh_reset_device - Perform actual reset of a pci slot
* @pe: EEH PE * @pe: EEH PE
...@@ -349,8 +401,9 @@ static void *eeh_report_failure(void *data, void *userdata) ...@@ -349,8 +401,9 @@ static void *eeh_report_failure(void *data, void *userdata)
*/ */
static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
{ {
struct pci_bus *frozen_bus = eeh_pe_bus_get(pe);
struct timeval tstamp; struct timeval tstamp;
int cnt, rc; int cnt, rc, removed = 0;
/* pcibios will clear the counter; save the value */ /* pcibios will clear the counter; save the value */
cnt = pe->freeze_count; cnt = pe->freeze_count;
...@@ -362,8 +415,11 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) ...@@ -362,8 +415,11 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
* devices are expected to be attached soon when calling * devices are expected to be attached soon when calling
* into pcibios_add_pci_devices(). * into pcibios_add_pci_devices().
*/ */
eeh_pe_state_mark(pe, EEH_PE_KEEP);
if (bus) if (bus)
__pcibios_remove_pci_devices(bus, 0); pcibios_remove_pci_devices(bus);
else if (frozen_bus)
eeh_pe_dev_traverse(pe, eeh_rmv_device, &removed);
/* Reset the pci controller. (Asserts RST#; resets config space). /* Reset the pci controller. (Asserts RST#; resets config space).
* Reconfigure bridges and devices. Don't try to bring the system * Reconfigure bridges and devices. Don't try to bring the system
...@@ -384,9 +440,24 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) ...@@ -384,9 +440,24 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
* potentially weird things happen. * potentially weird things happen.
*/ */
if (bus) { if (bus) {
pr_info("EEH: Sleep 5s ahead of complete hotplug\n");
ssleep(5); ssleep(5);
/*
* The EEH device is still connected with its parent
* PE. We should disconnect it so the binding can be
* rebuilt when adding PCI devices.
*/
eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL);
pcibios_add_pci_devices(bus); pcibios_add_pci_devices(bus);
} else if (frozen_bus && removed) {
pr_info("EEH: Sleep 5s ahead of partial hotplug\n");
ssleep(5);
eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL);
pcibios_add_pci_devices(frozen_bus);
} }
eeh_pe_state_clear(pe, EEH_PE_KEEP);
pe->tstamp = tstamp; pe->tstamp = tstamp;
pe->freeze_count = cnt; pe->freeze_count = cnt;
......
...@@ -149,8 +149,8 @@ static struct eeh_pe *eeh_pe_next(struct eeh_pe *pe, ...@@ -149,8 +149,8 @@ static struct eeh_pe *eeh_pe_next(struct eeh_pe *pe,
* callback returns something other than NULL, or no more PEs * callback returns something other than NULL, or no more PEs
* to be traversed. * to be traversed.
*/ */
static void *eeh_pe_traverse(struct eeh_pe *root, void *eeh_pe_traverse(struct eeh_pe *root,
eeh_traverse_func fn, void *flag) eeh_traverse_func fn, void *flag)
{ {
struct eeh_pe *pe; struct eeh_pe *pe;
void *ret; void *ret;
...@@ -176,7 +176,7 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root, ...@@ -176,7 +176,7 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root,
eeh_traverse_func fn, void *flag) eeh_traverse_func fn, void *flag)
{ {
struct eeh_pe *pe; struct eeh_pe *pe;
struct eeh_dev *edev; struct eeh_dev *edev, *tmp;
void *ret; void *ret;
if (!root) { if (!root) {
...@@ -186,7 +186,7 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root, ...@@ -186,7 +186,7 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root,
/* Traverse root PE */ /* Traverse root PE */
for (pe = root; pe; pe = eeh_pe_next(pe, root)) { for (pe = root; pe; pe = eeh_pe_next(pe, root)) {
eeh_pe_for_each_dev(pe, edev) { eeh_pe_for_each_dev(pe, edev, tmp) {
ret = fn(edev, flag); ret = fn(edev, flag);
if (ret) if (ret)
return ret; return ret;
...@@ -333,7 +333,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev) ...@@ -333,7 +333,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
while (parent) { while (parent) {
if (!(parent->type & EEH_PE_INVALID)) if (!(parent->type & EEH_PE_INVALID))
break; break;
parent->type &= ~EEH_PE_INVALID; parent->type &= ~(EEH_PE_INVALID | EEH_PE_KEEP);
parent = parent->parent; parent = parent->parent;
} }
pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n", pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n",
...@@ -397,21 +397,20 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev) ...@@ -397,21 +397,20 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
/** /**
* eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE * eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE
* @edev: EEH device * @edev: EEH device
* @purge_pe: remove PE or not
* *
* The PE hierarchy tree might be changed when doing PCI hotplug. * The PE hierarchy tree might be changed when doing PCI hotplug.
* Also, the PCI devices or buses could be removed from the system * Also, the PCI devices or buses could be removed from the system
* during EEH recovery. So we have to call the function remove the * during EEH recovery. So we have to call the function remove the
* corresponding PE accordingly if necessary. * corresponding PE accordingly if necessary.
*/ */
int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe) int eeh_rmv_from_parent_pe(struct eeh_dev *edev)
{ {
struct eeh_pe *pe, *parent, *child; struct eeh_pe *pe, *parent, *child;
int cnt; int cnt;
if (!edev->pe) { if (!edev->pe) {
pr_warning("%s: No PE found for EEH device %s\n", pr_debug("%s: No PE found for EEH device %s\n",
__func__, edev->dn->full_name); __func__, edev->dn->full_name);
return -EEXIST; return -EEXIST;
} }
...@@ -431,7 +430,7 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe) ...@@ -431,7 +430,7 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe)
if (pe->type & EEH_PE_PHB) if (pe->type & EEH_PE_PHB)
break; break;
if (purge_pe) { if (!(pe->state & EEH_PE_KEEP)) {
if (list_empty(&pe->edevs) && if (list_empty(&pe->edevs) &&
list_empty(&pe->child_list)) { list_empty(&pe->child_list)) {
list_del(&pe->child); list_del(&pe->child);
...@@ -502,7 +501,7 @@ static void *__eeh_pe_state_mark(void *data, void *flag) ...@@ -502,7 +501,7 @@ static void *__eeh_pe_state_mark(void *data, void *flag)
{ {
struct eeh_pe *pe = (struct eeh_pe *)data; struct eeh_pe *pe = (struct eeh_pe *)data;
int state = *((int *)flag); int state = *((int *)flag);
struct eeh_dev *tmp; struct eeh_dev *edev, *tmp;
struct pci_dev *pdev; struct pci_dev *pdev;
/* /*
...@@ -512,8 +511,8 @@ static void *__eeh_pe_state_mark(void *data, void *flag) ...@@ -512,8 +511,8 @@ static void *__eeh_pe_state_mark(void *data, void *flag)
* the PCI device driver. * the PCI device driver.
*/ */
pe->state |= state; pe->state |= state;
eeh_pe_for_each_dev(pe, tmp) { eeh_pe_for_each_dev(pe, edev, tmp) {
pdev = eeh_dev_to_pci_dev(tmp); pdev = eeh_dev_to_pci_dev(edev);
if (pdev) if (pdev)
pdev->error_state = pci_channel_io_frozen; pdev->error_state = pci_channel_io_frozen;
} }
...@@ -579,7 +578,7 @@ void eeh_pe_state_clear(struct eeh_pe *pe, int state) ...@@ -579,7 +578,7 @@ void eeh_pe_state_clear(struct eeh_pe *pe, int state)
* blocked on normal path during the stage. So we need utilize * blocked on normal path during the stage. So we need utilize
* eeh operations, which is always permitted. * eeh operations, which is always permitted.
*/ */
static void eeh_bridge_check_link(struct pci_dev *pdev, static void eeh_bridge_check_link(struct eeh_dev *edev,
struct device_node *dn) struct device_node *dn)
{ {
int cap; int cap;
...@@ -590,16 +589,17 @@ static void eeh_bridge_check_link(struct pci_dev *pdev, ...@@ -590,16 +589,17 @@ static void eeh_bridge_check_link(struct pci_dev *pdev,
* We only check root port and downstream ports of * We only check root port and downstream ports of
* PCIe switches * PCIe switches
*/ */
if (!pci_is_pcie(pdev) || if (!(edev->mode & (EEH_DEV_ROOT_PORT | EEH_DEV_DS_PORT)))
(pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT &&
pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM))
return; return;
pr_debug("%s: Check PCIe link for %s ...\n", pr_debug("%s: Check PCIe link for %04x:%02x:%02x.%01x ...\n",
__func__, pci_name(pdev)); __func__, edev->phb->global_number,
edev->config_addr >> 8,
PCI_SLOT(edev->config_addr & 0xFF),
PCI_FUNC(edev->config_addr & 0xFF));
/* Check slot status */ /* Check slot status */
cap = pdev->pcie_cap; cap = edev->pcie_cap;
eeh_ops->read_config(dn, cap + PCI_EXP_SLTSTA, 2, &val); eeh_ops->read_config(dn, cap + PCI_EXP_SLTSTA, 2, &val);
if (!(val & PCI_EXP_SLTSTA_PDS)) { if (!(val & PCI_EXP_SLTSTA_PDS)) {
pr_debug(" No card in the slot (0x%04x) !\n", val); pr_debug(" No card in the slot (0x%04x) !\n", val);
...@@ -653,8 +653,7 @@ static void eeh_bridge_check_link(struct pci_dev *pdev, ...@@ -653,8 +653,7 @@ static void eeh_bridge_check_link(struct pci_dev *pdev,
#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) #define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)])
static void eeh_restore_bridge_bars(struct pci_dev *pdev, static void eeh_restore_bridge_bars(struct eeh_dev *edev,
struct eeh_dev *edev,
struct device_node *dn) struct device_node *dn)
{ {
int i; int i;
...@@ -680,7 +679,7 @@ static void eeh_restore_bridge_bars(struct pci_dev *pdev, ...@@ -680,7 +679,7 @@ static void eeh_restore_bridge_bars(struct pci_dev *pdev,
eeh_ops->write_config(dn, PCI_COMMAND, 4, edev->config_space[1]); eeh_ops->write_config(dn, PCI_COMMAND, 4, edev->config_space[1]);
/* Check the PCIe link is ready */ /* Check the PCIe link is ready */
eeh_bridge_check_link(pdev, dn); eeh_bridge_check_link(edev, dn);
} }
static void eeh_restore_device_bars(struct eeh_dev *edev, static void eeh_restore_device_bars(struct eeh_dev *edev,
...@@ -729,19 +728,12 @@ static void eeh_restore_device_bars(struct eeh_dev *edev, ...@@ -729,19 +728,12 @@ static void eeh_restore_device_bars(struct eeh_dev *edev,
*/ */
static void *eeh_restore_one_device_bars(void *data, void *flag) static void *eeh_restore_one_device_bars(void *data, void *flag)
{ {
struct pci_dev *pdev = NULL;
struct eeh_dev *edev = (struct eeh_dev *)data; struct eeh_dev *edev = (struct eeh_dev *)data;
struct device_node *dn = eeh_dev_to_of_node(edev); struct device_node *dn = eeh_dev_to_of_node(edev);
/* Trace the PCI bridge */ /* Do special restore for bridges */
if (eeh_probe_mode_dev()) { if (edev->mode & EEH_DEV_BRIDGE)
pdev = eeh_dev_to_pci_dev(edev); eeh_restore_bridge_bars(edev, dn);
if (pdev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
pdev = NULL;
}
if (pdev)
eeh_restore_bridge_bars(pdev, edev, dn);
else else
eeh_restore_device_bars(edev, dn); eeh_restore_device_bars(edev, dn);
......
...@@ -56,19 +56,40 @@ EEH_SHOW_ATTR(eeh_pe_config_addr, pe_config_addr, "0x%x"); ...@@ -56,19 +56,40 @@ EEH_SHOW_ATTR(eeh_pe_config_addr, pe_config_addr, "0x%x");
void eeh_sysfs_add_device(struct pci_dev *pdev) void eeh_sysfs_add_device(struct pci_dev *pdev)
{ {
struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
int rc=0; int rc=0;
if (edev && (edev->mode & EEH_DEV_SYSFS))
return;
rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode); rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode);
rc += device_create_file(&pdev->dev, &dev_attr_eeh_config_addr); rc += device_create_file(&pdev->dev, &dev_attr_eeh_config_addr);
rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
if (rc) if (rc)
printk(KERN_WARNING "EEH: Unable to create sysfs entries\n"); printk(KERN_WARNING "EEH: Unable to create sysfs entries\n");
else if (edev)
edev->mode |= EEH_DEV_SYSFS;
} }
void eeh_sysfs_remove_device(struct pci_dev *pdev) void eeh_sysfs_remove_device(struct pci_dev *pdev)
{ {
struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
/*
* The parent directory might have been removed. We needn't
* continue for that case.
*/
if (!pdev->dev.kobj.sd) {
if (edev)
edev->mode &= ~EEH_DEV_SYSFS;
return;
}
device_remove_file(&pdev->dev, &dev_attr_eeh_mode); device_remove_file(&pdev->dev, &dev_attr_eeh_mode);
device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr); device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr);
device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr); device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
if (edev)
edev->mode &= ~EEH_DEV_SYSFS;
} }
...@@ -1462,6 +1462,8 @@ void pcibios_finish_adding_to_bus(struct pci_bus *bus) ...@@ -1462,6 +1462,8 @@ void pcibios_finish_adding_to_bus(struct pci_bus *bus)
/* Allocate bus and devices resources */ /* Allocate bus and devices resources */
pcibios_allocate_bus_resources(bus); pcibios_allocate_bus_resources(bus);
pcibios_claim_one_bus(bus); pcibios_claim_one_bus(bus);
if (!pci_has_flag(PCI_PROBE_ONLY))
pci_assign_unassigned_bus_resources(bus);
/* Fixup EEH */ /* Fixup EEH */
eeh_add_device_tree_late(bus); eeh_add_device_tree_late(bus);
......
...@@ -22,45 +22,40 @@ ...@@ -22,45 +22,40 @@
#include <asm/eeh.h> #include <asm/eeh.h>
/** /**
* __pcibios_remove_pci_devices - remove all devices under this bus * pcibios_release_device - release PCI device
* @dev: PCI device
*
* The function is called before releasing the indicated PCI device.
*/
void pcibios_release_device(struct pci_dev *dev)
{
eeh_remove_device(dev);
}
/**
* pcibios_remove_pci_devices - remove all devices under this bus
* @bus: the indicated PCI bus * @bus: the indicated PCI bus
* @purge_pe: destroy the PE on removal of PCI devices
* *
* Remove all of the PCI devices under this bus both from the * Remove all of the PCI devices under this bus both from the
* linux pci device tree, and from the powerpc EEH address cache. * linux pci device tree, and from the powerpc EEH address cache.
* By default, the corresponding PE will be destroied during the
* normal PCI hotplug path. For PCI hotplug during EEH recovery,
* the corresponding PE won't be destroied and deallocated.
*/ */
void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe) void pcibios_remove_pci_devices(struct pci_bus *bus)
{ {
struct pci_dev *dev, *tmp; struct pci_dev *dev, *tmp;
struct pci_bus *child_bus; struct pci_bus *child_bus;
/* First go down child busses */ /* First go down child busses */
list_for_each_entry(child_bus, &bus->children, node) list_for_each_entry(child_bus, &bus->children, node)
__pcibios_remove_pci_devices(child_bus, purge_pe); pcibios_remove_pci_devices(child_bus);
pr_debug("PCI: Removing devices on bus %04x:%02x\n", pr_debug("PCI: Removing devices on bus %04x:%02x\n",
pci_domain_nr(bus), bus->number); pci_domain_nr(bus), bus->number);
list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) { list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
pr_debug(" * Removing %s...\n", pci_name(dev)); pr_debug(" Removing %s...\n", pci_name(dev));
eeh_remove_bus_device(dev, purge_pe);
pci_stop_and_remove_bus_device(dev); pci_stop_and_remove_bus_device(dev);
} }
} }
/**
* pcibios_remove_pci_devices - remove all devices under this bus
* @bus: the indicated PCI bus
*
* Remove all of the PCI devices under this bus both from the
* linux pci device tree, and from the powerpc EEH address cache.
*/
void pcibios_remove_pci_devices(struct pci_bus *bus)
{
__pcibios_remove_pci_devices(bus, 1);
}
EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
/** /**
...@@ -76,7 +71,7 @@ EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); ...@@ -76,7 +71,7 @@ EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
*/ */
void pcibios_add_pci_devices(struct pci_bus * bus) void pcibios_add_pci_devices(struct pci_bus * bus)
{ {
int slotno, num, mode, pass, max; int slotno, mode, pass, max;
struct pci_dev *dev; struct pci_dev *dev;
struct device_node *dn = pci_bus_to_OF_node(bus); struct device_node *dn = pci_bus_to_OF_node(bus);
...@@ -90,11 +85,15 @@ void pcibios_add_pci_devices(struct pci_bus * bus) ...@@ -90,11 +85,15 @@ void pcibios_add_pci_devices(struct pci_bus * bus)
/* use ofdt-based probe */ /* use ofdt-based probe */
of_rescan_bus(dn, bus); of_rescan_bus(dn, bus);
} else if (mode == PCI_PROBE_NORMAL) { } else if (mode == PCI_PROBE_NORMAL) {
/* use legacy probe */ /*
* Use legacy probe. In the partial hotplug case, we
* probably have grandchildren devices unplugged. So
* we don't check the return value from pci_scan_slot() in
* order for fully rescan all the way down to pick them up.
* They can have been removed during partial hotplug.
*/
slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
if (!num)
return;
pcibios_setup_bus_devices(bus); pcibios_setup_bus_devices(bus);
max = bus->busn_res.start; max = bus->busn_res.start;
for (pass = 0; pass < 2; pass++) { for (pass = 0; pass < 2; pass++) {
......
...@@ -230,11 +230,14 @@ void of_scan_pci_bridge(struct pci_dev *dev) ...@@ -230,11 +230,14 @@ void of_scan_pci_bridge(struct pci_dev *dev)
return; return;
} }
bus = pci_add_new_bus(dev->bus, dev, busrange[0]); bus = pci_find_bus(pci_domain_nr(dev->bus), busrange[0]);
if (!bus) { if (!bus) {
printk(KERN_ERR "Failed to create pci bus for %s\n", bus = pci_add_new_bus(dev->bus, dev, busrange[0]);
node->full_name); if (!bus) {
return; printk(KERN_ERR "Failed to create pci bus for %s\n",
node->full_name);
return;
}
} }
bus->primary = dev->bus->number; bus->primary = dev->bus->number;
...@@ -292,6 +295,38 @@ void of_scan_pci_bridge(struct pci_dev *dev) ...@@ -292,6 +295,38 @@ void of_scan_pci_bridge(struct pci_dev *dev)
} }
EXPORT_SYMBOL(of_scan_pci_bridge); EXPORT_SYMBOL(of_scan_pci_bridge);
static struct pci_dev *of_scan_pci_dev(struct pci_bus *bus,
struct device_node *dn)
{
struct pci_dev *dev = NULL;
const u32 *reg;
int reglen, devfn;
pr_debug(" * %s\n", dn->full_name);
if (!of_device_is_available(dn))
return NULL;
reg = of_get_property(dn, "reg", &reglen);
if (reg == NULL || reglen < 20)
return NULL;
devfn = (reg[0] >> 8) & 0xff;
/* Check if the PCI device is already there */
dev = pci_get_slot(bus, devfn);
if (dev) {
pci_dev_put(dev);
return dev;
}
/* create a new pci_dev for this device */
dev = of_create_pci_dev(dn, bus, devfn);
if (!dev)
return NULL;
pr_debug(" dev header type: %x\n", dev->hdr_type);
return dev;
}
/** /**
* __of_scan_bus - given a PCI bus node, setup bus and scan for child devices * __of_scan_bus - given a PCI bus node, setup bus and scan for child devices
* @node: device tree node for the PCI bus * @node: device tree node for the PCI bus
...@@ -302,8 +337,6 @@ static void __of_scan_bus(struct device_node *node, struct pci_bus *bus, ...@@ -302,8 +337,6 @@ static void __of_scan_bus(struct device_node *node, struct pci_bus *bus,
int rescan_existing) int rescan_existing)
{ {
struct device_node *child; struct device_node *child;
const u32 *reg;
int reglen, devfn;
struct pci_dev *dev; struct pci_dev *dev;
pr_debug("of_scan_bus(%s) bus no %d...\n", pr_debug("of_scan_bus(%s) bus no %d...\n",
...@@ -311,16 +344,7 @@ static void __of_scan_bus(struct device_node *node, struct pci_bus *bus, ...@@ -311,16 +344,7 @@ static void __of_scan_bus(struct device_node *node, struct pci_bus *bus,
/* Scan direct children */ /* Scan direct children */
for_each_child_of_node(node, child) { for_each_child_of_node(node, child) {
pr_debug(" * %s\n", child->full_name); dev = of_scan_pci_dev(bus, child);
if (!of_device_is_available(child))
continue;
reg = of_get_property(child, "reg", &reglen);
if (reg == NULL || reglen < 20)
continue;
devfn = (reg[0] >> 8) & 0xff;
/* create a new pci_dev for this device */
dev = of_create_pci_dev(child, bus, devfn);
if (!dev) if (!dev)
continue; continue;
pr_debug(" dev header type: %x\n", dev->hdr_type); pr_debug(" dev header type: %x\n", dev->hdr_type);
......
...@@ -644,7 +644,8 @@ unsigned char ibm_architecture_vec[] = { ...@@ -644,7 +644,8 @@ unsigned char ibm_architecture_vec[] = {
W(0xfffe0000), W(0x003a0000), /* POWER5/POWER5+ */ W(0xfffe0000), W(0x003a0000), /* POWER5/POWER5+ */
W(0xffff0000), W(0x003e0000), /* POWER6 */ W(0xffff0000), W(0x003e0000), /* POWER6 */
W(0xffff0000), W(0x003f0000), /* POWER7 */ W(0xffff0000), W(0x003f0000), /* POWER7 */
W(0xffff0000), W(0x004b0000), /* POWER8 */ W(0xffff0000), W(0x004b0000), /* POWER8E */
W(0xffff0000), W(0x004d0000), /* POWER8 */
W(0xffffffff), W(0x0f000004), /* all 2.07-compliant */ W(0xffffffff), W(0x0f000004), /* all 2.07-compliant */
W(0xffffffff), W(0x0f000003), /* all 2.06-compliant */ W(0xffffffff), W(0x0f000003), /* all 2.06-compliant */
W(0xffffffff), W(0x0f000002), /* all 2.05-compliant */ W(0xffffffff), W(0x0f000002), /* all 2.05-compliant */
...@@ -706,7 +707,7 @@ unsigned char ibm_architecture_vec[] = { ...@@ -706,7 +707,7 @@ unsigned char ibm_architecture_vec[] = {
* must match by the macro below. Update the definition if * must match by the macro below. Update the definition if
* the structure layout changes. * the structure layout changes.
*/ */
#define IBM_ARCH_VEC_NRCORES_OFFSET 117 #define IBM_ARCH_VEC_NRCORES_OFFSET 125
W(NR_CPUS), /* number of cores supported */ W(NR_CPUS), /* number of cores supported */
0, 0,
0, 0,
......
...@@ -38,9 +38,6 @@ jiffies = jiffies_64 + 4; ...@@ -38,9 +38,6 @@ jiffies = jiffies_64 + 4;
#endif #endif
SECTIONS SECTIONS
{ {
. = 0;
reloc_start = .;
. = KERNELBASE; . = KERNELBASE;
/* /*
......
...@@ -43,6 +43,7 @@ static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize) ...@@ -43,6 +43,7 @@ static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize)
{ {
unsigned long va; unsigned long va;
unsigned int penc; unsigned int penc;
unsigned long sllp;
/* /*
* We need 14 to 65 bits of va for a tlibe of 4K page * We need 14 to 65 bits of va for a tlibe of 4K page
...@@ -64,7 +65,9 @@ static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize) ...@@ -64,7 +65,9 @@ static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize)
/* clear out bits after (52) [0....52.....63] */ /* clear out bits after (52) [0....52.....63] */
va &= ~((1ul << (64 - 52)) - 1); va &= ~((1ul << (64 - 52)) - 1);
va |= ssize << 8; va |= ssize << 8;
va |= mmu_psize_defs[apsize].sllp << 6; sllp = ((mmu_psize_defs[apsize].sllp & SLB_VSID_L) >> 6) |
((mmu_psize_defs[apsize].sllp & SLB_VSID_LP) >> 4);
va |= sllp << 5;
asm volatile(ASM_FTR_IFCLR("tlbie %0,0", PPC_TLBIE(%1,%0), %2) asm volatile(ASM_FTR_IFCLR("tlbie %0,0", PPC_TLBIE(%1,%0), %2)
: : "r" (va), "r"(0), "i" (CPU_FTR_ARCH_206) : : "r" (va), "r"(0), "i" (CPU_FTR_ARCH_206)
: "memory"); : "memory");
...@@ -98,6 +101,7 @@ static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize) ...@@ -98,6 +101,7 @@ static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize)
{ {
unsigned long va; unsigned long va;
unsigned int penc; unsigned int penc;
unsigned long sllp;
/* VPN_SHIFT can be atmost 12 */ /* VPN_SHIFT can be atmost 12 */
va = vpn << VPN_SHIFT; va = vpn << VPN_SHIFT;
...@@ -113,7 +117,9 @@ static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize) ...@@ -113,7 +117,9 @@ static inline void __tlbiel(unsigned long vpn, int psize, int apsize, int ssize)
/* clear out bits after(52) [0....52.....63] */ /* clear out bits after(52) [0....52.....63] */
va &= ~((1ul << (64 - 52)) - 1); va &= ~((1ul << (64 - 52)) - 1);
va |= ssize << 8; va |= ssize << 8;
va |= mmu_psize_defs[apsize].sllp << 6; sllp = ((mmu_psize_defs[apsize].sllp & SLB_VSID_L) >> 6) |
((mmu_psize_defs[apsize].sllp & SLB_VSID_LP) >> 4);
va |= sllp << 5;
asm volatile(".long 0x7c000224 | (%0 << 11) | (0 << 21)" asm volatile(".long 0x7c000224 | (%0 << 11) | (0 << 21)"
: : "r"(va) : "memory"); : : "r"(va) : "memory");
break; break;
...@@ -554,6 +560,7 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot, ...@@ -554,6 +560,7 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot,
seg_off |= vpi << shift; seg_off |= vpi << shift;
} }
*vpn = vsid << (SID_SHIFT - VPN_SHIFT) | seg_off >> VPN_SHIFT; *vpn = vsid << (SID_SHIFT - VPN_SHIFT) | seg_off >> VPN_SHIFT;
break;
case MMU_SEGSIZE_1T: case MMU_SEGSIZE_1T:
/* We only have 40 - 23 bits of seg_off in avpn */ /* We only have 40 - 23 bits of seg_off in avpn */
seg_off = (avpn & 0x1ffff) << 23; seg_off = (avpn & 0x1ffff) << 23;
...@@ -563,6 +570,7 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot, ...@@ -563,6 +570,7 @@ static void hpte_decode(struct hash_pte *hpte, unsigned long slot,
seg_off |= vpi << shift; seg_off |= vpi << shift;
} }
*vpn = vsid << (SID_SHIFT_1T - VPN_SHIFT) | seg_off >> VPN_SHIFT; *vpn = vsid << (SID_SHIFT_1T - VPN_SHIFT) | seg_off >> VPN_SHIFT;
break;
default: default:
*vpn = size = 0; *vpn = size = 0;
} }
......
...@@ -1252,8 +1252,11 @@ static int power_pmu_add(struct perf_event *event, int ef_flags) ...@@ -1252,8 +1252,11 @@ static int power_pmu_add(struct perf_event *event, int ef_flags)
ret = 0; ret = 0;
out: out:
if (has_branch_stack(event)) if (has_branch_stack(event)) {
power_pmu_bhrb_enable(event); power_pmu_bhrb_enable(event);
cpuhw->bhrb_filter = ppmu->bhrb_filter_map(
event->attr.branch_sample_type);
}
perf_pmu_enable(event->pmu); perf_pmu_enable(event->pmu);
local_irq_restore(flags); local_irq_restore(flags);
......
...@@ -561,18 +561,13 @@ static int power8_generic_events[] = { ...@@ -561,18 +561,13 @@ static int power8_generic_events[] = {
static u64 power8_bhrb_filter_map(u64 branch_sample_type) static u64 power8_bhrb_filter_map(u64 branch_sample_type)
{ {
u64 pmu_bhrb_filter = 0; u64 pmu_bhrb_filter = 0;
u64 br_privilege = branch_sample_type & ONLY_PLM;
/* BHRB and regular PMU events share the same prvillege state /* BHRB and regular PMU events share the same privilege state
* filter configuration. BHRB is always recorded along with a * filter configuration. BHRB is always recorded along with a
* regular PMU event. So privilege state filter criteria for BHRB * regular PMU event. As the privilege state filter is handled
* and the companion PMU events has to be the same. As a default * in the basic PMC configuration of the accompanying regular
* "perf record" tool sets all privillege bits ON when no filter * PMU event, we ignore any separate BHRB specific request.
* criteria is provided in the command line. So as along as all
* privillege bits are ON or they are OFF, we are good to go.
*/ */
if ((br_privilege != 7) && (br_privilege != 0))
return -1;
/* No branch filter requested */ /* No branch filter requested */
if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY) if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY)
...@@ -621,10 +616,19 @@ static struct power_pmu power8_pmu = { ...@@ -621,10 +616,19 @@ static struct power_pmu power8_pmu = {
static int __init init_power8_pmu(void) static int __init init_power8_pmu(void)
{ {
int rc;
if (!cur_cpu_spec->oprofile_cpu_type || if (!cur_cpu_spec->oprofile_cpu_type ||
strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power8")) strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power8"))
return -ENODEV; return -ENODEV;
return register_power_pmu(&power8_pmu); rc = register_power_pmu(&power8_pmu);
if (rc)
return rc;
/* Tell userspace that EBB is supported */
cur_cpu_spec->cpu_user_features2 |= PPC_FEATURE2_EBB;
return 0;
} }
early_initcall(init_power8_pmu); early_initcall(init_power8_pmu);
...@@ -114,7 +114,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag) ...@@ -114,7 +114,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
* the root bridge. So it's not reasonable to continue * the root bridge. So it's not reasonable to continue
* the probing. * the probing.
*/ */
if (!dn || !edev) if (!dn || !edev || edev->pe)
return 0; return 0;
/* Skip for PCI-ISA bridge */ /* Skip for PCI-ISA bridge */
...@@ -122,8 +122,19 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag) ...@@ -122,8 +122,19 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
return 0; return 0;
/* Initialize eeh device */ /* Initialize eeh device */
edev->class_code = dev->class; edev->class_code = dev->class;
edev->mode = 0; edev->mode &= 0xFFFFFF00;
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
edev->mode |= EEH_DEV_BRIDGE;
if (pci_is_pcie(dev)) {
edev->pcie_cap = pci_pcie_cap(dev);
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
edev->mode |= EEH_DEV_ROOT_PORT;
else if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM)
edev->mode |= EEH_DEV_DS_PORT;
}
edev->config_addr = ((dev->bus->number << 8) | dev->devfn); edev->config_addr = ((dev->bus->number << 8) | dev->devfn);
edev->pe_config_addr = phb->bdfn_to_pe(phb, dev->bus, dev->devfn & 0xff); edev->pe_config_addr = phb->bdfn_to_pe(phb, dev->bus, dev->devfn & 0xff);
......
...@@ -1266,7 +1266,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np, ...@@ -1266,7 +1266,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
opal_pci_set_pe(phb_id, 0, 0, 7, 1, 1 , OPAL_MAP_PE); opal_pci_set_pe(phb_id, 0, 0, 7, 1, 1 , OPAL_MAP_PE);
} }
void pnv_pci_init_ioda2_phb(struct device_node *np) void __init pnv_pci_init_ioda2_phb(struct device_node *np)
{ {
pnv_pci_init_ioda_phb(np, 0, PNV_PHB_IODA2); pnv_pci_init_ioda_phb(np, 0, PNV_PHB_IODA2);
} }
......
...@@ -19,7 +19,6 @@ config PPC_PSERIES ...@@ -19,7 +19,6 @@ config PPC_PSERIES
select ZLIB_DEFLATE select ZLIB_DEFLATE
select PPC_DOORBELL select PPC_DOORBELL
select HAVE_CONTEXT_TRACKING select HAVE_CONTEXT_TRACKING
select HOTPLUG if SMP
select HOTPLUG_CPU if SMP select HOTPLUG_CPU if SMP
default y default y
......
...@@ -133,6 +133,48 @@ static int pseries_eeh_init(void) ...@@ -133,6 +133,48 @@ static int pseries_eeh_init(void)
return 0; return 0;
} }
static int pseries_eeh_cap_start(struct device_node *dn)
{
struct pci_dn *pdn = PCI_DN(dn);
u32 status;
if (!pdn)
return 0;
rtas_read_config(pdn, PCI_STATUS, 2, &status);
if (!(status & PCI_STATUS_CAP_LIST))
return 0;
return PCI_CAPABILITY_LIST;
}
static int pseries_eeh_find_cap(struct device_node *dn, int cap)
{
struct pci_dn *pdn = PCI_DN(dn);
int pos = pseries_eeh_cap_start(dn);
int cnt = 48; /* Maximal number of capabilities */
u32 id;
if (!pos)
return 0;
while (cnt--) {
rtas_read_config(pdn, pos, 1, &pos);
if (pos < 0x40)
break;
pos &= ~3;
rtas_read_config(pdn, pos + PCI_CAP_LIST_ID, 1, &id);
if (id == 0xff)
break;
if (id == cap)
return pos;
pos += PCI_CAP_LIST_NEXT;
}
return 0;
}
/** /**
* pseries_eeh_of_probe - EEH probe on the given device * pseries_eeh_of_probe - EEH probe on the given device
* @dn: OF node * @dn: OF node
...@@ -146,14 +188,16 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag) ...@@ -146,14 +188,16 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
{ {
struct eeh_dev *edev; struct eeh_dev *edev;
struct eeh_pe pe; struct eeh_pe pe;
struct pci_dn *pdn = PCI_DN(dn);
const u32 *class_code, *vendor_id, *device_id; const u32 *class_code, *vendor_id, *device_id;
const u32 *regs; const u32 *regs;
u32 pcie_flags;
int enable = 0; int enable = 0;
int ret; int ret;
/* Retrieve OF node and eeh device */ /* Retrieve OF node and eeh device */
edev = of_node_to_eeh_dev(dn); edev = of_node_to_eeh_dev(dn);
if (!of_device_is_available(dn)) if (edev->pe || !of_device_is_available(dn))
return NULL; return NULL;
/* Retrieve class/vendor/device IDs */ /* Retrieve class/vendor/device IDs */
...@@ -167,9 +211,26 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag) ...@@ -167,9 +211,26 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
if (dn->type && !strcmp(dn->type, "isa")) if (dn->type && !strcmp(dn->type, "isa"))
return NULL; return NULL;
/* Update class code and mode of eeh device */ /*
* Update class code and mode of eeh device. We need
* correctly reflects that current device is root port
* or PCIe switch downstream port.
*/
edev->class_code = *class_code; edev->class_code = *class_code;
edev->mode = 0; edev->pcie_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_EXP);
edev->mode &= 0xFFFFFF00;
if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) {
edev->mode |= EEH_DEV_BRIDGE;
if (edev->pcie_cap) {
rtas_read_config(pdn, edev->pcie_cap + PCI_EXP_FLAGS,
2, &pcie_flags);
pcie_flags = (pcie_flags & PCI_EXP_FLAGS_TYPE) >> 4;
if (pcie_flags == PCI_EXP_TYPE_ROOT_PORT)
edev->mode |= EEH_DEV_ROOT_PORT;
else if (pcie_flags == PCI_EXP_TYPE_DOWNSTREAM)
edev->mode |= EEH_DEV_DS_PORT;
}
}
/* Retrieve the device address */ /* Retrieve the device address */
regs = of_get_property(dn, "reg", NULL); regs = of_get_property(dn, "reg", NULL);
......
...@@ -146,7 +146,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group, ...@@ -146,7 +146,7 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
flags = 0; flags = 0;
/* Make pHyp happy */ /* Make pHyp happy */
if ((rflags & _PAGE_NO_CACHE) & !(rflags & _PAGE_WRITETHRU)) if ((rflags & _PAGE_NO_CACHE) && !(rflags & _PAGE_WRITETHRU))
hpte_r &= ~_PAGE_COHERENT; hpte_r &= ~_PAGE_COHERENT;
if (firmware_has_feature(FW_FEATURE_XCMO) && !(hpte_r & HPTE_R_N)) if (firmware_has_feature(FW_FEATURE_XCMO) && !(hpte_r & HPTE_R_N))
flags |= H_COALESCE_CAND; flags |= H_COALESCE_CAND;
......
...@@ -287,6 +287,9 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) ...@@ -287,6 +287,9 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
unsigned long *savep; unsigned long *savep;
struct rtas_error_log *h, *errhdr = NULL; struct rtas_error_log *h, *errhdr = NULL;
/* Mask top two bits */
regs->gpr[3] &= ~(0x3UL << 62);
if (!VALID_FWNMI_BUFFER(regs->gpr[3])) { if (!VALID_FWNMI_BUFFER(regs->gpr[3])) {
printk(KERN_ERR "FWNMI: corrupt r3 0x%016lx\n", regs->gpr[3]); printk(KERN_ERR "FWNMI: corrupt r3 0x%016lx\n", regs->gpr[3]);
return NULL; return NULL;
......
...@@ -388,7 +388,6 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn) ...@@ -388,7 +388,6 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
/* Remove the EADS bridge device itself */ /* Remove the EADS bridge device itself */
BUG_ON(!bus->self); BUG_ON(!bus->self);
pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self)); pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
eeh_remove_bus_device(bus->self, true);
pci_stop_and_remove_bus_device(bus->self); pci_stop_and_remove_bus_device(bus->self);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment