Zhao, Yu
2008-Sep-27 08:59 UTC
[Xen-devel] [PATCH 1/9] dom0 PCI: export some functions and macros
Export some functions and move some macros from c file to header file. Signed-off-by: Yu Zhao <yu.zhao@intel.com> diff -r cc6fc966c613 -r 6301e7e967c0 drivers/pci/pci-sysfs.c --- a/drivers/pci/pci-sysfs.c Fri Sep 26 14:07:10 2008 +0100 +++ b/drivers/pci/pci-sysfs.c Sat Sep 27 01:23:54 2008 -0400 @@ -513,7 +513,7 @@ .mode = S_IRUGO | S_IWUSR, .owner = THIS_MODULE, }, - .size = 256, + .size = PCI_CFG_SPACE_SIZE, .read = pci_read_config, .write = pci_write_config, }; @@ -524,7 +524,7 @@ .mode = S_IRUGO | S_IWUSR, .owner = THIS_MODULE, }, - .size = 4096, + .size = PCI_CFG_SPACE_EXP_SIZE, .read = pci_read_config, .write = pci_write_config, }; @@ -534,7 +534,7 @@ if (!sysfs_initialized) return -EACCES; - if (pdev->cfg_size < 4096) + if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE) sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); else sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); @@ -574,7 +574,7 @@ if (!sysfs_initialized) return; - if (pdev->cfg_size < 4096) + if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE) sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); else sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); diff -r cc6fc966c613 -r 6301e7e967c0 drivers/pci/pci.c --- a/drivers/pci/pci.c Fri Sep 26 14:07:10 2008 +0100 +++ b/drivers/pci/pci.c Sat Sep 27 01:23:54 2008 -0400 @@ -185,7 +185,7 @@ int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */ int pos = 0x100; - if (dev->cfg_size <= 256) + if (dev->cfg_size <= PCI_CFG_SPACE_SIZE) return 0; if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL) diff -r cc6fc966c613 -r 6301e7e967c0 drivers/pci/pci.h --- a/drivers/pci/pci.h Fri Sep 26 14:07:10 2008 +0100 +++ b/drivers/pci/pci.h Sat Sep 27 01:23:54 2008 -0400 @@ -1,3 +1,9 @@ +#ifndef DRIVERS_PCI_H +#define DRIVERS_PCI_H + +#define PCI_CFG_SPACE_SIZE 256 +#define PCI_CFG_SPACE_EXP_SIZE 4096 + /* Functions internal to the PCI core code */ extern int pci_uevent(struct device *dev, char **envp, int num_envp, @@ -99,3 +105,17 @@ return NULL; } +enum pci_bar_type { + pci_bar_unknown, /* Standard PCI BAR probe */ + pci_bar_io, /* An io port BAR */ + pci_bar_mem32, /* A 32-bit memory BAR */ + pci_bar_mem64, /* A 64-bit memory BAR */ + pci_bar_rom, /* A ROM BAR */ +}; + +extern int pci_read_base(struct pci_dev *dev, enum pci_bar_type type, + struct resource *res, unsigned int reg); +extern struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, + struct pci_dev *bridge, int busnr); + +#endif /* DRIVERS_PCI_H */ diff -r cc6fc966c613 -r 6301e7e967c0 drivers/pci/probe.c --- a/drivers/pci/probe.c Fri Sep 26 14:07:10 2008 +0100 +++ b/drivers/pci/probe.c Sat Sep 27 01:23:54 2008 -0400 @@ -13,8 +13,6 @@ #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ #define CARDBUS_RESERVE_BUSNR 3 -#define PCI_CFG_SPACE_SIZE 256 -#define PCI_CFG_SPACE_EXP_SIZE 4096 /* Ugh. Need to stop exporting this to modules. */ LIST_HEAD(pci_root_buses); @@ -123,12 +121,9 @@ return IORESOURCE_MEM; } -/* - * Find the extent of a PCI decode.. - */ -static u32 pci_size(u32 base, u32 maxbase, u32 mask) +static u64 pci_size(u32 base, u32 maxbase, u32 mask) { - u32 size = mask & maxbase; /* Find the significant bits */ + u64 size = mask & maxbase; /* Find the significant bits */ if (!size) return 0; @@ -144,91 +139,140 @@ return size; } +static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar) +{ + if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { + res->flags = bar & ~PCI_BASE_ADDRESS_IO_MASK; + return pci_bar_io; + } + + res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK; + + if (res->flags == PCI_BASE_ADDRESS_MEM_TYPE_64) + return pci_bar_mem64; + return pci_bar_mem32; +} + +/** + * pci_read_base - read a PCI BAR + * @dev: the PCI device + * @type: type of the BAR + * @res: resource buffer to be filled in + * @pos: BAR position in the config space + * + * Returns 1 if the BAR is 64-bit, or 0 if 32-bit. + */ +int pci_read_base(struct pci_dev *dev, enum pci_bar_type type, + struct resource *res, unsigned int pos) +{ + u32 l, sz, mask; + + mask = (type == pci_bar_rom) ? ~PCI_ROM_ADDRESS_ENABLE : ~0; + + res->name = pci_name(dev); + + pci_read_config_dword(dev, pos, &l); + pci_write_config_dword(dev, pos, mask); + pci_read_config_dword(dev, pos, &sz); + pci_write_config_dword(dev, pos, l); + + /* + * All bits set in sz means the device isn''t working properly. + * If the BAR isn''t implemented, all bits must be 0. If it''s a + * memory BAR or a ROM, bit 0 must be clear; if it''s an io BAR, bit + * 1 must be clear. + */ + if (!sz || sz == 0xffffffff) + goto fail; + + /* + * I don''t know how l can have all bits set. Copied from old code. + * Maybe it fixes a bug on some ancient platform. + */ + if (l == 0xffffffff) + l = 0; + + if (type == pci_bar_rom) { + res->flags |= (l & IORESOURCE_ROM_ENABLE); + l &= PCI_ROM_ADDRESS_MASK; + mask = (u32)PCI_ROM_ADDRESS_MASK; + } else { + type = decode_bar(res, l); + res->flags |= pci_calc_resource_flags(l); + if (type == pci_bar_io) { + l &= PCI_BASE_ADDRESS_IO_MASK; + mask = PCI_BASE_ADDRESS_IO_MASK & 0xffff; + } else { + l &= PCI_BASE_ADDRESS_MEM_MASK; + mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; + } + } + + if (type == pci_bar_mem64) { + u64 l64 = l; + u64 sz64 = sz; + u64 mask64 = mask | (u64)~0 << 32; + + pci_read_config_dword(dev, pos + 4, &l); + pci_write_config_dword(dev, pos + 4, ~0); + pci_read_config_dword(dev, pos + 4, &sz); + pci_write_config_dword(dev, pos + 4, l); + + l64 |= ((u64)l << 32); + sz64 |= ((u64)sz << 32); + + sz64 = pci_size(l64, sz64, mask64); + + if (!sz64) + goto fail; + + if ((sizeof(resource_size_t) < 8) && (sz64 > 0x100000000ULL)) { + dev_err(&dev->dev, "can''t handle 64-bit BAR\n"); + goto fail; + } else if ((sizeof(resource_size_t) < 8) && l) { + /* Address above 32-bit boundary; disable the BAR */ + pci_write_config_dword(dev, pos, 0); + pci_write_config_dword(dev, pos + 4, 0); + res->start = 0; + res->end = sz64; + } else { + res->start = l64; + res->end = l64 + sz64; + } + } else { + sz = pci_size(l, sz, mask); + + if (!sz) + goto fail; + + res->start = l; + res->end = l + sz; + } + + out: + return (type == pci_bar_mem64) ? 1 : 0; + fail: + res->flags = 0; + goto out; +} +EXPORT_SYMBOL_GPL(pci_read_base); + static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) { - unsigned int pos, reg, next; - u32 l, sz; - struct resource *res; + unsigned int pos, reg; - for(pos=0; pos<howmany; pos = next) { - next = pos+1; - res = &dev->resource[pos]; - res->name = pci_name(dev); + for (pos = 0; pos < howmany; pos++) { + struct resource *res = &dev->resource[pos]; reg = PCI_BASE_ADDRESS_0 + (pos << 2); - pci_read_config_dword(dev, reg, &l); - pci_write_config_dword(dev, reg, ~0); - pci_read_config_dword(dev, reg, &sz); - pci_write_config_dword(dev, reg, l); - if (!sz || sz == 0xffffffff) - continue; - if (l == 0xffffffff) - l = 0; - if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) { - sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK); - if (!sz) - continue; - res->start = l & PCI_BASE_ADDRESS_MEM_MASK; - res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK; - } else { - sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff); - if (!sz) - continue; - res->start = l & PCI_BASE_ADDRESS_IO_MASK; - res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK; - } - res->end = res->start + (unsigned long) sz; - res->flags |= pci_calc_resource_flags(l); - if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) - == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { - u32 szhi, lhi; - pci_read_config_dword(dev, reg+4, &lhi); - pci_write_config_dword(dev, reg+4, ~0); - pci_read_config_dword(dev, reg+4, &szhi); - pci_write_config_dword(dev, reg+4, lhi); - szhi = pci_size(lhi, szhi, 0xffffffff); - next++; -#if BITS_PER_LONG == 64 - res->start |= ((unsigned long) lhi) << 32; - res->end = res->start + sz; - if (szhi) { - /* This BAR needs > 4GB? Wow. */ - res->end |= (unsigned long)szhi<<32; - } -#else - if (szhi) { - printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev)); - res->start = 0; - res->flags = 0; - } else if (lhi) { - /* 64-bit wide address, treat as disabled */ - pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); - pci_write_config_dword(dev, reg+4, 0); - res->start = 0; - res->end = sz; - } -#endif - } + pos += pci_read_base(dev, pci_bar_unknown, res, reg); } + if (rom) { + struct resource *res = &dev->resource[PCI_ROM_RESOURCE]; dev->rom_base_reg = rom; - res = &dev->resource[PCI_ROM_RESOURCE]; - res->name = pci_name(dev); - pci_read_config_dword(dev, rom, &l); - pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE); - pci_read_config_dword(dev, rom, &sz); - pci_write_config_dword(dev, rom, l); - if (l == 0xffffffff) - l = 0; - if (sz && sz != 0xffffffff) { - sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK); - if (sz) { - res->flags = (l & IORESOURCE_ROM_ENABLE) | - IORESOURCE_MEM | IORESOURCE_PREFETCH | - IORESOURCE_READONLY | IORESOURCE_CACHEABLE; - res->start = l & PCI_ROM_ADDRESS_MASK; - res->end = res->start + (unsigned long) sz; - } - } + res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | + IORESOURCE_READONLY | IORESOURCE_CACHEABLE; + pci_read_base(dev, pci_bar_rom, res, rom); } } @@ -249,9 +293,6 @@ for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++) child->resource[i] = child->parent->resource[i - 3]; } - - for(i=0; i<3; i++) - child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; res = child->resource[0]; pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); @@ -334,7 +375,7 @@ return b; } -static struct pci_bus * __devinit +struct pci_bus * __devinit pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) { struct pci_bus *child; @@ -347,12 +388,10 @@ if (!child) return NULL; - child->self = bridge; child->parent = parent; child->ops = parent->ops; child->sysdata = parent->sysdata; child->bus_flags = parent->bus_flags; - child->bridge = get_device(&bridge->dev); child->class_dev.class = &pcibus_class; sprintf(child->class_dev.class_id, "%04x:%02x", pci_domain_nr(child), busnr); @@ -367,6 +406,11 @@ child->primary = parent->secondary; child->subordinate = 0xff; + if (!bridge) + return child; + + child->self = bridge; + child->bridge = get_device(&bridge->dev); /* Set up default resource pointers and names.. */ for (i = 0; i < 4; i++) { child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i]; _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel