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: Bryant G. Ly <bryantly@linux.vnet.ibm.com> Signed-off-by: Juan J. Alvarez <jjalvare@linux.vnet.ibm.com> Acked-by: Russell Currey <ruscur@russell.cc> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
9a7f6b4386
commit
fc5f622163
@ -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)
|
|||||||
* @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)
|
|||||||
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)
|
|||||||
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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user