diff options
Diffstat (limited to 'drivers/pci/pcie/aer/aer_inject.c')
| -rw-r--r-- | drivers/pci/pcie/aer/aer_inject.c | 52 | 
1 files changed, 37 insertions, 15 deletions
diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c index b3cf6223f63..182224acedb 100644 --- a/drivers/pci/pcie/aer/aer_inject.c +++ b/drivers/pci/pcie/aer/aer_inject.c @@ -27,6 +27,10 @@  #include <linux/stddef.h>  #include "aerdrv.h" +/* Override the existing corrected and uncorrected error masks */ +static bool aer_mask_override; +module_param(aer_mask_override, bool, 0); +  struct aer_error_inj {  	u8 bus;  	u8 dev; @@ -208,8 +212,8 @@ out:  	return ops->read(bus, devfn, where, size, val);  } -int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where, int size, -		  u32 val) +static int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where, +			 int size, u32 val)  {  	u32 *sim;  	struct aer_error *err; @@ -284,7 +288,7 @@ static struct pci_dev *pcie_find_root_port(struct pci_dev *dev)  	while (1) {  		if (!pci_is_pcie(dev))  			break; -		if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) +		if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)  			return dev;  		if (!dev->bus->self)  			break; @@ -322,7 +326,7 @@ static int aer_inject(struct aer_error_inj *einj)  	unsigned long flags;  	unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn);  	int pos_cap_err, rp_pos_cap_err; -	u32 sever, cor_mask, uncor_mask; +	u32 sever, cor_mask, uncor_mask, cor_mask_orig = 0, uncor_mask_orig = 0;  	int ret = 0;  	dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn); @@ -330,13 +334,13 @@ static int aer_inject(struct aer_error_inj *einj)  		return -ENODEV;  	rpdev = pcie_find_root_port(dev);  	if (!rpdev) { -		ret = -ENOTTY; +		ret = -ENODEV;  		goto out_put;  	}  	pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);  	if (!pos_cap_err) { -		ret = -ENOTTY; +		ret = -EPERM;  		goto out_put;  	}  	pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever); @@ -346,7 +350,7 @@ static int aer_inject(struct aer_error_inj *einj)  	rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR);  	if (!rp_pos_cap_err) { -		ret = -ENOTTY; +		ret = -EPERM;  		goto out_put;  	} @@ -361,6 +365,18 @@ static int aer_inject(struct aer_error_inj *einj)  		goto out_put;  	} +	if (aer_mask_override) { +		cor_mask_orig = cor_mask; +		cor_mask &= !(einj->cor_status); +		pci_write_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, +				       cor_mask); + +		uncor_mask_orig = uncor_mask; +		uncor_mask &= !(einj->uncor_status); +		pci_write_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK, +				       uncor_mask); +	} +  	spin_lock_irqsave(&inject_lock, flags);  	err = __find_aer_error_by_dev(dev); @@ -378,17 +394,17 @@ static int aer_inject(struct aer_error_inj *einj)  	err->header_log2 = einj->header_log2;  	err->header_log3 = einj->header_log3; -	if (einj->cor_status && !(einj->cor_status & ~cor_mask)) { +	if (!aer_mask_override && einj->cor_status && +	    !(einj->cor_status & ~cor_mask)) {  		ret = -EINVAL; -		printk(KERN_WARNING "The correctable error(s) is masked " -				"by device\n"); +		printk(KERN_WARNING "The correctable error(s) is masked by device\n");  		spin_unlock_irqrestore(&inject_lock, flags);  		goto out_put;  	} -	if (einj->uncor_status && !(einj->uncor_status & ~uncor_mask)) { +	if (!aer_mask_override && einj->uncor_status && +	    !(einj->uncor_status & ~uncor_mask)) {  		ret = -EINVAL; -		printk(KERN_WARNING "The uncorrectable error(s) is masked " -				"by device\n"); +		printk(KERN_WARNING "The uncorrectable error(s) is masked by device\n");  		spin_unlock_irqrestore(&inject_lock, flags);  		goto out_put;  	} @@ -425,6 +441,13 @@ static int aer_inject(struct aer_error_inj *einj)  	}  	spin_unlock_irqrestore(&inject_lock, flags); +	if (aer_mask_override) { +		pci_write_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, +				       cor_mask_orig); +		pci_write_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK, +				       uncor_mask_orig); +	} +  	ret = pci_bus_set_aer_ops(dev->bus);  	if (ret)  		goto out_put; @@ -439,8 +462,7 @@ static int aer_inject(struct aer_error_inj *einj)  			goto out_put;  		}  		aer_irq(-1, edev); -	} -	else +	} else  		ret = -EINVAL;  out_put:  	kfree(err_alloc);  | 
