ia64/linux-2.6.18-xen.hg

changeset 807:bca9d4cfbca2

Backport: PCI: rewrite PCI BAR reading code

commit 6ac665c63dcac8fcec534a1d224ecbb8b867ad59
Author: Matthew Wilcox <matthew@wil.cx>
Date: Mon Jul 28 13:38:59 2008 -0400

PCI: rewrite PCI BAR reading code

Factor out the code to read one BAR from the loop in
pci_read_bases into
a new function, __pci_read_base. The new code is slightly more
readable, better commented and removes the ifdef.

Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>

Signed-off-by: Yu Zhao <yu.zhao@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Mar 13 07:39:48 2009 +0000 (2009-03-13)
parents 0430b1dbfb3a
children 31f138db8eef
files drivers/pci/probe.c
line diff
     1.1 --- a/drivers/pci/probe.c	Fri Mar 06 12:51:33 2009 +0000
     1.2 +++ b/drivers/pci/probe.c	Fri Mar 13 07:39:48 2009 +0000
     1.3 @@ -123,12 +123,9 @@ static inline unsigned int pci_calc_reso
     1.4  	return IORESOURCE_MEM;
     1.5  }
     1.6  
     1.7 -/*
     1.8 - * Find the extent of a PCI decode..
     1.9 - */
    1.10 -static u32 pci_size(u32 base, u32 maxbase, u32 mask)
    1.11 +static u64 pci_size(u64 base, u64 maxbase, u64 mask)
    1.12  {
    1.13 -	u32 size = mask & maxbase;	/* Find the significant bits */
    1.14 +	u64 size = mask & maxbase;	/* Find the significant bits */
    1.15  	if (!size)
    1.16  		return 0;
    1.17  
    1.18 @@ -144,91 +141,141 @@ static u32 pci_size(u32 base, u32 maxbas
    1.19  	return size;
    1.20  }
    1.21  
    1.22 +enum pci_bar_type {
    1.23 +	pci_bar_unknown,	/* Standard PCI BAR probe */
    1.24 +	pci_bar_io,		/* An io port BAR */
    1.25 +	pci_bar_mem32,		/* A 32-bit memory BAR */
    1.26 +	pci_bar_mem64,		/* A 64-bit memory BAR */
    1.27 +};
    1.28 +
    1.29 +static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar)
    1.30 +{
    1.31 +	if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
    1.32 +		res->flags = bar & ~PCI_BASE_ADDRESS_IO_MASK;
    1.33 +		return pci_bar_io;
    1.34 +	}
    1.35 +
    1.36 +	res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK;
    1.37 +
    1.38 +	if (res->flags == PCI_BASE_ADDRESS_MEM_TYPE_64)
    1.39 +		return pci_bar_mem64;
    1.40 +	return pci_bar_mem32;
    1.41 +}
    1.42 +
    1.43 +/*
    1.44 + * If the type is not unknown, we assume that the lowest bit is 'enable'.
    1.45 + * Returns 1 if the BAR was 64-bit and 0 if it was 32-bit.
    1.46 + */
    1.47 +static int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
    1.48 +			struct resource *res, unsigned int pos)
    1.49 +{
    1.50 +	u32 l, sz, mask;
    1.51 +
    1.52 +	mask = type ? ~PCI_ROM_ADDRESS_ENABLE : ~0;
    1.53 +
    1.54 +	res->name = pci_name(dev);
    1.55 +
    1.56 +	pci_read_config_dword(dev, pos, &l);
    1.57 +	pci_write_config_dword(dev, pos, mask);
    1.58 +	pci_read_config_dword(dev, pos, &sz);
    1.59 +	pci_write_config_dword(dev, pos, l);
    1.60 +
    1.61 +	/*
    1.62 +	 * All bits set in sz means the device isn't working properly.
    1.63 +	 * If the BAR isn't implemented, all bits must be 0.  If it's a
    1.64 +	 * memory BAR or a ROM, bit 0 must be clear; if it's an io BAR, bit
    1.65 +	 * 1 must be clear.
    1.66 +	 */
    1.67 +	if (!sz || sz == 0xffffffff)
    1.68 +		goto fail;
    1.69 +
    1.70 +	/*
    1.71 +	 * I don't know how l can have all bits set.  Copied from old code.
    1.72 +	 * Maybe it fixes a bug on some ancient platform.
    1.73 +	 */
    1.74 +	if (l == 0xffffffff)
    1.75 +		l = 0;
    1.76 +
    1.77 +	if (type == pci_bar_unknown) {
    1.78 +		type = decode_bar(res, l);
    1.79 +		res->flags |= pci_calc_resource_flags(l);
    1.80 +		if (type == pci_bar_io) {
    1.81 +			l &= PCI_BASE_ADDRESS_IO_MASK;
    1.82 +			mask = PCI_BASE_ADDRESS_IO_MASK & 0xffff;
    1.83 +		} else {
    1.84 +			l &= PCI_BASE_ADDRESS_MEM_MASK;
    1.85 +			mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
    1.86 +		}
    1.87 +	} else {
    1.88 +		res->flags |= (l & IORESOURCE_ROM_ENABLE);
    1.89 +		l &= PCI_ROM_ADDRESS_MASK;
    1.90 +		mask = (u32)PCI_ROM_ADDRESS_MASK;
    1.91 +	}
    1.92 +
    1.93 +	if (type == pci_bar_mem64) {
    1.94 +		u64 l64 = l;
    1.95 +		u64 sz64 = sz;
    1.96 +		u64 mask64 = mask | (u64)~0 << 32;
    1.97 +
    1.98 +		pci_read_config_dword(dev, pos + 4, &l);
    1.99 +		pci_write_config_dword(dev, pos + 4, ~0);
   1.100 +		pci_read_config_dword(dev, pos + 4, &sz);
   1.101 +		pci_write_config_dword(dev, pos + 4, l);
   1.102 +
   1.103 +		l64 |= ((u64)l << 32);
   1.104 +		sz64 |= ((u64)sz << 32);
   1.105 +
   1.106 +		sz64 = pci_size(l64, sz64, mask64);
   1.107 +
   1.108 +		if (!sz64)
   1.109 +			goto fail;
   1.110 +
   1.111 +		if ((BITS_PER_LONG < 64) && (sz64 > 0x100000000ULL)) {
   1.112 +			dev_err(&dev->dev, "can't handle 64-bit BAR\n");
   1.113 +			goto fail;
   1.114 +		} else if ((BITS_PER_LONG < 64) && l) {
   1.115 +			/* Address above 32-bit boundary; disable the BAR */
   1.116 +			pci_write_config_dword(dev, pos, 0);
   1.117 +			pci_write_config_dword(dev, pos + 4, 0);
   1.118 +			res->start = 0;
   1.119 +			res->end = sz64;
   1.120 +		} else {
   1.121 +			res->start = l64;
   1.122 +			res->end = l64 + sz64;
   1.123 +		}
   1.124 +	} else {
   1.125 +		sz = pci_size(l, sz, mask);
   1.126 +
   1.127 +		if (!sz)
   1.128 +			goto fail;
   1.129 +
   1.130 +		res->start = l;
   1.131 +		res->end = l + sz;
   1.132 +	}
   1.133 +
   1.134 + out:
   1.135 +	return (type == pci_bar_mem64) ? 1 : 0;
   1.136 + fail:
   1.137 +	res->flags = 0;
   1.138 +	goto out;
   1.139 +}
   1.140 +
   1.141  static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
   1.142  {
   1.143 -	unsigned int pos, reg, next;
   1.144 -	u32 l, sz;
   1.145 -	struct resource *res;
   1.146 +	unsigned int pos, reg;
   1.147  
   1.148 -	for(pos=0; pos<howmany; pos = next) {
   1.149 -		next = pos+1;
   1.150 -		res = &dev->resource[pos];
   1.151 -		res->name = pci_name(dev);
   1.152 +	for (pos = 0; pos < howmany; pos++) {
   1.153 +		struct resource *res = &dev->resource[pos];
   1.154  		reg = PCI_BASE_ADDRESS_0 + (pos << 2);
   1.155 -		pci_read_config_dword(dev, reg, &l);
   1.156 -		pci_write_config_dword(dev, reg, ~0);
   1.157 -		pci_read_config_dword(dev, reg, &sz);
   1.158 -		pci_write_config_dword(dev, reg, l);
   1.159 -		if (!sz || sz == 0xffffffff)
   1.160 -			continue;
   1.161 -		if (l == 0xffffffff)
   1.162 -			l = 0;
   1.163 -		if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
   1.164 -			sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK);
   1.165 -			if (!sz)
   1.166 -				continue;
   1.167 -			res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
   1.168 -			res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
   1.169 -		} else {
   1.170 -			sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
   1.171 -			if (!sz)
   1.172 -				continue;
   1.173 -			res->start = l & PCI_BASE_ADDRESS_IO_MASK;
   1.174 -			res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
   1.175 -		}
   1.176 -		res->end = res->start + (unsigned long) sz;
   1.177 -		res->flags |= pci_calc_resource_flags(l);
   1.178 -		if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
   1.179 -		    == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
   1.180 -			u32 szhi, lhi;
   1.181 -			pci_read_config_dword(dev, reg+4, &lhi);
   1.182 -			pci_write_config_dword(dev, reg+4, ~0);
   1.183 -			pci_read_config_dword(dev, reg+4, &szhi);
   1.184 -			pci_write_config_dword(dev, reg+4, lhi);
   1.185 -			szhi = pci_size(lhi, szhi, 0xffffffff);
   1.186 -			next++;
   1.187 -#if BITS_PER_LONG == 64
   1.188 -			res->start |= ((unsigned long) lhi) << 32;
   1.189 -			res->end = res->start + sz;
   1.190 -			if (szhi) {
   1.191 -				/* This BAR needs > 4GB?  Wow. */
   1.192 -				res->end |= (unsigned long)szhi<<32;
   1.193 -			}
   1.194 -#else
   1.195 -			if (szhi) {
   1.196 -				printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev));
   1.197 -				res->start = 0;
   1.198 -				res->flags = 0;
   1.199 -			} else if (lhi) {
   1.200 -				/* 64-bit wide address, treat as disabled */
   1.201 -				pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
   1.202 -				pci_write_config_dword(dev, reg+4, 0);
   1.203 -				res->start = 0;
   1.204 -				res->end = sz;
   1.205 -			}
   1.206 -#endif
   1.207 -		}
   1.208 +		pos += __pci_read_base(dev, pci_bar_unknown, res, reg);
   1.209  	}
   1.210 +
   1.211  	if (rom) {
   1.212 +		struct resource *res = &dev->resource[PCI_ROM_RESOURCE];
   1.213  		dev->rom_base_reg = rom;
   1.214 -		res = &dev->resource[PCI_ROM_RESOURCE];
   1.215 -		res->name = pci_name(dev);
   1.216 -		pci_read_config_dword(dev, rom, &l);
   1.217 -		pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
   1.218 -		pci_read_config_dword(dev, rom, &sz);
   1.219 -		pci_write_config_dword(dev, rom, l);
   1.220 -		if (l == 0xffffffff)
   1.221 -			l = 0;
   1.222 -		if (sz && sz != 0xffffffff) {
   1.223 -			sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK);
   1.224 -			if (sz) {
   1.225 -				res->flags = (l & IORESOURCE_ROM_ENABLE) |
   1.226 -				  IORESOURCE_MEM | IORESOURCE_PREFETCH |
   1.227 -				  IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
   1.228 -				res->start = l & PCI_ROM_ADDRESS_MASK;
   1.229 -				res->end = res->start + (unsigned long) sz;
   1.230 -			}
   1.231 -		}
   1.232 +		res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH |
   1.233 +				IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
   1.234 +		__pci_read_base(dev, pci_bar_mem32, res, rom);
   1.235  	}
   1.236  }
   1.237