diff options
author | Yinghai Lu <yinghai@kernel.org> | 2012-09-17 22:20:31 -0700 |
---|---|---|
committer | Yinghai Lu <yinghai@kernel.org> | 2012-09-17 22:20:31 -0700 |
commit | 34938b934f358cafddb1968a4f90ceef6e098a03 (patch) | |
tree | 902ce4dda0dfd6ff92ca3fc28a375607e70ebf36 | |
parent | 3e9c7e877487a93a45dfb29d7987273bbece846b (diff) | |
download | linux-yinghai-34938b934f358cafddb1968a4f90ceef6e098a03.tar.gz |
PCI: Add addon_resource support for pci_dev
Will add addon_resources list in pci_dev, it will be used for resources
other than standard, rom, sriov, bridges.
Some could be same as std reg, but using different register.
Some could have own way to read/write to them.
Kernel using different way to hack those resources like abusing
pci bridge resource spot on non bridge pci device.
With this patch, will treat addon-resource like standard resource with
special ops.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
-rw-r--r-- | drivers/pci/probe.c | 38 | ||||
-rw-r--r-- | include/linux/pci.h | 20 |
2 files changed, 56 insertions, 2 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 4f7fb8a60f1da6..5bae8c636cf398 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -107,22 +107,53 @@ postcore_initcall(pcibus_class_init); struct resource *pci_dev_resource_n(struct pci_dev *dev, int n) { - if (n >= 0 && n < PCI_NUM_RESOURCES) + struct pci_dev_addon_resource *addon_res; + + if (n < 0) + return NULL; + + if (n < PCI_NUM_RESOURCES) return &dev->resource[n]; + n -= PCI_NUM_RESOURCES; + list_for_each_entry(addon_res, &dev->addon_resources, list) { + if (n-- == 0) + return &addon_res->res; + } + return NULL; } EXPORT_SYMBOL(pci_dev_resource_n); int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res) { + struct pci_dev_addon_resource *addon_res; + int n; + if (res >= dev->resource && res <= dev->resource + (PCI_NUM_RESOURCES - 1)) return res - dev->resource; + n = PCI_NUM_RESOURCES; + list_for_each_entry(addon_res, &dev->addon_resources, list) { + if (res == &addon_res->res) + return n; + n++; + } + return -1; } +static void pci_release_dev_addon_res(struct pci_dev *dev) +{ + struct pci_dev_addon_resource *addon_res, *tmp; + + list_for_each_entry_safe(addon_res, tmp, &dev->addon_resources, list) { + list_del(&addon_res->list); + kfree(addon_res); + } +} + static void __init_res_idx_mask(unsigned long *mask, int flag) { bitmap_zero(mask, PCI_NUM_RESOURCES); @@ -167,6 +198,9 @@ int pci_next_resource_idx(int i, int flag) if (i < PCI_NUM_RESOURCES) return i; + if (flag & PCI_ADDON_RES) + return i; + return -1; } @@ -1182,6 +1216,7 @@ static void pci_release_dev(struct device *dev) pci_dev = to_pci_dev(dev); pci_release_capabilities(pci_dev); pci_release_of_node(pci_dev); + pci_release_dev_addon_res(pci_dev); kfree(pci_dev); } @@ -1259,6 +1294,7 @@ struct pci_dev *alloc_pci_dev(void) return NULL; INIT_LIST_HEAD(&dev->bus_list); + INIT_LIST_HEAD(&dev->addon_resources); return dev; } diff --git a/include/linux/pci.h b/include/linux/pci.h index d88b4d38e7f9fc..1940849ff7ccab 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -330,6 +330,7 @@ struct pci_dev { */ unsigned int irq; struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */ + struct list_head addon_resources; /* addon I/O and memory resource */ /* These fields are used by common fixups */ unsigned int transparent:1; /* Transparent PCI bridge */ @@ -380,6 +381,21 @@ struct pci_dev { #endif }; +struct resource_ops { + int (*read)(struct pci_dev *dev, struct resource *res, int addr); + int (*write)(struct pci_dev *dev, struct resource *res, int addr); +}; + +struct pci_dev_addon_resource { + struct list_head list; + int reg_addr; + int size; + struct resource res; + struct resource_ops *ops; +}; +#define to_pci_dev_addon_resource(n) \ + container_of(n, struct pci_dev_addon_resource, res) + struct resource *pci_dev_resource_n(struct pci_dev *dev, int n); int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res); @@ -388,8 +404,10 @@ int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res); #define PCI_IOV_RES (1<<2) #define PCI_BRIDGE_RES (1<<3) #define PCI_RES_BLOCK_NUM 4 +/* addon does not need use bitmap ...*/ +#define PCI_ADDON_RES (1<<4) -#define PCI_ALL_RES (PCI_STD_RES | PCI_ROM_RES | PCI_BRIDGE_RES | PCI_IOV_RES) +#define PCI_ALL_RES (PCI_STD_RES | PCI_ROM_RES | PCI_BRIDGE_RES | PCI_IOV_RES | PCI_ADDON_RES) #define PCI_NOSTD_RES (PCI_ALL_RES & ~PCI_STD_RES) #define PCI_NOIOV_RES (PCI_ALL_RES & ~PCI_IOV_RES) #define PCI_NOROM_RES (PCI_ALL_RES & ~PCI_ROM_RES) |