aboutsummaryrefslogtreecommitdiff
path: root/hw/phb3.c
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2015-09-24 17:27:17 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-10-08 15:34:44 +1100
commit0c1cbc1667754037be40b1405ba30645598fe711 (patch)
tree84c89a6e9898c6a3b24299b93c48fc632fa36f30 /hw/phb3.c
parent37a74a4d1b0badee5b971a676b09bbf18ff816a4 (diff)
downloadskiboot-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.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/hw/phb3.c b/hw/phb3.c
index f9efd81..58b4f73 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -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); \