[U-Boot] [RFC/RESEND 06/22] dm: pci: add PCI SR-IOV EA support

Tim Harvey tharvey at gateworks.com
Mon Mar 4 17:34:21 UTC 2019


Add Single Root I/O Virtualization (SR-IOV) and Enhanced Allocation support

Signed-off-by: Tim Harvey <tharvey at gateworks.com>
---
 arch/x86/cpu/baytrail/cpu.c  |   3 +-
 drivers/ata/ahci.c           |   8 +-
 drivers/i2c/designware_i2c.c |   4 +-
 drivers/i2c/intel_i2c.c      |   3 +-
 drivers/mmc/pci_mmc.c        |   3 +-
 drivers/net/e1000.c          |   5 +-
 drivers/net/pch_gbe.c        |   3 +-
 drivers/nvme/nvme.c          |   3 +-
 drivers/pci/pci-uclass.c     | 304 +++++++++++++++++++++++++++++++++--
 drivers/usb/host/ehci-pci.c  |   3 +-
 drivers/usb/host/xhci-pci.c  |   3 +-
 include/pci.h                |  56 ++++++-
 12 files changed, 370 insertions(+), 28 deletions(-)

diff --git a/arch/x86/cpu/baytrail/cpu.c b/arch/x86/cpu/baytrail/cpu.c
index 56e98131d7..cc3eae6cb2 100644
--- a/arch/x86/cpu/baytrail/cpu.c
+++ b/arch/x86/cpu/baytrail/cpu.c
@@ -46,6 +46,7 @@ int arch_cpu_init_dm(void)
 {
 	struct udevice *dev;
 	void *base;
+	size_t size;
 	int ret;
 	int i;
 
@@ -53,7 +54,7 @@ int arch_cpu_init_dm(void)
 	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, &size,
 					      PCI_REGION_MEM);
 			hsuart_clock_set(base);
 		}
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 5fafb63aeb..d6753f140d 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -455,8 +455,9 @@ static int ahci_init_one(struct ahci_uc_priv *uc_priv, pci_dev_t dev)
 	uc_priv->udma_mask = 0x7f;	/*Fixme,assume to support UDMA6 */
 
 #if !defined(CONFIG_DM_SCSI)
+	size_t size;
 #ifdef CONFIG_DM_PCI
-	uc_priv->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5,
+	uc_priv->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5, &size,
 					      PCI_REGION_MEM);
 
 	/* Take from kernel:
@@ -467,7 +468,7 @@ static int ahci_init_one(struct ahci_uc_priv *uc_priv, pci_dev_t dev)
 	if (vendor == 0x197b)
 		dm_pci_write_config8(dev, 0x41, 0xa1);
 #else
-	uc_priv->mmio_base = pci_map_bar(dev, PCI_BASE_ADDRESS_5,
+	uc_priv->mmio_base = pci_map_bar(dev, PCI_BASE_ADDRESS_5, &size,
 					   PCI_REGION_MEM);
 
 	/* Take from kernel:
@@ -1189,8 +1190,9 @@ int ahci_probe_scsi(struct udevice *ahci_dev, ulong base)
 int ahci_probe_scsi_pci(struct udevice *ahci_dev)
 {
 	ulong base;
+	size_t size;
 
-	base = (ulong)dm_pci_map_bar(ahci_dev, PCI_BASE_ADDRESS_5,
+	base = (ulong)dm_pci_map_bar(ahci_dev, PCI_BASE_ADDRESS_5, &size,
 				     PCI_REGION_MEM);
 
 	return ahci_probe_scsi(ahci_dev, base);
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c
index dbc3326b5a..bd6f4416ab 100644
--- a/drivers/i2c/designware_i2c.c
+++ b/drivers/i2c/designware_i2c.c
@@ -540,8 +540,10 @@ static int designware_i2c_probe(struct udevice *bus)
 	if (device_is_on_pci_bus(bus)) {
 #ifdef CONFIG_DM_PCI
 		/* Save base address from PCI BAR */
+		size_t size;
 		priv->regs = (struct i2c_regs *)
-			dm_pci_map_bar(bus, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+			dm_pci_map_bar(bus, PCI_BASE_ADDRESS_0, &size,
+				       PCI_REGION_MEM);
 #ifdef CONFIG_X86
 		/* Use BayTrail specific timing values */
 		priv->scl_sda_cfg = &byt_config;
diff --git a/drivers/i2c/intel_i2c.c b/drivers/i2c/intel_i2c.c
index f5509fef16..f9de161356 100644
--- a/drivers/i2c/intel_i2c.c
+++ b/drivers/i2c/intel_i2c.c
@@ -247,10 +247,11 @@ static int intel_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
 static int intel_i2c_probe(struct udevice *dev)
 {
 	struct intel_i2c *priv = dev_get_priv(dev);
+	size_t size;
 	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, &size,
 					   PCI_REGION_IO);
 	base = priv->base;
 
diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c
index 182d41637f..84701713a7 100644
--- a/drivers/mmc/pci_mmc.c
+++ b/drivers/mmc/pci_mmc.c
@@ -28,9 +28,10 @@ static int pci_mmc_probe(struct udevice *dev)
 	struct pci_mmc_plat *plat = dev_get_platdata(dev);
 	struct pci_mmc_priv *priv = dev_get_priv(dev);
 	struct sdhci_host *host = &priv->host;
+	size_t size;
 	int ret;
 
-	host->ioaddr = (void *)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+	host->ioaddr = (void *)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, &size,
 					      PCI_REGION_MEM);
 	host->name = dev->name;
 	ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0);
diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
index a34f697461..fbfb9052d8 100644
--- a/drivers/net/e1000.c
+++ b/drivers/net/e1000.c
@@ -5501,6 +5501,9 @@ static int e1000_init_one(struct e1000_hw *hw, int cardnum, pci_dev_t devno,
 #endif
 {
 	u32 val;
+#ifdef CONFIG_DM_ETH
+	size_t size;
+#endif
 
 	/* Assign the passed-in values */
 #ifdef CONFIG_DM_ETH
@@ -5551,7 +5554,7 @@ 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,
+	hw->hw_addr = dm_pci_map_bar(devno,	PCI_BASE_ADDRESS_0, &size,
 						PCI_REGION_MEM);
 #else
 	hw->hw_addr = pci_map_bar(devno,	PCI_BASE_ADDRESS_0,
diff --git a/drivers/net/pch_gbe.c b/drivers/net/pch_gbe.c
index 2286dd07e9..3194221796 100644
--- a/drivers/net/pch_gbe.c
+++ b/drivers/net/pch_gbe.c
@@ -434,6 +434,7 @@ static int pch_gbe_probe(struct udevice *dev)
 	struct pch_gbe_priv *priv;
 	struct eth_pdata *plat = dev_get_platdata(dev);
 	void *iobase;
+	size_t size;
 	int err;
 
 	/*
@@ -445,7 +446,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, &size, PCI_REGION_MEM);
 
 	plat->iobase = (ulong)iobase;
 	priv->mac_regs = (struct pch_gbe_regs *)iobase;
diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
index eb6fdeda50..49d8b12b2d 100644
--- a/drivers/nvme/nvme.c
+++ b/drivers/nvme/nvme.c
@@ -768,12 +768,13 @@ static int nvme_bind(struct udevice *udev)
 static int nvme_probe(struct udevice *udev)
 {
 	int ret;
+	size_t size;
 	struct nvme_dev *ndev = dev_get_priv(udev);
 
 	ndev->instance = trailing_strtol(udev->name);
 
 	INIT_LIST_HEAD(&ndev->namespaces);
-	ndev->bar = dm_pci_map_bar(udev, PCI_BASE_ADDRESS_0,
+	ndev->bar = dm_pci_map_bar(udev, PCI_BASE_ADDRESS_0, &size,
 			PCI_REGION_MEM);
 	if (readl(&ndev->bar->csts) == -1) {
 		ret = -ENODEV;
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index da49c96ed5..0720ffe5b4 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -599,12 +599,22 @@ int dm_pci_hose_probe_bus(struct udevice *bus)
 {
 	int sub_bus;
 	int ret;
+	int ea_pos;
+	u8 reg;
 
 	debug("%s\n", __func__);
 
-	sub_bus = pci_get_bus_max() + 1;
-	debug("%s: bus = %d/%s\n", __func__, sub_bus, bus->name);
-	dm_pciauto_prescan_setup_bridge(bus, sub_bus);
+	ea_pos = dm_pci_find_capability(bus, PCI_CAP_ID_EA);
+
+	if (ea_pos) {
+		dm_pci_read_config8(bus, ea_pos + sizeof(u32) + sizeof(u8), &reg);
+		sub_bus = reg;
+		debug("%s: bus = %d/%s\n", __func__, sub_bus, bus->name);
+	} else {
+		sub_bus = pci_get_bus_max() + 1;
+		debug("%s: bus = %d/%s\n", __func__, sub_bus, bus->name);
+		dm_pciauto_prescan_setup_bridge(bus, sub_bus);
+	}
 
 	ret = device_probe(bus);
 	if (ret) {
@@ -612,13 +622,16 @@ int dm_pci_hose_probe_bus(struct udevice *bus)
 		      ret);
 		return ret;
 	}
-	if (sub_bus != bus->seq) {
-		printf("%s: Internal error, bus '%s' got seq %d, expected %d\n",
-		       __func__, bus->name, bus->seq, sub_bus);
-		return -EPIPE;
+
+	if (!ea_pos) {
+		if (sub_bus != bus->seq) {
+			printf("%s: Internal error, bus '%s' got seq %d, expected %d\n",
+			       __func__, bus->name, bus->seq, sub_bus);
+			return -EPIPE;
+		}
+		sub_bus = pci_get_bus_max();
+		dm_pciauto_postscan_setup_bridge(bus, sub_bus);
 	}
-	sub_bus = pci_get_bus_max();
-	dm_pciauto_postscan_setup_bridge(bus, sub_bus);
 
 	return sub_bus;
 }
@@ -828,6 +841,7 @@ int pci_bind_bus_devices(struct udevice *bus)
 		pplat->vendor = vendor;
 		pplat->device = device;
 		pplat->class = class;
+		pplat->is_phys = true;
 	}
 
 	return 0;
@@ -1326,14 +1340,258 @@ pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t phys_addr,
 	return bus_addr;
 }
 
-void *dm_pci_map_bar(struct udevice *dev, int bar, int flags)
+/* Read an Enhanced Allocation (EA) entry */
+static int dm_pci_ea_entry_read(struct udevice *dev, int offset, int *bei,
+				pci_addr_t *start, size_t *size)
 {
-	pci_addr_t pci_bus_addr;
+	u32 base;
+	u32 max_offset;
+	u8  prop;
+	int ent_offset = offset;
+	int ent_size;
+	u32 dw0;
+
+	dm_pci_read_config32(dev, ent_offset, &dw0);
+
+	debug("%s: %d: dw0: %lx\n", __FUNCTION__, __LINE__, (unsigned long)dw0);
+
+	ent_offset += sizeof(u32);
+
+	/* Entry size field indicates DWORDs after 1st */
+	ent_size = ((dw0 & PCI_EA_ES) + 1) * sizeof(u32);
+
+	if (!(dw0 & PCI_EA_ENABLE))
+		goto out;
+	*bei = PCI_EA_BEI(dw0);
+
+	prop = PCI_EA_PP(dw0);
+
+	debug("EA property: %x\n", prop);
+
+	/*
+	* If the Property is in the reserved range, try the Secondary
+	* Property instead.
+	*/
+	if (prop > PCI_EA_P_BRIDGE_IO && prop < PCI_EA_P_MEM_RESERVED)
+		prop = PCI_EA_SP(dw0);
+	if (prop > PCI_EA_P_BRIDGE_IO)
+		goto out;
+
+	debug("EA property: %x\n", prop);
+
+	/* Read Base */
+	dm_pci_read_config32(dev, ent_offset, &base);
+	ent_offset += sizeof(u32);
+	*start = (pci_addr_t)base & PCI_EA_FIELD_MASK;
+
+	/* Read MaxOffset */
+	dm_pci_read_config32(dev, ent_offset, &max_offset);
+	ent_offset += sizeof(u32);
+
+	/* Read Base MSBs (if 64-bit entry) */
+	if (base & PCI_EA_IS_64) {
+		dm_pci_read_config32(dev, ent_offset, &base);
+		ent_offset += sizeof(u32);
+
+		*start |= (pci_addr_t)base << 32;
+	}
+
+	debug("EA (%u,%u) start = %lx\n", PCI_EA_BEI(dw0), prop, (unsigned long)*start);
+
+	*size = ((size_t)max_offset | 0x03) + 1;
+
+	/* Read MaxOffset MSBs (if 64-bit entry) */
+	if (max_offset & PCI_EA_IS_64) {
+		dm_pci_read_config32(dev, ent_offset, &max_offset);
+		ent_offset += sizeof(u32);
+
+		*size |= (size_t)max_offset << 32;
+	}
+
+	debug("EA (%u,%u) size = %lx\n", PCI_EA_BEI(dw0), prop, (unsigned long)*size);
+
+	if (*start + *size < *start) {
+		*size = 0;
+		*start = 0;
+		printf("EA Entry crosses address boundary\n");
+		goto out;
+	}
+
+	if (ent_size != ent_offset - offset) {
+		printf("EA Entry Size (%d) does not match length read (%d)\n",
+			ent_size, ent_offset - offset);
+		goto out;
+	}
+
+out:
+	return offset + ent_size;
+}
+
+/* Read an Enhanced Allocation (EA) BAR */
+int dm_pci_ea_bar_read(struct udevice *dev, int bar, pci_addr_t *start, size_t *size)
+{
+	int ea;
+	int offset;
+	u8  num_ent;
+	u8  hdr_type;
+	int i, bei = -1;
+
+	ea = dm_pci_find_capability(dev, PCI_CAP_ID_EA);
+
+	dm_pci_read_config8(dev, ea + PCI_EA_NUM_ENT, &num_ent);
+	num_ent &= PCI_EA_NUM_ENT_MASK;
+
+	offset = ea + PCI_EA_FIRST_ENT;
+
+	dm_pci_read_config8(dev, PCI_HEADER_TYPE, &hdr_type);
+
+	/* Skip DWORD 2 for type 1 functions */
+	if (hdr_type == PCI_HEADER_TYPE_BRIDGE)
+		offset += sizeof(u32);
+
+	for (i = 0; (i < num_ent) && (bar != bei); i++) {
+		offset = dm_pci_ea_entry_read(dev, offset, &bei, start, size);
+	}
+
+	return (bar == bei);
+}
+
+int dm_pci_sriov_init(struct udevice *pdev, int vf_en)
+{
+	u16 vendor, device;
+	struct udevice *bus;
+	struct udevice *dev;
+	pci_dev_t bdf;
+	u16 ctrl;
+	u16 num_vfs;
+	u16 total_vf;
+	u16 vf_offset;
+	u16 vf_stride;
+	int vf, ret;
+	int pos;
+
+	pos = dm_pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+	if (!pos) {
+		printf("Error: SRIOV capability not found\n");
+		return -ENODEV;
+	}
+
+	dm_pci_read_config16(pdev, pos + PCI_SRIOV_CTRL, &ctrl);
+
+	dm_pci_read_config16(pdev, pos + PCI_SRIOV_TOTAL_VF, &total_vf);
+
+	if (vf_en > total_vf)
+		vf_en = total_vf;
+
+	dm_pci_write_config16(pdev, pos + PCI_SRIOV_NUM_VF, vf_en);
+
+	ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
+	dm_pci_write_config16(pdev, pos + PCI_SRIOV_CTRL, ctrl);
+
+	dm_pci_read_config16(pdev, pos + PCI_SRIOV_NUM_VF, &num_vfs);
+
+	dm_pci_read_config16(pdev, pos + PCI_SRIOV_VF_OFFSET, &vf_offset);
+	dm_pci_read_config16(pdev, pos + PCI_SRIOV_VF_STRIDE, &vf_stride);
+
+	dm_pci_read_config16(pdev, PCI_VENDOR_ID, &vendor);
+	dm_pci_read_config16(pdev, pos + PCI_SRIOV_VF_DID, &device);
+
+	bdf = dm_pci_get_bdf(pdev);
+
+	pci_get_bus(PCI_BUS(bdf), &bus);
+
+	if (!bus)
+		return -ENODEV;
+
+	bdf += PCI_BDF(0, 0, vf_offset);
+
+	for (vf = 0; vf < num_vfs; vf++) {
+		struct pci_child_platdata *pplat;
+		ulong class;
+
+		pci_bus_read_config(bus, bdf, PCI_CLASS_REVISION,
+				    &class, PCI_SIZE_32);
+
+		class >>= 8;
+
+		debug("%s: bus %d/%s: found VF %x:%x\n", __func__,
+		      bus->seq, bus->name, PCI_DEV(bdf), PCI_FUNC(bdf));
+
+		/* Find this device in the device tree */
+		ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), &dev);
+
+		if (ret == -ENODEV) {
+			struct pci_device_id find_id;
+
+			memset(&find_id, 0, sizeof(find_id));
+
+			find_id.vendor = vendor;
+			find_id.device = device;
+			find_id.class = class >> 8;
+
+			ret = pci_find_and_bind_driver(bus, &find_id,
+						       bdf, &dev);
+
+			if (ret)
+				return ret;
+		}
+
+		/* Update the platform data */
+		pplat = dev_get_parent_platdata(dev);
+		pplat->devfn = PCI_MASK_BUS(bdf);
+		pplat->vendor = vendor;
+		pplat->device = device;
+		pplat->class = class;
+		pplat->is_phys = false;
+		pplat->pdev = pdev;
+		pplat->vf_id = vf * vf_stride + vf_offset;
+
+		bdf += PCI_BDF(0, 0, vf_stride);
+	}
+
+	return 0;
+
+}
+
+void *dm_pci_map_bar(struct udevice *dev, int bar, size_t *size, int flags)
+{
+	int pos;
+	pci_addr_t pci_bus_start;
 	u32 bar_response;
+	struct pci_child_platdata *pdata = dev_get_parent_platdata(dev);
 
-	/* read BAR address */
-	dm_pci_read_config32(dev, bar, &bar_response);
-	pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
+	if (!pdata->is_phys) {
+		if (bar < 9 || bar > 14)
+			return NULL;
+		dev = pdata->pdev;
+	}
+
+	pos = dm_pci_find_capability(dev, PCI_CAP_ID_EA);
+
+	if (pos) {
+		dm_pci_ea_bar_read(dev, bar, &pci_bus_start, size);
+	} else {
+		/* read BAR address */
+		if (bar >= 0 && bar <= 5) {
+			bar = PCI_BASE_ADDRESS_0 + bar * 4;
+		} else if (bar >= 9 && bar <= 14) {
+			pos = dm_pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
+			bar = pos + PCI_SRIOV_BAR + bar * 4;
+		}
+		dm_pci_read_config32(dev, bar,
+				     &bar_response);
+		pci_bus_start = (pci_addr_t)(bar_response & ~0xf);
+
+		if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+				PCI_BASE_ADDRESS_MEM_TYPE_64) {
+			dm_pci_read_config32(dev, bar + 4, &bar_response);
+		}
+		pci_bus_start |= (pci_addr_t)bar_response << 32;
+	}
+
+	if (!pdata->is_phys) {
+		pci_bus_start += (pdata->vf_id - 1) * (*size);
+	}
 
 	/*
 	 * Pass "0" as the length argument to pci_bus_to_virt.  The arg
@@ -1341,7 +1599,7 @@ void *dm_pci_map_bar(struct udevice *dev, int bar, int flags)
 	 * linear mapping.  In the future, this could read the BAR size
 	 * and pass that as the size if needed.
 	 */
-	return dm_pci_bus_to_virt(dev, pci_bus_addr, flags, 0, MAP_NOCACHE);
+	return dm_pci_bus_to_virt(dev, pci_bus_start, flags, 0, MAP_NOCACHE);
 }
 
 int dm_pci_find_capability(struct udevice *dev, int cap)
@@ -1412,6 +1670,22 @@ int dm_pci_find_ext_capability(struct udevice *dev, int cap)
 	return 0;
 }
 
+int dm_pci_sriov_get_totalvfs(struct udevice *pdev)
+{
+	u16 total_vf;
+	int pos;
+
+	pos = dm_pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+	if (!pos) {
+		printf("Error: SRIOV capability not found\n");
+		return -ENODEV;
+	}
+
+	dm_pci_read_config16(pdev, pos + PCI_SRIOV_TOTAL_VF, &total_vf);
+
+	return total_vf;
+}
+
 UCLASS_DRIVER(pci) = {
 	.id		= UCLASS_PCI,
 	.name		= "pci",
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 6150f3d888..db55d136b6 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -26,6 +26,7 @@ static int ehci_pci_init(struct udevice *dev, struct ehci_hccr **ret_hccr,
 	struct ehci_pci_priv *priv = dev_get_priv(dev);
 	struct ehci_hccr *hccr;
 	struct ehci_hcor *hcor;
+	size_t size;
 	int ret;
 	u32 cmd;
 
@@ -34,7 +35,7 @@ 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, &size, PCI_REGION_MEM);
 	hcor = (struct ehci_hcor *)((uintptr_t) hccr +
 			HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
 
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index b995aef997..d42f06bc32 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -16,10 +16,11 @@ static void xhci_pci_init(struct udevice *dev, struct xhci_hccr **ret_hccr,
 {
 	struct xhci_hccr *hccr;
 	struct xhci_hcor *hcor;
+	size_t size;
 	u32 cmd;
 
 	hccr = (struct xhci_hccr *)dm_pci_map_bar(dev,
-			PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+			PCI_BASE_ADDRESS_0, &size, PCI_REGION_MEM);
 	hcor = (struct xhci_hcor *)((uintptr_t) hccr +
 			HC_LENGTH(xhci_readl(&hccr->cr_capbase)));
 
diff --git a/include/pci.h b/include/pci.h
index 938a8390cb..033d5adf2a 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -411,6 +411,39 @@
 #define PCI_MSI_DATA_32		8	/* 16 bits of data for 32-bit devices */
 #define PCI_MSI_DATA_64		12	/* 16 bits of data for 64-bit devices */
 
+/* Single Root I/O Virtualization */
+#define PCI_SRIOV_BAR		0x24	/* VF BAR0 */
+#define PCI_SRIOV_BAR		0x24	/* VF BAR0 */
+#define PCI_SRIOV_CTRL		0x08	/* SR-IOV Control */
+#define  PCI_SRIOV_CTRL_VFE	0x01	/* VF Enable */
+#define  PCI_SRIOV_CTRL_VFM	0x02	/* VF Migration Enable */
+#define  PCI_SRIOV_CTRL_INTR	0x04	/* VF Migration Interrupt Enable */
+#define  PCI_SRIOV_CTRL_MSE	0x08	/* VF Memory Space Enable */
+#define  PCI_SRIOV_CTRL_ARI	0x10	/* ARI Capable Hierarchy */
+#define PCI_SRIOV_STATUS	0x0a	/* SR-IOV Status */
+#define  PCI_SRIOV_STATUS_VFM	0x01	/* VF Migration Status */
+#define PCI_SRIOV_INITIAL_VF	0x0c	/* Initial VFs */
+#define PCI_SRIOV_TOTAL_VF	0x0e	/* Total VFs */
+#define PCI_SRIOV_NUM_VF	0x10	/* Number of VFs */
+#define PCI_SRIOV_FUNC_LINK	0x12	/* Function Dependency Link */
+#define PCI_SRIOV_VF_OFFSET	0x14	/* First VF Offset */
+#define PCI_SRIOV_VF_STRIDE	0x16	/* Following VF Stride */
+#define PCI_SRIOV_VF_DID	0x1a	/* VF Device ID */
+
+/* Enhanced Allocation (EA) */
+#define PCI_EA_NUM_ENT		2	/* Number of Capability Entries */
+#define PCI_EA_NUM_ENT_MASK	0x3f	/* Num Entries Mask */
+#define PCI_EA_FIRST_ENT	4	/* First EA Entry in List */
+#define PCI_EA_ES		0x7	/* Entry Size */
+#define PCI_EA_BEI(x)  (((x) >> 4) & 0xf) /* BAR Equivalent Indicator */
+#define PCI_EA_PP(x)   (((x) >>  8) & 0xff)	/* Primary Properties */
+#define PCI_EA_SP(x)   (((x) >> 16) & 0xff)	/* Secondary Properties */
+#define  PCI_EA_P_BRIDGE_IO		0x07	/* Bridge I/O Space */
+#define  PCI_EA_P_MEM_RESERVED		0xfd	/* Reserved Memory */
+#define PCI_EA_ENABLE			(1 << 31) /* Enable for this entry */
+#define PCI_EA_IS_64			(1 << 1)	/* 64-bit field flag */
+#define PCI_EA_FIELD_MASK		0xfffffffc	/* For Base & Max Offset */
+
 #define PCI_MAX_PCI_DEVICES	32
 #define PCI_MAX_PCI_FUNCTIONS	8
 
@@ -841,6 +874,9 @@ struct pci_child_platdata {
 	unsigned short vendor;
 	unsigned short device;
 	unsigned int class;
+	bool is_phys;
+	struct udevice *pdev;
+	int vf_id;
 };
 
 /* PCI bus operations */
@@ -1307,10 +1343,11 @@ pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t addr,
  *
  * @dev:	Device to check
  * @bar:	Bar number to read (numbered from 0)
+ * @size:	pointer to var to assign BAR size
  * @flags:	Flags for the region type (PCI_REGION_...)
  * @return: pointer to the virtual address to use
  */
-void *dm_pci_map_bar(struct udevice *dev, int bar, int flags);
+void *dm_pci_map_bar(struct udevice *dev, int bar, size_t *size, int flags);
 
 /**
  * dm_pci_find_capability() - find a capability
@@ -1357,6 +1394,23 @@ int dm_pci_find_capability(struct udevice *dev, int cap);
  */
 int dm_pci_find_ext_capability(struct udevice *dev, int cap);
 
+/**
+ * dm_pci_sriov_init() - Enable SR-IOV virtual functions
+ *
+ * @dev:	PCI device
+ * @vf_en:	number of virtual functions to enable
+ * @return:	0 if successful, error otherwise
+ */
+int dm_pci_sriov_init(struct udevice *dev, int vf_en);
+
+/**
+ * dm_pci_sriov_get_totalvfs() - Get number of SR-IOV virtual functions
+ *
+ * @dev:	PCI device
+ * @return:	number of SR-IOV virtual functions
+ */
+int dm_pci_sriov_get_totalvfs(struct udevice *pdev);
+
 #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) \
-- 
2.17.1



More information about the U-Boot mailing list