mirror of
https://github.com/torvalds/linux.git
synced 2024-12-31 23:31:29 +00:00
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,
|
||||
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_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.
|
||||
* @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;
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user