|
@@ -492,6 +492,162 @@ static void pseries_setup_rfi_flush(void)
|
|
|
setup_rfi_flush(types, enable);
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_PCI_IOV
|
|
|
+enum rtas_iov_fw_value_map {
|
|
|
+ NUM_RES_PROPERTY = 0, /* Number of Resources */
|
|
|
+ LOW_INT = 1, /* Lowest 32 bits of Address */
|
|
|
+ START_OF_ENTRIES = 2, /* Always start of entry */
|
|
|
+ APERTURE_PROPERTY = 2, /* Start of entry+ to Aperture Size */
|
|
|
+ WDW_SIZE_PROPERTY = 4, /* Start of entry+ to Window Size */
|
|
|
+ NEXT_ENTRY = 7 /* Go to next entry on array */
|
|
|
+};
|
|
|
+
|
|
|
+enum get_iov_fw_value_index {
|
|
|
+ BAR_ADDRS = 1, /* Get Bar Address */
|
|
|
+ APERTURE_SIZE = 2, /* Get Aperture Size */
|
|
|
+ WDW_SIZE = 3 /* Get Window Size */
|
|
|
+};
|
|
|
+
|
|
|
+resource_size_t pseries_get_iov_fw_value(struct pci_dev *dev, int resno,
|
|
|
+ enum get_iov_fw_value_index value)
|
|
|
+{
|
|
|
+ const int *indexes;
|
|
|
+ struct device_node *dn = pci_device_to_OF_node(dev);
|
|
|
+ int i, num_res, ret = 0;
|
|
|
+
|
|
|
+ indexes = of_get_property(dn, "ibm,open-sriov-vf-bar-info", NULL);
|
|
|
+ if (!indexes)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * First element in the array is the number of Bars
|
|
|
+ * returned. Search through the list to find the matching
|
|
|
+ * bar
|
|
|
+ */
|
|
|
+ num_res = of_read_number(&indexes[NUM_RES_PROPERTY], 1);
|
|
|
+ if (resno >= num_res)
|
|
|
+ return 0; /* or an errror */
|
|
|
+
|
|
|
+ i = START_OF_ENTRIES + NEXT_ENTRY * resno;
|
|
|
+ switch (value) {
|
|
|
+ case BAR_ADDRS:
|
|
|
+ ret = of_read_number(&indexes[i], 2);
|
|
|
+ break;
|
|
|
+ case APERTURE_SIZE:
|
|
|
+ ret = of_read_number(&indexes[i + APERTURE_PROPERTY], 2);
|
|
|
+ break;
|
|
|
+ case WDW_SIZE:
|
|
|
+ ret = of_read_number(&indexes[i + WDW_SIZE_PROPERTY], 2);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+void of_pci_set_vf_bar_size(struct pci_dev *dev, const int *indexes)
|
|
|
+{
|
|
|
+ struct resource *res;
|
|
|
+ resource_size_t base, size;
|
|
|
+ int i, r, num_res;
|
|
|
+
|
|
|
+ num_res = of_read_number(&indexes[NUM_RES_PROPERTY], 1);
|
|
|
+ num_res = min_t(int, num_res, PCI_SRIOV_NUM_BARS);
|
|
|
+ for (i = START_OF_ENTRIES, r = 0; r < num_res && r < PCI_SRIOV_NUM_BARS;
|
|
|
+ i += NEXT_ENTRY, r++) {
|
|
|
+ res = &dev->resource[r + PCI_IOV_RESOURCES];
|
|
|
+ base = of_read_number(&indexes[i], 2);
|
|
|
+ size = of_read_number(&indexes[i + APERTURE_PROPERTY], 2);
|
|
|
+ res->flags = pci_parse_of_flags(of_read_number
|
|
|
+ (&indexes[i + LOW_INT], 1), 0);
|
|
|
+ res->flags |= (IORESOURCE_MEM_64 | IORESOURCE_PCI_FIXED);
|
|
|
+ res->name = pci_name(dev);
|
|
|
+ res->start = base;
|
|
|
+ res->end = base + size - 1;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void of_pci_parse_iov_addrs(struct pci_dev *dev, const int *indexes)
|
|
|
+{
|
|
|
+ struct resource *res, *root, *conflict;
|
|
|
+ resource_size_t base, size;
|
|
|
+ int i, r, num_res;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * First element in the array is the number of Bars
|
|
|
+ * returned. Search through the list to find the matching
|
|
|
+ * bars assign them from firmware into resources structure.
|
|
|
+ */
|
|
|
+ num_res = of_read_number(&indexes[NUM_RES_PROPERTY], 1);
|
|
|
+ for (i = START_OF_ENTRIES, r = 0; r < num_res && r < PCI_SRIOV_NUM_BARS;
|
|
|
+ i += NEXT_ENTRY, r++) {
|
|
|
+ res = &dev->resource[r + PCI_IOV_RESOURCES];
|
|
|
+ base = of_read_number(&indexes[i], 2);
|
|
|
+ size = of_read_number(&indexes[i + WDW_SIZE_PROPERTY], 2);
|
|
|
+ res->name = pci_name(dev);
|
|
|
+ res->start = base;
|
|
|
+ res->end = base + size - 1;
|
|
|
+ root = &iomem_resource;
|
|
|
+ dev_dbg(&dev->dev,
|
|
|
+ "pSeries IOV BAR %d: trying firmware assignment %pR\n",
|
|
|
+ r + PCI_IOV_RESOURCES, res);
|
|
|
+ conflict = request_resource_conflict(root, res);
|
|
|
+ if (conflict) {
|
|
|
+ dev_info(&dev->dev,
|
|
|
+ "BAR %d: %pR conflicts with %s %pR\n",
|
|
|
+ r + PCI_IOV_RESOURCES, res,
|
|
|
+ conflict->name, conflict);
|
|
|
+ res->flags |= IORESOURCE_UNSET;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void pseries_pci_fixup_resources(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ const int *indexes;
|
|
|
+ struct device_node *dn = pci_device_to_OF_node(pdev);
|
|
|
+
|
|
|
+ /*Firmware must support open sriov otherwise dont configure*/
|
|
|
+ indexes = of_get_property(dn, "ibm,open-sriov-vf-bar-info", NULL);
|
|
|
+ if (!indexes)
|
|
|
+ return;
|
|
|
+ /* Assign the addresses from device tree*/
|
|
|
+ of_pci_set_vf_bar_size(pdev, indexes);
|
|
|
+}
|
|
|
+
|
|
|
+static void pseries_pci_fixup_iov_resources(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ const int *indexes;
|
|
|
+ struct device_node *dn = pci_device_to_OF_node(pdev);
|
|
|
+
|
|
|
+ if (!pdev->is_physfn || pdev->is_added)
|
|
|
+ return;
|
|
|
+ /*Firmware must support open sriov otherwise dont configure*/
|
|
|
+ indexes = of_get_property(dn, "ibm,open-sriov-vf-bar-info", NULL);
|
|
|
+ if (!indexes)
|
|
|
+ return;
|
|
|
+ /* Assign the addresses from device tree*/
|
|
|
+ of_pci_parse_iov_addrs(pdev, indexes);
|
|
|
+}
|
|
|
+
|
|
|
+static resource_size_t pseries_pci_iov_resource_alignment(struct pci_dev *pdev,
|
|
|
+ int resno)
|
|
|
+{
|
|
|
+ const __be32 *reg;
|
|
|
+ struct device_node *dn = pci_device_to_OF_node(pdev);
|
|
|
+
|
|
|
+ /*Firmware must support open sriov otherwise report regular alignment*/
|
|
|
+ reg = of_get_property(dn, "ibm,is-open-sriov-pf", NULL);
|
|
|
+ if (!reg)
|
|
|
+ return pci_iov_resource_size(pdev, resno);
|
|
|
+
|
|
|
+ if (!pdev->is_physfn)
|
|
|
+ return 0;
|
|
|
+ return pseries_get_iov_fw_value(pdev,
|
|
|
+ resno - PCI_IOV_RESOURCES,
|
|
|
+ APERTURE_SIZE);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
static void __init pSeries_setup_arch(void)
|
|
|
{
|
|
|
set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT);
|
|
@@ -525,6 +681,14 @@ static void __init pSeries_setup_arch(void)
|
|
|
vpa_init(boot_cpuid);
|
|
|
ppc_md.power_save = pseries_lpar_idle;
|
|
|
ppc_md.enable_pmcs = pseries_lpar_enable_pmcs;
|
|
|
+#ifdef CONFIG_PCI_IOV
|
|
|
+ ppc_md.pcibios_fixup_resources =
|
|
|
+ pseries_pci_fixup_resources;
|
|
|
+ ppc_md.pcibios_fixup_sriov =
|
|
|
+ pseries_pci_fixup_iov_resources;
|
|
|
+ ppc_md.pcibios_iov_resource_alignment =
|
|
|
+ pseries_pci_iov_resource_alignment;
|
|
|
+#endif
|
|
|
} else {
|
|
|
/* No special idle routine */
|
|
|
ppc_md.enable_pmcs = power4_enable_pmcs;
|