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

Signed-off-by: Tim Harvey <thar...@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

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to