Commit fc5f6221 authored by Bryant G. Ly's avatar Bryant G. Ly Committed by Michael Ellerman

powerpc/pseries: Add Initialization of VF Bars

When enabling SR-IOV in pseries platform, the VF bar properties for a
PF are reported on the device node in the device tree.

This patch adds the IOV Bar resources to Linux structures from the
device tree for later use when configuring SR-IOV by PF driver.
Signed-off-by: default avatarBryant G. Ly <bryantly@linux.vnet.ibm.com>
Signed-off-by: default avatarJuan J. Alvarez <jjalvare@linux.vnet.ibm.com>
Acked-by: default avatarRussell Currey <ruscur@russell.cc>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 9a7f6b43
...@@ -121,6 +121,8 @@ extern int remove_phb_dynamic(struct pci_controller *phb); ...@@ -121,6 +121,8 @@ extern int remove_phb_dynamic(struct pci_controller *phb);
extern struct pci_dev *of_create_pci_dev(struct device_node *node, extern struct pci_dev *of_create_pci_dev(struct device_node *node,
struct pci_bus *bus, int devfn); struct pci_bus *bus, int devfn);
extern unsigned int pci_parse_of_flags(u32 addr0, int bridge);
extern void of_scan_pci_bridge(struct pci_dev *dev); extern void of_scan_pci_bridge(struct pci_dev *dev);
extern void of_scan_bus(struct device_node *node, struct pci_bus *bus); extern void of_scan_bus(struct device_node *node, struct pci_bus *bus);
......
...@@ -38,7 +38,7 @@ static u32 get_int_prop(struct device_node *np, const char *name, u32 def) ...@@ -38,7 +38,7 @@ static u32 get_int_prop(struct device_node *np, const char *name, u32 def)
* @addr0: value of 1st cell of a device tree PCI address. * @addr0: value of 1st cell of a device tree PCI address.
* @bridge: Set this flag if the address is from a bridge 'ranges' property * @bridge: Set this flag if the address is from a bridge 'ranges' property
*/ */
static unsigned int pci_parse_of_flags(u32 addr0, int bridge) unsigned int pci_parse_of_flags(u32 addr0, int bridge)
{ {
unsigned int flags = 0; unsigned int flags = 0;
......
...@@ -492,6 +492,162 @@ static void pseries_setup_rfi_flush(void) ...@@ -492,6 +492,162 @@ static void pseries_setup_rfi_flush(void)
setup_rfi_flush(types, enable); 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) static void __init pSeries_setup_arch(void)
{ {
set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT); set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT);
...@@ -525,6 +681,14 @@ static void __init pSeries_setup_arch(void) ...@@ -525,6 +681,14 @@ static void __init pSeries_setup_arch(void)
vpa_init(boot_cpuid); vpa_init(boot_cpuid);
ppc_md.power_save = pseries_lpar_idle; ppc_md.power_save = pseries_lpar_idle;
ppc_md.enable_pmcs = pseries_lpar_enable_pmcs; 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 { } else {
/* No special idle routine */ /* No special idle routine */
ppc_md.enable_pmcs = power4_enable_pmcs; ppc_md.enable_pmcs = power4_enable_pmcs;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment