diff options
author | Gavin Shan <gwshan@linux.vnet.ibm.com> | 2015-09-24 17:27:17 +1000 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2015-10-08 15:34:44 +1100 |
commit | 0c1cbc1667754037be40b1405ba30645598fe711 (patch) | |
tree | 84c89a6e9898c6a3b24299b93c48fc632fa36f30 /hw/phb3.c | |
parent | 37a74a4d1b0badee5b971a676b09bbf18ff816a4 (diff) | |
download | skiboot-0c1cbc1667754037be40b1405ba30645598fe711.zip skiboot-0c1cbc1667754037be40b1405ba30645598fe711.tar.gz skiboot-0c1cbc1667754037be40b1405ba30645598fe711.tar.bz2 |
PCI: Introduce config register filter
We have to provide the emulated result for PCI config register
access on some devices to eleminate the gap between hardware and
software. One example would be the 0x28 (prefetchable memory window
upper 32-bits) of the root complex on Naples isn't writable. Linux
kernel relies on that to detect 64-bits window successfully.
This introduces config register filter to PCI device to eleminate
above gap. Each PCI device maintains a list of filters, which are
populated when the PCI device is initialized. When PCI config space
is accessed, the filter is searched to override the result from user
(write) or hardware (read) if necessary.
Reported-by: Vaibhav Jain <vaibhav@linux.vnet.ibm.com>
Suggested-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Tested-by: Vaibhav Jain <vaibhav@linux.vnet.ibm.com>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw/phb3.c')
-rw-r--r-- | hw/phb3.c | 33 |
1 files changed, 33 insertions, 0 deletions
@@ -149,6 +149,33 @@ static int64_t phb3_pcicfg_check(struct phb3 *p, uint32_t bdfn, return OPAL_SUCCESS; } +static void phb3_pcicfg_filter(struct phb *phb, uint32_t bdfn, + uint32_t offset, uint32_t len, + uint32_t *data, bool write) +{ + struct pci_device *pd; + struct pci_cfg_reg_filter *pcrf; + uint32_t flags; + + /* FIXME: It harms the performance to search the PCI + * device which doesn't have any filters at all. So + * it's worthy to maintain a table in PHB to indicate + * the PCI devices who have filters. However, bitmap + * seems not supported by skiboot yet. To implement + * it after bitmap is supported. + */ + pd = pci_find_dev(phb, bdfn); + pcrf = pd ? pci_find_cfg_reg_filter(pd, offset, len) : NULL; + if (!pcrf || !pcrf->func) + return; + + flags = write ? PCI_REG_FLAG_WRITE : PCI_REG_FLAG_READ; + if ((pcrf->flags & flags) != flags) + return; + + pcrf->func(pd, pcrf, offset, len, data, write); +} + #define PHB3_PCI_CFG_READ(size, type) \ static int64_t phb3_pcicfg_read##size(struct phb *phb, uint32_t bdfn, \ uint32_t offset, type *data) \ @@ -189,6 +216,9 @@ static int64_t phb3_pcicfg_read##size(struct phb *phb, uint32_t bdfn, \ (offset & (4 - sizeof(type)))); \ } \ \ + phb3_pcicfg_filter(phb, bdfn, offset, sizeof(type), \ + (uint32_t *)data, false); \ + \ return OPAL_SUCCESS; \ } @@ -214,6 +244,9 @@ static int64_t phb3_pcicfg_write##size(struct phb *phb, uint32_t bdfn, \ return OPAL_HARDWARE; \ } \ \ + phb3_pcicfg_filter(phb, bdfn, offset, sizeof(type), \ + (uint32_t *)&data, true); \ + \ addr = PHB_CA_ENABLE; \ addr = SETFIELD(PHB_CA_BDFN, addr, bdfn); \ addr = SETFIELD(PHB_CA_REG, addr, offset); \ |