diff options
| author | Gavin Shan | 2015-02-16 04:45:41 +0100 | 
|---|---|---|
| committer | Benjamin Herrenschmidt | 2015-03-17 00:31:18 +0100 | 
| commit | 4cf17445589932155797444687dca1ef2dd47f10 (patch) | |
| tree | c956950ab218c9ca63a52480cfd59eac22eb1f3b /arch/powerpc | |
| parent | powerpc/powernv: Drop PHB operation err_inject() (diff) | |
| download | kernel-qcow2-linux-4cf17445589932155797444687dca1ef2dd47f10.tar.gz kernel-qcow2-linux-4cf17445589932155797444687dca1ef2dd47f10.tar.xz kernel-qcow2-linux-4cf17445589932155797444687dca1ef2dd47f10.zip | |
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>
Diffstat (limited to 'arch/powerpc')
| -rw-r--r-- | arch/powerpc/platforms/powernv/eeh-ioda.c | 193 | ||||
| -rw-r--r-- | arch/powerpc/platforms/powernv/eeh-powernv.c | 184 | ||||
| -rw-r--r-- | arch/powerpc/platforms/powernv/pci.h | 1 | 
3 files changed, 179 insertions, 199 deletions
| diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index dd154cf98085..bd509ad08211 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -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, diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index df33daab381c..641ba3378ccf 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -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;  } diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index a9f236229fe0..c7e047f19528 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -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); | 
