aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2022-05-03 15:51:46 -0400
committerTom Rini <trini@konsulko.com>2022-05-03 15:51:46 -0400
commita369c9b772c56a608f6d72c6aade7ce33f1b0e25 (patch)
tree8c0241b1adb7345fe8df34da06ff1dac83f74e4f
parentf8e7670f8b2a5ba8f25682eee56039fa5f0a20ca (diff)
parentc9873a925991f09f2a43e05db7d30ff127793faf (diff)
downloadu-boot-WIP/03May2022.zip
u-boot-WIP/03May2022.tar.gz
u-boot-WIP/03May2022.tar.bz2
Merge branch '2022-05-03-virtio-pci-add-and-fix-consistency-checks'WIP/03May2022
To quote the author: The virtio PCI drivers forgo a number of consistency checks, particularly around pointer validation and bounds checking. This series focuses on the modern driver to add those checks. The start of the series adds and fixes some basic bounds checks. Later patches ensure PCI addresses fall within the expected regions rather than any arbitrary address. This is acheived by introducing range parameters to a few of the dm_pci_* functions that allow the ranges to be checked. The series also adds a few new configs to allow parts of virtio and PCI to be disabled where the features may be unused and the current implementations don't have the needed consistencty checks.
-rw-r--r--arch/sandbox/dts/test.dts2
-rw-r--r--arch/x86/cpu/baytrail/cpu.c2
-rw-r--r--drivers/ata/ahci.c9
-rw-r--r--drivers/ata/sata_sil.c6
-rw-r--r--drivers/bios_emulator/atibios.c4
-rw-r--r--drivers/gpio/octeon_gpio.c2
-rw-r--r--drivers/i2c/designware_i2c_pci.c3
-rw-r--r--drivers/i2c/intel_i2c.c2
-rw-r--r--drivers/i2c/octeon_i2c.c2
-rw-r--r--drivers/mmc/octeontx_hsmmc.c2
-rw-r--r--drivers/mmc/pci_mmc.c2
-rw-r--r--drivers/mtd/nand/raw/octeontx_bch.c6
-rw-r--r--drivers/mtd/nand/raw/octeontx_nand.c2
-rw-r--r--drivers/net/bnxt/bnxt.c9
-rw-r--r--drivers/net/e1000.c4
-rw-r--r--drivers/net/fsl_enetc.c2
-rw-r--r--drivers/net/fsl_enetc_mdio.c2
-rw-r--r--drivers/net/mscc_eswitch/felix_switch.c4
-rw-r--r--drivers/net/octeontx/bgx.c2
-rw-r--r--drivers/net/octeontx/nic_main.c2
-rw-r--r--drivers/net/octeontx/nicvf_main.c2
-rw-r--r--drivers/net/octeontx/smi.c2
-rw-r--r--drivers/net/octeontx2/cgx.c2
-rw-r--r--drivers/net/octeontx2/rvu_af.c2
-rw-r--r--drivers/net/octeontx2/rvu_pf.c3
-rw-r--r--drivers/net/pch_gbe.c2
-rw-r--r--drivers/nvme/nvme_pci.c4
-rw-r--r--drivers/pci/Kconfig7
-rw-r--r--drivers/pci/pci-uclass.c185
-rw-r--r--drivers/spi/octeon_spi.c2
-rw-r--r--drivers/usb/host/ehci-pci.c3
-rw-r--r--drivers/usb/host/ohci-pci.c2
-rw-r--r--drivers/usb/host/xhci-pci.c3
-rw-r--r--drivers/virtio/Kconfig9
-rw-r--r--drivers/virtio/Makefile3
-rw-r--r--drivers/virtio/virtio_pci_legacy.c3
-rw-r--r--drivers/virtio/virtio_pci_modern.c143
-rw-r--r--include/pci.h46
-rw-r--r--test/dm/pci.c118
39 files changed, 401 insertions, 209 deletions
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index a8a86bc..8f93775 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -997,7 +997,7 @@
#address-cells = <3>;
#size-cells = <2>;
ranges = <0x02000000 0 0x30000000 0x30000000 0 0x2000 // MEM0
- 0x02000000 0 0x31000000 0x31000000 0 0x2000 // MEM1
+ 0x02000000 0 0x31000000 0x3e000000 0 0x2000 // MEM1
0x01000000 0 0x40000000 0x40000000 0 0x2000>;
sandbox,dev-info = <0x08 0x00 0x1234 0x5678
0x0c 0x00 0x1234 0x5678
diff --git a/arch/x86/cpu/baytrail/cpu.c b/arch/x86/cpu/baytrail/cpu.c
index 68bf40b..4fb6a48 100644
--- a/arch/x86/cpu/baytrail/cpu.c
+++ b/arch/x86/cpu/baytrail/cpu.c
@@ -56,7 +56,7 @@ static int baytrail_uart_init(void *ctx, struct event *event)
for (i = 0; i < 2; i++) {
ret = dm_pci_bus_find_bdf(PCI_BDF(0, 0x1e, 3 + i), &dev);
if (!ret) {
- base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
PCI_REGION_MEM);
hsuart_clock_set(base);
}
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 2062197..de6131f 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -416,8 +416,8 @@ static int ahci_init_one(struct ahci_uc_priv *uc_priv, struct udevice *dev)
uc_priv->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */
#if !defined(CONFIG_DM_SCSI)
- uc_priv->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5,
- PCI_REGION_MEM);
+ uc_priv->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
/* Take from kernel:
* JMicron-specific fixup:
@@ -1148,8 +1148,8 @@ int ahci_probe_scsi_pci(struct udevice *ahci_dev)
ulong base;
u16 vendor, device;
- base = (ulong)dm_pci_map_bar(ahci_dev, PCI_BASE_ADDRESS_5,
- PCI_REGION_MEM);
+ base = (ulong)dm_pci_map_bar(ahci_dev, PCI_BASE_ADDRESS_5, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
/*
* Note:
@@ -1164,6 +1164,7 @@ int ahci_probe_scsi_pci(struct udevice *ahci_dev)
if (vendor == PCI_VENDOR_ID_CAVIUM &&
device == PCI_DEVICE_ID_CAVIUM_SATA)
base = (uintptr_t)dm_pci_map_bar(ahci_dev, PCI_BASE_ADDRESS_0,
+ 0, 0, PCI_REGION_TYPE,
PCI_REGION_MEM);
return ahci_probe_scsi(ahci_dev, base);
}
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index b213eba..7065154 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -699,9 +699,11 @@ static int sil_pci_probe(struct udevice *dev)
/* Read out all BARs */
sata_info.iobase[0] = (ulong)dm_pci_map_bar(dev,
- PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+ PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
+ PCI_REGION_MEM);
sata_info.iobase[1] = (ulong)dm_pci_map_bar(dev,
- PCI_BASE_ADDRESS_2, PCI_REGION_MEM);
+ PCI_BASE_ADDRESS_2, 0, 0, PCI_REGION_TYPE,
+ PCI_REGION_MEM);
/* mask out the unused bits */
sata_info.iobase[0] &= 0xffffff80;
diff --git a/drivers/bios_emulator/atibios.c b/drivers/bios_emulator/atibios.c
index 9547470..cdc5ba6 100644
--- a/drivers/bios_emulator/atibios.c
+++ b/drivers/bios_emulator/atibios.c
@@ -368,8 +368,8 @@ void *PCI_mapBIOSImage(struct udevice *pcidev)
return NULL;
}
- BIOSImage = dm_pci_bus_to_virt(pcidev, BIOSImageBus,
- PCI_REGION_MEM, 0, MAP_NOCACHE);
+ BIOSImage = dm_pci_bus_to_virt(pcidev, BIOSImageBus, 0, PCI_REGION_TYPE,
+ PCI_REGION_MEM, MAP_NOCACHE);
/*Change the PCI BAR registers to map it onto the bus.*/
dm_pci_write_config32(pcidev, BIOSImageBAR, 0);
diff --git a/drivers/gpio/octeon_gpio.c b/drivers/gpio/octeon_gpio.c
index 42eae79..2b2465b 100644
--- a/drivers/gpio/octeon_gpio.c
+++ b/drivers/gpio/octeon_gpio.c
@@ -183,7 +183,7 @@ static int octeon_gpio_probe(struct udevice *dev)
priv->data = (const struct octeon_gpio_data *)dev_get_driver_data(dev);
if (priv->data->probe == PROBE_PCI) {
- priv->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ priv->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
PCI_REGION_MEM);
uc_priv->gpio_count = readq(priv->base +
priv->data->reg_offs + GPIO_CONST) &
diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c
index 9e38773..1572c2c 100644
--- a/drivers/i2c/designware_i2c_pci.c
+++ b/drivers/i2c/designware_i2c_pci.c
@@ -59,7 +59,8 @@ static int designware_i2c_pci_of_to_plat(struct udevice *dev)
priv->regs = (struct i2c_regs *)dm_pci_read_bar32(dev, 0);
} else {
priv->regs = (struct i2c_regs *)
- dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+ dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
}
if (!priv->regs)
return -EINVAL;
diff --git a/drivers/i2c/intel_i2c.c b/drivers/i2c/intel_i2c.c
index 52f7a52..dc26fa8 100644
--- a/drivers/i2c/intel_i2c.c
+++ b/drivers/i2c/intel_i2c.c
@@ -251,7 +251,7 @@ static int intel_i2c_probe(struct udevice *dev)
ulong base;
/* Save base address from PCI BAR */
- priv->base = (ulong)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_4,
+ priv->base = (ulong)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_4, 0, 0, PCI_REGION_TYPE,
PCI_REGION_IO);
base = priv->base;
diff --git a/drivers/i2c/octeon_i2c.c b/drivers/i2c/octeon_i2c.c
index 50199ff..e54ef18 100644
--- a/drivers/i2c/octeon_i2c.c
+++ b/drivers/i2c/octeon_i2c.c
@@ -792,7 +792,7 @@ static int octeon_i2c_probe(struct udevice *dev)
debug("TWSI PCI device: %x\n", bdf);
- twsi->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ twsi->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
PCI_REGION_MEM);
} else {
twsi->base = dev_remap_addr(dev);
diff --git a/drivers/mmc/octeontx_hsmmc.c b/drivers/mmc/octeontx_hsmmc.c
index f0519f0..6e9acf7 100644
--- a/drivers/mmc/octeontx_hsmmc.c
+++ b/drivers/mmc/octeontx_hsmmc.c
@@ -3822,7 +3822,7 @@ static int octeontx_mmc_host_probe(struct udevice *dev)
/* Octeon TX & TX2 use PCI based probing */
if (device_is_compatible(dev, "cavium,thunder-8890-mmc")) {
- host->base_addr = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ host->base_addr = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
PCI_REGION_MEM);
if (!host->base_addr) {
pr_err("%s: Error: MMC base address not found\n",
diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c
index b9ab064..cba2ea8 100644
--- a/drivers/mmc/pci_mmc.c
+++ b/drivers/mmc/pci_mmc.c
@@ -50,7 +50,7 @@ static int pci_mmc_probe(struct udevice *dev)
desc = mmc_get_blk_desc(&plat->mmc);
desc->removable = !(plat->cfg.host_caps & MMC_CAP_NONREMOVABLE);
- host->ioaddr = (void *)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ host->ioaddr = (void *)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
PCI_REGION_MEM);
host->name = dev->name;
host->cd_gpio = priv->cd_gpio;
diff --git a/drivers/mtd/nand/raw/octeontx_bch.c b/drivers/mtd/nand/raw/octeontx_bch.c
index 24ffa51..c1d721c 100644
--- a/drivers/mtd/nand/raw/octeontx_bch.c
+++ b/drivers/mtd/nand/raw/octeontx_bch.c
@@ -176,7 +176,8 @@ static int octeontx_pci_bchpf_probe(struct udevice *dev)
if (!bch)
return -ENOMEM;
- bch->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+ bch->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
bch->dev = dev;
debug("%s: base address: %p\n", __func__, bch->reg_base);
@@ -361,7 +362,8 @@ static int octeontx_pci_bchvf_probe(struct udevice *dev)
vf->dev = dev;
/* Map PF's configuration registers */
- vf->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+ vf->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
debug("%s: reg base: %p\n", __func__, vf->reg_base);
err = octeontx_cmd_queue_initialize(dev, QID_BCH, QDEPTH - 1, 0,
diff --git a/drivers/mtd/nand/raw/octeontx_nand.c b/drivers/mtd/nand/raw/octeontx_nand.c
index ff363a5..b338b20 100644
--- a/drivers/mtd/nand/raw/octeontx_nand.c
+++ b/drivers/mtd/nand/raw/octeontx_nand.c
@@ -2098,7 +2098,7 @@ static int octeontx_pci_nand_probe(struct udevice *dev)
tn->dev = dev;
INIT_LIST_HEAD(&tn->chips);
- tn->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+ tn->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, PCI_REGION_MEM);
if (!tn->base) {
ret = -EINVAL;
goto release;
diff --git a/drivers/net/bnxt/bnxt.c b/drivers/net/bnxt/bnxt.c
index 9844e96..1c9a996 100644
--- a/drivers/net/bnxt/bnxt.c
+++ b/drivers/net/bnxt/bnxt.c
@@ -28,9 +28,12 @@ static void bnxt_bring_pci(struct bnxt *bp)
dm_pci_read_config16(bp->pdev, PCI_SUBSYSTEM_ID, &bp->subsystem_device);
dm_pci_read_config16(bp->pdev, PCI_COMMAND, &bp->cmd_reg);
dm_pci_read_config8(bp->pdev, PCI_INTERRUPT_LINE, &bp->irq);
- bp->bar0 = dm_pci_map_bar(bp->pdev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
- bp->bar1 = dm_pci_map_bar(bp->pdev, PCI_BASE_ADDRESS_2, PCI_REGION_MEM);
- bp->bar2 = dm_pci_map_bar(bp->pdev, PCI_BASE_ADDRESS_4, PCI_REGION_MEM);
+ bp->bar0 = dm_pci_map_bar(bp->pdev, PCI_BASE_ADDRESS_0, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
+ bp->bar1 = dm_pci_map_bar(bp->pdev, PCI_BASE_ADDRESS_2, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
+ bp->bar2 = dm_pci_map_bar(bp->pdev, PCI_BASE_ADDRESS_4, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
cmd_reg = bp->cmd_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
cmd_reg |= PCI_COMMAND_INTX_DISABLE; /* disable intr */
dm_pci_write_config16(bp->pdev, PCI_COMMAND, cmd_reg);
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
index 4e34248..5fe016e 100644
--- a/drivers/net/e1000.c
+++ b/drivers/net/e1000.c
@@ -5549,8 +5549,8 @@ static int e1000_init_one(struct e1000_hw *hw, int cardnum, pci_dev_t devno,
hw->eeprom_semaphore_present = true;
#endif
#ifdef CONFIG_DM_ETH
- hw->hw_addr = dm_pci_map_bar(devno, PCI_BASE_ADDRESS_0,
- PCI_REGION_MEM);
+ hw->hw_addr = dm_pci_map_bar(devno, PCI_BASE_ADDRESS_0, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
#else
hw->hw_addr = pci_map_bar(devno, PCI_BASE_ADDRESS_0,
PCI_REGION_MEM);
diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c
index 1724f94..9b97a03 100644
--- a/drivers/net/fsl_enetc.c
+++ b/drivers/net/fsl_enetc.c
@@ -339,7 +339,7 @@ static int enetc_probe(struct udevice *dev)
}
/* initialize register */
- priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0);
+ priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, 0);
if (!priv->regs_base) {
enetc_dbg(dev, "failed to map BAR0\n");
return -EINVAL;
diff --git a/drivers/net/fsl_enetc_mdio.c b/drivers/net/fsl_enetc_mdio.c
index 3eb6ac9..50ad76d 100644
--- a/drivers/net/fsl_enetc_mdio.c
+++ b/drivers/net/fsl_enetc_mdio.c
@@ -125,7 +125,7 @@ static int enetc_mdio_probe(struct udevice *dev)
{
struct enetc_mdio_priv *priv = dev_get_priv(dev);
- priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0);
+ priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, 0);
if (!priv->regs_base) {
enetc_dbg(dev, "failed to map BAR0\n");
return -EINVAL;
diff --git a/drivers/net/mscc_eswitch/felix_switch.c b/drivers/net/mscc_eswitch/felix_switch.c
index 60b2e8f..709c9e3 100644
--- a/drivers/net/mscc_eswitch/felix_switch.c
+++ b/drivers/net/mscc_eswitch/felix_switch.c
@@ -292,13 +292,13 @@ static int felix_probe(struct udevice *dev)
return -ENODEV;
}
- priv->imdio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0);
+ priv->imdio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, 0);
if (!priv->imdio_base) {
dev_err(dev, "failed to map BAR0\n");
return -EINVAL;
}
- priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_4, 0);
+ priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_4, 0, 0, PCI_REGION_TYPE, 0);
if (!priv->regs_base) {
dev_err(dev, "failed to map BAR4\n");
return -EINVAL;
diff --git a/drivers/net/octeontx/bgx.c b/drivers/net/octeontx/bgx.c
index a5c0c9f..b6592ff 100644
--- a/drivers/net/octeontx/bgx.c
+++ b/drivers/net/octeontx/bgx.c
@@ -1458,7 +1458,7 @@ int octeontx_bgx_probe(struct udevice *dev)
int bgx_idx, node;
int inc = 1;
- bgx->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ bgx->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
PCI_REGION_MEM);
if (!bgx->reg_base) {
debug("No PCI region found\n");
diff --git a/drivers/net/octeontx/nic_main.c b/drivers/net/octeontx/nic_main.c
index 0f36f25..99886e3 100644
--- a/drivers/net/octeontx/nic_main.c
+++ b/drivers/net/octeontx/nic_main.c
@@ -713,7 +713,7 @@ int nic_initialize(struct udevice *dev)
return -ENOMEM;
/* MAP PF's configuration registers */
- nic->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ nic->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
PCI_REGION_MEM);
if (!nic->reg_base) {
printf("Cannot map config register space, aborting\n");
diff --git a/drivers/net/octeontx/nicvf_main.c b/drivers/net/octeontx/nicvf_main.c
index c30ba49..6e4d0a0 100644
--- a/drivers/net/octeontx/nicvf_main.c
+++ b/drivers/net/octeontx/nicvf_main.c
@@ -509,7 +509,7 @@ int nicvf_initialize(struct udevice *dev)
/* Enable TSO support */
nicvf->hw_tso = true;
- nicvf->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ nicvf->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
PCI_REGION_MEM);
debug("nicvf->reg_base: %p\n", nicvf->reg_base);
diff --git a/drivers/net/octeontx/smi.c b/drivers/net/octeontx/smi.c
index d70fa82..233c26f 100644
--- a/drivers/net/octeontx/smi.c
+++ b/drivers/net/octeontx/smi.c
@@ -322,7 +322,7 @@ int octeontx_smi_probe(struct udevice *dev)
u64 baseaddr;
debug("SMI PCI device: %x\n", bdf);
- if (!dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM)) {
+ if (!dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, PCI_REGION_MEM)) {
printf("Failed to map PCI region for bdf %x\n", bdf);
return -1;
}
diff --git a/drivers/net/octeontx2/cgx.c b/drivers/net/octeontx2/cgx.c
index d139029..c6ec320 100644
--- a/drivers/net/octeontx2/cgx.c
+++ b/drivers/net/octeontx2/cgx.c
@@ -253,7 +253,7 @@ int cgx_probe(struct udevice *dev)
struct cgx *cgx = dev_get_priv(dev);
int err;
- cgx->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ cgx->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
PCI_REGION_MEM);
cgx->dev = dev;
cgx->cgx_id = ((u64)(cgx->reg_base) >> 24) & 0x7;
diff --git a/drivers/net/octeontx2/rvu_af.c b/drivers/net/octeontx2/rvu_af.c
index d2f9654..0d3a9ff 100644
--- a/drivers/net/octeontx2/rvu_af.c
+++ b/drivers/net/octeontx2/rvu_af.c
@@ -127,7 +127,7 @@ int rvu_af_probe(struct udevice *dev)
{
struct rvu_af *af_ptr = dev_get_priv(dev);
- af_ptr->af_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ af_ptr->af_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
PCI_REGION_MEM);
debug("%s RVU AF BAR %p\n", __func__, af_ptr->af_base);
af_ptr->dev = dev;
diff --git a/drivers/net/octeontx2/rvu_pf.c b/drivers/net/octeontx2/rvu_pf.c
index 4b00178..5f3ea1f 100644
--- a/drivers/net/octeontx2/rvu_pf.c
+++ b/drivers/net/octeontx2/rvu_pf.c
@@ -58,7 +58,8 @@ int rvu_pf_probe(struct udevice *dev)
debug("%s: name: %s\n", __func__, dev->name);
- rvu->pf_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_2, PCI_REGION_MEM);
+ rvu->pf_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_2, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
rvu->pfid = dev_seq(dev) + 1; // RVU PF's start from 1;
rvu->dev = dev;
if (!rvu_af_dev) {
diff --git a/drivers/net/pch_gbe.c b/drivers/net/pch_gbe.c
index f189524..ad7b5b8 100644
--- a/drivers/net/pch_gbe.c
+++ b/drivers/net/pch_gbe.c
@@ -449,7 +449,7 @@ static int pch_gbe_probe(struct udevice *dev)
priv->dev = dev;
- iobase = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_1, PCI_REGION_MEM);
+ iobase = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_1, 0, 0, PCI_REGION_TYPE, PCI_REGION_MEM);
plat->iobase = (ulong)iobase;
priv->mac_regs = (struct pch_gbe_regs *)iobase;
diff --git a/drivers/nvme/nvme_pci.c b/drivers/nvme/nvme_pci.c
index 5f60fb88..36bf9c5 100644
--- a/drivers/nvme/nvme_pci.c
+++ b/drivers/nvme/nvme_pci.c
@@ -28,8 +28,8 @@ static int nvme_probe(struct udevice *udev)
sprintf(ndev->vendor, "0x%.4x", pplat->vendor);
ndev->instance = trailing_strtol(udev->name);
- ndev->bar = dm_pci_map_bar(udev, PCI_BASE_ADDRESS_0,
- PCI_REGION_MEM);
+ ndev->bar = dm_pci_map_bar(udev, PCI_BASE_ADDRESS_0, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
return nvme_init(udev);
}
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 47cd074..fd22034 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -67,6 +67,13 @@ config PCI_SRIOV
if available on a PCI Physical Function device and probe for
applicable drivers.
+config PCI_ENHANCED_ALLOCATION
+ bool "Enable support for Enhanced Allocation of resources"
+ default y
+ help
+ Enable support for Enhanced Allocation which can be used by supported
+ devices in place of traditional BARS for allocation of resources.
+
config PCI_ARID
bool "Enable Alternate Routing-ID support for PCI"
help
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 33dda00..970ee1a 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -645,7 +645,11 @@ int dm_pci_hose_probe_bus(struct udevice *bus)
return log_msg_ret("probe", -EINVAL);
}
- ea_pos = dm_pci_find_capability(bus, PCI_CAP_ID_EA);
+ if (IS_ENABLED(CONFIG_PCI_ENHANCED_ALLOCATION))
+ ea_pos = dm_pci_find_capability(bus, PCI_CAP_ID_EA);
+ else
+ ea_pos = 0;
+
if (ea_pos) {
dm_pci_read_config8(bus, ea_pos + sizeof(u32) + sizeof(u8),
&reg);
@@ -1013,7 +1017,22 @@ static void decode_regions(struct pci_controller *hose, ofnode parent_node,
if (!IS_ENABLED(CONFIG_SYS_PCI_64BIT) &&
type == PCI_REGION_MEM && upper_32_bits(pci_addr)) {
- debug(" - beyond the 32-bit boundary, ignoring\n");
+ debug(" - pci_addr beyond the 32-bit boundary, ignoring\n");
+ continue;
+ }
+
+ if (!IS_ENABLED(CONFIG_PHYS_64BIT) && upper_32_bits(addr)) {
+ debug(" - addr beyond the 32-bit boundary, ignoring\n");
+ continue;
+ }
+
+ if (~((pci_addr_t)0) - pci_addr < size) {
+ debug(" - PCI range exceeds max address, ignoring\n");
+ continue;
+ }
+
+ if (~((phys_addr_t)0) - addr < size) {
+ debug(" - phys range exceeds max address, ignoring\n");
continue;
}
@@ -1375,131 +1394,84 @@ void dm_pci_write_bar32(struct udevice *dev, int barnum, u32 addr)
dm_pci_write_config32(dev, bar, addr);
}
-static int _dm_pci_bus_to_phys(struct udevice *ctlr,
- pci_addr_t bus_addr, unsigned long flags,
- unsigned long skip_mask, phys_addr_t *pa)
+phys_addr_t dm_pci_bus_to_phys(struct udevice *dev, pci_addr_t bus_addr,
+ size_t len, unsigned long mask,
+ unsigned long flags)
{
- struct pci_controller *hose = dev_get_uclass_priv(ctlr);
+ struct udevice *ctlr;
+ struct pci_controller *hose;
struct pci_region *res;
+ pci_addr_t offset;
int i;
- if (hose->region_count == 0) {
- *pa = bus_addr;
- return 0;
- }
+ /* The root controller has the region information */
+ ctlr = pci_get_controller(dev);
+ hose = dev_get_uclass_priv(ctlr);
+
+ if (hose->region_count == 0)
+ return bus_addr;
for (i = 0; i < hose->region_count; i++) {
res = &hose->regions[i];
- if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
+ if ((res->flags & mask) != flags)
continue;
- if (res->flags & skip_mask)
+ if (bus_addr < res->bus_start)
continue;
- if (bus_addr >= res->bus_start &&
- (bus_addr - res->bus_start) < res->size) {
- *pa = (bus_addr - res->bus_start + res->phys_start);
- return 0;
- }
- }
-
- return 1;
-}
-
-phys_addr_t dm_pci_bus_to_phys(struct udevice *dev, pci_addr_t bus_addr,
- unsigned long flags)
-{
- phys_addr_t phys_addr = 0;
- struct udevice *ctlr;
- int ret;
+ offset = bus_addr - res->bus_start;
+ if (offset >= res->size)
+ continue;
- /* The root controller has the region information */
- ctlr = pci_get_controller(dev);
+ if (len > res->size - offset)
+ continue;
- /*
- * if PCI_REGION_MEM is set we do a two pass search with preference
- * on matches that don't have PCI_REGION_SYS_MEMORY set
- */
- if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
- ret = _dm_pci_bus_to_phys(ctlr, bus_addr,
- flags, PCI_REGION_SYS_MEMORY,
- &phys_addr);
- if (!ret)
- return phys_addr;
+ return res->phys_start + offset;
}
- ret = _dm_pci_bus_to_phys(ctlr, bus_addr, flags, 0, &phys_addr);
-
- if (ret)
- puts("pci_hose_bus_to_phys: invalid physical address\n");
-
- return phys_addr;
+ puts("pci_hose_bus_to_phys: invalid physical address\n");
+ return 0;
}
-static int _dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t phys_addr,
- unsigned long flags, unsigned long skip_mask,
- pci_addr_t *ba)
+pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t phys_addr,
+ size_t len, unsigned long mask,
+ unsigned long flags)
{
- struct pci_region *res;
struct udevice *ctlr;
- pci_addr_t bus_addr;
- int i;
struct pci_controller *hose;
+ struct pci_region *res;
+ phys_addr_t offset;
+ int i;
/* The root controller has the region information */
ctlr = pci_get_controller(dev);
hose = dev_get_uclass_priv(ctlr);
- if (hose->region_count == 0) {
- *ba = phys_addr;
- return 0;
- }
+ if (hose->region_count == 0)
+ return phys_addr;
for (i = 0; i < hose->region_count; i++) {
res = &hose->regions[i];
- if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
+ if ((res->flags & mask) != flags)
continue;
- if (res->flags & skip_mask)
+ if (phys_addr < res->phys_start)
continue;
- bus_addr = phys_addr - res->phys_start + res->bus_start;
-
- if (bus_addr >= res->bus_start &&
- (bus_addr - res->bus_start) < res->size) {
- *ba = bus_addr;
- return 0;
- }
- }
-
- return 1;
-}
+ offset = phys_addr - res->phys_start;
+ if (offset >= res->size)
+ continue;
-pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t phys_addr,
- unsigned long flags)
-{
- pci_addr_t bus_addr = 0;
- int ret;
+ if (len > res->size - offset)
+ continue;
- /*
- * if PCI_REGION_MEM is set we do a two pass search with preference
- * on matches that don't have PCI_REGION_SYS_MEMORY set
- */
- if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
- ret = _dm_pci_phys_to_bus(dev, phys_addr, flags,
- PCI_REGION_SYS_MEMORY, &bus_addr);
- if (!ret)
- return bus_addr;
+ return res->bus_start + offset;
}
- ret = _dm_pci_phys_to_bus(dev, phys_addr, flags, 0, &bus_addr);
-
- if (ret)
- puts("pci_hose_phys_to_bus: invalid physical address\n");
-
- return bus_addr;
+ puts("pci_hose_phys_to_bus: invalid physical address\n");
+ return 0;
}
static phys_addr_t dm_pci_map_ea_virt(struct udevice *dev, int ea_off,
@@ -1533,8 +1505,9 @@ static phys_addr_t dm_pci_map_ea_virt(struct udevice *dev, int ea_off,
return addr;
}
-static void *dm_pci_map_ea_bar(struct udevice *dev, int bar, int flags,
- int ea_off, struct pci_child_plat *pdata)
+static void *dm_pci_map_ea_bar(struct udevice *dev, int bar, size_t offset,
+ size_t len, int ea_off,
+ struct pci_child_plat *pdata)
{
int ea_cnt, i, entry_size;
int bar_id = (bar - PCI_BASE_ADDRESS_0) >> 2;
@@ -1576,14 +1549,18 @@ static void *dm_pci_map_ea_bar(struct udevice *dev, int bar, int flags,
if (IS_ENABLED(CONFIG_PCI_SRIOV))
addr += dm_pci_map_ea_virt(dev, ea_off, pdata);
+ if (~((phys_addr_t)0) - addr < offset)
+ return NULL;
+
/* size ignored for now */
- return map_physmem(addr, 0, flags);
+ return map_physmem(addr + offset, len, MAP_NOCACHE);
}
return 0;
}
-void *dm_pci_map_bar(struct udevice *dev, int bar, int flags)
+void *dm_pci_map_bar(struct udevice *dev, int bar, size_t offset, size_t len,
+ unsigned long mask, unsigned long flags)
{
struct pci_child_plat *pdata = dev_get_parent_plat(dev);
struct udevice *udev = dev;
@@ -1606,21 +1583,29 @@ void *dm_pci_map_bar(struct udevice *dev, int bar, int flags)
* Incase of virtual functions, pdata will help read VF BEI
* and EA entry size.
*/
- ea_off = dm_pci_find_capability(udev, PCI_CAP_ID_EA);
+ if (IS_ENABLED(CONFIG_PCI_ENHANCED_ALLOCATION))
+ ea_off = dm_pci_find_capability(udev, PCI_CAP_ID_EA);
+ else
+ ea_off = 0;
+
if (ea_off)
- return dm_pci_map_ea_bar(udev, bar, flags, ea_off, pdata);
+ return dm_pci_map_ea_bar(udev, bar, offset, len, ea_off, pdata);
/* read BAR address */
dm_pci_read_config32(udev, bar, &bar_response);
pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
+ if (~((pci_addr_t)0) - pci_bus_addr < offset)
+ return NULL;
+
/*
- * Pass "0" as the length argument to pci_bus_to_virt. The arg
- * isn't actually used on any platform because U-Boot assumes a static
- * linear mapping. In the future, this could read the BAR size
- * and pass that as the size if needed.
+ * Forward the length argument to dm_pci_bus_to_virt. The length will
+ * be used to check that the entire address range has been declared as
+ * a PCI range, but a better check would be to probe for the size of
+ * the bar and prevent overflow more locally.
*/
- return dm_pci_bus_to_virt(udev, pci_bus_addr, flags, 0, MAP_NOCACHE);
+ return dm_pci_bus_to_virt(udev, pci_bus_addr + offset, len, mask, flags,
+ MAP_NOCACHE);
}
static int _dm_pci_find_next_capability(struct udevice *dev, u8 pos, int cap)
diff --git a/drivers/spi/octeon_spi.c b/drivers/spi/octeon_spi.c
index fcabc11..c2a7ee23 100644
--- a/drivers/spi/octeon_spi.c
+++ b/drivers/spi/octeon_spi.c
@@ -568,7 +568,7 @@ static int octeon_spi_probe(struct udevice *dev)
pci_dev_t bdf = dm_pci_get_bdf(dev);
debug("SPI PCI device: %x\n", bdf);
- priv->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+ priv->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
PCI_REGION_MEM);
/* Add base offset */
priv->base += 0x1000;
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 4f711de..1ab3061 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -36,7 +36,8 @@ static int ehci_pci_init(struct udevice *dev, struct ehci_hccr **ret_hccr,
return ret;
hccr = (struct ehci_hccr *)dm_pci_map_bar(dev,
- PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+ PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
+ PCI_REGION_MEM);
hcor = (struct ehci_hcor *)((uintptr_t) hccr +
HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 6ddc9da..f061aec 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -18,7 +18,7 @@ static int ohci_pci_probe(struct udevice *dev)
{
struct ohci_regs *regs;
- regs = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+ regs = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, PCI_REGION_MEM);
return ohci_register(dev, regs);
}
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 630bc20..11f1c02 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -27,7 +27,8 @@ static int xhci_pci_init(struct udevice *dev, struct xhci_hccr **ret_hccr,
u32 cmd;
hccr = (struct xhci_hccr *)dm_pci_map_bar(dev,
- PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+ PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
+ PCI_REGION_MEM);
if (!hccr) {
printf("xhci-pci init cannot map PCI mem bar\n");
return -EIO;
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 863c3fb..586263e 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -37,6 +37,15 @@ config VIRTIO_PCI
This driver provides support for virtio based paravirtual device
drivers over PCI.
+config VIRTIO_PCI_LEGACY
+ bool "PCI driver for legacy virtio devices"
+ depends on PCI
+ select VIRTIO
+ default VIRTIO_PCI
+ help
+ This driver provides support for legacy virtio based paravirtual
+ device drivers over PCI.
+
config VIRTIO_SANDBOX
bool "Sandbox driver for virtio devices"
depends on SANDBOX
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index dc88809..4c63a6c 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -5,7 +5,8 @@
obj-y += virtio-uclass.o virtio_ring.o
obj-$(CONFIG_VIRTIO_MMIO) += virtio_mmio.o
-obj-$(CONFIG_VIRTIO_PCI) += virtio_pci_legacy.o virtio_pci_modern.o
+obj-$(CONFIG_VIRTIO_PCI) += virtio_pci_modern.o
+obj-$(CONFIG_VIRTIO_PCI_LEGACY) += virtio_pci_legacy.o
obj-$(CONFIG_VIRTIO_SANDBOX) += virtio_sandbox.o
obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o
diff --git a/drivers/virtio/virtio_pci_legacy.c b/drivers/virtio/virtio_pci_legacy.c
index 03fa5cb..cf5dfb1 100644
--- a/drivers/virtio/virtio_pci_legacy.c
+++ b/drivers/virtio/virtio_pci_legacy.c
@@ -319,7 +319,8 @@ static int virtio_pci_probe(struct udevice *udev)
uc_priv->device = subdevice;
uc_priv->vendor = subvendor;
- priv->ioaddr = dm_pci_map_bar(udev, PCI_BASE_ADDRESS_0, PCI_REGION_IO);
+ priv->ioaddr = dm_pci_map_bar(udev, PCI_BASE_ADDRESS_0, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_IO);
if (!priv->ioaddr)
return -ENXIO;
debug("(%s): virtio legacy device reg base %04lx\n",
diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c
index fd8a1f3..880a12c 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -94,6 +94,7 @@
*
* @common: pci transport device common register block base
* @notify_base: pci transport device notify register block base
+ * @notify_len: pci transport device notify register block length
* @device: pci transport device device-specific register block base
* @device_len: pci transport device device-specific register block length
* @notify_offset_multiplier: multiply queue_notify_off by this value
@@ -101,6 +102,7 @@
struct virtio_pci_priv {
struct virtio_pci_common_cfg __iomem *common;
void __iomem *notify_base;
+ u32 notify_len;
void __iomem *device;
u32 device_len;
u32 notify_offset_multiplier;
@@ -114,7 +116,11 @@ static int virtio_pci_get_config(struct udevice *udev, unsigned int offset,
__le16 w;
__le32 l;
- WARN_ON(offset + len > priv->device_len);
+ if (!priv->device)
+ return -ENOSYS;
+
+ if (offset + len > priv->device_len)
+ return -EINVAL;
switch (len) {
case 1:
@@ -136,7 +142,7 @@ static int virtio_pci_get_config(struct udevice *udev, unsigned int offset,
memcpy(buf + sizeof(l), &l, sizeof(l));
break;
default:
- WARN_ON(true);
+ return -EINVAL;
}
return 0;
@@ -150,7 +156,11 @@ static int virtio_pci_set_config(struct udevice *udev, unsigned int offset,
__le16 w;
__le32 l;
- WARN_ON(offset + len > priv->device_len);
+ if (!priv->device)
+ return -ENOSYS;
+
+ if (offset + len > priv->device_len)
+ return -EINVAL;
switch (len) {
case 1:
@@ -172,7 +182,7 @@ static int virtio_pci_set_config(struct udevice *udev, unsigned int offset,
iowrite32(le32_to_cpu(l), priv->device + offset + sizeof(l));
break;
default:
- WARN_ON(true);
+ return -EINVAL;
}
return 0;
@@ -365,11 +375,19 @@ static int virtio_pci_notify(struct udevice *udev, struct virtqueue *vq)
off = ioread16(&priv->common->queue_notify_off);
/*
+ * Check the effective offset is in bounds and leaves space for the
+ * notification, which is just a single 16-bit value since
+ * VIRTIO_F_NOTIFICATION_DATA isn't negotiated by the drivers.
+ */
+ off *= priv->notify_offset_multiplier;
+ if (off > priv->notify_len - sizeof(u16))
+ return -EIO;
+
+ /*
* We write the queue's selector into the notification register
* to signal the other end
*/
- iowrite16(vq->index,
- priv->notify_base + off * priv->notify_offset_multiplier);
+ iowrite16(vq->index, priv->notify_base + off);
return 0;
}
@@ -379,28 +397,51 @@ static int virtio_pci_notify(struct udevice *udev, struct virtqueue *vq)
*
* @udev: the transport device
* @cfg_type: the VIRTIO_PCI_CAP_* value we seek
+ * @cap_size: expected size of the capability
+ * @cap: capability read from the config space
*
* Return: offset of the configuration structure
*/
-static int virtio_pci_find_capability(struct udevice *udev, u8 cfg_type)
+static int virtio_pci_find_capability(struct udevice *udev, u8 cfg_type,
+ size_t cap_size,
+ struct virtio_pci_cap *cap)
{
int pos;
int offset;
- u8 type, bar;
+
+ assert(cap_size >= sizeof(struct virtio_pci_cap));
+ assert(cap_size <= PCI_CFG_SPACE_SIZE);
+
+ if (!cap)
+ return 0;
for (pos = dm_pci_find_capability(udev, PCI_CAP_ID_VNDR);
pos > 0;
pos = dm_pci_find_next_capability(udev, pos, PCI_CAP_ID_VNDR)) {
+ /* Ensure the capability is within bounds */
+ if (PCI_CFG_SPACE_SIZE - cap_size < pos)
+ return 0;
+
+ offset = pos + offsetof(struct virtio_pci_cap, cap_vndr);
+ dm_pci_read_config8(udev, offset, &cap->cap_vndr);
+ offset = pos + offsetof(struct virtio_pci_cap, cap_next);
+ dm_pci_read_config8(udev, offset, &cap->cap_next);
+ offset = pos + offsetof(struct virtio_pci_cap, cap_len);
+ dm_pci_read_config8(udev, offset, &cap->cap_len);
offset = pos + offsetof(struct virtio_pci_cap, cfg_type);
- dm_pci_read_config8(udev, offset, &type);
+ dm_pci_read_config8(udev, offset, &cap->cfg_type);
offset = pos + offsetof(struct virtio_pci_cap, bar);
- dm_pci_read_config8(udev, offset, &bar);
+ dm_pci_read_config8(udev, offset, &cap->bar);
+ offset = pos + offsetof(struct virtio_pci_cap, offset);
+ dm_pci_read_config32(udev, offset, &cap->offset);
+ offset = pos + offsetof(struct virtio_pci_cap, length);
+ dm_pci_read_config32(udev, offset, &cap->length);
/* Ignore structures with reserved BAR values */
- if (bar > 0x5)
+ if (cap->bar > 0x5)
continue;
- if (type == cfg_type)
+ if (cap->cfg_type == cfg_type)
return pos;
}
@@ -411,35 +452,24 @@ static int virtio_pci_find_capability(struct udevice *udev, u8 cfg_type)
* virtio_pci_map_capability - map base address of the capability
*
* @udev: the transport device
- * @off: offset of the configuration structure
+ * @cap: capability to map
*
* Return: base address of the capability
*/
-static void __iomem *virtio_pci_map_capability(struct udevice *udev, int off)
+static void __iomem *virtio_pci_map_capability(struct udevice *udev,
+ const struct virtio_pci_cap *cap)
{
- u8 bar;
- u32 offset;
- ulong base;
- void __iomem *p;
-
- if (!off)
- return NULL;
-
- offset = off + offsetof(struct virtio_pci_cap, bar);
- dm_pci_read_config8(udev, offset, &bar);
- offset = off + offsetof(struct virtio_pci_cap, offset);
- dm_pci_read_config32(udev, offset, &offset);
-
/*
- * TODO: adding 64-bit BAR support
- *
- * Per spec, the BAR is permitted to be either 32-bit or 64-bit.
- * For simplicity, only read the BAR address as 32-bit.
+ * Find the corresponding memory region that isn't system memory but is
+ * writable.
*/
- base = dm_pci_read_bar32(udev, bar);
- p = (void __iomem *)base + offset;
+ unsigned long mask =
+ PCI_REGION_TYPE | PCI_REGION_SYS_MEMORY | PCI_REGION_RO;
+ unsigned long flags = PCI_REGION_MEM;
+ u8 *p = dm_pci_map_bar(udev, PCI_BASE_ADDRESS_0 + cap->bar, cap->offset,
+ cap->length, mask, flags);
- return p;
+ return (void __iomem *)p;
}
static int virtio_pci_bind(struct udevice *udev)
@@ -462,6 +492,7 @@ static int virtio_pci_probe(struct udevice *udev)
u16 subvendor;
u8 revision;
int common, notify, device;
+ struct virtio_pci_cap common_cap, notify_cap, device_cap;
int offset;
/* We only own devices >= 0x1040 and <= 0x107f: leave the rest. */
@@ -477,34 +508,60 @@ static int virtio_pci_probe(struct udevice *udev)
uc_priv->vendor = subvendor;
/* Check for a common config: if not, use legacy mode (bar 0) */
- common = virtio_pci_find_capability(udev, VIRTIO_PCI_CAP_COMMON_CFG);
+ common = virtio_pci_find_capability(udev, VIRTIO_PCI_CAP_COMMON_CFG,
+ sizeof(struct virtio_pci_cap),
+ &common_cap);
if (!common) {
printf("(%s): leaving for legacy driver\n", udev->name);
return -ENODEV;
}
+ if (common_cap.length < sizeof(struct virtio_pci_common_cfg)) {
+ printf("(%s): virtio common config too small\n", udev->name);
+ return -EINVAL;
+ }
+
/* If common is there, notify should be too */
- notify = virtio_pci_find_capability(udev, VIRTIO_PCI_CAP_NOTIFY_CFG);
+ notify = virtio_pci_find_capability(udev, VIRTIO_PCI_CAP_NOTIFY_CFG,
+ sizeof(struct virtio_pci_notify_cap),
+ &notify_cap);
if (!notify) {
printf("(%s): missing capabilities %i/%i\n", udev->name,
common, notify);
return -EINVAL;
}
+ /* Map configuration structures */
+ priv->common = virtio_pci_map_capability(udev, &common_cap);
+ if (!priv->common) {
+ printf("(%s): could not map common config\n", udev->name);
+ return -EINVAL;
+ }
+
+ priv->notify_len = notify_cap.length;
+ priv->notify_base = virtio_pci_map_capability(udev, &notify_cap);
+ if (!priv->notify_base) {
+ printf("(%s): could not map notify config\n", udev->name);
+ return -EINVAL;
+ }
+
/*
* Device capability is only mandatory for devices that have
* device-specific configuration.
*/
- device = virtio_pci_find_capability(udev, VIRTIO_PCI_CAP_DEVICE_CFG);
+ device = virtio_pci_find_capability(udev, VIRTIO_PCI_CAP_DEVICE_CFG,
+ sizeof(struct virtio_pci_cap),
+ &device_cap);
if (device) {
- offset = notify + offsetof(struct virtio_pci_cap, length);
- dm_pci_read_config32(udev, offset, &priv->device_len);
+ priv->device_len = device_cap.length;
+ priv->device = virtio_pci_map_capability(udev, &device_cap);
+ if (!priv->device) {
+ printf("(%s): could not map device config\n",
+ udev->name);
+ return -EINVAL;
+ }
}
- /* Map configuration structures */
- priv->common = virtio_pci_map_capability(udev, common);
- priv->notify_base = virtio_pci_map_capability(udev, notify);
- priv->device = virtio_pci_map_capability(udev, device);
debug("(%p): common @ %p, notify base @ %p, device @ %p\n",
udev, priv->common, priv->notify_base, priv->device);
diff --git a/include/pci.h b/include/pci.h
index 5dbdcb0..d7ed35d 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -1313,26 +1313,30 @@ void dm_pci_write_bar32(struct udevice *dev, int barnum, u32 addr);
u32 dm_pci_read_bar32(const struct udevice *dev, int barnum);
/**
- * dm_pci_bus_to_phys() - convert a PCI bus address to a physical address
+ * dm_pci_bus_to_phys() - convert a PCI bus address range to a physical address
*
* @dev: Device containing the PCI address
* @addr: PCI address to convert
+ * @len: Length of the address range
+ * @mask: Mask to match flags for the region type
* @flags: Flags for the region type (PCI_REGION_...)
* Return: physical address corresponding to that PCI bus address
*/
-phys_addr_t dm_pci_bus_to_phys(struct udevice *dev, pci_addr_t addr,
- unsigned long flags);
+phys_addr_t dm_pci_bus_to_phys(struct udevice *dev, pci_addr_t addr, size_t len,
+ unsigned long mask, unsigned long flags);
/**
* dm_pci_phys_to_bus() - convert a physical address to a PCI bus address
*
* @dev: Device containing the bus address
* @addr: Physical address to convert
+ * @len: Length of the address range
+ * @mask: Mask to match flags for the region type
* @flags: Flags for the region type (PCI_REGION_...)
* Return: PCI bus address corresponding to that physical address
*/
-pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t addr,
- unsigned long flags);
+pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t addr, size_t len,
+ unsigned long mask, unsigned long flags);
/**
* dm_pci_map_bar() - get a virtual address associated with a BAR region
@@ -1346,10 +1350,14 @@ pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t addr,
*
* @dev: Device to check
* @bar: Bar register offset (PCI_BASE_ADDRESS_...)
+ * @offset: Offset from the base to map
+ * @len: Length to map
+ * @mask: Mask to match flags for the region type
* @flags: Flags for the region type (PCI_REGION_...)
* @return: pointer to the virtual address to use or 0 on error
*/
-void *dm_pci_map_bar(struct udevice *dev, int bar, int flags);
+void *dm_pci_map_bar(struct udevice *dev, int bar, size_t offset, size_t len,
+ unsigned long mask, unsigned long flags);
/**
* dm_pci_find_next_capability() - find a capability starting from an offset
@@ -1453,28 +1461,34 @@ int dm_pci_find_ext_capability(struct udevice *dev, int cap);
int dm_pci_flr(struct udevice *dev);
#define dm_pci_virt_to_bus(dev, addr, flags) \
- dm_pci_phys_to_bus(dev, (virt_to_phys(addr)), (flags))
-#define dm_pci_bus_to_virt(dev, addr, flags, len, map_flags) \
- map_physmem(dm_pci_bus_to_phys(dev, (addr), (flags)), \
- (len), (map_flags))
+ dm_pci_phys_to_bus(dev, (virt_to_phys(addr)), 0, PCI_REGION_TYPE, (flags))
+#define dm_pci_bus_to_virt(dev, addr, len, mask, flags, map_flags) \
+({ \
+ size_t _len = (len); \
+ phys_addr_t phys_addr = dm_pci_bus_to_phys((dev), (addr), _len, \
+ (mask), (flags)); \
+ map_physmem(phys_addr, _len, (map_flags)); \
+})
#define dm_pci_phys_to_mem(dev, addr) \
- dm_pci_phys_to_bus((dev), (addr), PCI_REGION_MEM)
+ dm_pci_phys_to_bus((dev), (addr), 0, PCI_REGION_TYPE, PCI_REGION_MEM)
#define dm_pci_mem_to_phys(dev, addr) \
- dm_pci_bus_to_phys((dev), (addr), PCI_REGION_MEM)
+ dm_pci_bus_to_phys((dev), (addr), 0, PCI_REGION_TYPE, PCI_REGION_MEM)
#define dm_pci_phys_to_io(dev, addr) \
- dm_pci_phys_to_bus((dev), (addr), PCI_REGION_IO)
+ dm_pci_phys_to_bus((dev), (addr), 0, PCI_REGION_TYPE, PCI_REGION_IO)
#define dm_pci_io_to_phys(dev, addr) \
- dm_pci_bus_to_phys((dev), (addr), PCI_REGION_IO)
+ dm_pci_bus_to_phys((dev), (addr), 0, PCI_REGION_TYPE, PCI_REGION_IO)
#define dm_pci_virt_to_mem(dev, addr) \
dm_pci_virt_to_bus((dev), (addr), PCI_REGION_MEM)
#define dm_pci_mem_to_virt(dev, addr, len, map_flags) \
- dm_pci_bus_to_virt((dev), (addr), PCI_REGION_MEM, (len), (map_flags))
+ dm_pci_bus_to_virt((dev), (addr), (len), PCI_REGION_TYPE, \
+ PCI_REGION_MEM, (map_flags))
#define dm_pci_virt_to_io(dev, addr) \
dm_pci_virt_to_bus((dev), (addr), PCI_REGION_IO)
#define dm_pci_io_to_virt(dev, addr, len, map_flags) \
- dm_pci_bus_to_virt((dev), (addr), PCI_REGION_IO, (len), (map_flags))
+ dm_pci_bus_to_virt((dev), (addr), (len), PCI_REGION_TYPE, \
+ PCI_REGION_IO, (map_flags))
/**
* dm_pci_find_device() - find a device by vendor/device ID
diff --git a/test/dm/pci.c b/test/dm/pci.c
index 00e4440..70a736c 100644
--- a/test/dm/pci.c
+++ b/test/dm/pci.c
@@ -268,27 +268,27 @@ static int dm_test_pci_ea(struct unit_test_state *uts)
ut_asserteq(PCI_CAP_ID_EA_OFFSET, cap);
/* test swap case in BAR 1 */
- bar = dm_pci_map_bar(swap, PCI_BASE_ADDRESS_0, 0);
+ bar = dm_pci_map_bar(swap, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, 0);
ut_assertnonnull(bar);
*(int *)bar = 2; /* swap upper/lower */
- bar = dm_pci_map_bar(swap, PCI_BASE_ADDRESS_1, 0);
+ bar = dm_pci_map_bar(swap, PCI_BASE_ADDRESS_1, 0, 0, PCI_REGION_TYPE, 0);
ut_assertnonnull(bar);
strcpy(bar, "ea TEST");
unmap_sysmem(bar);
- bar = dm_pci_map_bar(swap, PCI_BASE_ADDRESS_1, 0);
+ bar = dm_pci_map_bar(swap, PCI_BASE_ADDRESS_1, 0, 0, PCI_REGION_TYPE, 0);
ut_assertnonnull(bar);
ut_asserteq_str("EA test", bar);
/* test magic values in BARs2, 4; BAR 3 is n/a */
- bar = dm_pci_map_bar(swap, PCI_BASE_ADDRESS_2, 0);
+ bar = dm_pci_map_bar(swap, PCI_BASE_ADDRESS_2, 0, 0, PCI_REGION_TYPE, 0);
ut_assertnonnull(bar);
ut_asserteq(PCI_EA_BAR2_MAGIC, *(u32 *)bar);
- bar = dm_pci_map_bar(swap, PCI_BASE_ADDRESS_3, 0);
+ bar = dm_pci_map_bar(swap, PCI_BASE_ADDRESS_3, 0, 0, PCI_REGION_TYPE, 0);
ut_assertnull(bar);
- bar = dm_pci_map_bar(swap, PCI_BASE_ADDRESS_4, 0);
+ bar = dm_pci_map_bar(swap, PCI_BASE_ADDRESS_4, 0, 0, PCI_REGION_TYPE, 0);
ut_assertnonnull(bar);
ut_asserteq(PCI_EA_BAR4_MAGIC, *(u32 *)bar);
@@ -376,3 +376,109 @@ static int dm_test_pci_region_multi(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_pci_region_multi, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+/*
+ * Test the translation of PCI bus addresses to physical addresses using the
+ * ranges from bus#1.
+ */
+static int dm_test_pci_bus_to_phys(struct unit_test_state *uts)
+{
+ unsigned long mask = PCI_REGION_TYPE;
+ unsigned long flags = PCI_REGION_MEM;
+ struct udevice *dev;
+ phys_addr_t phys_addr;
+
+ ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(1, 0x08, 0), &dev));
+
+ /* Before any of the ranges. */
+ phys_addr = dm_pci_bus_to_phys(dev, 0x20000000, 0x400, mask, flags);
+ ut_asserteq(0, phys_addr);
+
+ /* Identity range: whole, start, mid, end */
+ phys_addr = dm_pci_bus_to_phys(dev, 0x2ffff000, 0x2000, mask, flags);
+ ut_asserteq(0, phys_addr);
+ phys_addr = dm_pci_bus_to_phys(dev, 0x30000000, 0x2000, mask, flags);
+ ut_asserteq(0x30000000, phys_addr);
+ phys_addr = dm_pci_bus_to_phys(dev, 0x30000000, 0x1000, mask, flags);
+ ut_asserteq(0x30000000, phys_addr);
+ phys_addr = dm_pci_bus_to_phys(dev, 0x30000abc, 0x12, mask, flags);
+ ut_asserteq(0x30000abc, phys_addr);
+ phys_addr = dm_pci_bus_to_phys(dev, 0x30000800, 0x1800, mask, flags);
+ ut_asserteq(0x30000800, phys_addr);
+ phys_addr = dm_pci_bus_to_phys(dev, 0x30008000, 0x1801, mask, flags);
+ ut_asserteq(0, phys_addr);
+
+ /* Translated range: whole, start, mid, end */
+ phys_addr = dm_pci_bus_to_phys(dev, 0x30fff000, 0x2000, mask, flags);
+ ut_asserteq(0, phys_addr);
+ phys_addr = dm_pci_bus_to_phys(dev, 0x31000000, 0x2000, mask, flags);
+ ut_asserteq(0x3e000000, phys_addr);
+ phys_addr = dm_pci_bus_to_phys(dev, 0x31000000, 0x1000, mask, flags);
+ ut_asserteq(0x3e000000, phys_addr);
+ phys_addr = dm_pci_bus_to_phys(dev, 0x31000abc, 0x12, mask, flags);
+ ut_asserteq(0x3e000abc, phys_addr);
+ phys_addr = dm_pci_bus_to_phys(dev, 0x31000800, 0x1800, mask, flags);
+ ut_asserteq(0x3e000800, phys_addr);
+ phys_addr = dm_pci_bus_to_phys(dev, 0x31008000, 0x1801, mask, flags);
+ ut_asserteq(0, phys_addr);
+
+ /* Beyond all of the ranges. */
+ phys_addr = dm_pci_bus_to_phys(dev, 0x32000000, 0x400, mask, flags);
+ ut_asserteq(0, phys_addr);
+
+ return 0;
+}
+DM_TEST(dm_test_pci_bus_to_phys, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+/*
+ * Test the translation of physical addresses to PCI bus addresses using the
+ * ranges from bus#1.
+ */
+static int dm_test_pci_phys_to_bus(struct unit_test_state *uts)
+{
+ unsigned long mask = PCI_REGION_TYPE;
+ unsigned long flags = PCI_REGION_MEM;
+ struct udevice *dev;
+ pci_addr_t pci_addr;
+
+ ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(1, 0x08, 0), &dev));
+
+ /* Before any of the ranges. */
+ pci_addr = dm_pci_phys_to_bus(dev, 0x20000000, 0x400, mask, flags);
+ ut_asserteq(0, pci_addr);
+
+ /* Identity range: partial overlap, whole, start, mid, end */
+ pci_addr = dm_pci_phys_to_bus(dev, 0x2ffff000, 0x2000, mask, flags);
+ ut_asserteq(0, pci_addr);
+ pci_addr = dm_pci_phys_to_bus(dev, 0x30000000, 0x2000, mask, flags);
+ ut_asserteq(0x30000000, pci_addr);
+ pci_addr = dm_pci_phys_to_bus(dev, 0x30000000, 0x1000, mask, flags);
+ ut_asserteq(0x30000000, pci_addr);
+ pci_addr = dm_pci_phys_to_bus(dev, 0x30000abc, 0x12, mask, flags);
+ ut_asserteq(0x30000abc, pci_addr);
+ pci_addr = dm_pci_phys_to_bus(dev, 0x30000800, 0x1800, mask, flags);
+ ut_asserteq(0x30000800, pci_addr);
+ pci_addr = dm_pci_phys_to_bus(dev, 0x30008000, 0x1801, mask, flags);
+ ut_asserteq(0, pci_addr);
+
+ /* Translated range: partial overlap, whole, start, mid, end */
+ pci_addr = dm_pci_phys_to_bus(dev, 0x3dfff000, 0x2000, mask, flags);
+ ut_asserteq(0, pci_addr);
+ pci_addr = dm_pci_phys_to_bus(dev, 0x3e000000, 0x2000, mask, flags);
+ ut_asserteq(0x31000000, pci_addr);
+ pci_addr = dm_pci_phys_to_bus(dev, 0x3e000000, 0x1000, mask, flags);
+ ut_asserteq(0x31000000, pci_addr);
+ pci_addr = dm_pci_phys_to_bus(dev, 0x3e000abc, 0x12, mask, flags);
+ ut_asserteq(0x31000abc, pci_addr);
+ pci_addr = dm_pci_phys_to_bus(dev, 0x3e000800, 0x1800, mask, flags);
+ ut_asserteq(0x31000800, pci_addr);
+ pci_addr = dm_pci_phys_to_bus(dev, 0x3e008000, 0x1801, mask, flags);
+ ut_asserteq(0, pci_addr);
+
+ /* Beyond all of the ranges. */
+ pci_addr = dm_pci_phys_to_bus(dev, 0x3f000000, 0x400, mask, flags);
+ ut_asserteq(0, pci_addr);
+
+ return 0;
+}
+DM_TEST(dm_test_pci_phys_to_bus, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);