powerpc/powernv: Drop PHB operation post_init()
The patch drops PHB EEH operation post_init() and merge its logic to eeh_ops::post_init(). Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
parent
fa646c3cab
commit
4cf1744558
|
@ -34,198 +34,6 @@
|
|||
#include "powernv.h"
|
||||
#include "pci.h"
|
||||
|
||||
static int ioda_eeh_nb_init = 0;
|
||||
|
||||
static int ioda_eeh_event(struct notifier_block *nb,
|
||||
unsigned long events, void *change)
|
||||
{
|
||||
uint64_t changed_evts = (uint64_t)change;
|
||||
|
||||
/*
|
||||
* We simply send special EEH event if EEH has
|
||||
* been enabled, or clear pending events in
|
||||
* case that we enable EEH soon
|
||||
*/
|
||||
if (!(changed_evts & OPAL_EVENT_PCI_ERROR) ||
|
||||
!(events & OPAL_EVENT_PCI_ERROR))
|
||||
return 0;
|
||||
|
||||
if (eeh_enabled())
|
||||
eeh_send_failure_event(NULL);
|
||||
else
|
||||
opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block ioda_eeh_nb = {
|
||||
.notifier_call = ioda_eeh_event,
|
||||
.next = NULL,
|
||||
.priority = 0
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static ssize_t ioda_eeh_ei_write(struct file *filp,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct pci_controller *hose = filp->private_data;
|
||||
struct eeh_dev *edev;
|
||||
struct eeh_pe *pe;
|
||||
int pe_no, type, func;
|
||||
unsigned long addr, mask;
|
||||
char buf[50];
|
||||
int ret;
|
||||
|
||||
if (!eeh_ops || !eeh_ops->err_inject)
|
||||
return -ENXIO;
|
||||
|
||||
ret = simple_write_to_buffer(buf, sizeof(buf), ppos, user_buf, count);
|
||||
if (!ret)
|
||||
return -EFAULT;
|
||||
|
||||
/* Retrieve parameters */
|
||||
ret = sscanf(buf, "%x:%x:%x:%lx:%lx",
|
||||
&pe_no, &type, &func, &addr, &mask);
|
||||
if (ret != 5)
|
||||
return -EINVAL;
|
||||
|
||||
/* Retrieve PE */
|
||||
edev = kzalloc(sizeof(*edev), GFP_KERNEL);
|
||||
if (!edev)
|
||||
return -ENOMEM;
|
||||
edev->phb = hose;
|
||||
edev->pe_config_addr = pe_no;
|
||||
pe = eeh_pe_get(edev);
|
||||
kfree(edev);
|
||||
if (!pe)
|
||||
return -ENODEV;
|
||||
|
||||
/* Do error injection */
|
||||
ret = eeh_ops->err_inject(pe, type, func, addr, mask);
|
||||
return ret < 0 ? ret : count;
|
||||
}
|
||||
|
||||
static const struct file_operations ioda_eeh_ei_fops = {
|
||||
.open = simple_open,
|
||||
.llseek = no_llseek,
|
||||
.write = ioda_eeh_ei_write,
|
||||
};
|
||||
|
||||
static int ioda_eeh_dbgfs_set(void *data, int offset, u64 val)
|
||||
{
|
||||
struct pci_controller *hose = data;
|
||||
struct pnv_phb *phb = hose->private_data;
|
||||
|
||||
out_be64(phb->regs + offset, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioda_eeh_dbgfs_get(void *data, int offset, u64 *val)
|
||||
{
|
||||
struct pci_controller *hose = data;
|
||||
struct pnv_phb *phb = hose->private_data;
|
||||
|
||||
*val = in_be64(phb->regs + offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioda_eeh_outb_dbgfs_set(void *data, u64 val)
|
||||
{
|
||||
return ioda_eeh_dbgfs_set(data, 0xD10, val);
|
||||
}
|
||||
|
||||
static int ioda_eeh_outb_dbgfs_get(void *data, u64 *val)
|
||||
{
|
||||
return ioda_eeh_dbgfs_get(data, 0xD10, val);
|
||||
}
|
||||
|
||||
static int ioda_eeh_inbA_dbgfs_set(void *data, u64 val)
|
||||
{
|
||||
return ioda_eeh_dbgfs_set(data, 0xD90, val);
|
||||
}
|
||||
|
||||
static int ioda_eeh_inbA_dbgfs_get(void *data, u64 *val)
|
||||
{
|
||||
return ioda_eeh_dbgfs_get(data, 0xD90, val);
|
||||
}
|
||||
|
||||
static int ioda_eeh_inbB_dbgfs_set(void *data, u64 val)
|
||||
{
|
||||
return ioda_eeh_dbgfs_set(data, 0xE10, val);
|
||||
}
|
||||
|
||||
static int ioda_eeh_inbB_dbgfs_get(void *data, u64 *val)
|
||||
{
|
||||
return ioda_eeh_dbgfs_get(data, 0xE10, val);
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_outb_dbgfs_ops, ioda_eeh_outb_dbgfs_get,
|
||||
ioda_eeh_outb_dbgfs_set, "0x%llx\n");
|
||||
DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_inbA_dbgfs_ops, ioda_eeh_inbA_dbgfs_get,
|
||||
ioda_eeh_inbA_dbgfs_set, "0x%llx\n");
|
||||
DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_inbB_dbgfs_ops, ioda_eeh_inbB_dbgfs_get,
|
||||
ioda_eeh_inbB_dbgfs_set, "0x%llx\n");
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
|
||||
/**
|
||||
* ioda_eeh_post_init - Chip dependent post initialization
|
||||
* @hose: PCI controller
|
||||
*
|
||||
* The function will be called after eeh PEs and devices
|
||||
* have been built. That means the EEH is ready to supply
|
||||
* service with I/O cache.
|
||||
*/
|
||||
static int ioda_eeh_post_init(struct pci_controller *hose)
|
||||
{
|
||||
struct pnv_phb *phb = hose->private_data;
|
||||
int ret;
|
||||
|
||||
/* Register OPAL event notifier */
|
||||
if (!ioda_eeh_nb_init) {
|
||||
ret = opal_notifier_register(&ioda_eeh_nb);
|
||||
if (ret) {
|
||||
pr_err("%s: Can't register OPAL event notifier (%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ioda_eeh_nb_init = 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
if (!phb->has_dbgfs && phb->dbgfs) {
|
||||
phb->has_dbgfs = 1;
|
||||
|
||||
debugfs_create_file("err_injct", 0200,
|
||||
phb->dbgfs, hose,
|
||||
&ioda_eeh_ei_fops);
|
||||
|
||||
debugfs_create_file("err_injct_outbound", 0600,
|
||||
phb->dbgfs, hose,
|
||||
&ioda_eeh_outb_dbgfs_ops);
|
||||
debugfs_create_file("err_injct_inboundA", 0600,
|
||||
phb->dbgfs, hose,
|
||||
&ioda_eeh_inbA_dbgfs_ops);
|
||||
debugfs_create_file("err_injct_inboundB", 0600,
|
||||
phb->dbgfs, hose,
|
||||
&ioda_eeh_inbB_dbgfs_ops);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If EEH is enabled, we're going to rely on that.
|
||||
* Otherwise, we restore to conventional mechanism
|
||||
* to clear frozen PE during PCI config access.
|
||||
*/
|
||||
if (eeh_enabled())
|
||||
phb->flags |= PNV_PHB_FLAG_EEH;
|
||||
else
|
||||
phb->flags &= ~PNV_PHB_FLAG_EEH;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ioda_eeh_set_option - Set EEH operation or I/O setting
|
||||
* @pe: EEH PE
|
||||
|
@ -1094,7 +902,6 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
|
|||
}
|
||||
|
||||
struct pnv_eeh_ops ioda_eeh_ops = {
|
||||
.post_init = ioda_eeh_post_init,
|
||||
.set_option = ioda_eeh_set_option,
|
||||
.get_state = ioda_eeh_get_state,
|
||||
.reset = ioda_eeh_reset,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -38,6 +39,8 @@
|
|||
#include "powernv.h"
|
||||
#include "pci.h"
|
||||
|
||||
static bool pnv_eeh_nb_init = false;
|
||||
|
||||
/**
|
||||
* pnv_eeh_init - EEH platform dependent initialization
|
||||
*
|
||||
|
@ -85,6 +88,139 @@ static int pnv_eeh_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pnv_eeh_event(struct notifier_block *nb,
|
||||
unsigned long events, void *change)
|
||||
{
|
||||
uint64_t changed_evts = (uint64_t)change;
|
||||
|
||||
/*
|
||||
* We simply send special EEH event if EEH has
|
||||
* been enabled, or clear pending events in
|
||||
* case that we enable EEH soon
|
||||
*/
|
||||
if (!(changed_evts & OPAL_EVENT_PCI_ERROR) ||
|
||||
!(events & OPAL_EVENT_PCI_ERROR))
|
||||
return 0;
|
||||
|
||||
if (eeh_enabled())
|
||||
eeh_send_failure_event(NULL);
|
||||
else
|
||||
opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block pnv_eeh_nb = {
|
||||
.notifier_call = pnv_eeh_event,
|
||||
.next = NULL,
|
||||
.priority = 0
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static ssize_t pnv_eeh_ei_write(struct file *filp,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct pci_controller *hose = filp->private_data;
|
||||
struct eeh_dev *edev;
|
||||
struct eeh_pe *pe;
|
||||
int pe_no, type, func;
|
||||
unsigned long addr, mask;
|
||||
char buf[50];
|
||||
int ret;
|
||||
|
||||
if (!eeh_ops || !eeh_ops->err_inject)
|
||||
return -ENXIO;
|
||||
|
||||
/* Copy over argument buffer */
|
||||
ret = simple_write_to_buffer(buf, sizeof(buf), ppos, user_buf, count);
|
||||
if (!ret)
|
||||
return -EFAULT;
|
||||
|
||||
/* Retrieve parameters */
|
||||
ret = sscanf(buf, "%x:%x:%x:%lx:%lx",
|
||||
&pe_no, &type, &func, &addr, &mask);
|
||||
if (ret != 5)
|
||||
return -EINVAL;
|
||||
|
||||
/* Retrieve PE */
|
||||
edev = kzalloc(sizeof(*edev), GFP_KERNEL);
|
||||
if (!edev)
|
||||
return -ENOMEM;
|
||||
edev->phb = hose;
|
||||
edev->pe_config_addr = pe_no;
|
||||
pe = eeh_pe_get(edev);
|
||||
kfree(edev);
|
||||
if (!pe)
|
||||
return -ENODEV;
|
||||
|
||||
/* Do error injection */
|
||||
ret = eeh_ops->err_inject(pe, type, func, addr, mask);
|
||||
return ret < 0 ? ret : count;
|
||||
}
|
||||
|
||||
static const struct file_operations pnv_eeh_ei_fops = {
|
||||
.open = simple_open,
|
||||
.llseek = no_llseek,
|
||||
.write = pnv_eeh_ei_write,
|
||||
};
|
||||
|
||||
static int pnv_eeh_dbgfs_set(void *data, int offset, u64 val)
|
||||
{
|
||||
struct pci_controller *hose = data;
|
||||
struct pnv_phb *phb = hose->private_data;
|
||||
|
||||
out_be64(phb->regs + offset, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pnv_eeh_dbgfs_get(void *data, int offset, u64 *val)
|
||||
{
|
||||
struct pci_controller *hose = data;
|
||||
struct pnv_phb *phb = hose->private_data;
|
||||
|
||||
*val = in_be64(phb->regs + offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pnv_eeh_outb_dbgfs_set(void *data, u64 val)
|
||||
{
|
||||
return pnv_eeh_dbgfs_set(data, 0xD10, val);
|
||||
}
|
||||
|
||||
static int pnv_eeh_outb_dbgfs_get(void *data, u64 *val)
|
||||
{
|
||||
return pnv_eeh_dbgfs_get(data, 0xD10, val);
|
||||
}
|
||||
|
||||
static int pnv_eeh_inbA_dbgfs_set(void *data, u64 val)
|
||||
{
|
||||
return pnv_eeh_dbgfs_set(data, 0xD90, val);
|
||||
}
|
||||
|
||||
static int pnv_eeh_inbA_dbgfs_get(void *data, u64 *val)
|
||||
{
|
||||
return pnv_eeh_dbgfs_get(data, 0xD90, val);
|
||||
}
|
||||
|
||||
static int pnv_eeh_inbB_dbgfs_set(void *data, u64 val)
|
||||
{
|
||||
return pnv_eeh_dbgfs_set(data, 0xE10, val);
|
||||
}
|
||||
|
||||
static int pnv_eeh_inbB_dbgfs_get(void *data, u64 *val)
|
||||
{
|
||||
return pnv_eeh_dbgfs_get(data, 0xE10, val);
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(pnv_eeh_outb_dbgfs_ops, pnv_eeh_outb_dbgfs_get,
|
||||
pnv_eeh_outb_dbgfs_set, "0x%llx\n");
|
||||
DEFINE_SIMPLE_ATTRIBUTE(pnv_eeh_inbA_dbgfs_ops, pnv_eeh_inbA_dbgfs_get,
|
||||
pnv_eeh_inbA_dbgfs_set, "0x%llx\n");
|
||||
DEFINE_SIMPLE_ATTRIBUTE(pnv_eeh_inbB_dbgfs_ops, pnv_eeh_inbB_dbgfs_get,
|
||||
pnv_eeh_inbB_dbgfs_set, "0x%llx\n");
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
/**
|
||||
* pnv_eeh_post_init - EEH platform dependent post initialization
|
||||
*
|
||||
|
@ -99,16 +235,54 @@ static int pnv_eeh_post_init(void)
|
|||
struct pnv_phb *phb;
|
||||
int ret = 0;
|
||||
|
||||
/* Register OPAL event notifier */
|
||||
if (!pnv_eeh_nb_init) {
|
||||
ret = opal_notifier_register(&pnv_eeh_nb);
|
||||
if (ret) {
|
||||
pr_warn("%s: Can't register OPAL event notifier (%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pnv_eeh_nb_init = true;
|
||||
}
|
||||
|
||||
list_for_each_entry(hose, &hose_list, list_node) {
|
||||
phb = hose->private_data;
|
||||
|
||||
if (phb->eeh_ops && phb->eeh_ops->post_init) {
|
||||
ret = phb->eeh_ops->post_init(hose);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* If EEH is enabled, we're going to rely on that.
|
||||
* Otherwise, we restore to conventional mechanism
|
||||
* to clear frozen PE during PCI config access.
|
||||
*/
|
||||
if (eeh_enabled())
|
||||
phb->flags |= PNV_PHB_FLAG_EEH;
|
||||
else
|
||||
phb->flags &= ~PNV_PHB_FLAG_EEH;
|
||||
|
||||
/* Create debugfs entries */
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
if (phb->has_dbgfs || !phb->dbgfs)
|
||||
continue;
|
||||
|
||||
phb->has_dbgfs = 1;
|
||||
debugfs_create_file("err_injct", 0200,
|
||||
phb->dbgfs, hose,
|
||||
&pnv_eeh_ei_fops);
|
||||
|
||||
debugfs_create_file("err_injct_outbound", 0600,
|
||||
phb->dbgfs, hose,
|
||||
&pnv_eeh_outb_dbgfs_ops);
|
||||
debugfs_create_file("err_injct_inboundA", 0600,
|
||||
phb->dbgfs, hose,
|
||||
&pnv_eeh_inbA_dbgfs_ops);
|
||||
debugfs_create_file("err_injct_inboundB", 0600,
|
||||
phb->dbgfs, hose,
|
||||
&pnv_eeh_inbB_dbgfs_ops);
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ struct pnv_ioda_pe {
|
|||
/* IOC dependent EEH operations */
|
||||
#ifdef CONFIG_EEH
|
||||
struct pnv_eeh_ops {
|
||||
int (*post_init)(struct pci_controller *hose);
|
||||
int (*set_option)(struct eeh_pe *pe, int option);
|
||||
int (*get_state)(struct eeh_pe *pe);
|
||||
int (*reset)(struct eeh_pe *pe, int option);
|
||||
|
|
Loading…
Reference in New Issue