[PATCH 05/23] staging: comedi: me_daq: factor out the PLX bug workaround

Ian Abbott abbotti at mev.co.uk
Fri Oct 26 09:59:01 UTC 2012


On 25/10/12 23:06, H Hartley Sweeten wrote:
> Factor out the code in me_attach_pci() that handles the PLX-Bug
> workaround to a separate function.
>
> This looks odd. It appears that the bug workaround either swaps
> PCI bars 0 and 5 or it modifies PCI bar 0. Shouldn't this happen
> before PCI bar 0 is ioremap'ed?

Yes, the workaround is wrong as it ends up ioremap'ing the wrong 
address.  It should ioremap whatever gets written to the 
PCI_BASE_ADDRESS_0 config dword, or the original 
pci_resource_start(pcidev, 0) value if no workaround is needed.

The workaround is pretty dodgy anyway and should be done by 
pci/quirks.c.  The case where it subtracts 0x80 before writing back is 
particularly dodgy as it is likely to screw up other devices in the system.

There is a hardware bug in the PLX PCI 9050 that means its local 
configuration registers cannot be read through PCI BAR 0 if bit 7 of PCI 
BAR 0 is set - the local configuration registers would read back as 0. 
The same applies to PCI BAR 1.  PCI BAR 0 is memory of size 128 or 0 
(disabled); PCI BAR 1 is I/O of size 128 or 0 (disabled).  If not 
disabled, they both map to the chip's local configuration registers.

The _real_ fix at the hardware design level is to replace the PCI 9050 
with a PCI 9052 in subsequent issues of the hardware.

>
> Signed-off-by: H Hartley Sweeten <hsweeten at visionengravers.com>
> Cc: Ian Abbott <abbotti at mev.co.uk>
> Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
> ---
>   drivers/staging/comedi/drivers/me_daq.c | 95 ++++++++++++++++-----------------
>   1 file changed, 47 insertions(+), 48 deletions(-)
>
> diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
> index 95fbecc..182a184 100644
> --- a/drivers/staging/comedi/drivers/me_daq.c
> +++ b/drivers/staging/comedi/drivers/me_daq.c
> @@ -617,6 +617,48 @@ static int me_reset(struct comedi_device *dev)
>   	return 0;
>   }
>
> +static int me_plx_bug_check(struct comedi_device *dev,
> +			    struct pci_dev *pcidev)
> +{
> +	resource_size_t plx_regbase_tmp = pci_resource_start(pcidev, 0);
> +	resource_size_t swap_regbase_tmp = pci_resource_start(pcidev, 5);
> +	resource_size_t regbase_tmp;
> +	int ret;
> +
> +	if (!swap_regbase_tmp)
> +		dev_err(dev->class_dev, "Swap not present\n");
> +
> +	if (plx_regbase_tmp & 0x0080) {
> +		dev_err(dev->class_dev, "PLX-Bug detected\n");
> +
> +		if (swap_regbase_tmp) {
> +			regbase_tmp = plx_regbase_tmp;
> +			plx_regbase_tmp = swap_regbase_tmp;
> +			swap_regbase_tmp = regbase_tmp;
> +
> +			ret = pci_write_config_dword(pcidev,
> +						     PCI_BASE_ADDRESS_0,
> +						     plx_regbase_tmp);
> +			if (ret != PCIBIOS_SUCCESSFUL)
> +				return -EIO;
> +
> +			ret = pci_write_config_dword(pcidev,
> +						     PCI_BASE_ADDRESS_5,
> +						     swap_regbase_tmp);
> +			if (ret != PCIBIOS_SUCCESSFUL)
> +				return -EIO;
> +		} else {
> +			plx_regbase_tmp -= 0x80;
> +			ret = pci_write_config_dword(pcidev,
> +						     PCI_BASE_ADDRESS_0,
> +						     plx_regbase_tmp);
> +			if (ret != PCIBIOS_SUCCESSFUL)
> +				return -EIO;
> +		}
> +	}
> +	return 0;
> +}
> +
>   static const void *me_find_boardinfo(struct comedi_device *dev,
>   				     struct pci_dev *pcidev)
>   {
> @@ -636,10 +678,6 @@ static int me_attach_pci(struct comedi_device *dev, struct pci_dev *pcidev)
>   	const struct me_board *board;
>   	struct me_private_data *dev_private;
>   	struct comedi_subdevice *s;
> -	resource_size_t plx_regbase_tmp;
> -	resource_size_t swap_regbase_tmp;
> -	unsigned long swap_regbase_size_tmp;
> -	resource_size_t regbase_tmp;
>   	int ret;
>
>   	board = me_find_boardinfo(dev, pcidev);
> @@ -658,53 +696,14 @@ static int me_attach_pci(struct comedi_device *dev, struct pci_dev *pcidev)
>   		return ret;
>   	dev->iobase = 1;	/* detach needs this */
>
> -	/* Read PLX register base address [PCI_BASE_ADDRESS #0]. */
> -	plx_regbase_tmp = pci_resource_start(pcidev, 0);
> -	dev_private->plx_regbase = ioremap(plx_regbase_tmp,
> +	dev_private->plx_regbase = ioremap(pci_resource_start(pcidev, 0),
>   					   pci_resource_len(pcidev, 0));
> -	if (!dev_private->plx_regbase) {
> -		dev_err(dev->class_dev, "Failed to remap I/O memory\n");
> +	if (!dev_private->plx_regbase)
>   		return -ENOMEM;
> -	}
> -
> -	/* Read Swap base address [PCI_BASE_ADDRESS #5]. */
> -
> -	swap_regbase_tmp = pci_resource_start(pcidev, 5);
> -	swap_regbase_size_tmp = pci_resource_len(pcidev, 5);
> -
> -	if (!swap_regbase_tmp)
> -		dev_err(dev->class_dev, "Swap not present\n");
> -
> -	/*---------------------------------------------- Workaround start ---*/
> -	if (plx_regbase_tmp & 0x0080) {
> -		dev_err(dev->class_dev, "PLX-Bug detected\n");
> -
> -		if (swap_regbase_tmp) {
> -			regbase_tmp = plx_regbase_tmp;
> -			plx_regbase_tmp = swap_regbase_tmp;
> -			swap_regbase_tmp = regbase_tmp;
>
> -			ret = pci_write_config_dword(pcidev,
> -							PCI_BASE_ADDRESS_0,
> -							plx_regbase_tmp);
> -			if (ret != PCIBIOS_SUCCESSFUL)
> -				return -EIO;
> -
> -			ret = pci_write_config_dword(pcidev,
> -							PCI_BASE_ADDRESS_5,
> -							swap_regbase_tmp);
> -			if (ret != PCIBIOS_SUCCESSFUL)
> -				return -EIO;
> -		} else {
> -			plx_regbase_tmp -= 0x80;
> -			ret = pci_write_config_dword(pcidev,
> -							PCI_BASE_ADDRESS_0,
> -							plx_regbase_tmp);
> -			if (ret != PCIBIOS_SUCCESSFUL)
> -				return -EIO;
> -		}
> -	}
> -	/*--------------------------------------------- Workaround end -----*/
> +	ret = me_plx_bug_check(dev, pcidev);
> +	if (ret)
> +		return ret;
>
>   	dev_private->me_regbase = ioremap(pci_resource_start(pcidev, 2),
>   					  pci_resource_len(pcidev, 2));
>


-- 
-=( Ian Abbott @ MEV Ltd.    E-mail: <abbotti at mev.co.uk>        )=-
-=( Tel: +44 (0)161 477 1898   FAX: +44 (0)161 718 3587         )=-



More information about the devel mailing list