Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: Add generic config accessors

Many PCI controllers' configuration space accesses are memory-mapped and
vary only in address calculation and access checks. There are 2 main
access methods: a decoded address space such as ECAM or a single address
and data register similar to x86. This implementation can support both
cases as well as be used in cases that need additional pre- or post-access
handling.

Add a new pci_ops member, map_bus, which can do access checks and any
necessary setup. It returns the address to use for the configuration space
access. The access types supported are 32-bit only accesses or correct
byte, word, or dword sized accesses.

Tested-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Rob Herring <robh@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Thierry Reding <treding@nvidia.com>

authored by

Rob Herring and committed by
Bjorn Helgaas
1f94a94f 453c02c2

+98
+87
drivers/pci/access.c
··· 67 67 EXPORT_SYMBOL(pci_bus_write_config_word); 68 68 EXPORT_SYMBOL(pci_bus_write_config_dword); 69 69 70 + int pci_generic_config_read(struct pci_bus *bus, unsigned int devfn, 71 + int where, int size, u32 *val) 72 + { 73 + void __iomem *addr; 74 + 75 + addr = bus->ops->map_bus(bus, devfn, where); 76 + if (!addr) { 77 + *val = ~0; 78 + return PCIBIOS_DEVICE_NOT_FOUND; 79 + } 80 + 81 + if (size == 1) 82 + *val = readb(addr); 83 + else if (size == 2) 84 + *val = readw(addr); 85 + else 86 + *val = readl(addr); 87 + 88 + return PCIBIOS_SUCCESSFUL; 89 + } 90 + EXPORT_SYMBOL_GPL(pci_generic_config_read); 91 + 92 + int pci_generic_config_write(struct pci_bus *bus, unsigned int devfn, 93 + int where, int size, u32 val) 94 + { 95 + void __iomem *addr; 96 + 97 + addr = bus->ops->map_bus(bus, devfn, where); 98 + if (!addr) 99 + return PCIBIOS_DEVICE_NOT_FOUND; 100 + 101 + if (size == 1) 102 + writeb(val, addr); 103 + else if (size == 2) 104 + writew(val, addr); 105 + else 106 + writel(val, addr); 107 + 108 + return PCIBIOS_SUCCESSFUL; 109 + } 110 + EXPORT_SYMBOL_GPL(pci_generic_config_write); 111 + 112 + int pci_generic_config_read32(struct pci_bus *bus, unsigned int devfn, 113 + int where, int size, u32 *val) 114 + { 115 + void __iomem *addr; 116 + 117 + addr = bus->ops->map_bus(bus, devfn, where & ~0x3); 118 + if (!addr) { 119 + *val = ~0; 120 + return PCIBIOS_DEVICE_NOT_FOUND; 121 + } 122 + 123 + *val = readl(addr); 124 + 125 + if (size <= 2) 126 + *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1); 127 + 128 + return PCIBIOS_SUCCESSFUL; 129 + } 130 + EXPORT_SYMBOL_GPL(pci_generic_config_read32); 131 + 132 + int pci_generic_config_write32(struct pci_bus *bus, unsigned int devfn, 133 + int where, int size, u32 val) 134 + { 135 + void __iomem *addr; 136 + u32 mask, tmp; 137 + 138 + addr = bus->ops->map_bus(bus, devfn, where & ~0x3); 139 + if (!addr) 140 + return PCIBIOS_DEVICE_NOT_FOUND; 141 + 142 + if (size == 4) { 143 + writel(val, addr); 144 + return PCIBIOS_SUCCESSFUL; 145 + } else { 146 + mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); 147 + } 148 + 149 + tmp = readl(addr) & mask; 150 + tmp |= val << ((where & 0x3) * 8); 151 + writel(tmp, addr); 152 + 153 + return PCIBIOS_SUCCESSFUL; 154 + } 155 + EXPORT_SYMBOL_GPL(pci_generic_config_write32); 156 + 70 157 /** 71 158 * pci_bus_set_ops - Set raw operations of pci bus 72 159 * @bus: pci bus struct
+11
include/linux/pci.h
··· 560 560 /* Low-level architecture-dependent routines */ 561 561 562 562 struct pci_ops { 563 + void __iomem *(*map_bus)(struct pci_bus *bus, unsigned int devfn, int where); 563 564 int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val); 564 565 int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); 565 566 }; ··· 858 857 int where, u16 val); 859 858 int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn, 860 859 int where, u32 val); 860 + 861 + int pci_generic_config_read(struct pci_bus *bus, unsigned int devfn, 862 + int where, int size, u32 *val); 863 + int pci_generic_config_write(struct pci_bus *bus, unsigned int devfn, 864 + int where, int size, u32 val); 865 + int pci_generic_config_read32(struct pci_bus *bus, unsigned int devfn, 866 + int where, int size, u32 *val); 867 + int pci_generic_config_write32(struct pci_bus *bus, unsigned int devfn, 868 + int where, int size, u32 val); 869 + 861 870 struct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops); 862 871 863 872 static inline int pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val)