18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#include <linux/kernel.h>
48c2ecf20Sopenharmony_ci#include <linux/ioport.h>
58c2ecf20Sopenharmony_ci#include <linux/bitmap.h>
68c2ecf20Sopenharmony_ci#include <linux/pci.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <asm/opal.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "pci.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci/* for pci_dev_is_added() */
138c2ecf20Sopenharmony_ci#include "../../../../drivers/pci/pci.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/*
168c2ecf20Sopenharmony_ci * The majority of the complexity in supporting SR-IOV on PowerNV comes from
178c2ecf20Sopenharmony_ci * the need to put the MMIO space for each VF into a separate PE. Internally
188c2ecf20Sopenharmony_ci * the PHB maps MMIO addresses to a specific PE using the "Memory BAR Table".
198c2ecf20Sopenharmony_ci * The MBT historically only applied to the 64bit MMIO window of the PHB
208c2ecf20Sopenharmony_ci * so it's common to see it referred to as the "M64BT".
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * An MBT entry stores the mapped range as an <base>,<mask> pair. This forces
238c2ecf20Sopenharmony_ci * the address range that we want to map to be power-of-two sized and aligned.
248c2ecf20Sopenharmony_ci * For conventional PCI devices this isn't really an issue since PCI device BARs
258c2ecf20Sopenharmony_ci * have the same requirement.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * For a SR-IOV BAR things are a little more awkward since size and alignment
288c2ecf20Sopenharmony_ci * are not coupled. The alignment is set based on the the per-VF BAR size, but
298c2ecf20Sopenharmony_ci * the total BAR area is: number-of-vfs * per-vf-size. The number of VFs
308c2ecf20Sopenharmony_ci * isn't necessarily a power of two, so neither is the total size. To fix that
318c2ecf20Sopenharmony_ci * we need to finesse (read: hack) the Linux BAR allocator so that it will
328c2ecf20Sopenharmony_ci * allocate the SR-IOV BARs in a way that lets us map them using the MBT.
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci * The changes to size and alignment that we need to do depend on the "mode"
358c2ecf20Sopenharmony_ci * of MBT entry that we use. We only support SR-IOV on PHB3 (IODA2) and above,
368c2ecf20Sopenharmony_ci * so as a baseline we can assume that we have the following BAR modes
378c2ecf20Sopenharmony_ci * available:
388c2ecf20Sopenharmony_ci *
398c2ecf20Sopenharmony_ci *   NB: $PE_COUNT is the number of PEs that the PHB supports.
408c2ecf20Sopenharmony_ci *
418c2ecf20Sopenharmony_ci * a) A segmented BAR that splits the mapped range into $PE_COUNT equally sized
428c2ecf20Sopenharmony_ci *    segments. The n'th segment is mapped to the n'th PE.
438c2ecf20Sopenharmony_ci * b) An un-segmented BAR that maps the whole address range to a specific PE.
448c2ecf20Sopenharmony_ci *
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci * We prefer to use mode a) since it only requires one MBT entry per SR-IOV BAR
478c2ecf20Sopenharmony_ci * For comparison b) requires one entry per-VF per-BAR, or:
488c2ecf20Sopenharmony_ci * (num-vfs * num-sriov-bars) in total. To use a) we need the size of each segment
498c2ecf20Sopenharmony_ci * to equal the size of the per-VF BAR area. So:
508c2ecf20Sopenharmony_ci *
518c2ecf20Sopenharmony_ci *	new_size = per-vf-size * number-of-PEs
528c2ecf20Sopenharmony_ci *
538c2ecf20Sopenharmony_ci * The alignment for the SR-IOV BAR also needs to be changed from per-vf-size
548c2ecf20Sopenharmony_ci * to "new_size", calculated above. Implementing this is a convoluted process
558c2ecf20Sopenharmony_ci * which requires several hooks in the PCI core:
568c2ecf20Sopenharmony_ci *
578c2ecf20Sopenharmony_ci * 1. In pcibios_add_device() we call pnv_pci_ioda_fixup_iov().
588c2ecf20Sopenharmony_ci *
598c2ecf20Sopenharmony_ci *    At this point the device has been probed and the device's BARs are sized,
608c2ecf20Sopenharmony_ci *    but no resource allocations have been done. The SR-IOV BARs are sized
618c2ecf20Sopenharmony_ci *    based on the maximum number of VFs supported by the device and we need
628c2ecf20Sopenharmony_ci *    to increase that to new_size.
638c2ecf20Sopenharmony_ci *
648c2ecf20Sopenharmony_ci * 2. Later, when Linux actually assigns resources it tries to make the resource
658c2ecf20Sopenharmony_ci *    allocations for each PCI bus as compact as possible. As a part of that it
668c2ecf20Sopenharmony_ci *    sorts the BARs on a bus by their required alignment, which is calculated
678c2ecf20Sopenharmony_ci *    using pci_resource_alignment().
688c2ecf20Sopenharmony_ci *
698c2ecf20Sopenharmony_ci *    For IOV resources this goes:
708c2ecf20Sopenharmony_ci *    pci_resource_alignment()
718c2ecf20Sopenharmony_ci *        pci_sriov_resource_alignment()
728c2ecf20Sopenharmony_ci *            pcibios_sriov_resource_alignment()
738c2ecf20Sopenharmony_ci *                pnv_pci_iov_resource_alignment()
748c2ecf20Sopenharmony_ci *
758c2ecf20Sopenharmony_ci *    Our hook overrides the default alignment, equal to the per-vf-size, with
768c2ecf20Sopenharmony_ci *    new_size computed above.
778c2ecf20Sopenharmony_ci *
788c2ecf20Sopenharmony_ci * 3. When userspace enables VFs for a device:
798c2ecf20Sopenharmony_ci *
808c2ecf20Sopenharmony_ci *    sriov_enable()
818c2ecf20Sopenharmony_ci *       pcibios_sriov_enable()
828c2ecf20Sopenharmony_ci *           pnv_pcibios_sriov_enable()
838c2ecf20Sopenharmony_ci *
848c2ecf20Sopenharmony_ci *    This is where we actually allocate PE numbers for each VF and setup the
858c2ecf20Sopenharmony_ci *    MBT mapping for each SR-IOV BAR. In steps 1) and 2) we setup an "arena"
868c2ecf20Sopenharmony_ci *    where each MBT segment is equal in size to the VF BAR so we can shift
878c2ecf20Sopenharmony_ci *    around the actual SR-IOV BAR location within this arena. We need this
888c2ecf20Sopenharmony_ci *    ability because the PE space is shared by all devices on the same PHB.
898c2ecf20Sopenharmony_ci *    When using mode a) described above segment 0 in maps to PE#0 which might
908c2ecf20Sopenharmony_ci *    be already being used by another device on the PHB.
918c2ecf20Sopenharmony_ci *
928c2ecf20Sopenharmony_ci *    As a result we need allocate a contigious range of PE numbers, then shift
938c2ecf20Sopenharmony_ci *    the address programmed into the SR-IOV BAR of the PF so that the address
948c2ecf20Sopenharmony_ci *    of VF0 matches up with the segment corresponding to the first allocated
958c2ecf20Sopenharmony_ci *    PE number. This is handled in pnv_pci_vf_resource_shift().
968c2ecf20Sopenharmony_ci *
978c2ecf20Sopenharmony_ci *    Once all that is done we return to the PCI core which then enables VFs,
988c2ecf20Sopenharmony_ci *    scans them and creates pci_devs for each. The init process for a VF is
998c2ecf20Sopenharmony_ci *    largely the same as a normal device, but the VF is inserted into the IODA
1008c2ecf20Sopenharmony_ci *    PE that we allocated for it rather than the PE associated with the bus.
1018c2ecf20Sopenharmony_ci *
1028c2ecf20Sopenharmony_ci * 4. When userspace disables VFs we unwind the above in
1038c2ecf20Sopenharmony_ci *    pnv_pcibios_sriov_disable(). Fortunately this is relatively simple since
1048c2ecf20Sopenharmony_ci *    we don't need to validate anything, just tear down the mappings and
1058c2ecf20Sopenharmony_ci *    move SR-IOV resource back to its "proper" location.
1068c2ecf20Sopenharmony_ci *
1078c2ecf20Sopenharmony_ci * That's how mode a) works. In theory mode b) (single PE mapping) is less work
1088c2ecf20Sopenharmony_ci * since we can map each individual VF with a separate BAR. However, there's a
1098c2ecf20Sopenharmony_ci * few limitations:
1108c2ecf20Sopenharmony_ci *
1118c2ecf20Sopenharmony_ci * 1) For IODA2 mode b) has a minimum alignment requirement of 32MB. This makes
1128c2ecf20Sopenharmony_ci *    it only usable for devices with very large per-VF BARs. Such devices are
1138c2ecf20Sopenharmony_ci *    similar to Big Foot. They definitely exist, but I've never seen one.
1148c2ecf20Sopenharmony_ci *
1158c2ecf20Sopenharmony_ci * 2) The number of MBT entries that we have is limited. PHB3 and PHB4 only
1168c2ecf20Sopenharmony_ci *    16 total and some are needed for. Most SR-IOV capable network cards can support
1178c2ecf20Sopenharmony_ci *    more than 16 VFs on each port.
1188c2ecf20Sopenharmony_ci *
1198c2ecf20Sopenharmony_ci * We use b) when using a) would use more than 1/4 of the entire 64 bit MMIO
1208c2ecf20Sopenharmony_ci * window of the PHB.
1218c2ecf20Sopenharmony_ci *
1228c2ecf20Sopenharmony_ci *
1238c2ecf20Sopenharmony_ci *
1248c2ecf20Sopenharmony_ci * PHB4 (IODA3) added a few new features that would be useful for SR-IOV. It
1258c2ecf20Sopenharmony_ci * allowed the MBT to map 32bit MMIO space in addition to 64bit which allows
1268c2ecf20Sopenharmony_ci * us to support SR-IOV BARs in the 32bit MMIO window. This is useful since
1278c2ecf20Sopenharmony_ci * the Linux BAR allocation will place any BAR marked as non-prefetchable into
1288c2ecf20Sopenharmony_ci * the non-prefetchable bridge window, which is 32bit only. It also added two
1298c2ecf20Sopenharmony_ci * new modes:
1308c2ecf20Sopenharmony_ci *
1318c2ecf20Sopenharmony_ci * c) A segmented BAR similar to a), but each segment can be individually
1328c2ecf20Sopenharmony_ci *    mapped to any PE. This is matches how the 32bit MMIO window worked on
1338c2ecf20Sopenharmony_ci *    IODA1&2.
1348c2ecf20Sopenharmony_ci *
1358c2ecf20Sopenharmony_ci * d) A segmented BAR with 8, 64, or 128 segments. This works similarly to a),
1368c2ecf20Sopenharmony_ci *    but with fewer segments and configurable base PE.
1378c2ecf20Sopenharmony_ci *
1388c2ecf20Sopenharmony_ci *    i.e. The n'th segment maps to the (n + base)'th PE.
1398c2ecf20Sopenharmony_ci *
1408c2ecf20Sopenharmony_ci *    The base PE is also required to be a multiple of the window size.
1418c2ecf20Sopenharmony_ci *
1428c2ecf20Sopenharmony_ci * Unfortunately, the OPAL API doesn't currently (as of skiboot v6.6) allow us
1438c2ecf20Sopenharmony_ci * to exploit any of the IODA3 features.
1448c2ecf20Sopenharmony_ci */
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic void pnv_pci_ioda_fixup_iov_resources(struct pci_dev *pdev)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(pdev->bus);
1498c2ecf20Sopenharmony_ci	struct resource *res;
1508c2ecf20Sopenharmony_ci	int i;
1518c2ecf20Sopenharmony_ci	resource_size_t vf_bar_sz;
1528c2ecf20Sopenharmony_ci	struct pnv_iov_data *iov;
1538c2ecf20Sopenharmony_ci	int mul;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	iov = kzalloc(sizeof(*iov), GFP_KERNEL);
1568c2ecf20Sopenharmony_ci	if (!iov)
1578c2ecf20Sopenharmony_ci		goto disable_iov;
1588c2ecf20Sopenharmony_ci	pdev->dev.archdata.iov_data = iov;
1598c2ecf20Sopenharmony_ci	mul = phb->ioda.total_pe_num;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
1628c2ecf20Sopenharmony_ci		res = &pdev->resource[i + PCI_IOV_RESOURCES];
1638c2ecf20Sopenharmony_ci		if (!res->flags || res->parent)
1648c2ecf20Sopenharmony_ci			continue;
1658c2ecf20Sopenharmony_ci		if (!pnv_pci_is_m64_flags(res->flags)) {
1668c2ecf20Sopenharmony_ci			dev_warn(&pdev->dev, "Don't support SR-IOV with non M64 VF BAR%d: %pR. \n",
1678c2ecf20Sopenharmony_ci				 i, res);
1688c2ecf20Sopenharmony_ci			goto disable_iov;
1698c2ecf20Sopenharmony_ci		}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci		vf_bar_sz = pci_iov_resource_size(pdev, i + PCI_IOV_RESOURCES);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci		/*
1748c2ecf20Sopenharmony_ci		 * Generally, one segmented M64 BAR maps one IOV BAR. However,
1758c2ecf20Sopenharmony_ci		 * if a VF BAR is too large we end up wasting a lot of space.
1768c2ecf20Sopenharmony_ci		 * If each VF needs more than 1/4 of the default m64 segment
1778c2ecf20Sopenharmony_ci		 * then each VF BAR should be mapped in single-PE mode to reduce
1788c2ecf20Sopenharmony_ci		 * the amount of space required. This does however limit the
1798c2ecf20Sopenharmony_ci		 * number of VFs we can support.
1808c2ecf20Sopenharmony_ci		 *
1818c2ecf20Sopenharmony_ci		 * The 1/4 limit is arbitrary and can be tweaked.
1828c2ecf20Sopenharmony_ci		 */
1838c2ecf20Sopenharmony_ci		if (vf_bar_sz > (phb->ioda.m64_segsize >> 2)) {
1848c2ecf20Sopenharmony_ci			/*
1858c2ecf20Sopenharmony_ci			 * On PHB3, the minimum size alignment of M64 BAR in
1868c2ecf20Sopenharmony_ci			 * single mode is 32MB. If this VF BAR is smaller than
1878c2ecf20Sopenharmony_ci			 * 32MB, but still too large for a segmented window
1888c2ecf20Sopenharmony_ci			 * then we can't map it and need to disable SR-IOV for
1898c2ecf20Sopenharmony_ci			 * this device.
1908c2ecf20Sopenharmony_ci			 */
1918c2ecf20Sopenharmony_ci			if (vf_bar_sz < SZ_32M) {
1928c2ecf20Sopenharmony_ci				pci_err(pdev, "VF BAR%d: %pR can't be mapped in single PE mode\n",
1938c2ecf20Sopenharmony_ci					i, res);
1948c2ecf20Sopenharmony_ci				goto disable_iov;
1958c2ecf20Sopenharmony_ci			}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci			iov->m64_single_mode[i] = true;
1988c2ecf20Sopenharmony_ci			continue;
1998c2ecf20Sopenharmony_ci		}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		/*
2028c2ecf20Sopenharmony_ci		 * This BAR can be mapped with one segmented window, so adjust
2038c2ecf20Sopenharmony_ci		 * te resource size to accommodate.
2048c2ecf20Sopenharmony_ci		 */
2058c2ecf20Sopenharmony_ci		pci_dbg(pdev, " Fixing VF BAR%d: %pR to\n", i, res);
2068c2ecf20Sopenharmony_ci		res->end = res->start + vf_bar_sz * mul - 1;
2078c2ecf20Sopenharmony_ci		pci_dbg(pdev, "                       %pR\n", res);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		pci_info(pdev, "VF BAR%d: %pR (expanded to %d VFs for PE alignment)",
2108c2ecf20Sopenharmony_ci			 i, res, mul);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci		iov->need_shift = true;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	return;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cidisable_iov:
2188c2ecf20Sopenharmony_ci	/* Save ourselves some MMIO space by disabling the unusable BARs */
2198c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
2208c2ecf20Sopenharmony_ci		res = &pdev->resource[i + PCI_IOV_RESOURCES];
2218c2ecf20Sopenharmony_ci		res->flags = 0;
2228c2ecf20Sopenharmony_ci		res->end = res->start - 1;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	pdev->dev.archdata.iov_data = NULL;
2268c2ecf20Sopenharmony_ci	kfree(iov);
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_civoid pnv_pci_ioda_fixup_iov(struct pci_dev *pdev)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	if (WARN_ON(pci_dev_is_added(pdev)))
2328c2ecf20Sopenharmony_ci		return;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	if (pdev->is_virtfn) {
2358c2ecf20Sopenharmony_ci		struct pnv_ioda_pe *pe = pnv_ioda_get_pe(pdev);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		/*
2388c2ecf20Sopenharmony_ci		 * VF PEs are single-device PEs so their pdev pointer needs to
2398c2ecf20Sopenharmony_ci		 * be set. The pdev doesn't exist when the PE is allocated (in
2408c2ecf20Sopenharmony_ci		 * (pcibios_sriov_enable()) so we fix it up here.
2418c2ecf20Sopenharmony_ci		 */
2428c2ecf20Sopenharmony_ci		pe->pdev = pdev;
2438c2ecf20Sopenharmony_ci		WARN_ON(!(pe->flags & PNV_IODA_PE_VF));
2448c2ecf20Sopenharmony_ci	} else if (pdev->is_physfn) {
2458c2ecf20Sopenharmony_ci		/*
2468c2ecf20Sopenharmony_ci		 * For PFs adjust their allocated IOV resources to match what
2478c2ecf20Sopenharmony_ci		 * the PHB can support using it's M64 BAR table.
2488c2ecf20Sopenharmony_ci		 */
2498c2ecf20Sopenharmony_ci		pnv_pci_ioda_fixup_iov_resources(pdev);
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ciresource_size_t pnv_pci_iov_resource_alignment(struct pci_dev *pdev,
2548c2ecf20Sopenharmony_ci						      int resno)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	resource_size_t align = pci_iov_resource_size(pdev, resno);
2578c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(pdev->bus);
2588c2ecf20Sopenharmony_ci	struct pnv_iov_data *iov = pnv_iov_get(pdev);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	/*
2618c2ecf20Sopenharmony_ci	 * iov can be null if we have an SR-IOV device with IOV BAR that can't
2628c2ecf20Sopenharmony_ci	 * be placed in the m64 space (i.e. The BAR is 32bit or non-prefetch).
2638c2ecf20Sopenharmony_ci	 * In that case we don't allow VFs to be enabled since one of their
2648c2ecf20Sopenharmony_ci	 * BARs would not be placed in the correct PE.
2658c2ecf20Sopenharmony_ci	 */
2668c2ecf20Sopenharmony_ci	if (!iov)
2678c2ecf20Sopenharmony_ci		return align;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	/*
2708c2ecf20Sopenharmony_ci	 * If we're using single mode then we can just use the native VF BAR
2718c2ecf20Sopenharmony_ci	 * alignment. We validated that it's possible to use a single PE
2728c2ecf20Sopenharmony_ci	 * window above when we did the fixup.
2738c2ecf20Sopenharmony_ci	 */
2748c2ecf20Sopenharmony_ci	if (iov->m64_single_mode[resno - PCI_IOV_RESOURCES])
2758c2ecf20Sopenharmony_ci		return align;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	/*
2788c2ecf20Sopenharmony_ci	 * On PowerNV platform, IOV BAR is mapped by M64 BAR to enable the
2798c2ecf20Sopenharmony_ci	 * SR-IOV. While from hardware perspective, the range mapped by M64
2808c2ecf20Sopenharmony_ci	 * BAR should be size aligned.
2818c2ecf20Sopenharmony_ci	 *
2828c2ecf20Sopenharmony_ci	 * This function returns the total IOV BAR size if M64 BAR is in
2838c2ecf20Sopenharmony_ci	 * Shared PE mode or just VF BAR size if not.
2848c2ecf20Sopenharmony_ci	 * If the M64 BAR is in Single PE mode, return the VF BAR size or
2858c2ecf20Sopenharmony_ci	 * M64 segment size if IOV BAR size is less.
2868c2ecf20Sopenharmony_ci	 */
2878c2ecf20Sopenharmony_ci	return phb->ioda.total_pe_num * align;
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic int pnv_pci_vf_release_m64(struct pci_dev *pdev, u16 num_vfs)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct pnv_iov_data   *iov;
2938c2ecf20Sopenharmony_ci	struct pnv_phb        *phb;
2948c2ecf20Sopenharmony_ci	int window_id;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	phb = pci_bus_to_pnvhb(pdev->bus);
2978c2ecf20Sopenharmony_ci	iov = pnv_iov_get(pdev);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	for_each_set_bit(window_id, iov->used_m64_bar_mask, MAX_M64_BARS) {
3008c2ecf20Sopenharmony_ci		opal_pci_phb_mmio_enable(phb->opal_id,
3018c2ecf20Sopenharmony_ci					 OPAL_M64_WINDOW_TYPE,
3028c2ecf20Sopenharmony_ci					 window_id,
3038c2ecf20Sopenharmony_ci					 0);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci		clear_bit(window_id, &phb->ioda.m64_bar_alloc);
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	return 0;
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci/*
3138c2ecf20Sopenharmony_ci * PHB3 and beyond support segmented windows. The window's address range
3148c2ecf20Sopenharmony_ci * is subdivided into phb->ioda.total_pe_num segments and there's a 1-1
3158c2ecf20Sopenharmony_ci * mapping between PEs and segments.
3168c2ecf20Sopenharmony_ci */
3178c2ecf20Sopenharmony_cistatic int64_t pnv_ioda_map_m64_segmented(struct pnv_phb *phb,
3188c2ecf20Sopenharmony_ci					  int window_id,
3198c2ecf20Sopenharmony_ci					  resource_size_t start,
3208c2ecf20Sopenharmony_ci					  resource_size_t size)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	int64_t rc;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	rc = opal_pci_set_phb_mem_window(phb->opal_id,
3258c2ecf20Sopenharmony_ci					 OPAL_M64_WINDOW_TYPE,
3268c2ecf20Sopenharmony_ci					 window_id,
3278c2ecf20Sopenharmony_ci					 start,
3288c2ecf20Sopenharmony_ci					 0, /* unused */
3298c2ecf20Sopenharmony_ci					 size);
3308c2ecf20Sopenharmony_ci	if (rc)
3318c2ecf20Sopenharmony_ci		goto out;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	rc = opal_pci_phb_mmio_enable(phb->opal_id,
3348c2ecf20Sopenharmony_ci				      OPAL_M64_WINDOW_TYPE,
3358c2ecf20Sopenharmony_ci				      window_id,
3368c2ecf20Sopenharmony_ci				      OPAL_ENABLE_M64_SPLIT);
3378c2ecf20Sopenharmony_ciout:
3388c2ecf20Sopenharmony_ci	if (rc)
3398c2ecf20Sopenharmony_ci		pr_err("Failed to map M64 window #%d: %lld\n", window_id, rc);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	return rc;
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic int64_t pnv_ioda_map_m64_single(struct pnv_phb *phb,
3458c2ecf20Sopenharmony_ci				       int pe_num,
3468c2ecf20Sopenharmony_ci				       int window_id,
3478c2ecf20Sopenharmony_ci				       resource_size_t start,
3488c2ecf20Sopenharmony_ci				       resource_size_t size)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	int64_t rc;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/*
3538c2ecf20Sopenharmony_ci	 * The API for setting up m64 mmio windows seems to have been designed
3548c2ecf20Sopenharmony_ci	 * with P7-IOC in mind. For that chip each M64 BAR (window) had a fixed
3558c2ecf20Sopenharmony_ci	 * split of 8 equally sized segments each of which could individually
3568c2ecf20Sopenharmony_ci	 * assigned to a PE.
3578c2ecf20Sopenharmony_ci	 *
3588c2ecf20Sopenharmony_ci	 * The problem with this is that the API doesn't have any way to
3598c2ecf20Sopenharmony_ci	 * communicate the number of segments we want on a BAR. This wasn't
3608c2ecf20Sopenharmony_ci	 * a problem for p7-ioc since you didn't have a choice, but the
3618c2ecf20Sopenharmony_ci	 * single PE windows added in PHB3 don't map cleanly to this API.
3628c2ecf20Sopenharmony_ci	 *
3638c2ecf20Sopenharmony_ci	 * As a result we've got this slightly awkward process where we
3648c2ecf20Sopenharmony_ci	 * call opal_pci_map_pe_mmio_window() to put the single in single
3658c2ecf20Sopenharmony_ci	 * PE mode, and set the PE for the window before setting the address
3668c2ecf20Sopenharmony_ci	 * bounds. We need to do it this way because the single PE windows
3678c2ecf20Sopenharmony_ci	 * for PHB3 have different alignment requirements on PHB3.
3688c2ecf20Sopenharmony_ci	 */
3698c2ecf20Sopenharmony_ci	rc = opal_pci_map_pe_mmio_window(phb->opal_id,
3708c2ecf20Sopenharmony_ci					 pe_num,
3718c2ecf20Sopenharmony_ci					 OPAL_M64_WINDOW_TYPE,
3728c2ecf20Sopenharmony_ci					 window_id,
3738c2ecf20Sopenharmony_ci					 0);
3748c2ecf20Sopenharmony_ci	if (rc)
3758c2ecf20Sopenharmony_ci		goto out;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	/*
3788c2ecf20Sopenharmony_ci	 * NB: In single PE mode the window needs to be aligned to 32MB
3798c2ecf20Sopenharmony_ci	 */
3808c2ecf20Sopenharmony_ci	rc = opal_pci_set_phb_mem_window(phb->opal_id,
3818c2ecf20Sopenharmony_ci					 OPAL_M64_WINDOW_TYPE,
3828c2ecf20Sopenharmony_ci					 window_id,
3838c2ecf20Sopenharmony_ci					 start,
3848c2ecf20Sopenharmony_ci					 0, /* ignored by FW, m64 is 1-1 */
3858c2ecf20Sopenharmony_ci					 size);
3868c2ecf20Sopenharmony_ci	if (rc)
3878c2ecf20Sopenharmony_ci		goto out;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	/*
3908c2ecf20Sopenharmony_ci	 * Now actually enable it. We specified the BAR should be in "non-split"
3918c2ecf20Sopenharmony_ci	 * mode so FW will validate that the BAR is in single PE mode.
3928c2ecf20Sopenharmony_ci	 */
3938c2ecf20Sopenharmony_ci	rc = opal_pci_phb_mmio_enable(phb->opal_id,
3948c2ecf20Sopenharmony_ci				      OPAL_M64_WINDOW_TYPE,
3958c2ecf20Sopenharmony_ci				      window_id,
3968c2ecf20Sopenharmony_ci				      OPAL_ENABLE_M64_NON_SPLIT);
3978c2ecf20Sopenharmony_ciout:
3988c2ecf20Sopenharmony_ci	if (rc)
3998c2ecf20Sopenharmony_ci		pr_err("Error mapping single PE BAR\n");
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	return rc;
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic int pnv_pci_alloc_m64_bar(struct pnv_phb *phb, struct pnv_iov_data *iov)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	int win;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	do {
4098c2ecf20Sopenharmony_ci		win = find_next_zero_bit(&phb->ioda.m64_bar_alloc,
4108c2ecf20Sopenharmony_ci				phb->ioda.m64_bar_idx + 1, 0);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci		if (win >= phb->ioda.m64_bar_idx + 1)
4138c2ecf20Sopenharmony_ci			return -1;
4148c2ecf20Sopenharmony_ci	} while (test_and_set_bit(win, &phb->ioda.m64_bar_alloc));
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	set_bit(win, iov->used_m64_bar_mask);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	return win;
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic int pnv_pci_vf_assign_m64(struct pci_dev *pdev, u16 num_vfs)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	struct pnv_iov_data   *iov;
4248c2ecf20Sopenharmony_ci	struct pnv_phb        *phb;
4258c2ecf20Sopenharmony_ci	int                    win;
4268c2ecf20Sopenharmony_ci	struct resource       *res;
4278c2ecf20Sopenharmony_ci	int                    i, j;
4288c2ecf20Sopenharmony_ci	int64_t                rc;
4298c2ecf20Sopenharmony_ci	resource_size_t        size, start;
4308c2ecf20Sopenharmony_ci	int                    base_pe_num;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	phb = pci_bus_to_pnvhb(pdev->bus);
4338c2ecf20Sopenharmony_ci	iov = pnv_iov_get(pdev);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
4368c2ecf20Sopenharmony_ci		res = &pdev->resource[i + PCI_IOV_RESOURCES];
4378c2ecf20Sopenharmony_ci		if (!res->flags || !res->parent)
4388c2ecf20Sopenharmony_ci			continue;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci		/* don't need single mode? map everything in one go! */
4418c2ecf20Sopenharmony_ci		if (!iov->m64_single_mode[i]) {
4428c2ecf20Sopenharmony_ci			win = pnv_pci_alloc_m64_bar(phb, iov);
4438c2ecf20Sopenharmony_ci			if (win < 0)
4448c2ecf20Sopenharmony_ci				goto m64_failed;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci			size = resource_size(res);
4478c2ecf20Sopenharmony_ci			start = res->start;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci			rc = pnv_ioda_map_m64_segmented(phb, win, start, size);
4508c2ecf20Sopenharmony_ci			if (rc)
4518c2ecf20Sopenharmony_ci				goto m64_failed;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci			continue;
4548c2ecf20Sopenharmony_ci		}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		/* otherwise map each VF with single PE BARs */
4578c2ecf20Sopenharmony_ci		size = pci_iov_resource_size(pdev, PCI_IOV_RESOURCES + i);
4588c2ecf20Sopenharmony_ci		base_pe_num = iov->vf_pe_arr[0].pe_number;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci		for (j = 0; j < num_vfs; j++) {
4618c2ecf20Sopenharmony_ci			win = pnv_pci_alloc_m64_bar(phb, iov);
4628c2ecf20Sopenharmony_ci			if (win < 0)
4638c2ecf20Sopenharmony_ci				goto m64_failed;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci			start = res->start + size * j;
4668c2ecf20Sopenharmony_ci			rc = pnv_ioda_map_m64_single(phb, win,
4678c2ecf20Sopenharmony_ci						     base_pe_num + j,
4688c2ecf20Sopenharmony_ci						     start,
4698c2ecf20Sopenharmony_ci						     size);
4708c2ecf20Sopenharmony_ci			if (rc)
4718c2ecf20Sopenharmony_ci				goto m64_failed;
4728c2ecf20Sopenharmony_ci		}
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci	return 0;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cim64_failed:
4778c2ecf20Sopenharmony_ci	pnv_pci_vf_release_m64(pdev, num_vfs);
4788c2ecf20Sopenharmony_ci	return -EBUSY;
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_cistatic void pnv_ioda_release_vf_PE(struct pci_dev *pdev)
4828c2ecf20Sopenharmony_ci{
4838c2ecf20Sopenharmony_ci	struct pnv_phb        *phb;
4848c2ecf20Sopenharmony_ci	struct pnv_ioda_pe    *pe, *pe_n;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	phb = pci_bus_to_pnvhb(pdev->bus);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	if (!pdev->is_physfn)
4898c2ecf20Sopenharmony_ci		return;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	/* FIXME: Use pnv_ioda_release_pe()? */
4928c2ecf20Sopenharmony_ci	list_for_each_entry_safe(pe, pe_n, &phb->ioda.pe_list, list) {
4938c2ecf20Sopenharmony_ci		if (pe->parent_dev != pdev)
4948c2ecf20Sopenharmony_ci			continue;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci		pnv_pci_ioda2_release_pe_dma(pe);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci		/* Remove from list */
4998c2ecf20Sopenharmony_ci		mutex_lock(&phb->ioda.pe_list_mutex);
5008c2ecf20Sopenharmony_ci		list_del(&pe->list);
5018c2ecf20Sopenharmony_ci		mutex_unlock(&phb->ioda.pe_list_mutex);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci		pnv_ioda_deconfigure_pe(phb, pe);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci		pnv_ioda_free_pe(pe);
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistatic int pnv_pci_vf_resource_shift(struct pci_dev *dev, int offset)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	struct resource *res, res2;
5128c2ecf20Sopenharmony_ci	struct pnv_iov_data *iov;
5138c2ecf20Sopenharmony_ci	resource_size_t size;
5148c2ecf20Sopenharmony_ci	u16 num_vfs;
5158c2ecf20Sopenharmony_ci	int i;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	if (!dev->is_physfn)
5188c2ecf20Sopenharmony_ci		return -EINVAL;
5198c2ecf20Sopenharmony_ci	iov = pnv_iov_get(dev);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	/*
5228c2ecf20Sopenharmony_ci	 * "offset" is in VFs.  The M64 windows are sized so that when they
5238c2ecf20Sopenharmony_ci	 * are segmented, each segment is the same size as the IOV BAR.
5248c2ecf20Sopenharmony_ci	 * Each segment is in a separate PE, and the high order bits of the
5258c2ecf20Sopenharmony_ci	 * address are the PE number.  Therefore, each VF's BAR is in a
5268c2ecf20Sopenharmony_ci	 * separate PE, and changing the IOV BAR start address changes the
5278c2ecf20Sopenharmony_ci	 * range of PEs the VFs are in.
5288c2ecf20Sopenharmony_ci	 */
5298c2ecf20Sopenharmony_ci	num_vfs = iov->num_vfs;
5308c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
5318c2ecf20Sopenharmony_ci		res = &dev->resource[i + PCI_IOV_RESOURCES];
5328c2ecf20Sopenharmony_ci		if (!res->flags || !res->parent)
5338c2ecf20Sopenharmony_ci			continue;
5348c2ecf20Sopenharmony_ci		if (iov->m64_single_mode[i])
5358c2ecf20Sopenharmony_ci			continue;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci		/*
5388c2ecf20Sopenharmony_ci		 * The actual IOV BAR range is determined by the start address
5398c2ecf20Sopenharmony_ci		 * and the actual size for num_vfs VFs BAR.  This check is to
5408c2ecf20Sopenharmony_ci		 * make sure that after shifting, the range will not overlap
5418c2ecf20Sopenharmony_ci		 * with another device.
5428c2ecf20Sopenharmony_ci		 */
5438c2ecf20Sopenharmony_ci		size = pci_iov_resource_size(dev, i + PCI_IOV_RESOURCES);
5448c2ecf20Sopenharmony_ci		res2.flags = res->flags;
5458c2ecf20Sopenharmony_ci		res2.start = res->start + (size * offset);
5468c2ecf20Sopenharmony_ci		res2.end = res2.start + (size * num_vfs) - 1;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci		if (res2.end > res->end) {
5498c2ecf20Sopenharmony_ci			dev_err(&dev->dev, "VF BAR%d: %pR would extend past %pR (trying to enable %d VFs shifted by %d)\n",
5508c2ecf20Sopenharmony_ci				i, &res2, res, num_vfs, offset);
5518c2ecf20Sopenharmony_ci			return -EBUSY;
5528c2ecf20Sopenharmony_ci		}
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	/*
5568c2ecf20Sopenharmony_ci	 * Since M64 BAR shares segments among all possible 256 PEs,
5578c2ecf20Sopenharmony_ci	 * we have to shift the beginning of PF IOV BAR to make it start from
5588c2ecf20Sopenharmony_ci	 * the segment which belongs to the PE number assigned to the first VF.
5598c2ecf20Sopenharmony_ci	 * This creates a "hole" in the /proc/iomem which could be used for
5608c2ecf20Sopenharmony_ci	 * allocating other resources so we reserve this area below and
5618c2ecf20Sopenharmony_ci	 * release when IOV is released.
5628c2ecf20Sopenharmony_ci	 */
5638c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
5648c2ecf20Sopenharmony_ci		res = &dev->resource[i + PCI_IOV_RESOURCES];
5658c2ecf20Sopenharmony_ci		if (!res->flags || !res->parent)
5668c2ecf20Sopenharmony_ci			continue;
5678c2ecf20Sopenharmony_ci		if (iov->m64_single_mode[i])
5688c2ecf20Sopenharmony_ci			continue;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		size = pci_iov_resource_size(dev, i + PCI_IOV_RESOURCES);
5718c2ecf20Sopenharmony_ci		res2 = *res;
5728c2ecf20Sopenharmony_ci		res->start += size * offset;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci		dev_info(&dev->dev, "VF BAR%d: %pR shifted to %pR (%sabling %d VFs shifted by %d)\n",
5758c2ecf20Sopenharmony_ci			 i, &res2, res, (offset > 0) ? "En" : "Dis",
5768c2ecf20Sopenharmony_ci			 num_vfs, offset);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci		if (offset < 0) {
5798c2ecf20Sopenharmony_ci			devm_release_resource(&dev->dev, &iov->holes[i]);
5808c2ecf20Sopenharmony_ci			memset(&iov->holes[i], 0, sizeof(iov->holes[i]));
5818c2ecf20Sopenharmony_ci		}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci		pci_update_resource(dev, i + PCI_IOV_RESOURCES);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci		if (offset > 0) {
5868c2ecf20Sopenharmony_ci			iov->holes[i].start = res2.start;
5878c2ecf20Sopenharmony_ci			iov->holes[i].end = res2.start + size * offset - 1;
5888c2ecf20Sopenharmony_ci			iov->holes[i].flags = IORESOURCE_BUS;
5898c2ecf20Sopenharmony_ci			iov->holes[i].name = "pnv_iov_reserved";
5908c2ecf20Sopenharmony_ci			devm_request_resource(&dev->dev, res->parent,
5918c2ecf20Sopenharmony_ci					&iov->holes[i]);
5928c2ecf20Sopenharmony_ci		}
5938c2ecf20Sopenharmony_ci	}
5948c2ecf20Sopenharmony_ci	return 0;
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic void pnv_pci_sriov_disable(struct pci_dev *pdev)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	u16                    num_vfs, base_pe;
6008c2ecf20Sopenharmony_ci	struct pnv_iov_data   *iov;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	iov = pnv_iov_get(pdev);
6038c2ecf20Sopenharmony_ci	if (WARN_ON(!iov))
6048c2ecf20Sopenharmony_ci		return;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	num_vfs = iov->num_vfs;
6078c2ecf20Sopenharmony_ci	base_pe = iov->vf_pe_arr[0].pe_number;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	/* Release VF PEs */
6108c2ecf20Sopenharmony_ci	pnv_ioda_release_vf_PE(pdev);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	/* Un-shift the IOV BARs if we need to */
6138c2ecf20Sopenharmony_ci	if (iov->need_shift)
6148c2ecf20Sopenharmony_ci		pnv_pci_vf_resource_shift(pdev, -base_pe);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	/* Release M64 windows */
6178c2ecf20Sopenharmony_ci	pnv_pci_vf_release_m64(pdev, num_vfs);
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_cistatic void pnv_ioda_setup_vf_PE(struct pci_dev *pdev, u16 num_vfs)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci	struct pnv_phb        *phb;
6238c2ecf20Sopenharmony_ci	struct pnv_ioda_pe    *pe;
6248c2ecf20Sopenharmony_ci	int                    pe_num;
6258c2ecf20Sopenharmony_ci	u16                    vf_index;
6268c2ecf20Sopenharmony_ci	struct pnv_iov_data   *iov;
6278c2ecf20Sopenharmony_ci	struct pci_dn         *pdn;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	if (!pdev->is_physfn)
6308c2ecf20Sopenharmony_ci		return;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	phb = pci_bus_to_pnvhb(pdev->bus);
6338c2ecf20Sopenharmony_ci	pdn = pci_get_pdn(pdev);
6348c2ecf20Sopenharmony_ci	iov = pnv_iov_get(pdev);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	/* Reserve PE for each VF */
6378c2ecf20Sopenharmony_ci	for (vf_index = 0; vf_index < num_vfs; vf_index++) {
6388c2ecf20Sopenharmony_ci		int vf_devfn = pci_iov_virtfn_devfn(pdev, vf_index);
6398c2ecf20Sopenharmony_ci		int vf_bus = pci_iov_virtfn_bus(pdev, vf_index);
6408c2ecf20Sopenharmony_ci		struct pci_dn *vf_pdn;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci		pe = &iov->vf_pe_arr[vf_index];
6438c2ecf20Sopenharmony_ci		pe->phb = phb;
6448c2ecf20Sopenharmony_ci		pe->flags = PNV_IODA_PE_VF;
6458c2ecf20Sopenharmony_ci		pe->pbus = NULL;
6468c2ecf20Sopenharmony_ci		pe->parent_dev = pdev;
6478c2ecf20Sopenharmony_ci		pe->mve_number = -1;
6488c2ecf20Sopenharmony_ci		pe->rid = (vf_bus << 8) | vf_devfn;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci		pe_num = pe->pe_number;
6518c2ecf20Sopenharmony_ci		pe_info(pe, "VF %04d:%02d:%02d.%d associated with PE#%x\n",
6528c2ecf20Sopenharmony_ci			pci_domain_nr(pdev->bus), pdev->bus->number,
6538c2ecf20Sopenharmony_ci			PCI_SLOT(vf_devfn), PCI_FUNC(vf_devfn), pe_num);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci		if (pnv_ioda_configure_pe(phb, pe)) {
6568c2ecf20Sopenharmony_ci			/* XXX What do we do here ? */
6578c2ecf20Sopenharmony_ci			pnv_ioda_free_pe(pe);
6588c2ecf20Sopenharmony_ci			pe->pdev = NULL;
6598c2ecf20Sopenharmony_ci			continue;
6608c2ecf20Sopenharmony_ci		}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci		/* Put PE to the list */
6638c2ecf20Sopenharmony_ci		mutex_lock(&phb->ioda.pe_list_mutex);
6648c2ecf20Sopenharmony_ci		list_add_tail(&pe->list, &phb->ioda.pe_list);
6658c2ecf20Sopenharmony_ci		mutex_unlock(&phb->ioda.pe_list_mutex);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci		/* associate this pe to it's pdn */
6688c2ecf20Sopenharmony_ci		list_for_each_entry(vf_pdn, &pdn->parent->child_list, list) {
6698c2ecf20Sopenharmony_ci			if (vf_pdn->busno == vf_bus &&
6708c2ecf20Sopenharmony_ci			    vf_pdn->devfn == vf_devfn) {
6718c2ecf20Sopenharmony_ci				vf_pdn->pe_number = pe_num;
6728c2ecf20Sopenharmony_ci				break;
6738c2ecf20Sopenharmony_ci			}
6748c2ecf20Sopenharmony_ci		}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci		pnv_pci_ioda2_setup_dma_pe(phb, pe);
6778c2ecf20Sopenharmony_ci	}
6788c2ecf20Sopenharmony_ci}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_cistatic int pnv_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs)
6818c2ecf20Sopenharmony_ci{
6828c2ecf20Sopenharmony_ci	struct pnv_ioda_pe    *base_pe;
6838c2ecf20Sopenharmony_ci	struct pnv_iov_data   *iov;
6848c2ecf20Sopenharmony_ci	struct pnv_phb        *phb;
6858c2ecf20Sopenharmony_ci	int                    ret;
6868c2ecf20Sopenharmony_ci	u16                    i;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	phb = pci_bus_to_pnvhb(pdev->bus);
6898c2ecf20Sopenharmony_ci	iov = pnv_iov_get(pdev);
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	/*
6928c2ecf20Sopenharmony_ci	 * There's a calls to IODA2 PE setup code littered throughout. We could
6938c2ecf20Sopenharmony_ci	 * probably fix that, but we'd still have problems due to the
6948c2ecf20Sopenharmony_ci	 * restriction inherent on IODA1 PHBs.
6958c2ecf20Sopenharmony_ci	 *
6968c2ecf20Sopenharmony_ci	 * NB: We class IODA3 as IODA2 since they're very similar.
6978c2ecf20Sopenharmony_ci	 */
6988c2ecf20Sopenharmony_ci	if (phb->type != PNV_PHB_IODA2) {
6998c2ecf20Sopenharmony_ci		pci_err(pdev, "SR-IOV is not supported on this PHB\n");
7008c2ecf20Sopenharmony_ci		return -ENXIO;
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	if (!iov) {
7048c2ecf20Sopenharmony_ci		dev_info(&pdev->dev, "don't support this SRIOV device with non 64bit-prefetchable IOV BAR\n");
7058c2ecf20Sopenharmony_ci		return -ENOSPC;
7068c2ecf20Sopenharmony_ci	}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	/* allocate a contigious block of PEs for our VFs */
7098c2ecf20Sopenharmony_ci	base_pe = pnv_ioda_alloc_pe(phb, num_vfs);
7108c2ecf20Sopenharmony_ci	if (!base_pe) {
7118c2ecf20Sopenharmony_ci		pci_err(pdev, "Unable to allocate PEs for %d VFs\n", num_vfs);
7128c2ecf20Sopenharmony_ci		return -EBUSY;
7138c2ecf20Sopenharmony_ci	}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	iov->vf_pe_arr = base_pe;
7168c2ecf20Sopenharmony_ci	iov->num_vfs = num_vfs;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	/* Assign M64 window accordingly */
7198c2ecf20Sopenharmony_ci	ret = pnv_pci_vf_assign_m64(pdev, num_vfs);
7208c2ecf20Sopenharmony_ci	if (ret) {
7218c2ecf20Sopenharmony_ci		dev_info(&pdev->dev, "Not enough M64 window resources\n");
7228c2ecf20Sopenharmony_ci		goto m64_failed;
7238c2ecf20Sopenharmony_ci	}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	/*
7268c2ecf20Sopenharmony_ci	 * When using one M64 BAR to map one IOV BAR, we need to shift
7278c2ecf20Sopenharmony_ci	 * the IOV BAR according to the PE# allocated to the VFs.
7288c2ecf20Sopenharmony_ci	 * Otherwise, the PE# for the VF will conflict with others.
7298c2ecf20Sopenharmony_ci	 */
7308c2ecf20Sopenharmony_ci	if (iov->need_shift) {
7318c2ecf20Sopenharmony_ci		ret = pnv_pci_vf_resource_shift(pdev, base_pe->pe_number);
7328c2ecf20Sopenharmony_ci		if (ret)
7338c2ecf20Sopenharmony_ci			goto shift_failed;
7348c2ecf20Sopenharmony_ci	}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	/* Setup VF PEs */
7378c2ecf20Sopenharmony_ci	pnv_ioda_setup_vf_PE(pdev, num_vfs);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	return 0;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_cishift_failed:
7428c2ecf20Sopenharmony_ci	pnv_pci_vf_release_m64(pdev, num_vfs);
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_cim64_failed:
7458c2ecf20Sopenharmony_ci	for (i = 0; i < num_vfs; i++)
7468c2ecf20Sopenharmony_ci		pnv_ioda_free_pe(&iov->vf_pe_arr[i]);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	return ret;
7498c2ecf20Sopenharmony_ci}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ciint pnv_pcibios_sriov_disable(struct pci_dev *pdev)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	pnv_pci_sriov_disable(pdev);
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	/* Release PCI data */
7568c2ecf20Sopenharmony_ci	remove_sriov_vf_pdns(pdev);
7578c2ecf20Sopenharmony_ci	return 0;
7588c2ecf20Sopenharmony_ci}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ciint pnv_pcibios_sriov_enable(struct pci_dev *pdev, u16 num_vfs)
7618c2ecf20Sopenharmony_ci{
7628c2ecf20Sopenharmony_ci	/* Allocate PCI data */
7638c2ecf20Sopenharmony_ci	add_sriov_vf_pdns(pdev);
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	return pnv_pci_sriov_enable(pdev, num_vfs);
7668c2ecf20Sopenharmony_ci}
767