18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Support PCI/PCIe on PowerNV platforms
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2011 Benjamin Herrenschmidt, IBM Corp.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#undef DEBUG
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/pci.h>
128c2ecf20Sopenharmony_ci#include <linux/crash_dump.h>
138c2ecf20Sopenharmony_ci#include <linux/delay.h>
148c2ecf20Sopenharmony_ci#include <linux/string.h>
158c2ecf20Sopenharmony_ci#include <linux/init.h>
168c2ecf20Sopenharmony_ci#include <linux/memblock.h>
178c2ecf20Sopenharmony_ci#include <linux/irq.h>
188c2ecf20Sopenharmony_ci#include <linux/io.h>
198c2ecf20Sopenharmony_ci#include <linux/msi.h>
208c2ecf20Sopenharmony_ci#include <linux/iommu.h>
218c2ecf20Sopenharmony_ci#include <linux/rculist.h>
228c2ecf20Sopenharmony_ci#include <linux/sizes.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <asm/sections.h>
258c2ecf20Sopenharmony_ci#include <asm/io.h>
268c2ecf20Sopenharmony_ci#include <asm/prom.h>
278c2ecf20Sopenharmony_ci#include <asm/pci-bridge.h>
288c2ecf20Sopenharmony_ci#include <asm/machdep.h>
298c2ecf20Sopenharmony_ci#include <asm/msi_bitmap.h>
308c2ecf20Sopenharmony_ci#include <asm/ppc-pci.h>
318c2ecf20Sopenharmony_ci#include <asm/opal.h>
328c2ecf20Sopenharmony_ci#include <asm/iommu.h>
338c2ecf20Sopenharmony_ci#include <asm/tce.h>
348c2ecf20Sopenharmony_ci#include <asm/xics.h>
358c2ecf20Sopenharmony_ci#include <asm/debugfs.h>
368c2ecf20Sopenharmony_ci#include <asm/firmware.h>
378c2ecf20Sopenharmony_ci#include <asm/pnv-pci.h>
388c2ecf20Sopenharmony_ci#include <asm/mmzone.h>
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#include <misc/cxl-base.h>
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#include "powernv.h"
438c2ecf20Sopenharmony_ci#include "pci.h"
448c2ecf20Sopenharmony_ci#include "../../../../drivers/pci/pci.h"
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define PNV_IODA1_M64_NUM	16	/* Number of M64 BARs	*/
478c2ecf20Sopenharmony_ci#define PNV_IODA1_M64_SEGS	8	/* Segments per M64 BAR	*/
488c2ecf20Sopenharmony_ci#define PNV_IODA1_DMA32_SEGSIZE	0x10000000
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic const char * const pnv_phb_names[] = { "IODA1", "IODA2", "NPU_NVLINK",
518c2ecf20Sopenharmony_ci					      "NPU_OCAPI" };
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic void pnv_pci_ioda2_set_bypass(struct pnv_ioda_pe *pe, bool enable);
548c2ecf20Sopenharmony_cistatic void pnv_pci_configure_bus(struct pci_bus *bus);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_civoid pe_level_printk(const struct pnv_ioda_pe *pe, const char *level,
578c2ecf20Sopenharmony_ci			    const char *fmt, ...)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct va_format vaf;
608c2ecf20Sopenharmony_ci	va_list args;
618c2ecf20Sopenharmony_ci	char pfix[32];
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	va_start(args, fmt);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	vaf.fmt = fmt;
668c2ecf20Sopenharmony_ci	vaf.va = &args;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if (pe->flags & PNV_IODA_PE_DEV)
698c2ecf20Sopenharmony_ci		strlcpy(pfix, dev_name(&pe->pdev->dev), sizeof(pfix));
708c2ecf20Sopenharmony_ci	else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL))
718c2ecf20Sopenharmony_ci		sprintf(pfix, "%04x:%02x     ",
728c2ecf20Sopenharmony_ci			pci_domain_nr(pe->pbus), pe->pbus->number);
738c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV
748c2ecf20Sopenharmony_ci	else if (pe->flags & PNV_IODA_PE_VF)
758c2ecf20Sopenharmony_ci		sprintf(pfix, "%04x:%02x:%2x.%d",
768c2ecf20Sopenharmony_ci			pci_domain_nr(pe->parent_dev->bus),
778c2ecf20Sopenharmony_ci			(pe->rid & 0xff00) >> 8,
788c2ecf20Sopenharmony_ci			PCI_SLOT(pe->rid), PCI_FUNC(pe->rid));
798c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI_IOV*/
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	printk("%spci %s: [PE# %.2x] %pV",
828c2ecf20Sopenharmony_ci	       level, pfix, pe->pe_number, &vaf);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	va_end(args);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic bool pnv_iommu_bypass_disabled __read_mostly;
888c2ecf20Sopenharmony_cistatic bool pci_reset_phbs __read_mostly;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int __init iommu_setup(char *str)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	if (!str)
938c2ecf20Sopenharmony_ci		return -EINVAL;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	while (*str) {
968c2ecf20Sopenharmony_ci		if (!strncmp(str, "nobypass", 8)) {
978c2ecf20Sopenharmony_ci			pnv_iommu_bypass_disabled = true;
988c2ecf20Sopenharmony_ci			pr_info("PowerNV: IOMMU bypass window disabled.\n");
998c2ecf20Sopenharmony_ci			break;
1008c2ecf20Sopenharmony_ci		}
1018c2ecf20Sopenharmony_ci		str += strcspn(str, ",");
1028c2ecf20Sopenharmony_ci		if (*str == ',')
1038c2ecf20Sopenharmony_ci			str++;
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	return 0;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ciearly_param("iommu", iommu_setup);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic int __init pci_reset_phbs_setup(char *str)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	pci_reset_phbs = true;
1138c2ecf20Sopenharmony_ci	return 0;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ciearly_param("ppc_pci_reset_phbs", pci_reset_phbs_setup);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic struct pnv_ioda_pe *pnv_ioda_init_pe(struct pnv_phb *phb, int pe_no)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	s64 rc;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	phb->ioda.pe_array[pe_no].phb = phb;
1238c2ecf20Sopenharmony_ci	phb->ioda.pe_array[pe_no].pe_number = pe_no;
1248c2ecf20Sopenharmony_ci	phb->ioda.pe_array[pe_no].dma_setup_done = false;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/*
1278c2ecf20Sopenharmony_ci	 * Clear the PE frozen state as it might be put into frozen state
1288c2ecf20Sopenharmony_ci	 * in the last PCI remove path. It's not harmful to do so when the
1298c2ecf20Sopenharmony_ci	 * PE is already in unfrozen state.
1308c2ecf20Sopenharmony_ci	 */
1318c2ecf20Sopenharmony_ci	rc = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no,
1328c2ecf20Sopenharmony_ci				       OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
1338c2ecf20Sopenharmony_ci	if (rc != OPAL_SUCCESS && rc != OPAL_UNSUPPORTED)
1348c2ecf20Sopenharmony_ci		pr_warn("%s: Error %lld unfreezing PHB#%x-PE#%x\n",
1358c2ecf20Sopenharmony_ci			__func__, rc, phb->hose->global_number, pe_no);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	return &phb->ioda.pe_array[pe_no];
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic void pnv_ioda_reserve_pe(struct pnv_phb *phb, int pe_no)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	if (!(pe_no >= 0 && pe_no < phb->ioda.total_pe_num)) {
1438c2ecf20Sopenharmony_ci		pr_warn("%s: Invalid PE %x on PHB#%x\n",
1448c2ecf20Sopenharmony_ci			__func__, pe_no, phb->hose->global_number);
1458c2ecf20Sopenharmony_ci		return;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	mutex_lock(&phb->ioda.pe_alloc_mutex);
1498c2ecf20Sopenharmony_ci	if (test_and_set_bit(pe_no, phb->ioda.pe_alloc))
1508c2ecf20Sopenharmony_ci		pr_debug("%s: PE %x was reserved on PHB#%x\n",
1518c2ecf20Sopenharmony_ci			 __func__, pe_no, phb->hose->global_number);
1528c2ecf20Sopenharmony_ci	mutex_unlock(&phb->ioda.pe_alloc_mutex);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	pnv_ioda_init_pe(phb, pe_no);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistruct pnv_ioda_pe *pnv_ioda_alloc_pe(struct pnv_phb *phb, int count)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *ret = NULL;
1608c2ecf20Sopenharmony_ci	int run = 0, pe, i;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	mutex_lock(&phb->ioda.pe_alloc_mutex);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	/* scan backwards for a run of @count cleared bits */
1658c2ecf20Sopenharmony_ci	for (pe = phb->ioda.total_pe_num - 1; pe >= 0; pe--) {
1668c2ecf20Sopenharmony_ci		if (test_bit(pe, phb->ioda.pe_alloc)) {
1678c2ecf20Sopenharmony_ci			run = 0;
1688c2ecf20Sopenharmony_ci			continue;
1698c2ecf20Sopenharmony_ci		}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci		run++;
1728c2ecf20Sopenharmony_ci		if (run == count)
1738c2ecf20Sopenharmony_ci			break;
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci	if (run != count)
1768c2ecf20Sopenharmony_ci		goto out;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	for (i = pe; i < pe + count; i++) {
1798c2ecf20Sopenharmony_ci		set_bit(i, phb->ioda.pe_alloc);
1808c2ecf20Sopenharmony_ci		pnv_ioda_init_pe(phb, i);
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci	ret = &phb->ioda.pe_array[pe];
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ciout:
1858c2ecf20Sopenharmony_ci	mutex_unlock(&phb->ioda.pe_alloc_mutex);
1868c2ecf20Sopenharmony_ci	return ret;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_civoid pnv_ioda_free_pe(struct pnv_ioda_pe *pe)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pe->phb;
1928c2ecf20Sopenharmony_ci	unsigned int pe_num = pe->pe_number;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	WARN_ON(pe->pdev);
1958c2ecf20Sopenharmony_ci	WARN_ON(pe->npucomp); /* NPUs for nvlink are not supposed to be freed */
1968c2ecf20Sopenharmony_ci	kfree(pe->npucomp);
1978c2ecf20Sopenharmony_ci	memset(pe, 0, sizeof(struct pnv_ioda_pe));
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	mutex_lock(&phb->ioda.pe_alloc_mutex);
2008c2ecf20Sopenharmony_ci	clear_bit(pe_num, phb->ioda.pe_alloc);
2018c2ecf20Sopenharmony_ci	mutex_unlock(&phb->ioda.pe_alloc_mutex);
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci/* The default M64 BAR is shared by all PEs */
2058c2ecf20Sopenharmony_cistatic int pnv_ioda2_init_m64(struct pnv_phb *phb)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	const char *desc;
2088c2ecf20Sopenharmony_ci	struct resource *r;
2098c2ecf20Sopenharmony_ci	s64 rc;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* Configure the default M64 BAR */
2128c2ecf20Sopenharmony_ci	rc = opal_pci_set_phb_mem_window(phb->opal_id,
2138c2ecf20Sopenharmony_ci					 OPAL_M64_WINDOW_TYPE,
2148c2ecf20Sopenharmony_ci					 phb->ioda.m64_bar_idx,
2158c2ecf20Sopenharmony_ci					 phb->ioda.m64_base,
2168c2ecf20Sopenharmony_ci					 0, /* unused */
2178c2ecf20Sopenharmony_ci					 phb->ioda.m64_size);
2188c2ecf20Sopenharmony_ci	if (rc != OPAL_SUCCESS) {
2198c2ecf20Sopenharmony_ci		desc = "configuring";
2208c2ecf20Sopenharmony_ci		goto fail;
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	/* Enable the default M64 BAR */
2248c2ecf20Sopenharmony_ci	rc = opal_pci_phb_mmio_enable(phb->opal_id,
2258c2ecf20Sopenharmony_ci				      OPAL_M64_WINDOW_TYPE,
2268c2ecf20Sopenharmony_ci				      phb->ioda.m64_bar_idx,
2278c2ecf20Sopenharmony_ci				      OPAL_ENABLE_M64_SPLIT);
2288c2ecf20Sopenharmony_ci	if (rc != OPAL_SUCCESS) {
2298c2ecf20Sopenharmony_ci		desc = "enabling";
2308c2ecf20Sopenharmony_ci		goto fail;
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/*
2348c2ecf20Sopenharmony_ci	 * Exclude the segments for reserved and root bus PE, which
2358c2ecf20Sopenharmony_ci	 * are first or last two PEs.
2368c2ecf20Sopenharmony_ci	 */
2378c2ecf20Sopenharmony_ci	r = &phb->hose->mem_resources[1];
2388c2ecf20Sopenharmony_ci	if (phb->ioda.reserved_pe_idx == 0)
2398c2ecf20Sopenharmony_ci		r->start += (2 * phb->ioda.m64_segsize);
2408c2ecf20Sopenharmony_ci	else if (phb->ioda.reserved_pe_idx == (phb->ioda.total_pe_num - 1))
2418c2ecf20Sopenharmony_ci		r->end -= (2 * phb->ioda.m64_segsize);
2428c2ecf20Sopenharmony_ci	else
2438c2ecf20Sopenharmony_ci		pr_warn("  Cannot strip M64 segment for reserved PE#%x\n",
2448c2ecf20Sopenharmony_ci			phb->ioda.reserved_pe_idx);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	return 0;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cifail:
2498c2ecf20Sopenharmony_ci	pr_warn("  Failure %lld %s M64 BAR#%d\n",
2508c2ecf20Sopenharmony_ci		rc, desc, phb->ioda.m64_bar_idx);
2518c2ecf20Sopenharmony_ci	opal_pci_phb_mmio_enable(phb->opal_id,
2528c2ecf20Sopenharmony_ci				 OPAL_M64_WINDOW_TYPE,
2538c2ecf20Sopenharmony_ci				 phb->ioda.m64_bar_idx,
2548c2ecf20Sopenharmony_ci				 OPAL_DISABLE_M64);
2558c2ecf20Sopenharmony_ci	return -EIO;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic void pnv_ioda_reserve_dev_m64_pe(struct pci_dev *pdev,
2598c2ecf20Sopenharmony_ci					 unsigned long *pe_bitmap)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(pdev->bus);
2628c2ecf20Sopenharmony_ci	struct resource *r;
2638c2ecf20Sopenharmony_ci	resource_size_t base, sgsz, start, end;
2648c2ecf20Sopenharmony_ci	int segno, i;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	base = phb->ioda.m64_base;
2678c2ecf20Sopenharmony_ci	sgsz = phb->ioda.m64_segsize;
2688c2ecf20Sopenharmony_ci	for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
2698c2ecf20Sopenharmony_ci		r = &pdev->resource[i];
2708c2ecf20Sopenharmony_ci		if (!r->parent || !pnv_pci_is_m64(phb, r))
2718c2ecf20Sopenharmony_ci			continue;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci		start = ALIGN_DOWN(r->start - base, sgsz);
2748c2ecf20Sopenharmony_ci		end = ALIGN(r->end - base, sgsz);
2758c2ecf20Sopenharmony_ci		for (segno = start / sgsz; segno < end / sgsz; segno++) {
2768c2ecf20Sopenharmony_ci			if (pe_bitmap)
2778c2ecf20Sopenharmony_ci				set_bit(segno, pe_bitmap);
2788c2ecf20Sopenharmony_ci			else
2798c2ecf20Sopenharmony_ci				pnv_ioda_reserve_pe(phb, segno);
2808c2ecf20Sopenharmony_ci		}
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic int pnv_ioda1_init_m64(struct pnv_phb *phb)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	struct resource *r;
2878c2ecf20Sopenharmony_ci	int index;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	/*
2908c2ecf20Sopenharmony_ci	 * There are 16 M64 BARs, each of which has 8 segments. So
2918c2ecf20Sopenharmony_ci	 * there are as many M64 segments as the maximum number of
2928c2ecf20Sopenharmony_ci	 * PEs, which is 128.
2938c2ecf20Sopenharmony_ci	 */
2948c2ecf20Sopenharmony_ci	for (index = 0; index < PNV_IODA1_M64_NUM; index++) {
2958c2ecf20Sopenharmony_ci		unsigned long base, segsz = phb->ioda.m64_segsize;
2968c2ecf20Sopenharmony_ci		int64_t rc;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci		base = phb->ioda.m64_base +
2998c2ecf20Sopenharmony_ci		       index * PNV_IODA1_M64_SEGS * segsz;
3008c2ecf20Sopenharmony_ci		rc = opal_pci_set_phb_mem_window(phb->opal_id,
3018c2ecf20Sopenharmony_ci				OPAL_M64_WINDOW_TYPE, index, base, 0,
3028c2ecf20Sopenharmony_ci				PNV_IODA1_M64_SEGS * segsz);
3038c2ecf20Sopenharmony_ci		if (rc != OPAL_SUCCESS) {
3048c2ecf20Sopenharmony_ci			pr_warn("  Error %lld setting M64 PHB#%x-BAR#%d\n",
3058c2ecf20Sopenharmony_ci				rc, phb->hose->global_number, index);
3068c2ecf20Sopenharmony_ci			goto fail;
3078c2ecf20Sopenharmony_ci		}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci		rc = opal_pci_phb_mmio_enable(phb->opal_id,
3108c2ecf20Sopenharmony_ci				OPAL_M64_WINDOW_TYPE, index,
3118c2ecf20Sopenharmony_ci				OPAL_ENABLE_M64_SPLIT);
3128c2ecf20Sopenharmony_ci		if (rc != OPAL_SUCCESS) {
3138c2ecf20Sopenharmony_ci			pr_warn("  Error %lld enabling M64 PHB#%x-BAR#%d\n",
3148c2ecf20Sopenharmony_ci				rc, phb->hose->global_number, index);
3158c2ecf20Sopenharmony_ci			goto fail;
3168c2ecf20Sopenharmony_ci		}
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	for (index = 0; index < phb->ioda.total_pe_num; index++) {
3208c2ecf20Sopenharmony_ci		int64_t rc;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci		/*
3238c2ecf20Sopenharmony_ci		 * P7IOC supports M64DT, which helps mapping M64 segment
3248c2ecf20Sopenharmony_ci		 * to one particular PE#. However, PHB3 has fixed mapping
3258c2ecf20Sopenharmony_ci		 * between M64 segment and PE#. In order to have same logic
3268c2ecf20Sopenharmony_ci		 * for P7IOC and PHB3, we enforce fixed mapping between M64
3278c2ecf20Sopenharmony_ci		 * segment and PE# on P7IOC.
3288c2ecf20Sopenharmony_ci		 */
3298c2ecf20Sopenharmony_ci		rc = opal_pci_map_pe_mmio_window(phb->opal_id,
3308c2ecf20Sopenharmony_ci				index, OPAL_M64_WINDOW_TYPE,
3318c2ecf20Sopenharmony_ci				index / PNV_IODA1_M64_SEGS,
3328c2ecf20Sopenharmony_ci				index % PNV_IODA1_M64_SEGS);
3338c2ecf20Sopenharmony_ci		if (rc != OPAL_SUCCESS) {
3348c2ecf20Sopenharmony_ci			pr_warn("%s: Error %lld mapping M64 for PHB#%x-PE#%x\n",
3358c2ecf20Sopenharmony_ci				__func__, rc, phb->hose->global_number,
3368c2ecf20Sopenharmony_ci				index);
3378c2ecf20Sopenharmony_ci			goto fail;
3388c2ecf20Sopenharmony_ci		}
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	/*
3428c2ecf20Sopenharmony_ci	 * Exclude the segments for reserved and root bus PE, which
3438c2ecf20Sopenharmony_ci	 * are first or last two PEs.
3448c2ecf20Sopenharmony_ci	 */
3458c2ecf20Sopenharmony_ci	r = &phb->hose->mem_resources[1];
3468c2ecf20Sopenharmony_ci	if (phb->ioda.reserved_pe_idx == 0)
3478c2ecf20Sopenharmony_ci		r->start += (2 * phb->ioda.m64_segsize);
3488c2ecf20Sopenharmony_ci	else if (phb->ioda.reserved_pe_idx == (phb->ioda.total_pe_num - 1))
3498c2ecf20Sopenharmony_ci		r->end -= (2 * phb->ioda.m64_segsize);
3508c2ecf20Sopenharmony_ci	else
3518c2ecf20Sopenharmony_ci		WARN(1, "Wrong reserved PE#%x on PHB#%x\n",
3528c2ecf20Sopenharmony_ci		     phb->ioda.reserved_pe_idx, phb->hose->global_number);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	return 0;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cifail:
3578c2ecf20Sopenharmony_ci	for ( ; index >= 0; index--)
3588c2ecf20Sopenharmony_ci		opal_pci_phb_mmio_enable(phb->opal_id,
3598c2ecf20Sopenharmony_ci			OPAL_M64_WINDOW_TYPE, index, OPAL_DISABLE_M64);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	return -EIO;
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic void pnv_ioda_reserve_m64_pe(struct pci_bus *bus,
3658c2ecf20Sopenharmony_ci				    unsigned long *pe_bitmap,
3668c2ecf20Sopenharmony_ci				    bool all)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	list_for_each_entry(pdev, &bus->devices, bus_list) {
3718c2ecf20Sopenharmony_ci		pnv_ioda_reserve_dev_m64_pe(pdev, pe_bitmap);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci		if (all && pdev->subordinate)
3748c2ecf20Sopenharmony_ci			pnv_ioda_reserve_m64_pe(pdev->subordinate,
3758c2ecf20Sopenharmony_ci						pe_bitmap, all);
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic struct pnv_ioda_pe *pnv_ioda_pick_m64_pe(struct pci_bus *bus, bool all)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(bus);
3828c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *master_pe, *pe;
3838c2ecf20Sopenharmony_ci	unsigned long size, *pe_alloc;
3848c2ecf20Sopenharmony_ci	int i;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	/* Root bus shouldn't use M64 */
3878c2ecf20Sopenharmony_ci	if (pci_is_root_bus(bus))
3888c2ecf20Sopenharmony_ci		return NULL;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	/* Allocate bitmap */
3918c2ecf20Sopenharmony_ci	size = ALIGN(phb->ioda.total_pe_num / 8, sizeof(unsigned long));
3928c2ecf20Sopenharmony_ci	pe_alloc = kzalloc(size, GFP_KERNEL);
3938c2ecf20Sopenharmony_ci	if (!pe_alloc) {
3948c2ecf20Sopenharmony_ci		pr_warn("%s: Out of memory !\n",
3958c2ecf20Sopenharmony_ci			__func__);
3968c2ecf20Sopenharmony_ci		return NULL;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	/* Figure out reserved PE numbers by the PE */
4008c2ecf20Sopenharmony_ci	pnv_ioda_reserve_m64_pe(bus, pe_alloc, all);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	/*
4038c2ecf20Sopenharmony_ci	 * the current bus might not own M64 window and that's all
4048c2ecf20Sopenharmony_ci	 * contributed by its child buses. For the case, we needn't
4058c2ecf20Sopenharmony_ci	 * pick M64 dependent PE#.
4068c2ecf20Sopenharmony_ci	 */
4078c2ecf20Sopenharmony_ci	if (bitmap_empty(pe_alloc, phb->ioda.total_pe_num)) {
4088c2ecf20Sopenharmony_ci		kfree(pe_alloc);
4098c2ecf20Sopenharmony_ci		return NULL;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	/*
4138c2ecf20Sopenharmony_ci	 * Figure out the master PE and put all slave PEs to master
4148c2ecf20Sopenharmony_ci	 * PE's list to form compound PE.
4158c2ecf20Sopenharmony_ci	 */
4168c2ecf20Sopenharmony_ci	master_pe = NULL;
4178c2ecf20Sopenharmony_ci	i = -1;
4188c2ecf20Sopenharmony_ci	while ((i = find_next_bit(pe_alloc, phb->ioda.total_pe_num, i + 1)) <
4198c2ecf20Sopenharmony_ci		phb->ioda.total_pe_num) {
4208c2ecf20Sopenharmony_ci		pe = &phb->ioda.pe_array[i];
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		phb->ioda.m64_segmap[pe->pe_number] = pe->pe_number;
4238c2ecf20Sopenharmony_ci		if (!master_pe) {
4248c2ecf20Sopenharmony_ci			pe->flags |= PNV_IODA_PE_MASTER;
4258c2ecf20Sopenharmony_ci			INIT_LIST_HEAD(&pe->slaves);
4268c2ecf20Sopenharmony_ci			master_pe = pe;
4278c2ecf20Sopenharmony_ci		} else {
4288c2ecf20Sopenharmony_ci			pe->flags |= PNV_IODA_PE_SLAVE;
4298c2ecf20Sopenharmony_ci			pe->master = master_pe;
4308c2ecf20Sopenharmony_ci			list_add_tail(&pe->list, &master_pe->slaves);
4318c2ecf20Sopenharmony_ci		}
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	kfree(pe_alloc);
4358c2ecf20Sopenharmony_ci	return master_pe;
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	struct pci_controller *hose = phb->hose;
4418c2ecf20Sopenharmony_ci	struct device_node *dn = hose->dn;
4428c2ecf20Sopenharmony_ci	struct resource *res;
4438c2ecf20Sopenharmony_ci	u32 m64_range[2], i;
4448c2ecf20Sopenharmony_ci	const __be32 *r;
4458c2ecf20Sopenharmony_ci	u64 pci_addr;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (phb->type != PNV_PHB_IODA1 && phb->type != PNV_PHB_IODA2) {
4488c2ecf20Sopenharmony_ci		pr_info("  Not support M64 window\n");
4498c2ecf20Sopenharmony_ci		return;
4508c2ecf20Sopenharmony_ci	}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	if (!firmware_has_feature(FW_FEATURE_OPAL)) {
4538c2ecf20Sopenharmony_ci		pr_info("  Firmware too old to support M64 window\n");
4548c2ecf20Sopenharmony_ci		return;
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	r = of_get_property(dn, "ibm,opal-m64-window", NULL);
4588c2ecf20Sopenharmony_ci	if (!r) {
4598c2ecf20Sopenharmony_ci		pr_info("  No <ibm,opal-m64-window> on %pOF\n",
4608c2ecf20Sopenharmony_ci			dn);
4618c2ecf20Sopenharmony_ci		return;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	/*
4658c2ecf20Sopenharmony_ci	 * Find the available M64 BAR range and pickup the last one for
4668c2ecf20Sopenharmony_ci	 * covering the whole 64-bits space. We support only one range.
4678c2ecf20Sopenharmony_ci	 */
4688c2ecf20Sopenharmony_ci	if (of_property_read_u32_array(dn, "ibm,opal-available-m64-ranges",
4698c2ecf20Sopenharmony_ci				       m64_range, 2)) {
4708c2ecf20Sopenharmony_ci		/* In absence of the property, assume 0..15 */
4718c2ecf20Sopenharmony_ci		m64_range[0] = 0;
4728c2ecf20Sopenharmony_ci		m64_range[1] = 16;
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci	/* We only support 64 bits in our allocator */
4758c2ecf20Sopenharmony_ci	if (m64_range[1] > 63) {
4768c2ecf20Sopenharmony_ci		pr_warn("%s: Limiting M64 range to 63 (from %d) on PHB#%x\n",
4778c2ecf20Sopenharmony_ci			__func__, m64_range[1], phb->hose->global_number);
4788c2ecf20Sopenharmony_ci		m64_range[1] = 63;
4798c2ecf20Sopenharmony_ci	}
4808c2ecf20Sopenharmony_ci	/* Empty range, no m64 */
4818c2ecf20Sopenharmony_ci	if (m64_range[1] <= m64_range[0]) {
4828c2ecf20Sopenharmony_ci		pr_warn("%s: M64 empty, disabling M64 usage on PHB#%x\n",
4838c2ecf20Sopenharmony_ci			__func__, phb->hose->global_number);
4848c2ecf20Sopenharmony_ci		return;
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	/* Configure M64 informations */
4888c2ecf20Sopenharmony_ci	res = &hose->mem_resources[1];
4898c2ecf20Sopenharmony_ci	res->name = dn->full_name;
4908c2ecf20Sopenharmony_ci	res->start = of_translate_address(dn, r + 2);
4918c2ecf20Sopenharmony_ci	res->end = res->start + of_read_number(r + 4, 2) - 1;
4928c2ecf20Sopenharmony_ci	res->flags = (IORESOURCE_MEM | IORESOURCE_MEM_64 | IORESOURCE_PREFETCH);
4938c2ecf20Sopenharmony_ci	pci_addr = of_read_number(r, 2);
4948c2ecf20Sopenharmony_ci	hose->mem_offset[1] = res->start - pci_addr;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	phb->ioda.m64_size = resource_size(res);
4978c2ecf20Sopenharmony_ci	phb->ioda.m64_segsize = phb->ioda.m64_size / phb->ioda.total_pe_num;
4988c2ecf20Sopenharmony_ci	phb->ioda.m64_base = pci_addr;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	/* This lines up nicely with the display from processing OF ranges */
5018c2ecf20Sopenharmony_ci	pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx (M64 #%d..%d)\n",
5028c2ecf20Sopenharmony_ci		res->start, res->end, pci_addr, m64_range[0],
5038c2ecf20Sopenharmony_ci		m64_range[0] + m64_range[1] - 1);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	/* Mark all M64 used up by default */
5068c2ecf20Sopenharmony_ci	phb->ioda.m64_bar_alloc = (unsigned long)-1;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	/* Use last M64 BAR to cover M64 window */
5098c2ecf20Sopenharmony_ci	m64_range[1]--;
5108c2ecf20Sopenharmony_ci	phb->ioda.m64_bar_idx = m64_range[0] + m64_range[1];
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	pr_info(" Using M64 #%d as default window\n", phb->ioda.m64_bar_idx);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	/* Mark remaining ones free */
5158c2ecf20Sopenharmony_ci	for (i = m64_range[0]; i < m64_range[1]; i++)
5168c2ecf20Sopenharmony_ci		clear_bit(i, &phb->ioda.m64_bar_alloc);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	/*
5198c2ecf20Sopenharmony_ci	 * Setup init functions for M64 based on IODA version, IODA3 uses
5208c2ecf20Sopenharmony_ci	 * the IODA2 code.
5218c2ecf20Sopenharmony_ci	 */
5228c2ecf20Sopenharmony_ci	if (phb->type == PNV_PHB_IODA1)
5238c2ecf20Sopenharmony_ci		phb->init_m64 = pnv_ioda1_init_m64;
5248c2ecf20Sopenharmony_ci	else
5258c2ecf20Sopenharmony_ci		phb->init_m64 = pnv_ioda2_init_m64;
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic void pnv_ioda_freeze_pe(struct pnv_phb *phb, int pe_no)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe = &phb->ioda.pe_array[pe_no];
5318c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *slave;
5328c2ecf20Sopenharmony_ci	s64 rc;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	/* Fetch master PE */
5358c2ecf20Sopenharmony_ci	if (pe->flags & PNV_IODA_PE_SLAVE) {
5368c2ecf20Sopenharmony_ci		pe = pe->master;
5378c2ecf20Sopenharmony_ci		if (WARN_ON(!pe || !(pe->flags & PNV_IODA_PE_MASTER)))
5388c2ecf20Sopenharmony_ci			return;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci		pe_no = pe->pe_number;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	/* Freeze master PE */
5448c2ecf20Sopenharmony_ci	rc = opal_pci_eeh_freeze_set(phb->opal_id,
5458c2ecf20Sopenharmony_ci				     pe_no,
5468c2ecf20Sopenharmony_ci				     OPAL_EEH_ACTION_SET_FREEZE_ALL);
5478c2ecf20Sopenharmony_ci	if (rc != OPAL_SUCCESS) {
5488c2ecf20Sopenharmony_ci		pr_warn("%s: Failure %lld freezing PHB#%x-PE#%x\n",
5498c2ecf20Sopenharmony_ci			__func__, rc, phb->hose->global_number, pe_no);
5508c2ecf20Sopenharmony_ci		return;
5518c2ecf20Sopenharmony_ci	}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	/* Freeze slave PEs */
5548c2ecf20Sopenharmony_ci	if (!(pe->flags & PNV_IODA_PE_MASTER))
5558c2ecf20Sopenharmony_ci		return;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	list_for_each_entry(slave, &pe->slaves, list) {
5588c2ecf20Sopenharmony_ci		rc = opal_pci_eeh_freeze_set(phb->opal_id,
5598c2ecf20Sopenharmony_ci					     slave->pe_number,
5608c2ecf20Sopenharmony_ci					     OPAL_EEH_ACTION_SET_FREEZE_ALL);
5618c2ecf20Sopenharmony_ci		if (rc != OPAL_SUCCESS)
5628c2ecf20Sopenharmony_ci			pr_warn("%s: Failure %lld freezing PHB#%x-PE#%x\n",
5638c2ecf20Sopenharmony_ci				__func__, rc, phb->hose->global_number,
5648c2ecf20Sopenharmony_ci				slave->pe_number);
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cistatic int pnv_ioda_unfreeze_pe(struct pnv_phb *phb, int pe_no, int opt)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe, *slave;
5718c2ecf20Sopenharmony_ci	s64 rc;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	/* Find master PE */
5748c2ecf20Sopenharmony_ci	pe = &phb->ioda.pe_array[pe_no];
5758c2ecf20Sopenharmony_ci	if (pe->flags & PNV_IODA_PE_SLAVE) {
5768c2ecf20Sopenharmony_ci		pe = pe->master;
5778c2ecf20Sopenharmony_ci		WARN_ON(!pe || !(pe->flags & PNV_IODA_PE_MASTER));
5788c2ecf20Sopenharmony_ci		pe_no = pe->pe_number;
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	/* Clear frozen state for master PE */
5828c2ecf20Sopenharmony_ci	rc = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no, opt);
5838c2ecf20Sopenharmony_ci	if (rc != OPAL_SUCCESS) {
5848c2ecf20Sopenharmony_ci		pr_warn("%s: Failure %lld clear %d on PHB#%x-PE#%x\n",
5858c2ecf20Sopenharmony_ci			__func__, rc, opt, phb->hose->global_number, pe_no);
5868c2ecf20Sopenharmony_ci		return -EIO;
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	if (!(pe->flags & PNV_IODA_PE_MASTER))
5908c2ecf20Sopenharmony_ci		return 0;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	/* Clear frozen state for slave PEs */
5938c2ecf20Sopenharmony_ci	list_for_each_entry(slave, &pe->slaves, list) {
5948c2ecf20Sopenharmony_ci		rc = opal_pci_eeh_freeze_clear(phb->opal_id,
5958c2ecf20Sopenharmony_ci					     slave->pe_number,
5968c2ecf20Sopenharmony_ci					     opt);
5978c2ecf20Sopenharmony_ci		if (rc != OPAL_SUCCESS) {
5988c2ecf20Sopenharmony_ci			pr_warn("%s: Failure %lld clear %d on PHB#%x-PE#%x\n",
5998c2ecf20Sopenharmony_ci				__func__, rc, opt, phb->hose->global_number,
6008c2ecf20Sopenharmony_ci				slave->pe_number);
6018c2ecf20Sopenharmony_ci			return -EIO;
6028c2ecf20Sopenharmony_ci		}
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	return 0;
6068c2ecf20Sopenharmony_ci}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic int pnv_ioda_get_pe_state(struct pnv_phb *phb, int pe_no)
6098c2ecf20Sopenharmony_ci{
6108c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *slave, *pe;
6118c2ecf20Sopenharmony_ci	u8 fstate = 0, state;
6128c2ecf20Sopenharmony_ci	__be16 pcierr = 0;
6138c2ecf20Sopenharmony_ci	s64 rc;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	/* Sanity check on PE number */
6168c2ecf20Sopenharmony_ci	if (pe_no < 0 || pe_no >= phb->ioda.total_pe_num)
6178c2ecf20Sopenharmony_ci		return OPAL_EEH_STOPPED_PERM_UNAVAIL;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	/*
6208c2ecf20Sopenharmony_ci	 * Fetch the master PE and the PE instance might be
6218c2ecf20Sopenharmony_ci	 * not initialized yet.
6228c2ecf20Sopenharmony_ci	 */
6238c2ecf20Sopenharmony_ci	pe = &phb->ioda.pe_array[pe_no];
6248c2ecf20Sopenharmony_ci	if (pe->flags & PNV_IODA_PE_SLAVE) {
6258c2ecf20Sopenharmony_ci		pe = pe->master;
6268c2ecf20Sopenharmony_ci		WARN_ON(!pe || !(pe->flags & PNV_IODA_PE_MASTER));
6278c2ecf20Sopenharmony_ci		pe_no = pe->pe_number;
6288c2ecf20Sopenharmony_ci	}
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	/* Check the master PE */
6318c2ecf20Sopenharmony_ci	rc = opal_pci_eeh_freeze_status(phb->opal_id, pe_no,
6328c2ecf20Sopenharmony_ci					&state, &pcierr, NULL);
6338c2ecf20Sopenharmony_ci	if (rc != OPAL_SUCCESS) {
6348c2ecf20Sopenharmony_ci		pr_warn("%s: Failure %lld getting "
6358c2ecf20Sopenharmony_ci			"PHB#%x-PE#%x state\n",
6368c2ecf20Sopenharmony_ci			__func__, rc,
6378c2ecf20Sopenharmony_ci			phb->hose->global_number, pe_no);
6388c2ecf20Sopenharmony_ci		return OPAL_EEH_STOPPED_TEMP_UNAVAIL;
6398c2ecf20Sopenharmony_ci	}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	/* Check the slave PE */
6428c2ecf20Sopenharmony_ci	if (!(pe->flags & PNV_IODA_PE_MASTER))
6438c2ecf20Sopenharmony_ci		return state;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	list_for_each_entry(slave, &pe->slaves, list) {
6468c2ecf20Sopenharmony_ci		rc = opal_pci_eeh_freeze_status(phb->opal_id,
6478c2ecf20Sopenharmony_ci						slave->pe_number,
6488c2ecf20Sopenharmony_ci						&fstate,
6498c2ecf20Sopenharmony_ci						&pcierr,
6508c2ecf20Sopenharmony_ci						NULL);
6518c2ecf20Sopenharmony_ci		if (rc != OPAL_SUCCESS) {
6528c2ecf20Sopenharmony_ci			pr_warn("%s: Failure %lld getting "
6538c2ecf20Sopenharmony_ci				"PHB#%x-PE#%x state\n",
6548c2ecf20Sopenharmony_ci				__func__, rc,
6558c2ecf20Sopenharmony_ci				phb->hose->global_number, slave->pe_number);
6568c2ecf20Sopenharmony_ci			return OPAL_EEH_STOPPED_TEMP_UNAVAIL;
6578c2ecf20Sopenharmony_ci		}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci		/*
6608c2ecf20Sopenharmony_ci		 * Override the result based on the ascending
6618c2ecf20Sopenharmony_ci		 * priority.
6628c2ecf20Sopenharmony_ci		 */
6638c2ecf20Sopenharmony_ci		if (fstate > state)
6648c2ecf20Sopenharmony_ci			state = fstate;
6658c2ecf20Sopenharmony_ci	}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	return state;
6688c2ecf20Sopenharmony_ci}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_cistruct pnv_ioda_pe *pnv_pci_bdfn_to_pe(struct pnv_phb *phb, u16 bdfn)
6718c2ecf20Sopenharmony_ci{
6728c2ecf20Sopenharmony_ci	int pe_number = phb->ioda.pe_rmap[bdfn];
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	if (pe_number == IODA_INVALID_PE)
6758c2ecf20Sopenharmony_ci		return NULL;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	return &phb->ioda.pe_array[pe_number];
6788c2ecf20Sopenharmony_ci}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_cistruct pnv_ioda_pe *pnv_ioda_get_pe(struct pci_dev *dev)
6818c2ecf20Sopenharmony_ci{
6828c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(dev->bus);
6838c2ecf20Sopenharmony_ci	struct pci_dn *pdn = pci_get_pdn(dev);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	if (!pdn)
6868c2ecf20Sopenharmony_ci		return NULL;
6878c2ecf20Sopenharmony_ci	if (pdn->pe_number == IODA_INVALID_PE)
6888c2ecf20Sopenharmony_ci		return NULL;
6898c2ecf20Sopenharmony_ci	return &phb->ioda.pe_array[pdn->pe_number];
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_cistatic int pnv_ioda_set_one_peltv(struct pnv_phb *phb,
6938c2ecf20Sopenharmony_ci				  struct pnv_ioda_pe *parent,
6948c2ecf20Sopenharmony_ci				  struct pnv_ioda_pe *child,
6958c2ecf20Sopenharmony_ci				  bool is_add)
6968c2ecf20Sopenharmony_ci{
6978c2ecf20Sopenharmony_ci	const char *desc = is_add ? "adding" : "removing";
6988c2ecf20Sopenharmony_ci	uint8_t op = is_add ? OPAL_ADD_PE_TO_DOMAIN :
6998c2ecf20Sopenharmony_ci			      OPAL_REMOVE_PE_FROM_DOMAIN;
7008c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *slave;
7018c2ecf20Sopenharmony_ci	long rc;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	/* Parent PE affects child PE */
7048c2ecf20Sopenharmony_ci	rc = opal_pci_set_peltv(phb->opal_id, parent->pe_number,
7058c2ecf20Sopenharmony_ci				child->pe_number, op);
7068c2ecf20Sopenharmony_ci	if (rc != OPAL_SUCCESS) {
7078c2ecf20Sopenharmony_ci		pe_warn(child, "OPAL error %ld %s to parent PELTV\n",
7088c2ecf20Sopenharmony_ci			rc, desc);
7098c2ecf20Sopenharmony_ci		return -ENXIO;
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	if (!(child->flags & PNV_IODA_PE_MASTER))
7138c2ecf20Sopenharmony_ci		return 0;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	/* Compound case: parent PE affects slave PEs */
7168c2ecf20Sopenharmony_ci	list_for_each_entry(slave, &child->slaves, list) {
7178c2ecf20Sopenharmony_ci		rc = opal_pci_set_peltv(phb->opal_id, parent->pe_number,
7188c2ecf20Sopenharmony_ci					slave->pe_number, op);
7198c2ecf20Sopenharmony_ci		if (rc != OPAL_SUCCESS) {
7208c2ecf20Sopenharmony_ci			pe_warn(slave, "OPAL error %ld %s to parent PELTV\n",
7218c2ecf20Sopenharmony_ci				rc, desc);
7228c2ecf20Sopenharmony_ci			return -ENXIO;
7238c2ecf20Sopenharmony_ci		}
7248c2ecf20Sopenharmony_ci	}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	return 0;
7278c2ecf20Sopenharmony_ci}
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_cistatic int pnv_ioda_set_peltv(struct pnv_phb *phb,
7308c2ecf20Sopenharmony_ci			      struct pnv_ioda_pe *pe,
7318c2ecf20Sopenharmony_ci			      bool is_add)
7328c2ecf20Sopenharmony_ci{
7338c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *slave;
7348c2ecf20Sopenharmony_ci	struct pci_dev *pdev = NULL;
7358c2ecf20Sopenharmony_ci	int ret;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	/*
7388c2ecf20Sopenharmony_ci	 * Clear PE frozen state. If it's master PE, we need
7398c2ecf20Sopenharmony_ci	 * clear slave PE frozen state as well.
7408c2ecf20Sopenharmony_ci	 */
7418c2ecf20Sopenharmony_ci	if (is_add) {
7428c2ecf20Sopenharmony_ci		opal_pci_eeh_freeze_clear(phb->opal_id, pe->pe_number,
7438c2ecf20Sopenharmony_ci					  OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
7448c2ecf20Sopenharmony_ci		if (pe->flags & PNV_IODA_PE_MASTER) {
7458c2ecf20Sopenharmony_ci			list_for_each_entry(slave, &pe->slaves, list)
7468c2ecf20Sopenharmony_ci				opal_pci_eeh_freeze_clear(phb->opal_id,
7478c2ecf20Sopenharmony_ci							  slave->pe_number,
7488c2ecf20Sopenharmony_ci							  OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
7498c2ecf20Sopenharmony_ci		}
7508c2ecf20Sopenharmony_ci	}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	/*
7538c2ecf20Sopenharmony_ci	 * Associate PE in PELT. We need add the PE into the
7548c2ecf20Sopenharmony_ci	 * corresponding PELT-V as well. Otherwise, the error
7558c2ecf20Sopenharmony_ci	 * originated from the PE might contribute to other
7568c2ecf20Sopenharmony_ci	 * PEs.
7578c2ecf20Sopenharmony_ci	 */
7588c2ecf20Sopenharmony_ci	ret = pnv_ioda_set_one_peltv(phb, pe, pe, is_add);
7598c2ecf20Sopenharmony_ci	if (ret)
7608c2ecf20Sopenharmony_ci		return ret;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	/* For compound PEs, any one affects all of them */
7638c2ecf20Sopenharmony_ci	if (pe->flags & PNV_IODA_PE_MASTER) {
7648c2ecf20Sopenharmony_ci		list_for_each_entry(slave, &pe->slaves, list) {
7658c2ecf20Sopenharmony_ci			ret = pnv_ioda_set_one_peltv(phb, slave, pe, is_add);
7668c2ecf20Sopenharmony_ci			if (ret)
7678c2ecf20Sopenharmony_ci				return ret;
7688c2ecf20Sopenharmony_ci		}
7698c2ecf20Sopenharmony_ci	}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	if (pe->flags & (PNV_IODA_PE_BUS_ALL | PNV_IODA_PE_BUS))
7728c2ecf20Sopenharmony_ci		pdev = pe->pbus->self;
7738c2ecf20Sopenharmony_ci	else if (pe->flags & PNV_IODA_PE_DEV)
7748c2ecf20Sopenharmony_ci		pdev = pe->pdev->bus->self;
7758c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV
7768c2ecf20Sopenharmony_ci	else if (pe->flags & PNV_IODA_PE_VF)
7778c2ecf20Sopenharmony_ci		pdev = pe->parent_dev;
7788c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI_IOV */
7798c2ecf20Sopenharmony_ci	while (pdev) {
7808c2ecf20Sopenharmony_ci		struct pci_dn *pdn = pci_get_pdn(pdev);
7818c2ecf20Sopenharmony_ci		struct pnv_ioda_pe *parent;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci		if (pdn && pdn->pe_number != IODA_INVALID_PE) {
7848c2ecf20Sopenharmony_ci			parent = &phb->ioda.pe_array[pdn->pe_number];
7858c2ecf20Sopenharmony_ci			ret = pnv_ioda_set_one_peltv(phb, parent, pe, is_add);
7868c2ecf20Sopenharmony_ci			if (ret)
7878c2ecf20Sopenharmony_ci				return ret;
7888c2ecf20Sopenharmony_ci		}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci		pdev = pdev->bus->self;
7918c2ecf20Sopenharmony_ci	}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	return 0;
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic void pnv_ioda_unset_peltv(struct pnv_phb *phb,
7978c2ecf20Sopenharmony_ci				 struct pnv_ioda_pe *pe,
7988c2ecf20Sopenharmony_ci				 struct pci_dev *parent)
7998c2ecf20Sopenharmony_ci{
8008c2ecf20Sopenharmony_ci	int64_t rc;
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	while (parent) {
8038c2ecf20Sopenharmony_ci		struct pci_dn *pdn = pci_get_pdn(parent);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci		if (pdn && pdn->pe_number != IODA_INVALID_PE) {
8068c2ecf20Sopenharmony_ci			rc = opal_pci_set_peltv(phb->opal_id, pdn->pe_number,
8078c2ecf20Sopenharmony_ci						pe->pe_number,
8088c2ecf20Sopenharmony_ci						OPAL_REMOVE_PE_FROM_DOMAIN);
8098c2ecf20Sopenharmony_ci			/* XXX What to do in case of error ? */
8108c2ecf20Sopenharmony_ci		}
8118c2ecf20Sopenharmony_ci		parent = parent->bus->self;
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	opal_pci_eeh_freeze_clear(phb->opal_id, pe->pe_number,
8158c2ecf20Sopenharmony_ci				  OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	/* Disassociate PE in PELT */
8188c2ecf20Sopenharmony_ci	rc = opal_pci_set_peltv(phb->opal_id, pe->pe_number,
8198c2ecf20Sopenharmony_ci				pe->pe_number, OPAL_REMOVE_PE_FROM_DOMAIN);
8208c2ecf20Sopenharmony_ci	if (rc)
8218c2ecf20Sopenharmony_ci		pe_warn(pe, "OPAL error %lld remove self from PELTV\n", rc);
8228c2ecf20Sopenharmony_ci}
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ciint pnv_ioda_deconfigure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
8258c2ecf20Sopenharmony_ci{
8268c2ecf20Sopenharmony_ci	struct pci_dev *parent;
8278c2ecf20Sopenharmony_ci	uint8_t bcomp, dcomp, fcomp;
8288c2ecf20Sopenharmony_ci	int64_t rc;
8298c2ecf20Sopenharmony_ci	long rid_end, rid;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	/* Currently, we just deconfigure VF PE. Bus PE will always there.*/
8328c2ecf20Sopenharmony_ci	if (pe->pbus) {
8338c2ecf20Sopenharmony_ci		int count;
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci		dcomp = OPAL_IGNORE_RID_DEVICE_NUMBER;
8368c2ecf20Sopenharmony_ci		fcomp = OPAL_IGNORE_RID_FUNCTION_NUMBER;
8378c2ecf20Sopenharmony_ci		parent = pe->pbus->self;
8388c2ecf20Sopenharmony_ci		if (pe->flags & PNV_IODA_PE_BUS_ALL)
8398c2ecf20Sopenharmony_ci			count = resource_size(&pe->pbus->busn_res);
8408c2ecf20Sopenharmony_ci		else
8418c2ecf20Sopenharmony_ci			count = 1;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci		switch(count) {
8448c2ecf20Sopenharmony_ci		case  1: bcomp = OpalPciBusAll;         break;
8458c2ecf20Sopenharmony_ci		case  2: bcomp = OpalPciBus7Bits;       break;
8468c2ecf20Sopenharmony_ci		case  4: bcomp = OpalPciBus6Bits;       break;
8478c2ecf20Sopenharmony_ci		case  8: bcomp = OpalPciBus5Bits;       break;
8488c2ecf20Sopenharmony_ci		case 16: bcomp = OpalPciBus4Bits;       break;
8498c2ecf20Sopenharmony_ci		case 32: bcomp = OpalPciBus3Bits;       break;
8508c2ecf20Sopenharmony_ci		default:
8518c2ecf20Sopenharmony_ci			dev_err(&pe->pbus->dev, "Number of subordinate buses %d unsupported\n",
8528c2ecf20Sopenharmony_ci			        count);
8538c2ecf20Sopenharmony_ci			/* Do an exact match only */
8548c2ecf20Sopenharmony_ci			bcomp = OpalPciBusAll;
8558c2ecf20Sopenharmony_ci		}
8568c2ecf20Sopenharmony_ci		rid_end = pe->rid + (count << 8);
8578c2ecf20Sopenharmony_ci	} else {
8588c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV
8598c2ecf20Sopenharmony_ci		if (pe->flags & PNV_IODA_PE_VF)
8608c2ecf20Sopenharmony_ci			parent = pe->parent_dev;
8618c2ecf20Sopenharmony_ci		else
8628c2ecf20Sopenharmony_ci#endif
8638c2ecf20Sopenharmony_ci			parent = pe->pdev->bus->self;
8648c2ecf20Sopenharmony_ci		bcomp = OpalPciBusAll;
8658c2ecf20Sopenharmony_ci		dcomp = OPAL_COMPARE_RID_DEVICE_NUMBER;
8668c2ecf20Sopenharmony_ci		fcomp = OPAL_COMPARE_RID_FUNCTION_NUMBER;
8678c2ecf20Sopenharmony_ci		rid_end = pe->rid + 1;
8688c2ecf20Sopenharmony_ci	}
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	/* Clear the reverse map */
8718c2ecf20Sopenharmony_ci	for (rid = pe->rid; rid < rid_end; rid++)
8728c2ecf20Sopenharmony_ci		phb->ioda.pe_rmap[rid] = IODA_INVALID_PE;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	/*
8758c2ecf20Sopenharmony_ci	 * Release from all parents PELT-V. NPUs don't have a PELTV
8768c2ecf20Sopenharmony_ci	 * table
8778c2ecf20Sopenharmony_ci	 */
8788c2ecf20Sopenharmony_ci	if (phb->type != PNV_PHB_NPU_NVLINK && phb->type != PNV_PHB_NPU_OCAPI)
8798c2ecf20Sopenharmony_ci		pnv_ioda_unset_peltv(phb, pe, parent);
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	rc = opal_pci_set_pe(phb->opal_id, pe->pe_number, pe->rid,
8828c2ecf20Sopenharmony_ci			     bcomp, dcomp, fcomp, OPAL_UNMAP_PE);
8838c2ecf20Sopenharmony_ci	if (rc)
8848c2ecf20Sopenharmony_ci		pe_err(pe, "OPAL error %lld trying to setup PELT table\n", rc);
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	pe->pbus = NULL;
8878c2ecf20Sopenharmony_ci	pe->pdev = NULL;
8888c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV
8898c2ecf20Sopenharmony_ci	pe->parent_dev = NULL;
8908c2ecf20Sopenharmony_ci#endif
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	return 0;
8938c2ecf20Sopenharmony_ci}
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ciint pnv_ioda_configure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
8968c2ecf20Sopenharmony_ci{
8978c2ecf20Sopenharmony_ci	uint8_t bcomp, dcomp, fcomp;
8988c2ecf20Sopenharmony_ci	long rc, rid_end, rid;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	/* Bus validation ? */
9018c2ecf20Sopenharmony_ci	if (pe->pbus) {
9028c2ecf20Sopenharmony_ci		int count;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci		dcomp = OPAL_IGNORE_RID_DEVICE_NUMBER;
9058c2ecf20Sopenharmony_ci		fcomp = OPAL_IGNORE_RID_FUNCTION_NUMBER;
9068c2ecf20Sopenharmony_ci		if (pe->flags & PNV_IODA_PE_BUS_ALL)
9078c2ecf20Sopenharmony_ci			count = resource_size(&pe->pbus->busn_res);
9088c2ecf20Sopenharmony_ci		else
9098c2ecf20Sopenharmony_ci			count = 1;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci		switch(count) {
9128c2ecf20Sopenharmony_ci		case  1: bcomp = OpalPciBusAll;		break;
9138c2ecf20Sopenharmony_ci		case  2: bcomp = OpalPciBus7Bits;	break;
9148c2ecf20Sopenharmony_ci		case  4: bcomp = OpalPciBus6Bits;	break;
9158c2ecf20Sopenharmony_ci		case  8: bcomp = OpalPciBus5Bits;	break;
9168c2ecf20Sopenharmony_ci		case 16: bcomp = OpalPciBus4Bits;	break;
9178c2ecf20Sopenharmony_ci		case 32: bcomp = OpalPciBus3Bits;	break;
9188c2ecf20Sopenharmony_ci		default:
9198c2ecf20Sopenharmony_ci			dev_err(&pe->pbus->dev, "Number of subordinate buses %d unsupported\n",
9208c2ecf20Sopenharmony_ci			        count);
9218c2ecf20Sopenharmony_ci			/* Do an exact match only */
9228c2ecf20Sopenharmony_ci			bcomp = OpalPciBusAll;
9238c2ecf20Sopenharmony_ci		}
9248c2ecf20Sopenharmony_ci		rid_end = pe->rid + (count << 8);
9258c2ecf20Sopenharmony_ci	} else {
9268c2ecf20Sopenharmony_ci		bcomp = OpalPciBusAll;
9278c2ecf20Sopenharmony_ci		dcomp = OPAL_COMPARE_RID_DEVICE_NUMBER;
9288c2ecf20Sopenharmony_ci		fcomp = OPAL_COMPARE_RID_FUNCTION_NUMBER;
9298c2ecf20Sopenharmony_ci		rid_end = pe->rid + 1;
9308c2ecf20Sopenharmony_ci	}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	/*
9338c2ecf20Sopenharmony_ci	 * Associate PE in PELT. We need add the PE into the
9348c2ecf20Sopenharmony_ci	 * corresponding PELT-V as well. Otherwise, the error
9358c2ecf20Sopenharmony_ci	 * originated from the PE might contribute to other
9368c2ecf20Sopenharmony_ci	 * PEs.
9378c2ecf20Sopenharmony_ci	 */
9388c2ecf20Sopenharmony_ci	rc = opal_pci_set_pe(phb->opal_id, pe->pe_number, pe->rid,
9398c2ecf20Sopenharmony_ci			     bcomp, dcomp, fcomp, OPAL_MAP_PE);
9408c2ecf20Sopenharmony_ci	if (rc) {
9418c2ecf20Sopenharmony_ci		pe_err(pe, "OPAL error %ld trying to setup PELT table\n", rc);
9428c2ecf20Sopenharmony_ci		return -ENXIO;
9438c2ecf20Sopenharmony_ci	}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	/*
9468c2ecf20Sopenharmony_ci	 * Configure PELTV. NPUs don't have a PELTV table so skip
9478c2ecf20Sopenharmony_ci	 * configuration on them.
9488c2ecf20Sopenharmony_ci	 */
9498c2ecf20Sopenharmony_ci	if (phb->type != PNV_PHB_NPU_NVLINK && phb->type != PNV_PHB_NPU_OCAPI)
9508c2ecf20Sopenharmony_ci		pnv_ioda_set_peltv(phb, pe, true);
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	/* Setup reverse map */
9538c2ecf20Sopenharmony_ci	for (rid = pe->rid; rid < rid_end; rid++)
9548c2ecf20Sopenharmony_ci		phb->ioda.pe_rmap[rid] = pe->pe_number;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	/* Setup one MVTs on IODA1 */
9578c2ecf20Sopenharmony_ci	if (phb->type != PNV_PHB_IODA1) {
9588c2ecf20Sopenharmony_ci		pe->mve_number = 0;
9598c2ecf20Sopenharmony_ci		goto out;
9608c2ecf20Sopenharmony_ci	}
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	pe->mve_number = pe->pe_number;
9638c2ecf20Sopenharmony_ci	rc = opal_pci_set_mve(phb->opal_id, pe->mve_number, pe->pe_number);
9648c2ecf20Sopenharmony_ci	if (rc != OPAL_SUCCESS) {
9658c2ecf20Sopenharmony_ci		pe_err(pe, "OPAL error %ld setting up MVE %x\n",
9668c2ecf20Sopenharmony_ci		       rc, pe->mve_number);
9678c2ecf20Sopenharmony_ci		pe->mve_number = -1;
9688c2ecf20Sopenharmony_ci	} else {
9698c2ecf20Sopenharmony_ci		rc = opal_pci_set_mve_enable(phb->opal_id,
9708c2ecf20Sopenharmony_ci					     pe->mve_number, OPAL_ENABLE_MVE);
9718c2ecf20Sopenharmony_ci		if (rc) {
9728c2ecf20Sopenharmony_ci			pe_err(pe, "OPAL error %ld enabling MVE %x\n",
9738c2ecf20Sopenharmony_ci			       rc, pe->mve_number);
9748c2ecf20Sopenharmony_ci			pe->mve_number = -1;
9758c2ecf20Sopenharmony_ci		}
9768c2ecf20Sopenharmony_ci	}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ciout:
9798c2ecf20Sopenharmony_ci	return 0;
9808c2ecf20Sopenharmony_ci}
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_cistatic struct pnv_ioda_pe *pnv_ioda_setup_dev_PE(struct pci_dev *dev)
9838c2ecf20Sopenharmony_ci{
9848c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(dev->bus);
9858c2ecf20Sopenharmony_ci	struct pci_dn *pdn = pci_get_pdn(dev);
9868c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	if (!pdn) {
9898c2ecf20Sopenharmony_ci		pr_err("%s: Device tree node not associated properly\n",
9908c2ecf20Sopenharmony_ci			   pci_name(dev));
9918c2ecf20Sopenharmony_ci		return NULL;
9928c2ecf20Sopenharmony_ci	}
9938c2ecf20Sopenharmony_ci	if (pdn->pe_number != IODA_INVALID_PE)
9948c2ecf20Sopenharmony_ci		return NULL;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	pe = pnv_ioda_alloc_pe(phb, 1);
9978c2ecf20Sopenharmony_ci	if (!pe) {
9988c2ecf20Sopenharmony_ci		pr_warn("%s: Not enough PE# available, disabling device\n",
9998c2ecf20Sopenharmony_ci			pci_name(dev));
10008c2ecf20Sopenharmony_ci		return NULL;
10018c2ecf20Sopenharmony_ci	}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	/* NOTE: We don't get a reference for the pointer in the PE
10048c2ecf20Sopenharmony_ci	 * data structure, both the device and PE structures should be
10058c2ecf20Sopenharmony_ci	 * destroyed at the same time. However, removing nvlink
10068c2ecf20Sopenharmony_ci	 * devices will need some work.
10078c2ecf20Sopenharmony_ci	 *
10088c2ecf20Sopenharmony_ci	 * At some point we want to remove the PDN completely anyways
10098c2ecf20Sopenharmony_ci	 */
10108c2ecf20Sopenharmony_ci	pdn->pe_number = pe->pe_number;
10118c2ecf20Sopenharmony_ci	pe->flags = PNV_IODA_PE_DEV;
10128c2ecf20Sopenharmony_ci	pe->pdev = dev;
10138c2ecf20Sopenharmony_ci	pe->pbus = NULL;
10148c2ecf20Sopenharmony_ci	pe->mve_number = -1;
10158c2ecf20Sopenharmony_ci	pe->rid = dev->bus->number << 8 | pdn->devfn;
10168c2ecf20Sopenharmony_ci	pe->device_count++;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	pe_info(pe, "Associated device to PE\n");
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	if (pnv_ioda_configure_pe(phb, pe)) {
10218c2ecf20Sopenharmony_ci		/* XXX What do we do here ? */
10228c2ecf20Sopenharmony_ci		pnv_ioda_free_pe(pe);
10238c2ecf20Sopenharmony_ci		pdn->pe_number = IODA_INVALID_PE;
10248c2ecf20Sopenharmony_ci		pe->pdev = NULL;
10258c2ecf20Sopenharmony_ci		return NULL;
10268c2ecf20Sopenharmony_ci	}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	/* Put PE to the list */
10298c2ecf20Sopenharmony_ci	mutex_lock(&phb->ioda.pe_list_mutex);
10308c2ecf20Sopenharmony_ci	list_add_tail(&pe->list, &phb->ioda.pe_list);
10318c2ecf20Sopenharmony_ci	mutex_unlock(&phb->ioda.pe_list_mutex);
10328c2ecf20Sopenharmony_ci	return pe;
10338c2ecf20Sopenharmony_ci}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci/*
10368c2ecf20Sopenharmony_ci * There're 2 types of PCI bus sensitive PEs: One that is compromised of
10378c2ecf20Sopenharmony_ci * single PCI bus. Another one that contains the primary PCI bus and its
10388c2ecf20Sopenharmony_ci * subordinate PCI devices and buses. The second type of PE is normally
10398c2ecf20Sopenharmony_ci * orgiriated by PCIe-to-PCI bridge or PLX switch downstream ports.
10408c2ecf20Sopenharmony_ci */
10418c2ecf20Sopenharmony_cistatic struct pnv_ioda_pe *pnv_ioda_setup_bus_PE(struct pci_bus *bus, bool all)
10428c2ecf20Sopenharmony_ci{
10438c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(bus);
10448c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe = NULL;
10458c2ecf20Sopenharmony_ci	unsigned int pe_num;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	/*
10488c2ecf20Sopenharmony_ci	 * In partial hotplug case, the PE instance might be still alive.
10498c2ecf20Sopenharmony_ci	 * We should reuse it instead of allocating a new one.
10508c2ecf20Sopenharmony_ci	 */
10518c2ecf20Sopenharmony_ci	pe_num = phb->ioda.pe_rmap[bus->number << 8];
10528c2ecf20Sopenharmony_ci	if (WARN_ON(pe_num != IODA_INVALID_PE)) {
10538c2ecf20Sopenharmony_ci		pe = &phb->ioda.pe_array[pe_num];
10548c2ecf20Sopenharmony_ci		return NULL;
10558c2ecf20Sopenharmony_ci	}
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	/* PE number for root bus should have been reserved */
10588c2ecf20Sopenharmony_ci	if (pci_is_root_bus(bus))
10598c2ecf20Sopenharmony_ci		pe = &phb->ioda.pe_array[phb->ioda.root_pe_idx];
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	/* Check if PE is determined by M64 */
10628c2ecf20Sopenharmony_ci	if (!pe)
10638c2ecf20Sopenharmony_ci		pe = pnv_ioda_pick_m64_pe(bus, all);
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	/* The PE number isn't pinned by M64 */
10668c2ecf20Sopenharmony_ci	if (!pe)
10678c2ecf20Sopenharmony_ci		pe = pnv_ioda_alloc_pe(phb, 1);
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	if (!pe) {
10708c2ecf20Sopenharmony_ci		pr_warn("%s: Not enough PE# available for PCI bus %04x:%02x\n",
10718c2ecf20Sopenharmony_ci			__func__, pci_domain_nr(bus), bus->number);
10728c2ecf20Sopenharmony_ci		return NULL;
10738c2ecf20Sopenharmony_ci	}
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	pe->flags |= (all ? PNV_IODA_PE_BUS_ALL : PNV_IODA_PE_BUS);
10768c2ecf20Sopenharmony_ci	pe->pbus = bus;
10778c2ecf20Sopenharmony_ci	pe->pdev = NULL;
10788c2ecf20Sopenharmony_ci	pe->mve_number = -1;
10798c2ecf20Sopenharmony_ci	pe->rid = bus->busn_res.start << 8;
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	if (all)
10828c2ecf20Sopenharmony_ci		pe_info(pe, "Secondary bus %pad..%pad associated with PE#%x\n",
10838c2ecf20Sopenharmony_ci			&bus->busn_res.start, &bus->busn_res.end,
10848c2ecf20Sopenharmony_ci			pe->pe_number);
10858c2ecf20Sopenharmony_ci	else
10868c2ecf20Sopenharmony_ci		pe_info(pe, "Secondary bus %pad associated with PE#%x\n",
10878c2ecf20Sopenharmony_ci			&bus->busn_res.start, pe->pe_number);
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	if (pnv_ioda_configure_pe(phb, pe)) {
10908c2ecf20Sopenharmony_ci		/* XXX What do we do here ? */
10918c2ecf20Sopenharmony_ci		pnv_ioda_free_pe(pe);
10928c2ecf20Sopenharmony_ci		pe->pbus = NULL;
10938c2ecf20Sopenharmony_ci		return NULL;
10948c2ecf20Sopenharmony_ci	}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	/* Put PE to the list */
10978c2ecf20Sopenharmony_ci	list_add_tail(&pe->list, &phb->ioda.pe_list);
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	return pe;
11008c2ecf20Sopenharmony_ci}
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_cistatic struct pnv_ioda_pe *pnv_ioda_setup_npu_PE(struct pci_dev *npu_pdev)
11038c2ecf20Sopenharmony_ci{
11048c2ecf20Sopenharmony_ci	int pe_num, found_pe = false, rc;
11058c2ecf20Sopenharmony_ci	long rid;
11068c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe;
11078c2ecf20Sopenharmony_ci	struct pci_dev *gpu_pdev;
11088c2ecf20Sopenharmony_ci	struct pci_dn *npu_pdn;
11098c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(npu_pdev->bus);
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	/*
11128c2ecf20Sopenharmony_ci	 * Intentionally leak a reference on the npu device (for
11138c2ecf20Sopenharmony_ci	 * nvlink only; this is not an opencapi path) to make sure it
11148c2ecf20Sopenharmony_ci	 * never goes away, as it's been the case all along and some
11158c2ecf20Sopenharmony_ci	 * work is needed otherwise.
11168c2ecf20Sopenharmony_ci	 */
11178c2ecf20Sopenharmony_ci	pci_dev_get(npu_pdev);
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	/*
11208c2ecf20Sopenharmony_ci	 * Due to a hardware errata PE#0 on the NPU is reserved for
11218c2ecf20Sopenharmony_ci	 * error handling. This means we only have three PEs remaining
11228c2ecf20Sopenharmony_ci	 * which need to be assigned to four links, implying some
11238c2ecf20Sopenharmony_ci	 * links must share PEs.
11248c2ecf20Sopenharmony_ci	 *
11258c2ecf20Sopenharmony_ci	 * To achieve this we assign PEs such that NPUs linking the
11268c2ecf20Sopenharmony_ci	 * same GPU get assigned the same PE.
11278c2ecf20Sopenharmony_ci	 */
11288c2ecf20Sopenharmony_ci	gpu_pdev = pnv_pci_get_gpu_dev(npu_pdev);
11298c2ecf20Sopenharmony_ci	for (pe_num = 0; pe_num < phb->ioda.total_pe_num; pe_num++) {
11308c2ecf20Sopenharmony_ci		pe = &phb->ioda.pe_array[pe_num];
11318c2ecf20Sopenharmony_ci		if (!pe->pdev)
11328c2ecf20Sopenharmony_ci			continue;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci		if (pnv_pci_get_gpu_dev(pe->pdev) == gpu_pdev) {
11358c2ecf20Sopenharmony_ci			/*
11368c2ecf20Sopenharmony_ci			 * This device has the same peer GPU so should
11378c2ecf20Sopenharmony_ci			 * be assigned the same PE as the existing
11388c2ecf20Sopenharmony_ci			 * peer NPU.
11398c2ecf20Sopenharmony_ci			 */
11408c2ecf20Sopenharmony_ci			dev_info(&npu_pdev->dev,
11418c2ecf20Sopenharmony_ci				"Associating to existing PE %x\n", pe_num);
11428c2ecf20Sopenharmony_ci			npu_pdn = pci_get_pdn(npu_pdev);
11438c2ecf20Sopenharmony_ci			rid = npu_pdev->bus->number << 8 | npu_pdn->devfn;
11448c2ecf20Sopenharmony_ci			npu_pdn->pe_number = pe_num;
11458c2ecf20Sopenharmony_ci			phb->ioda.pe_rmap[rid] = pe->pe_number;
11468c2ecf20Sopenharmony_ci			pe->device_count++;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci			/* Map the PE to this link */
11498c2ecf20Sopenharmony_ci			rc = opal_pci_set_pe(phb->opal_id, pe_num, rid,
11508c2ecf20Sopenharmony_ci					OpalPciBusAll,
11518c2ecf20Sopenharmony_ci					OPAL_COMPARE_RID_DEVICE_NUMBER,
11528c2ecf20Sopenharmony_ci					OPAL_COMPARE_RID_FUNCTION_NUMBER,
11538c2ecf20Sopenharmony_ci					OPAL_MAP_PE);
11548c2ecf20Sopenharmony_ci			WARN_ON(rc != OPAL_SUCCESS);
11558c2ecf20Sopenharmony_ci			found_pe = true;
11568c2ecf20Sopenharmony_ci			break;
11578c2ecf20Sopenharmony_ci		}
11588c2ecf20Sopenharmony_ci	}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	if (!found_pe)
11618c2ecf20Sopenharmony_ci		/*
11628c2ecf20Sopenharmony_ci		 * Could not find an existing PE so allocate a new
11638c2ecf20Sopenharmony_ci		 * one.
11648c2ecf20Sopenharmony_ci		 */
11658c2ecf20Sopenharmony_ci		return pnv_ioda_setup_dev_PE(npu_pdev);
11668c2ecf20Sopenharmony_ci	else
11678c2ecf20Sopenharmony_ci		return pe;
11688c2ecf20Sopenharmony_ci}
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_cistatic void pnv_ioda_setup_npu_PEs(struct pci_bus *bus)
11718c2ecf20Sopenharmony_ci{
11728c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	list_for_each_entry(pdev, &bus->devices, bus_list)
11758c2ecf20Sopenharmony_ci		pnv_ioda_setup_npu_PE(pdev);
11768c2ecf20Sopenharmony_ci}
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_cistatic void pnv_pci_ioda_setup_nvlink(void)
11798c2ecf20Sopenharmony_ci{
11808c2ecf20Sopenharmony_ci	struct pci_controller *hose;
11818c2ecf20Sopenharmony_ci	struct pnv_phb *phb;
11828c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	list_for_each_entry(hose, &hose_list, list_node) {
11858c2ecf20Sopenharmony_ci		phb = hose->private_data;
11868c2ecf20Sopenharmony_ci		if (phb->type == PNV_PHB_NPU_NVLINK) {
11878c2ecf20Sopenharmony_ci			/* PE#0 is needed for error reporting */
11888c2ecf20Sopenharmony_ci			pnv_ioda_reserve_pe(phb, 0);
11898c2ecf20Sopenharmony_ci			pnv_ioda_setup_npu_PEs(hose->bus);
11908c2ecf20Sopenharmony_ci			if (phb->model == PNV_PHB_MODEL_NPU2)
11918c2ecf20Sopenharmony_ci				WARN_ON_ONCE(pnv_npu2_init(hose));
11928c2ecf20Sopenharmony_ci		}
11938c2ecf20Sopenharmony_ci	}
11948c2ecf20Sopenharmony_ci	list_for_each_entry(hose, &hose_list, list_node) {
11958c2ecf20Sopenharmony_ci		phb = hose->private_data;
11968c2ecf20Sopenharmony_ci		if (phb->type != PNV_PHB_IODA2)
11978c2ecf20Sopenharmony_ci			continue;
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci		list_for_each_entry(pe, &phb->ioda.pe_list, list)
12008c2ecf20Sopenharmony_ci			pnv_npu2_map_lpar(pe, MSR_DR | MSR_PR | MSR_HV);
12018c2ecf20Sopenharmony_ci	}
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci#ifdef CONFIG_IOMMU_API
12048c2ecf20Sopenharmony_ci	/* setup iommu groups so we can do nvlink pass-thru */
12058c2ecf20Sopenharmony_ci	pnv_pci_npu_setup_iommu_groups();
12068c2ecf20Sopenharmony_ci#endif
12078c2ecf20Sopenharmony_ci}
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_cistatic void pnv_pci_ioda1_setup_dma_pe(struct pnv_phb *phb,
12108c2ecf20Sopenharmony_ci				       struct pnv_ioda_pe *pe);
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_cistatic void pnv_pci_ioda_dma_dev_setup(struct pci_dev *pdev)
12138c2ecf20Sopenharmony_ci{
12148c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(pdev->bus);
12158c2ecf20Sopenharmony_ci	struct pci_dn *pdn = pci_get_pdn(pdev);
12168c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	/* Check if the BDFN for this device is associated with a PE yet */
12198c2ecf20Sopenharmony_ci	pe = pnv_pci_bdfn_to_pe(phb, pdev->devfn | (pdev->bus->number << 8));
12208c2ecf20Sopenharmony_ci	if (!pe) {
12218c2ecf20Sopenharmony_ci		/* VF PEs should be pre-configured in pnv_pci_sriov_enable() */
12228c2ecf20Sopenharmony_ci		if (WARN_ON(pdev->is_virtfn))
12238c2ecf20Sopenharmony_ci			return;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci		pnv_pci_configure_bus(pdev->bus);
12268c2ecf20Sopenharmony_ci		pe = pnv_pci_bdfn_to_pe(phb, pdev->devfn | (pdev->bus->number << 8));
12278c2ecf20Sopenharmony_ci		pci_info(pdev, "Configured PE#%x\n", pe ? pe->pe_number : 0xfffff);
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci		/*
12318c2ecf20Sopenharmony_ci		 * If we can't setup the IODA PE something has gone horribly
12328c2ecf20Sopenharmony_ci		 * wrong and we can't enable DMA for the device.
12338c2ecf20Sopenharmony_ci		 */
12348c2ecf20Sopenharmony_ci		if (WARN_ON(!pe))
12358c2ecf20Sopenharmony_ci			return;
12368c2ecf20Sopenharmony_ci	} else {
12378c2ecf20Sopenharmony_ci		pci_info(pdev, "Added to existing PE#%x\n", pe->pe_number);
12388c2ecf20Sopenharmony_ci	}
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	/*
12418c2ecf20Sopenharmony_ci	 * We assume that bridges *probably* don't need to do any DMA so we can
12428c2ecf20Sopenharmony_ci	 * skip allocating a TCE table, etc unless we get a non-bridge device.
12438c2ecf20Sopenharmony_ci	 */
12448c2ecf20Sopenharmony_ci	if (!pe->dma_setup_done && !pci_is_bridge(pdev)) {
12458c2ecf20Sopenharmony_ci		switch (phb->type) {
12468c2ecf20Sopenharmony_ci		case PNV_PHB_IODA1:
12478c2ecf20Sopenharmony_ci			pnv_pci_ioda1_setup_dma_pe(phb, pe);
12488c2ecf20Sopenharmony_ci			break;
12498c2ecf20Sopenharmony_ci		case PNV_PHB_IODA2:
12508c2ecf20Sopenharmony_ci			pnv_pci_ioda2_setup_dma_pe(phb, pe);
12518c2ecf20Sopenharmony_ci			break;
12528c2ecf20Sopenharmony_ci		default:
12538c2ecf20Sopenharmony_ci			pr_warn("%s: No DMA for PHB#%x (type %d)\n",
12548c2ecf20Sopenharmony_ci				__func__, phb->hose->global_number, phb->type);
12558c2ecf20Sopenharmony_ci		}
12568c2ecf20Sopenharmony_ci	}
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	if (pdn)
12598c2ecf20Sopenharmony_ci		pdn->pe_number = pe->pe_number;
12608c2ecf20Sopenharmony_ci	pe->device_count++;
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	WARN_ON(get_dma_ops(&pdev->dev) != &dma_iommu_ops);
12638c2ecf20Sopenharmony_ci	pdev->dev.archdata.dma_offset = pe->tce_bypass_base;
12648c2ecf20Sopenharmony_ci	set_iommu_table_base(&pdev->dev, pe->table_group.tables[0]);
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	/* PEs with a DMA weight of zero won't have a group */
12678c2ecf20Sopenharmony_ci	if (pe->table_group.group)
12688c2ecf20Sopenharmony_ci		iommu_add_device(&pe->table_group, &pdev->dev);
12698c2ecf20Sopenharmony_ci}
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci/*
12728c2ecf20Sopenharmony_ci * Reconfigure TVE#0 to be usable as 64-bit DMA space.
12738c2ecf20Sopenharmony_ci *
12748c2ecf20Sopenharmony_ci * The first 4GB of virtual memory for a PE is reserved for 32-bit accesses.
12758c2ecf20Sopenharmony_ci * Devices can only access more than that if bit 59 of the PCI address is set
12768c2ecf20Sopenharmony_ci * by hardware, which indicates TVE#1 should be used instead of TVE#0.
12778c2ecf20Sopenharmony_ci * Many PCI devices are not capable of addressing that many bits, and as a
12788c2ecf20Sopenharmony_ci * result are limited to the 4GB of virtual memory made available to 32-bit
12798c2ecf20Sopenharmony_ci * devices in TVE#0.
12808c2ecf20Sopenharmony_ci *
12818c2ecf20Sopenharmony_ci * In order to work around this, reconfigure TVE#0 to be suitable for 64-bit
12828c2ecf20Sopenharmony_ci * devices by configuring the virtual memory past the first 4GB inaccessible
12838c2ecf20Sopenharmony_ci * by 64-bit DMAs.  This should only be used by devices that want more than
12848c2ecf20Sopenharmony_ci * 4GB, and only on PEs that have no 32-bit devices.
12858c2ecf20Sopenharmony_ci *
12868c2ecf20Sopenharmony_ci * Currently this will only work on PHB3 (POWER8).
12878c2ecf20Sopenharmony_ci */
12888c2ecf20Sopenharmony_cistatic int pnv_pci_ioda_dma_64bit_bypass(struct pnv_ioda_pe *pe)
12898c2ecf20Sopenharmony_ci{
12908c2ecf20Sopenharmony_ci	u64 window_size, table_size, tce_count, addr;
12918c2ecf20Sopenharmony_ci	struct page *table_pages;
12928c2ecf20Sopenharmony_ci	u64 tce_order = 28; /* 256MB TCEs */
12938c2ecf20Sopenharmony_ci	__be64 *tces;
12948c2ecf20Sopenharmony_ci	s64 rc;
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	/*
12978c2ecf20Sopenharmony_ci	 * Window size needs to be a power of two, but needs to account for
12988c2ecf20Sopenharmony_ci	 * shifting memory by the 4GB offset required to skip 32bit space.
12998c2ecf20Sopenharmony_ci	 */
13008c2ecf20Sopenharmony_ci	window_size = roundup_pow_of_two(memory_hotplug_max() + (1ULL << 32));
13018c2ecf20Sopenharmony_ci	tce_count = window_size >> tce_order;
13028c2ecf20Sopenharmony_ci	table_size = tce_count << 3;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	if (table_size < PAGE_SIZE)
13058c2ecf20Sopenharmony_ci		table_size = PAGE_SIZE;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	table_pages = alloc_pages_node(pe->phb->hose->node, GFP_KERNEL,
13088c2ecf20Sopenharmony_ci				       get_order(table_size));
13098c2ecf20Sopenharmony_ci	if (!table_pages)
13108c2ecf20Sopenharmony_ci		goto err;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	tces = page_address(table_pages);
13138c2ecf20Sopenharmony_ci	if (!tces)
13148c2ecf20Sopenharmony_ci		goto err;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	memset(tces, 0, table_size);
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	for (addr = 0; addr < memory_hotplug_max(); addr += (1 << tce_order)) {
13198c2ecf20Sopenharmony_ci		tces[(addr + (1ULL << 32)) >> tce_order] =
13208c2ecf20Sopenharmony_ci			cpu_to_be64(addr | TCE_PCI_READ | TCE_PCI_WRITE);
13218c2ecf20Sopenharmony_ci	}
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	rc = opal_pci_map_pe_dma_window(pe->phb->opal_id,
13248c2ecf20Sopenharmony_ci					pe->pe_number,
13258c2ecf20Sopenharmony_ci					/* reconfigure window 0 */
13268c2ecf20Sopenharmony_ci					(pe->pe_number << 1) + 0,
13278c2ecf20Sopenharmony_ci					1,
13288c2ecf20Sopenharmony_ci					__pa(tces),
13298c2ecf20Sopenharmony_ci					table_size,
13308c2ecf20Sopenharmony_ci					1 << tce_order);
13318c2ecf20Sopenharmony_ci	if (rc == OPAL_SUCCESS) {
13328c2ecf20Sopenharmony_ci		pe_info(pe, "Using 64-bit DMA iommu bypass (through TVE#0)\n");
13338c2ecf20Sopenharmony_ci		return 0;
13348c2ecf20Sopenharmony_ci	}
13358c2ecf20Sopenharmony_cierr:
13368c2ecf20Sopenharmony_ci	pe_err(pe, "Error configuring 64-bit DMA bypass\n");
13378c2ecf20Sopenharmony_ci	return -EIO;
13388c2ecf20Sopenharmony_ci}
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_cistatic bool pnv_pci_ioda_iommu_bypass_supported(struct pci_dev *pdev,
13418c2ecf20Sopenharmony_ci		u64 dma_mask)
13428c2ecf20Sopenharmony_ci{
13438c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(pdev->bus);
13448c2ecf20Sopenharmony_ci	struct pci_dn *pdn = pci_get_pdn(pdev);
13458c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe;
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE))
13488c2ecf20Sopenharmony_ci		return false;
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	pe = &phb->ioda.pe_array[pdn->pe_number];
13518c2ecf20Sopenharmony_ci	if (pe->tce_bypass_enabled) {
13528c2ecf20Sopenharmony_ci		u64 top = pe->tce_bypass_base + memblock_end_of_DRAM() - 1;
13538c2ecf20Sopenharmony_ci		if (dma_mask >= top)
13548c2ecf20Sopenharmony_ci			return true;
13558c2ecf20Sopenharmony_ci	}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	/*
13588c2ecf20Sopenharmony_ci	 * If the device can't set the TCE bypass bit but still wants
13598c2ecf20Sopenharmony_ci	 * to access 4GB or more, on PHB3 we can reconfigure TVE#0 to
13608c2ecf20Sopenharmony_ci	 * bypass the 32-bit region and be usable for 64-bit DMAs.
13618c2ecf20Sopenharmony_ci	 * The device needs to be able to address all of this space.
13628c2ecf20Sopenharmony_ci	 */
13638c2ecf20Sopenharmony_ci	if (dma_mask >> 32 &&
13648c2ecf20Sopenharmony_ci	    dma_mask > (memory_hotplug_max() + (1ULL << 32)) &&
13658c2ecf20Sopenharmony_ci	    /* pe->pdev should be set if it's a single device, pe->pbus if not */
13668c2ecf20Sopenharmony_ci	    (pe->device_count == 1 || !pe->pbus) &&
13678c2ecf20Sopenharmony_ci	    phb->model == PNV_PHB_MODEL_PHB3) {
13688c2ecf20Sopenharmony_ci		/* Configure the bypass mode */
13698c2ecf20Sopenharmony_ci		s64 rc = pnv_pci_ioda_dma_64bit_bypass(pe);
13708c2ecf20Sopenharmony_ci		if (rc)
13718c2ecf20Sopenharmony_ci			return false;
13728c2ecf20Sopenharmony_ci		/* 4GB offset bypasses 32-bit space */
13738c2ecf20Sopenharmony_ci		pdev->dev.archdata.dma_offset = (1ULL << 32);
13748c2ecf20Sopenharmony_ci		return true;
13758c2ecf20Sopenharmony_ci	}
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	return false;
13788c2ecf20Sopenharmony_ci}
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_cistatic inline __be64 __iomem *pnv_ioda_get_inval_reg(struct pnv_phb *phb,
13818c2ecf20Sopenharmony_ci						     bool real_mode)
13828c2ecf20Sopenharmony_ci{
13838c2ecf20Sopenharmony_ci	return real_mode ? (__be64 __iomem *)(phb->regs_phys + 0x210) :
13848c2ecf20Sopenharmony_ci		(phb->regs + 0x210);
13858c2ecf20Sopenharmony_ci}
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_cistatic void pnv_pci_p7ioc_tce_invalidate(struct iommu_table *tbl,
13888c2ecf20Sopenharmony_ci		unsigned long index, unsigned long npages, bool rm)
13898c2ecf20Sopenharmony_ci{
13908c2ecf20Sopenharmony_ci	struct iommu_table_group_link *tgl = list_first_entry_or_null(
13918c2ecf20Sopenharmony_ci			&tbl->it_group_list, struct iommu_table_group_link,
13928c2ecf20Sopenharmony_ci			next);
13938c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe = container_of(tgl->table_group,
13948c2ecf20Sopenharmony_ci			struct pnv_ioda_pe, table_group);
13958c2ecf20Sopenharmony_ci	__be64 __iomem *invalidate = pnv_ioda_get_inval_reg(pe->phb, rm);
13968c2ecf20Sopenharmony_ci	unsigned long start, end, inc;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	start = __pa(((__be64 *)tbl->it_base) + index - tbl->it_offset);
13998c2ecf20Sopenharmony_ci	end = __pa(((__be64 *)tbl->it_base) + index - tbl->it_offset +
14008c2ecf20Sopenharmony_ci			npages - 1);
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	/* p7ioc-style invalidation, 2 TCEs per write */
14038c2ecf20Sopenharmony_ci	start |= (1ull << 63);
14048c2ecf20Sopenharmony_ci	end |= (1ull << 63);
14058c2ecf20Sopenharmony_ci	inc = 16;
14068c2ecf20Sopenharmony_ci        end |= inc - 1;	/* round up end to be different than start */
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci        mb(); /* Ensure above stores are visible */
14098c2ecf20Sopenharmony_ci        while (start <= end) {
14108c2ecf20Sopenharmony_ci		if (rm)
14118c2ecf20Sopenharmony_ci			__raw_rm_writeq_be(start, invalidate);
14128c2ecf20Sopenharmony_ci		else
14138c2ecf20Sopenharmony_ci			__raw_writeq_be(start, invalidate);
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci                start += inc;
14168c2ecf20Sopenharmony_ci        }
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	/*
14198c2ecf20Sopenharmony_ci	 * The iommu layer will do another mb() for us on build()
14208c2ecf20Sopenharmony_ci	 * and we don't care on free()
14218c2ecf20Sopenharmony_ci	 */
14228c2ecf20Sopenharmony_ci}
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_cistatic int pnv_ioda1_tce_build(struct iommu_table *tbl, long index,
14258c2ecf20Sopenharmony_ci		long npages, unsigned long uaddr,
14268c2ecf20Sopenharmony_ci		enum dma_data_direction direction,
14278c2ecf20Sopenharmony_ci		unsigned long attrs)
14288c2ecf20Sopenharmony_ci{
14298c2ecf20Sopenharmony_ci	int ret = pnv_tce_build(tbl, index, npages, uaddr, direction,
14308c2ecf20Sopenharmony_ci			attrs);
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	if (!ret)
14338c2ecf20Sopenharmony_ci		pnv_pci_p7ioc_tce_invalidate(tbl, index, npages, false);
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	return ret;
14368c2ecf20Sopenharmony_ci}
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci#ifdef CONFIG_IOMMU_API
14398c2ecf20Sopenharmony_ci/* Common for IODA1 and IODA2 */
14408c2ecf20Sopenharmony_cistatic int pnv_ioda_tce_xchg_no_kill(struct iommu_table *tbl, long index,
14418c2ecf20Sopenharmony_ci		unsigned long *hpa, enum dma_data_direction *direction,
14428c2ecf20Sopenharmony_ci		bool realmode)
14438c2ecf20Sopenharmony_ci{
14448c2ecf20Sopenharmony_ci	return pnv_tce_xchg(tbl, index, hpa, direction, !realmode);
14458c2ecf20Sopenharmony_ci}
14468c2ecf20Sopenharmony_ci#endif
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_cistatic void pnv_ioda1_tce_free(struct iommu_table *tbl, long index,
14498c2ecf20Sopenharmony_ci		long npages)
14508c2ecf20Sopenharmony_ci{
14518c2ecf20Sopenharmony_ci	pnv_tce_free(tbl, index, npages);
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	pnv_pci_p7ioc_tce_invalidate(tbl, index, npages, false);
14548c2ecf20Sopenharmony_ci}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_cistatic struct iommu_table_ops pnv_ioda1_iommu_ops = {
14578c2ecf20Sopenharmony_ci	.set = pnv_ioda1_tce_build,
14588c2ecf20Sopenharmony_ci#ifdef CONFIG_IOMMU_API
14598c2ecf20Sopenharmony_ci	.xchg_no_kill = pnv_ioda_tce_xchg_no_kill,
14608c2ecf20Sopenharmony_ci	.tce_kill = pnv_pci_p7ioc_tce_invalidate,
14618c2ecf20Sopenharmony_ci	.useraddrptr = pnv_tce_useraddrptr,
14628c2ecf20Sopenharmony_ci#endif
14638c2ecf20Sopenharmony_ci	.clear = pnv_ioda1_tce_free,
14648c2ecf20Sopenharmony_ci	.get = pnv_tce_get,
14658c2ecf20Sopenharmony_ci};
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci#define PHB3_TCE_KILL_INVAL_ALL		PPC_BIT(0)
14688c2ecf20Sopenharmony_ci#define PHB3_TCE_KILL_INVAL_PE		PPC_BIT(1)
14698c2ecf20Sopenharmony_ci#define PHB3_TCE_KILL_INVAL_ONE		PPC_BIT(2)
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_cistatic void pnv_pci_phb3_tce_invalidate_entire(struct pnv_phb *phb, bool rm)
14728c2ecf20Sopenharmony_ci{
14738c2ecf20Sopenharmony_ci	__be64 __iomem *invalidate = pnv_ioda_get_inval_reg(phb, rm);
14748c2ecf20Sopenharmony_ci	const unsigned long val = PHB3_TCE_KILL_INVAL_ALL;
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	mb(); /* Ensure previous TCE table stores are visible */
14778c2ecf20Sopenharmony_ci	if (rm)
14788c2ecf20Sopenharmony_ci		__raw_rm_writeq_be(val, invalidate);
14798c2ecf20Sopenharmony_ci	else
14808c2ecf20Sopenharmony_ci		__raw_writeq_be(val, invalidate);
14818c2ecf20Sopenharmony_ci}
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_cistatic inline void pnv_pci_phb3_tce_invalidate_pe(struct pnv_ioda_pe *pe)
14848c2ecf20Sopenharmony_ci{
14858c2ecf20Sopenharmony_ci	/* 01xb - invalidate TCEs that match the specified PE# */
14868c2ecf20Sopenharmony_ci	__be64 __iomem *invalidate = pnv_ioda_get_inval_reg(pe->phb, false);
14878c2ecf20Sopenharmony_ci	unsigned long val = PHB3_TCE_KILL_INVAL_PE | (pe->pe_number & 0xFF);
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	mb(); /* Ensure above stores are visible */
14908c2ecf20Sopenharmony_ci	__raw_writeq_be(val, invalidate);
14918c2ecf20Sopenharmony_ci}
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_cistatic void pnv_pci_phb3_tce_invalidate(struct pnv_ioda_pe *pe, bool rm,
14948c2ecf20Sopenharmony_ci					unsigned shift, unsigned long index,
14958c2ecf20Sopenharmony_ci					unsigned long npages)
14968c2ecf20Sopenharmony_ci{
14978c2ecf20Sopenharmony_ci	__be64 __iomem *invalidate = pnv_ioda_get_inval_reg(pe->phb, rm);
14988c2ecf20Sopenharmony_ci	unsigned long start, end, inc;
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci	/* We'll invalidate DMA address in PE scope */
15018c2ecf20Sopenharmony_ci	start = PHB3_TCE_KILL_INVAL_ONE;
15028c2ecf20Sopenharmony_ci	start |= (pe->pe_number & 0xFF);
15038c2ecf20Sopenharmony_ci	end = start;
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	/* Figure out the start, end and step */
15068c2ecf20Sopenharmony_ci	start |= (index << shift);
15078c2ecf20Sopenharmony_ci	end |= ((index + npages - 1) << shift);
15088c2ecf20Sopenharmony_ci	inc = (0x1ull << shift);
15098c2ecf20Sopenharmony_ci	mb();
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	while (start <= end) {
15128c2ecf20Sopenharmony_ci		if (rm)
15138c2ecf20Sopenharmony_ci			__raw_rm_writeq_be(start, invalidate);
15148c2ecf20Sopenharmony_ci		else
15158c2ecf20Sopenharmony_ci			__raw_writeq_be(start, invalidate);
15168c2ecf20Sopenharmony_ci		start += inc;
15178c2ecf20Sopenharmony_ci	}
15188c2ecf20Sopenharmony_ci}
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_cistatic inline void pnv_pci_ioda2_tce_invalidate_pe(struct pnv_ioda_pe *pe)
15218c2ecf20Sopenharmony_ci{
15228c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pe->phb;
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	if (phb->model == PNV_PHB_MODEL_PHB3 && phb->regs)
15258c2ecf20Sopenharmony_ci		pnv_pci_phb3_tce_invalidate_pe(pe);
15268c2ecf20Sopenharmony_ci	else
15278c2ecf20Sopenharmony_ci		opal_pci_tce_kill(phb->opal_id, OPAL_PCI_TCE_KILL_PE,
15288c2ecf20Sopenharmony_ci				  pe->pe_number, 0, 0, 0);
15298c2ecf20Sopenharmony_ci}
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_cistatic void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,
15328c2ecf20Sopenharmony_ci		unsigned long index, unsigned long npages, bool rm)
15338c2ecf20Sopenharmony_ci{
15348c2ecf20Sopenharmony_ci	struct iommu_table_group_link *tgl;
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	list_for_each_entry_lockless(tgl, &tbl->it_group_list, next) {
15378c2ecf20Sopenharmony_ci		struct pnv_ioda_pe *pe = container_of(tgl->table_group,
15388c2ecf20Sopenharmony_ci				struct pnv_ioda_pe, table_group);
15398c2ecf20Sopenharmony_ci		struct pnv_phb *phb = pe->phb;
15408c2ecf20Sopenharmony_ci		unsigned int shift = tbl->it_page_shift;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci		/*
15438c2ecf20Sopenharmony_ci		 * NVLink1 can use the TCE kill register directly as
15448c2ecf20Sopenharmony_ci		 * it's the same as PHB3. NVLink2 is different and
15458c2ecf20Sopenharmony_ci		 * should go via the OPAL call.
15468c2ecf20Sopenharmony_ci		 */
15478c2ecf20Sopenharmony_ci		if (phb->model == PNV_PHB_MODEL_NPU) {
15488c2ecf20Sopenharmony_ci			/*
15498c2ecf20Sopenharmony_ci			 * The NVLink hardware does not support TCE kill
15508c2ecf20Sopenharmony_ci			 * per TCE entry so we have to invalidate
15518c2ecf20Sopenharmony_ci			 * the entire cache for it.
15528c2ecf20Sopenharmony_ci			 */
15538c2ecf20Sopenharmony_ci			pnv_pci_phb3_tce_invalidate_entire(phb, rm);
15548c2ecf20Sopenharmony_ci			continue;
15558c2ecf20Sopenharmony_ci		}
15568c2ecf20Sopenharmony_ci		if (phb->model == PNV_PHB_MODEL_PHB3 && phb->regs)
15578c2ecf20Sopenharmony_ci			pnv_pci_phb3_tce_invalidate(pe, rm, shift,
15588c2ecf20Sopenharmony_ci						    index, npages);
15598c2ecf20Sopenharmony_ci		else
15608c2ecf20Sopenharmony_ci			opal_pci_tce_kill(phb->opal_id,
15618c2ecf20Sopenharmony_ci					  OPAL_PCI_TCE_KILL_PAGES,
15628c2ecf20Sopenharmony_ci					  pe->pe_number, 1u << shift,
15638c2ecf20Sopenharmony_ci					  index << shift, npages);
15648c2ecf20Sopenharmony_ci	}
15658c2ecf20Sopenharmony_ci}
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_civoid pnv_pci_ioda2_tce_invalidate_entire(struct pnv_phb *phb, bool rm)
15688c2ecf20Sopenharmony_ci{
15698c2ecf20Sopenharmony_ci	if (phb->model == PNV_PHB_MODEL_NPU || phb->model == PNV_PHB_MODEL_PHB3)
15708c2ecf20Sopenharmony_ci		pnv_pci_phb3_tce_invalidate_entire(phb, rm);
15718c2ecf20Sopenharmony_ci	else
15728c2ecf20Sopenharmony_ci		opal_pci_tce_kill(phb->opal_id, OPAL_PCI_TCE_KILL, 0, 0, 0, 0);
15738c2ecf20Sopenharmony_ci}
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_cistatic int pnv_ioda2_tce_build(struct iommu_table *tbl, long index,
15768c2ecf20Sopenharmony_ci		long npages, unsigned long uaddr,
15778c2ecf20Sopenharmony_ci		enum dma_data_direction direction,
15788c2ecf20Sopenharmony_ci		unsigned long attrs)
15798c2ecf20Sopenharmony_ci{
15808c2ecf20Sopenharmony_ci	int ret = pnv_tce_build(tbl, index, npages, uaddr, direction,
15818c2ecf20Sopenharmony_ci			attrs);
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	if (!ret)
15848c2ecf20Sopenharmony_ci		pnv_pci_ioda2_tce_invalidate(tbl, index, npages, false);
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	return ret;
15878c2ecf20Sopenharmony_ci}
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_cistatic void pnv_ioda2_tce_free(struct iommu_table *tbl, long index,
15908c2ecf20Sopenharmony_ci		long npages)
15918c2ecf20Sopenharmony_ci{
15928c2ecf20Sopenharmony_ci	pnv_tce_free(tbl, index, npages);
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	pnv_pci_ioda2_tce_invalidate(tbl, index, npages, false);
15958c2ecf20Sopenharmony_ci}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_cistatic struct iommu_table_ops pnv_ioda2_iommu_ops = {
15988c2ecf20Sopenharmony_ci	.set = pnv_ioda2_tce_build,
15998c2ecf20Sopenharmony_ci#ifdef CONFIG_IOMMU_API
16008c2ecf20Sopenharmony_ci	.xchg_no_kill = pnv_ioda_tce_xchg_no_kill,
16018c2ecf20Sopenharmony_ci	.tce_kill = pnv_pci_ioda2_tce_invalidate,
16028c2ecf20Sopenharmony_ci	.useraddrptr = pnv_tce_useraddrptr,
16038c2ecf20Sopenharmony_ci#endif
16048c2ecf20Sopenharmony_ci	.clear = pnv_ioda2_tce_free,
16058c2ecf20Sopenharmony_ci	.get = pnv_tce_get,
16068c2ecf20Sopenharmony_ci	.free = pnv_pci_ioda2_table_free_pages,
16078c2ecf20Sopenharmony_ci};
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_cistatic int pnv_pci_ioda_dev_dma_weight(struct pci_dev *dev, void *data)
16108c2ecf20Sopenharmony_ci{
16118c2ecf20Sopenharmony_ci	unsigned int *weight = (unsigned int *)data;
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	/* This is quite simplistic. The "base" weight of a device
16148c2ecf20Sopenharmony_ci	 * is 10. 0 means no DMA is to be accounted for it.
16158c2ecf20Sopenharmony_ci	 */
16168c2ecf20Sopenharmony_ci	if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL)
16178c2ecf20Sopenharmony_ci		return 0;
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	if (dev->class == PCI_CLASS_SERIAL_USB_UHCI ||
16208c2ecf20Sopenharmony_ci	    dev->class == PCI_CLASS_SERIAL_USB_OHCI ||
16218c2ecf20Sopenharmony_ci	    dev->class == PCI_CLASS_SERIAL_USB_EHCI)
16228c2ecf20Sopenharmony_ci		*weight += 3;
16238c2ecf20Sopenharmony_ci	else if ((dev->class >> 8) == PCI_CLASS_STORAGE_RAID)
16248c2ecf20Sopenharmony_ci		*weight += 15;
16258c2ecf20Sopenharmony_ci	else
16268c2ecf20Sopenharmony_ci		*weight += 10;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	return 0;
16298c2ecf20Sopenharmony_ci}
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_cistatic unsigned int pnv_pci_ioda_pe_dma_weight(struct pnv_ioda_pe *pe)
16328c2ecf20Sopenharmony_ci{
16338c2ecf20Sopenharmony_ci	unsigned int weight = 0;
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	/* SRIOV VF has same DMA32 weight as its PF */
16368c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV
16378c2ecf20Sopenharmony_ci	if ((pe->flags & PNV_IODA_PE_VF) && pe->parent_dev) {
16388c2ecf20Sopenharmony_ci		pnv_pci_ioda_dev_dma_weight(pe->parent_dev, &weight);
16398c2ecf20Sopenharmony_ci		return weight;
16408c2ecf20Sopenharmony_ci	}
16418c2ecf20Sopenharmony_ci#endif
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci	if ((pe->flags & PNV_IODA_PE_DEV) && pe->pdev) {
16448c2ecf20Sopenharmony_ci		pnv_pci_ioda_dev_dma_weight(pe->pdev, &weight);
16458c2ecf20Sopenharmony_ci	} else if ((pe->flags & PNV_IODA_PE_BUS) && pe->pbus) {
16468c2ecf20Sopenharmony_ci		struct pci_dev *pdev;
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci		list_for_each_entry(pdev, &pe->pbus->devices, bus_list)
16498c2ecf20Sopenharmony_ci			pnv_pci_ioda_dev_dma_weight(pdev, &weight);
16508c2ecf20Sopenharmony_ci	} else if ((pe->flags & PNV_IODA_PE_BUS_ALL) && pe->pbus) {
16518c2ecf20Sopenharmony_ci		pci_walk_bus(pe->pbus, pnv_pci_ioda_dev_dma_weight, &weight);
16528c2ecf20Sopenharmony_ci	}
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	return weight;
16558c2ecf20Sopenharmony_ci}
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_cistatic void pnv_pci_ioda1_setup_dma_pe(struct pnv_phb *phb,
16588c2ecf20Sopenharmony_ci				       struct pnv_ioda_pe *pe)
16598c2ecf20Sopenharmony_ci{
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	struct page *tce_mem = NULL;
16628c2ecf20Sopenharmony_ci	struct iommu_table *tbl;
16638c2ecf20Sopenharmony_ci	unsigned int weight, total_weight = 0;
16648c2ecf20Sopenharmony_ci	unsigned int tce32_segsz, base, segs, avail, i;
16658c2ecf20Sopenharmony_ci	int64_t rc;
16668c2ecf20Sopenharmony_ci	void *addr;
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	/* XXX FIXME: Handle 64-bit only DMA devices */
16698c2ecf20Sopenharmony_ci	/* XXX FIXME: Provide 64-bit DMA facilities & non-4K TCE tables etc.. */
16708c2ecf20Sopenharmony_ci	/* XXX FIXME: Allocate multi-level tables on PHB3 */
16718c2ecf20Sopenharmony_ci	weight = pnv_pci_ioda_pe_dma_weight(pe);
16728c2ecf20Sopenharmony_ci	if (!weight)
16738c2ecf20Sopenharmony_ci		return;
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci	pci_walk_bus(phb->hose->bus, pnv_pci_ioda_dev_dma_weight,
16768c2ecf20Sopenharmony_ci		     &total_weight);
16778c2ecf20Sopenharmony_ci	segs = (weight * phb->ioda.dma32_count) / total_weight;
16788c2ecf20Sopenharmony_ci	if (!segs)
16798c2ecf20Sopenharmony_ci		segs = 1;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	/*
16828c2ecf20Sopenharmony_ci	 * Allocate contiguous DMA32 segments. We begin with the expected
16838c2ecf20Sopenharmony_ci	 * number of segments. With one more attempt, the number of DMA32
16848c2ecf20Sopenharmony_ci	 * segments to be allocated is decreased by one until one segment
16858c2ecf20Sopenharmony_ci	 * is allocated successfully.
16868c2ecf20Sopenharmony_ci	 */
16878c2ecf20Sopenharmony_ci	do {
16888c2ecf20Sopenharmony_ci		for (base = 0; base <= phb->ioda.dma32_count - segs; base++) {
16898c2ecf20Sopenharmony_ci			for (avail = 0, i = base; i < base + segs; i++) {
16908c2ecf20Sopenharmony_ci				if (phb->ioda.dma32_segmap[i] ==
16918c2ecf20Sopenharmony_ci				    IODA_INVALID_PE)
16928c2ecf20Sopenharmony_ci					avail++;
16938c2ecf20Sopenharmony_ci			}
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci			if (avail == segs)
16968c2ecf20Sopenharmony_ci				goto found;
16978c2ecf20Sopenharmony_ci		}
16988c2ecf20Sopenharmony_ci	} while (--segs);
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci	if (!segs) {
17018c2ecf20Sopenharmony_ci		pe_warn(pe, "No available DMA32 segments\n");
17028c2ecf20Sopenharmony_ci		return;
17038c2ecf20Sopenharmony_ci	}
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_cifound:
17068c2ecf20Sopenharmony_ci	tbl = pnv_pci_table_alloc(phb->hose->node);
17078c2ecf20Sopenharmony_ci	if (WARN_ON(!tbl))
17088c2ecf20Sopenharmony_ci		return;
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci	iommu_register_group(&pe->table_group, phb->hose->global_number,
17118c2ecf20Sopenharmony_ci			pe->pe_number);
17128c2ecf20Sopenharmony_ci	pnv_pci_link_table_and_group(phb->hose->node, 0, tbl, &pe->table_group);
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	/* Grab a 32-bit TCE table */
17158c2ecf20Sopenharmony_ci	pe_info(pe, "DMA weight %d (%d), assigned (%d) %d DMA32 segments\n",
17168c2ecf20Sopenharmony_ci		weight, total_weight, base, segs);
17178c2ecf20Sopenharmony_ci	pe_info(pe, " Setting up 32-bit TCE table at %08x..%08x\n",
17188c2ecf20Sopenharmony_ci		base * PNV_IODA1_DMA32_SEGSIZE,
17198c2ecf20Sopenharmony_ci		(base + segs) * PNV_IODA1_DMA32_SEGSIZE - 1);
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	/* XXX Currently, we allocate one big contiguous table for the
17228c2ecf20Sopenharmony_ci	 * TCEs. We only really need one chunk per 256M of TCE space
17238c2ecf20Sopenharmony_ci	 * (ie per segment) but that's an optimization for later, it
17248c2ecf20Sopenharmony_ci	 * requires some added smarts with our get/put_tce implementation
17258c2ecf20Sopenharmony_ci	 *
17268c2ecf20Sopenharmony_ci	 * Each TCE page is 4KB in size and each TCE entry occupies 8
17278c2ecf20Sopenharmony_ci	 * bytes
17288c2ecf20Sopenharmony_ci	 */
17298c2ecf20Sopenharmony_ci	tce32_segsz = PNV_IODA1_DMA32_SEGSIZE >> (IOMMU_PAGE_SHIFT_4K - 3);
17308c2ecf20Sopenharmony_ci	tce_mem = alloc_pages_node(phb->hose->node, GFP_KERNEL,
17318c2ecf20Sopenharmony_ci				   get_order(tce32_segsz * segs));
17328c2ecf20Sopenharmony_ci	if (!tce_mem) {
17338c2ecf20Sopenharmony_ci		pe_err(pe, " Failed to allocate a 32-bit TCE memory\n");
17348c2ecf20Sopenharmony_ci		goto fail;
17358c2ecf20Sopenharmony_ci	}
17368c2ecf20Sopenharmony_ci	addr = page_address(tce_mem);
17378c2ecf20Sopenharmony_ci	memset(addr, 0, tce32_segsz * segs);
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	/* Configure HW */
17408c2ecf20Sopenharmony_ci	for (i = 0; i < segs; i++) {
17418c2ecf20Sopenharmony_ci		rc = opal_pci_map_pe_dma_window(phb->opal_id,
17428c2ecf20Sopenharmony_ci					      pe->pe_number,
17438c2ecf20Sopenharmony_ci					      base + i, 1,
17448c2ecf20Sopenharmony_ci					      __pa(addr) + tce32_segsz * i,
17458c2ecf20Sopenharmony_ci					      tce32_segsz, IOMMU_PAGE_SIZE_4K);
17468c2ecf20Sopenharmony_ci		if (rc) {
17478c2ecf20Sopenharmony_ci			pe_err(pe, " Failed to configure 32-bit TCE table, err %lld\n",
17488c2ecf20Sopenharmony_ci			       rc);
17498c2ecf20Sopenharmony_ci			goto fail;
17508c2ecf20Sopenharmony_ci		}
17518c2ecf20Sopenharmony_ci	}
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	/* Setup DMA32 segment mapping */
17548c2ecf20Sopenharmony_ci	for (i = base; i < base + segs; i++)
17558c2ecf20Sopenharmony_ci		phb->ioda.dma32_segmap[i] = pe->pe_number;
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	/* Setup linux iommu table */
17588c2ecf20Sopenharmony_ci	pnv_pci_setup_iommu_table(tbl, addr, tce32_segsz * segs,
17598c2ecf20Sopenharmony_ci				  base * PNV_IODA1_DMA32_SEGSIZE,
17608c2ecf20Sopenharmony_ci				  IOMMU_PAGE_SHIFT_4K);
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci	tbl->it_ops = &pnv_ioda1_iommu_ops;
17638c2ecf20Sopenharmony_ci	pe->table_group.tce32_start = tbl->it_offset << tbl->it_page_shift;
17648c2ecf20Sopenharmony_ci	pe->table_group.tce32_size = tbl->it_size << tbl->it_page_shift;
17658c2ecf20Sopenharmony_ci	iommu_init_table(tbl, phb->hose->node, 0, 0);
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	pe->dma_setup_done = true;
17688c2ecf20Sopenharmony_ci	return;
17698c2ecf20Sopenharmony_ci fail:
17708c2ecf20Sopenharmony_ci	/* XXX Failure: Try to fallback to 64-bit only ? */
17718c2ecf20Sopenharmony_ci	if (tce_mem)
17728c2ecf20Sopenharmony_ci		__free_pages(tce_mem, get_order(tce32_segsz * segs));
17738c2ecf20Sopenharmony_ci	if (tbl) {
17748c2ecf20Sopenharmony_ci		pnv_pci_unlink_table_and_group(tbl, &pe->table_group);
17758c2ecf20Sopenharmony_ci		iommu_tce_table_put(tbl);
17768c2ecf20Sopenharmony_ci	}
17778c2ecf20Sopenharmony_ci}
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_cistatic long pnv_pci_ioda2_set_window(struct iommu_table_group *table_group,
17808c2ecf20Sopenharmony_ci		int num, struct iommu_table *tbl)
17818c2ecf20Sopenharmony_ci{
17828c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe,
17838c2ecf20Sopenharmony_ci			table_group);
17848c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pe->phb;
17858c2ecf20Sopenharmony_ci	int64_t rc;
17868c2ecf20Sopenharmony_ci	const unsigned long size = tbl->it_indirect_levels ?
17878c2ecf20Sopenharmony_ci			tbl->it_level_size : tbl->it_size;
17888c2ecf20Sopenharmony_ci	const __u64 start_addr = tbl->it_offset << tbl->it_page_shift;
17898c2ecf20Sopenharmony_ci	const __u64 win_size = tbl->it_size << tbl->it_page_shift;
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	pe_info(pe, "Setting up window#%d %llx..%llx pg=%lx\n",
17928c2ecf20Sopenharmony_ci		num, start_addr, start_addr + win_size - 1,
17938c2ecf20Sopenharmony_ci		IOMMU_PAGE_SIZE(tbl));
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci	/*
17968c2ecf20Sopenharmony_ci	 * Map TCE table through TVT. The TVE index is the PE number
17978c2ecf20Sopenharmony_ci	 * shifted by 1 bit for 32-bits DMA space.
17988c2ecf20Sopenharmony_ci	 */
17998c2ecf20Sopenharmony_ci	rc = opal_pci_map_pe_dma_window(phb->opal_id,
18008c2ecf20Sopenharmony_ci			pe->pe_number,
18018c2ecf20Sopenharmony_ci			(pe->pe_number << 1) + num,
18028c2ecf20Sopenharmony_ci			tbl->it_indirect_levels + 1,
18038c2ecf20Sopenharmony_ci			__pa(tbl->it_base),
18048c2ecf20Sopenharmony_ci			size << 3,
18058c2ecf20Sopenharmony_ci			IOMMU_PAGE_SIZE(tbl));
18068c2ecf20Sopenharmony_ci	if (rc) {
18078c2ecf20Sopenharmony_ci		pe_err(pe, "Failed to configure TCE table, err %lld\n", rc);
18088c2ecf20Sopenharmony_ci		return rc;
18098c2ecf20Sopenharmony_ci	}
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci	pnv_pci_link_table_and_group(phb->hose->node, num,
18128c2ecf20Sopenharmony_ci			tbl, &pe->table_group);
18138c2ecf20Sopenharmony_ci	pnv_pci_ioda2_tce_invalidate_pe(pe);
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	return 0;
18168c2ecf20Sopenharmony_ci}
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_cistatic void pnv_pci_ioda2_set_bypass(struct pnv_ioda_pe *pe, bool enable)
18198c2ecf20Sopenharmony_ci{
18208c2ecf20Sopenharmony_ci	uint16_t window_id = (pe->pe_number << 1 ) + 1;
18218c2ecf20Sopenharmony_ci	int64_t rc;
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	pe_info(pe, "%sabling 64-bit DMA bypass\n", enable ? "En" : "Dis");
18248c2ecf20Sopenharmony_ci	if (enable) {
18258c2ecf20Sopenharmony_ci		phys_addr_t top = memblock_end_of_DRAM();
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci		top = roundup_pow_of_two(top);
18288c2ecf20Sopenharmony_ci		rc = opal_pci_map_pe_dma_window_real(pe->phb->opal_id,
18298c2ecf20Sopenharmony_ci						     pe->pe_number,
18308c2ecf20Sopenharmony_ci						     window_id,
18318c2ecf20Sopenharmony_ci						     pe->tce_bypass_base,
18328c2ecf20Sopenharmony_ci						     top);
18338c2ecf20Sopenharmony_ci	} else {
18348c2ecf20Sopenharmony_ci		rc = opal_pci_map_pe_dma_window_real(pe->phb->opal_id,
18358c2ecf20Sopenharmony_ci						     pe->pe_number,
18368c2ecf20Sopenharmony_ci						     window_id,
18378c2ecf20Sopenharmony_ci						     pe->tce_bypass_base,
18388c2ecf20Sopenharmony_ci						     0);
18398c2ecf20Sopenharmony_ci	}
18408c2ecf20Sopenharmony_ci	if (rc)
18418c2ecf20Sopenharmony_ci		pe_err(pe, "OPAL error %lld configuring bypass window\n", rc);
18428c2ecf20Sopenharmony_ci	else
18438c2ecf20Sopenharmony_ci		pe->tce_bypass_enabled = enable;
18448c2ecf20Sopenharmony_ci}
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_cistatic long pnv_pci_ioda2_create_table(struct iommu_table_group *table_group,
18478c2ecf20Sopenharmony_ci		int num, __u32 page_shift, __u64 window_size, __u32 levels,
18488c2ecf20Sopenharmony_ci		bool alloc_userspace_copy, struct iommu_table **ptbl)
18498c2ecf20Sopenharmony_ci{
18508c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe,
18518c2ecf20Sopenharmony_ci			table_group);
18528c2ecf20Sopenharmony_ci	int nid = pe->phb->hose->node;
18538c2ecf20Sopenharmony_ci	__u64 bus_offset = num ? pe->tce_bypass_base : table_group->tce32_start;
18548c2ecf20Sopenharmony_ci	long ret;
18558c2ecf20Sopenharmony_ci	struct iommu_table *tbl;
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	tbl = pnv_pci_table_alloc(nid);
18588c2ecf20Sopenharmony_ci	if (!tbl)
18598c2ecf20Sopenharmony_ci		return -ENOMEM;
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	tbl->it_ops = &pnv_ioda2_iommu_ops;
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci	ret = pnv_pci_ioda2_table_alloc_pages(nid,
18648c2ecf20Sopenharmony_ci			bus_offset, page_shift, window_size,
18658c2ecf20Sopenharmony_ci			levels, alloc_userspace_copy, tbl);
18668c2ecf20Sopenharmony_ci	if (ret) {
18678c2ecf20Sopenharmony_ci		iommu_tce_table_put(tbl);
18688c2ecf20Sopenharmony_ci		return ret;
18698c2ecf20Sopenharmony_ci	}
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	*ptbl = tbl;
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	return 0;
18748c2ecf20Sopenharmony_ci}
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_cistatic long pnv_pci_ioda2_setup_default_config(struct pnv_ioda_pe *pe)
18778c2ecf20Sopenharmony_ci{
18788c2ecf20Sopenharmony_ci	struct iommu_table *tbl = NULL;
18798c2ecf20Sopenharmony_ci	long rc;
18808c2ecf20Sopenharmony_ci	unsigned long res_start, res_end;
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	/*
18838c2ecf20Sopenharmony_ci	 * crashkernel= specifies the kdump kernel's maximum memory at
18848c2ecf20Sopenharmony_ci	 * some offset and there is no guaranteed the result is a power
18858c2ecf20Sopenharmony_ci	 * of 2, which will cause errors later.
18868c2ecf20Sopenharmony_ci	 */
18878c2ecf20Sopenharmony_ci	const u64 max_memory = __rounddown_pow_of_two(memory_hotplug_max());
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	/*
18908c2ecf20Sopenharmony_ci	 * In memory constrained environments, e.g. kdump kernel, the
18918c2ecf20Sopenharmony_ci	 * DMA window can be larger than available memory, which will
18928c2ecf20Sopenharmony_ci	 * cause errors later.
18938c2ecf20Sopenharmony_ci	 */
18948c2ecf20Sopenharmony_ci	const u64 maxblock = 1UL << (PAGE_SHIFT + MAX_ORDER - 1);
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_ci	/*
18978c2ecf20Sopenharmony_ci	 * We create the default window as big as we can. The constraint is
18988c2ecf20Sopenharmony_ci	 * the max order of allocation possible. The TCE table is likely to
18998c2ecf20Sopenharmony_ci	 * end up being multilevel and with on-demand allocation in place,
19008c2ecf20Sopenharmony_ci	 * the initial use is not going to be huge as the default window aims
19018c2ecf20Sopenharmony_ci	 * to support crippled devices (i.e. not fully 64bit DMAble) only.
19028c2ecf20Sopenharmony_ci	 */
19038c2ecf20Sopenharmony_ci	/* iommu_table::it_map uses 1 bit per IOMMU page, hence 8 */
19048c2ecf20Sopenharmony_ci	const u64 window_size = min((maxblock * 8) << PAGE_SHIFT, max_memory);
19058c2ecf20Sopenharmony_ci	/* Each TCE level cannot exceed maxblock so go multilevel if needed */
19068c2ecf20Sopenharmony_ci	unsigned long tces_order = ilog2(window_size >> PAGE_SHIFT);
19078c2ecf20Sopenharmony_ci	unsigned long tcelevel_order = ilog2(maxblock >> 3);
19088c2ecf20Sopenharmony_ci	unsigned int levels = tces_order / tcelevel_order;
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	if (tces_order % tcelevel_order)
19118c2ecf20Sopenharmony_ci		levels += 1;
19128c2ecf20Sopenharmony_ci	/*
19138c2ecf20Sopenharmony_ci	 * We try to stick to default levels (which is >1 at the moment) in
19148c2ecf20Sopenharmony_ci	 * order to save memory by relying on on-demain TCE level allocation.
19158c2ecf20Sopenharmony_ci	 */
19168c2ecf20Sopenharmony_ci	levels = max_t(unsigned int, levels, POWERNV_IOMMU_DEFAULT_LEVELS);
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	rc = pnv_pci_ioda2_create_table(&pe->table_group, 0, PAGE_SHIFT,
19198c2ecf20Sopenharmony_ci			window_size, levels, false, &tbl);
19208c2ecf20Sopenharmony_ci	if (rc) {
19218c2ecf20Sopenharmony_ci		pe_err(pe, "Failed to create 32-bit TCE table, err %ld",
19228c2ecf20Sopenharmony_ci				rc);
19238c2ecf20Sopenharmony_ci		return rc;
19248c2ecf20Sopenharmony_ci	}
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci	/* We use top part of 32bit space for MMIO so exclude it from DMA */
19278c2ecf20Sopenharmony_ci	res_start = 0;
19288c2ecf20Sopenharmony_ci	res_end = 0;
19298c2ecf20Sopenharmony_ci	if (window_size > pe->phb->ioda.m32_pci_base) {
19308c2ecf20Sopenharmony_ci		res_start = pe->phb->ioda.m32_pci_base >> tbl->it_page_shift;
19318c2ecf20Sopenharmony_ci		res_end = min(window_size, SZ_4G) >> tbl->it_page_shift;
19328c2ecf20Sopenharmony_ci	}
19338c2ecf20Sopenharmony_ci	iommu_init_table(tbl, pe->phb->hose->node, res_start, res_end);
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	rc = pnv_pci_ioda2_set_window(&pe->table_group, 0, tbl);
19368c2ecf20Sopenharmony_ci	if (rc) {
19378c2ecf20Sopenharmony_ci		pe_err(pe, "Failed to configure 32-bit TCE table, err %ld\n",
19388c2ecf20Sopenharmony_ci				rc);
19398c2ecf20Sopenharmony_ci		iommu_tce_table_put(tbl);
19408c2ecf20Sopenharmony_ci		return rc;
19418c2ecf20Sopenharmony_ci	}
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci	if (!pnv_iommu_bypass_disabled)
19448c2ecf20Sopenharmony_ci		pnv_pci_ioda2_set_bypass(pe, true);
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	/*
19478c2ecf20Sopenharmony_ci	 * Set table base for the case of IOMMU DMA use. Usually this is done
19488c2ecf20Sopenharmony_ci	 * from dma_dev_setup() which is not called when a device is returned
19498c2ecf20Sopenharmony_ci	 * from VFIO so do it here.
19508c2ecf20Sopenharmony_ci	 */
19518c2ecf20Sopenharmony_ci	if (pe->pdev)
19528c2ecf20Sopenharmony_ci		set_iommu_table_base(&pe->pdev->dev, tbl);
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_ci	return 0;
19558c2ecf20Sopenharmony_ci}
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_cistatic long pnv_pci_ioda2_unset_window(struct iommu_table_group *table_group,
19588c2ecf20Sopenharmony_ci		int num)
19598c2ecf20Sopenharmony_ci{
19608c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe,
19618c2ecf20Sopenharmony_ci			table_group);
19628c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pe->phb;
19638c2ecf20Sopenharmony_ci	long ret;
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	pe_info(pe, "Removing DMA window #%d\n", num);
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci	ret = opal_pci_map_pe_dma_window(phb->opal_id, pe->pe_number,
19688c2ecf20Sopenharmony_ci			(pe->pe_number << 1) + num,
19698c2ecf20Sopenharmony_ci			0/* levels */, 0/* table address */,
19708c2ecf20Sopenharmony_ci			0/* table size */, 0/* page size */);
19718c2ecf20Sopenharmony_ci	if (ret)
19728c2ecf20Sopenharmony_ci		pe_warn(pe, "Unmapping failed, ret = %ld\n", ret);
19738c2ecf20Sopenharmony_ci	else
19748c2ecf20Sopenharmony_ci		pnv_pci_ioda2_tce_invalidate_pe(pe);
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci	pnv_pci_unlink_table_and_group(table_group->tables[num], table_group);
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	return ret;
19798c2ecf20Sopenharmony_ci}
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ci#ifdef CONFIG_IOMMU_API
19828c2ecf20Sopenharmony_ciunsigned long pnv_pci_ioda2_get_table_size(__u32 page_shift,
19838c2ecf20Sopenharmony_ci		__u64 window_size, __u32 levels)
19848c2ecf20Sopenharmony_ci{
19858c2ecf20Sopenharmony_ci	unsigned long bytes = 0;
19868c2ecf20Sopenharmony_ci	const unsigned window_shift = ilog2(window_size);
19878c2ecf20Sopenharmony_ci	unsigned entries_shift = window_shift - page_shift;
19888c2ecf20Sopenharmony_ci	unsigned table_shift = entries_shift + 3;
19898c2ecf20Sopenharmony_ci	unsigned long tce_table_size = max(0x1000UL, 1UL << table_shift);
19908c2ecf20Sopenharmony_ci	unsigned long direct_table_size;
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci	if (!levels || (levels > POWERNV_IOMMU_MAX_LEVELS) ||
19938c2ecf20Sopenharmony_ci			!is_power_of_2(window_size))
19948c2ecf20Sopenharmony_ci		return 0;
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	/* Calculate a direct table size from window_size and levels */
19978c2ecf20Sopenharmony_ci	entries_shift = (entries_shift + levels - 1) / levels;
19988c2ecf20Sopenharmony_ci	table_shift = entries_shift + 3;
19998c2ecf20Sopenharmony_ci	table_shift = max_t(unsigned, table_shift, PAGE_SHIFT);
20008c2ecf20Sopenharmony_ci	direct_table_size =  1UL << table_shift;
20018c2ecf20Sopenharmony_ci
20028c2ecf20Sopenharmony_ci	for ( ; levels; --levels) {
20038c2ecf20Sopenharmony_ci		bytes += ALIGN(tce_table_size, direct_table_size);
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_ci		tce_table_size /= direct_table_size;
20068c2ecf20Sopenharmony_ci		tce_table_size <<= 3;
20078c2ecf20Sopenharmony_ci		tce_table_size = max_t(unsigned long,
20088c2ecf20Sopenharmony_ci				tce_table_size, direct_table_size);
20098c2ecf20Sopenharmony_ci	}
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	return bytes + bytes; /* one for HW table, one for userspace copy */
20128c2ecf20Sopenharmony_ci}
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_cistatic long pnv_pci_ioda2_create_table_userspace(
20158c2ecf20Sopenharmony_ci		struct iommu_table_group *table_group,
20168c2ecf20Sopenharmony_ci		int num, __u32 page_shift, __u64 window_size, __u32 levels,
20178c2ecf20Sopenharmony_ci		struct iommu_table **ptbl)
20188c2ecf20Sopenharmony_ci{
20198c2ecf20Sopenharmony_ci	long ret = pnv_pci_ioda2_create_table(table_group,
20208c2ecf20Sopenharmony_ci			num, page_shift, window_size, levels, true, ptbl);
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	if (!ret)
20238c2ecf20Sopenharmony_ci		(*ptbl)->it_allocated_size = pnv_pci_ioda2_get_table_size(
20248c2ecf20Sopenharmony_ci				page_shift, window_size, levels);
20258c2ecf20Sopenharmony_ci	return ret;
20268c2ecf20Sopenharmony_ci}
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_cistatic void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus)
20298c2ecf20Sopenharmony_ci{
20308c2ecf20Sopenharmony_ci	struct pci_dev *dev;
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
20338c2ecf20Sopenharmony_ci		set_iommu_table_base(&dev->dev, pe->table_group.tables[0]);
20348c2ecf20Sopenharmony_ci		dev->dev.archdata.dma_offset = pe->tce_bypass_base;
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci		if ((pe->flags & PNV_IODA_PE_BUS_ALL) && dev->subordinate)
20378c2ecf20Sopenharmony_ci			pnv_ioda_setup_bus_dma(pe, dev->subordinate);
20388c2ecf20Sopenharmony_ci	}
20398c2ecf20Sopenharmony_ci}
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_cistatic void pnv_ioda2_take_ownership(struct iommu_table_group *table_group)
20428c2ecf20Sopenharmony_ci{
20438c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe,
20448c2ecf20Sopenharmony_ci						table_group);
20458c2ecf20Sopenharmony_ci	/* Store @tbl as pnv_pci_ioda2_unset_window() resets it */
20468c2ecf20Sopenharmony_ci	struct iommu_table *tbl = pe->table_group.tables[0];
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	pnv_pci_ioda2_set_bypass(pe, false);
20498c2ecf20Sopenharmony_ci	pnv_pci_ioda2_unset_window(&pe->table_group, 0);
20508c2ecf20Sopenharmony_ci	if (pe->pbus)
20518c2ecf20Sopenharmony_ci		pnv_ioda_setup_bus_dma(pe, pe->pbus);
20528c2ecf20Sopenharmony_ci	else if (pe->pdev)
20538c2ecf20Sopenharmony_ci		set_iommu_table_base(&pe->pdev->dev, NULL);
20548c2ecf20Sopenharmony_ci	iommu_tce_table_put(tbl);
20558c2ecf20Sopenharmony_ci}
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_cistatic void pnv_ioda2_release_ownership(struct iommu_table_group *table_group)
20588c2ecf20Sopenharmony_ci{
20598c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe = container_of(table_group, struct pnv_ioda_pe,
20608c2ecf20Sopenharmony_ci						table_group);
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci	pnv_pci_ioda2_setup_default_config(pe);
20638c2ecf20Sopenharmony_ci	if (pe->pbus)
20648c2ecf20Sopenharmony_ci		pnv_ioda_setup_bus_dma(pe, pe->pbus);
20658c2ecf20Sopenharmony_ci}
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_cistatic struct iommu_table_group_ops pnv_pci_ioda2_ops = {
20688c2ecf20Sopenharmony_ci	.get_table_size = pnv_pci_ioda2_get_table_size,
20698c2ecf20Sopenharmony_ci	.create_table = pnv_pci_ioda2_create_table_userspace,
20708c2ecf20Sopenharmony_ci	.set_window = pnv_pci_ioda2_set_window,
20718c2ecf20Sopenharmony_ci	.unset_window = pnv_pci_ioda2_unset_window,
20728c2ecf20Sopenharmony_ci	.take_ownership = pnv_ioda2_take_ownership,
20738c2ecf20Sopenharmony_ci	.release_ownership = pnv_ioda2_release_ownership,
20748c2ecf20Sopenharmony_ci};
20758c2ecf20Sopenharmony_ci#endif
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_civoid pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
20788c2ecf20Sopenharmony_ci				struct pnv_ioda_pe *pe)
20798c2ecf20Sopenharmony_ci{
20808c2ecf20Sopenharmony_ci	int64_t rc;
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci	/* TVE #1 is selected by PCI address bit 59 */
20838c2ecf20Sopenharmony_ci	pe->tce_bypass_base = 1ull << 59;
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci	/* The PE will reserve all possible 32-bits space */
20868c2ecf20Sopenharmony_ci	pe_info(pe, "Setting up 32-bit TCE table at 0..%08x\n",
20878c2ecf20Sopenharmony_ci		phb->ioda.m32_pci_base);
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	/* Setup linux iommu table */
20908c2ecf20Sopenharmony_ci	pe->table_group.tce32_start = 0;
20918c2ecf20Sopenharmony_ci	pe->table_group.tce32_size = phb->ioda.m32_pci_base;
20928c2ecf20Sopenharmony_ci	pe->table_group.max_dynamic_windows_supported =
20938c2ecf20Sopenharmony_ci			IOMMU_TABLE_GROUP_MAX_TABLES;
20948c2ecf20Sopenharmony_ci	pe->table_group.max_levels = POWERNV_IOMMU_MAX_LEVELS;
20958c2ecf20Sopenharmony_ci	pe->table_group.pgsizes = pnv_ioda_parse_tce_sizes(phb);
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci	rc = pnv_pci_ioda2_setup_default_config(pe);
20988c2ecf20Sopenharmony_ci	if (rc)
20998c2ecf20Sopenharmony_ci		return;
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci#ifdef CONFIG_IOMMU_API
21028c2ecf20Sopenharmony_ci	pe->table_group.ops = &pnv_pci_ioda2_ops;
21038c2ecf20Sopenharmony_ci	iommu_register_group(&pe->table_group, phb->hose->global_number,
21048c2ecf20Sopenharmony_ci			     pe->pe_number);
21058c2ecf20Sopenharmony_ci#endif
21068c2ecf20Sopenharmony_ci	pe->dma_setup_done = true;
21078c2ecf20Sopenharmony_ci}
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ciint64_t pnv_opal_pci_msi_eoi(struct irq_chip *chip, unsigned int hw_irq)
21108c2ecf20Sopenharmony_ci{
21118c2ecf20Sopenharmony_ci	struct pnv_phb *phb = container_of(chip, struct pnv_phb,
21128c2ecf20Sopenharmony_ci					   ioda.irq_chip);
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	return opal_pci_msi_eoi(phb->opal_id, hw_irq);
21158c2ecf20Sopenharmony_ci}
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_cistatic void pnv_ioda2_msi_eoi(struct irq_data *d)
21188c2ecf20Sopenharmony_ci{
21198c2ecf20Sopenharmony_ci	int64_t rc;
21208c2ecf20Sopenharmony_ci	unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
21218c2ecf20Sopenharmony_ci	struct irq_chip *chip = irq_data_get_irq_chip(d);
21228c2ecf20Sopenharmony_ci
21238c2ecf20Sopenharmony_ci	rc = pnv_opal_pci_msi_eoi(chip, hw_irq);
21248c2ecf20Sopenharmony_ci	WARN_ON_ONCE(rc);
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_ci	icp_native_eoi(d);
21278c2ecf20Sopenharmony_ci}
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_civoid pnv_set_msi_irq_chip(struct pnv_phb *phb, unsigned int virq)
21318c2ecf20Sopenharmony_ci{
21328c2ecf20Sopenharmony_ci	struct irq_data *idata;
21338c2ecf20Sopenharmony_ci	struct irq_chip *ichip;
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci	/* The MSI EOI OPAL call is only needed on PHB3 */
21368c2ecf20Sopenharmony_ci	if (phb->model != PNV_PHB_MODEL_PHB3)
21378c2ecf20Sopenharmony_ci		return;
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_ci	if (!phb->ioda.irq_chip_init) {
21408c2ecf20Sopenharmony_ci		/*
21418c2ecf20Sopenharmony_ci		 * First time we setup an MSI IRQ, we need to setup the
21428c2ecf20Sopenharmony_ci		 * corresponding IRQ chip to route correctly.
21438c2ecf20Sopenharmony_ci		 */
21448c2ecf20Sopenharmony_ci		idata = irq_get_irq_data(virq);
21458c2ecf20Sopenharmony_ci		ichip = irq_data_get_irq_chip(idata);
21468c2ecf20Sopenharmony_ci		phb->ioda.irq_chip_init = 1;
21478c2ecf20Sopenharmony_ci		phb->ioda.irq_chip = *ichip;
21488c2ecf20Sopenharmony_ci		phb->ioda.irq_chip.irq_eoi = pnv_ioda2_msi_eoi;
21498c2ecf20Sopenharmony_ci	}
21508c2ecf20Sopenharmony_ci	irq_set_chip(virq, &phb->ioda.irq_chip);
21518c2ecf20Sopenharmony_ci}
21528c2ecf20Sopenharmony_ci
21538c2ecf20Sopenharmony_ci/*
21548c2ecf20Sopenharmony_ci * Returns true iff chip is something that we could call
21558c2ecf20Sopenharmony_ci * pnv_opal_pci_msi_eoi for.
21568c2ecf20Sopenharmony_ci */
21578c2ecf20Sopenharmony_cibool is_pnv_opal_msi(struct irq_chip *chip)
21588c2ecf20Sopenharmony_ci{
21598c2ecf20Sopenharmony_ci	return chip->irq_eoi == pnv_ioda2_msi_eoi;
21608c2ecf20Sopenharmony_ci}
21618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(is_pnv_opal_msi);
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_cistatic int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev,
21648c2ecf20Sopenharmony_ci				  unsigned int hwirq, unsigned int virq,
21658c2ecf20Sopenharmony_ci				  unsigned int is_64, struct msi_msg *msg)
21668c2ecf20Sopenharmony_ci{
21678c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe = pnv_ioda_get_pe(dev);
21688c2ecf20Sopenharmony_ci	unsigned int xive_num = hwirq - phb->msi_base;
21698c2ecf20Sopenharmony_ci	__be32 data;
21708c2ecf20Sopenharmony_ci	int rc;
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci	/* No PE assigned ? bail out ... no MSI for you ! */
21738c2ecf20Sopenharmony_ci	if (pe == NULL)
21748c2ecf20Sopenharmony_ci		return -ENXIO;
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci	/* Check if we have an MVE */
21778c2ecf20Sopenharmony_ci	if (pe->mve_number < 0)
21788c2ecf20Sopenharmony_ci		return -ENXIO;
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci	/* Force 32-bit MSI on some broken devices */
21818c2ecf20Sopenharmony_ci	if (dev->no_64bit_msi)
21828c2ecf20Sopenharmony_ci		is_64 = 0;
21838c2ecf20Sopenharmony_ci
21848c2ecf20Sopenharmony_ci	/* Assign XIVE to PE */
21858c2ecf20Sopenharmony_ci	rc = opal_pci_set_xive_pe(phb->opal_id, pe->pe_number, xive_num);
21868c2ecf20Sopenharmony_ci	if (rc) {
21878c2ecf20Sopenharmony_ci		pr_warn("%s: OPAL error %d setting XIVE %d PE\n",
21888c2ecf20Sopenharmony_ci			pci_name(dev), rc, xive_num);
21898c2ecf20Sopenharmony_ci		return -EIO;
21908c2ecf20Sopenharmony_ci	}
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci	if (is_64) {
21938c2ecf20Sopenharmony_ci		__be64 addr64;
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci		rc = opal_get_msi_64(phb->opal_id, pe->mve_number, xive_num, 1,
21968c2ecf20Sopenharmony_ci				     &addr64, &data);
21978c2ecf20Sopenharmony_ci		if (rc) {
21988c2ecf20Sopenharmony_ci			pr_warn("%s: OPAL error %d getting 64-bit MSI data\n",
21998c2ecf20Sopenharmony_ci				pci_name(dev), rc);
22008c2ecf20Sopenharmony_ci			return -EIO;
22018c2ecf20Sopenharmony_ci		}
22028c2ecf20Sopenharmony_ci		msg->address_hi = be64_to_cpu(addr64) >> 32;
22038c2ecf20Sopenharmony_ci		msg->address_lo = be64_to_cpu(addr64) & 0xfffffffful;
22048c2ecf20Sopenharmony_ci	} else {
22058c2ecf20Sopenharmony_ci		__be32 addr32;
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci		rc = opal_get_msi_32(phb->opal_id, pe->mve_number, xive_num, 1,
22088c2ecf20Sopenharmony_ci				     &addr32, &data);
22098c2ecf20Sopenharmony_ci		if (rc) {
22108c2ecf20Sopenharmony_ci			pr_warn("%s: OPAL error %d getting 32-bit MSI data\n",
22118c2ecf20Sopenharmony_ci				pci_name(dev), rc);
22128c2ecf20Sopenharmony_ci			return -EIO;
22138c2ecf20Sopenharmony_ci		}
22148c2ecf20Sopenharmony_ci		msg->address_hi = 0;
22158c2ecf20Sopenharmony_ci		msg->address_lo = be32_to_cpu(addr32);
22168c2ecf20Sopenharmony_ci	}
22178c2ecf20Sopenharmony_ci	msg->data = be32_to_cpu(data);
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci	pnv_set_msi_irq_chip(phb, virq);
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_ci	pr_devel("%s: %s-bit MSI on hwirq %x (xive #%d),"
22228c2ecf20Sopenharmony_ci		 " address=%x_%08x data=%x PE# %x\n",
22238c2ecf20Sopenharmony_ci		 pci_name(dev), is_64 ? "64" : "32", hwirq, xive_num,
22248c2ecf20Sopenharmony_ci		 msg->address_hi, msg->address_lo, data, pe->pe_number);
22258c2ecf20Sopenharmony_ci
22268c2ecf20Sopenharmony_ci	return 0;
22278c2ecf20Sopenharmony_ci}
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_cistatic void pnv_pci_init_ioda_msis(struct pnv_phb *phb)
22308c2ecf20Sopenharmony_ci{
22318c2ecf20Sopenharmony_ci	unsigned int count;
22328c2ecf20Sopenharmony_ci	const __be32 *prop = of_get_property(phb->hose->dn,
22338c2ecf20Sopenharmony_ci					     "ibm,opal-msi-ranges", NULL);
22348c2ecf20Sopenharmony_ci	if (!prop) {
22358c2ecf20Sopenharmony_ci		/* BML Fallback */
22368c2ecf20Sopenharmony_ci		prop = of_get_property(phb->hose->dn, "msi-ranges", NULL);
22378c2ecf20Sopenharmony_ci	}
22388c2ecf20Sopenharmony_ci	if (!prop)
22398c2ecf20Sopenharmony_ci		return;
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	phb->msi_base = be32_to_cpup(prop);
22428c2ecf20Sopenharmony_ci	count = be32_to_cpup(prop + 1);
22438c2ecf20Sopenharmony_ci	if (msi_bitmap_alloc(&phb->msi_bmp, count, phb->hose->dn)) {
22448c2ecf20Sopenharmony_ci		pr_err("PCI %d: Failed to allocate MSI bitmap !\n",
22458c2ecf20Sopenharmony_ci		       phb->hose->global_number);
22468c2ecf20Sopenharmony_ci		return;
22478c2ecf20Sopenharmony_ci	}
22488c2ecf20Sopenharmony_ci
22498c2ecf20Sopenharmony_ci	phb->msi_setup = pnv_pci_ioda_msi_setup;
22508c2ecf20Sopenharmony_ci	phb->msi32_support = 1;
22518c2ecf20Sopenharmony_ci	pr_info("  Allocated bitmap for %d MSIs (base IRQ 0x%x)\n",
22528c2ecf20Sopenharmony_ci		count, phb->msi_base);
22538c2ecf20Sopenharmony_ci}
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_cistatic void pnv_ioda_setup_pe_res(struct pnv_ioda_pe *pe,
22568c2ecf20Sopenharmony_ci				  struct resource *res)
22578c2ecf20Sopenharmony_ci{
22588c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pe->phb;
22598c2ecf20Sopenharmony_ci	struct pci_bus_region region;
22608c2ecf20Sopenharmony_ci	int index;
22618c2ecf20Sopenharmony_ci	int64_t rc;
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci	if (!res || !res->flags || res->start > res->end ||
22648c2ecf20Sopenharmony_ci	    res->flags & IORESOURCE_UNSET)
22658c2ecf20Sopenharmony_ci		return;
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_IO) {
22688c2ecf20Sopenharmony_ci		region.start = res->start - phb->ioda.io_pci_base;
22698c2ecf20Sopenharmony_ci		region.end   = res->end - phb->ioda.io_pci_base;
22708c2ecf20Sopenharmony_ci		index = region.start / phb->ioda.io_segsize;
22718c2ecf20Sopenharmony_ci
22728c2ecf20Sopenharmony_ci		while (index < phb->ioda.total_pe_num &&
22738c2ecf20Sopenharmony_ci		       region.start <= region.end) {
22748c2ecf20Sopenharmony_ci			phb->ioda.io_segmap[index] = pe->pe_number;
22758c2ecf20Sopenharmony_ci			rc = opal_pci_map_pe_mmio_window(phb->opal_id,
22768c2ecf20Sopenharmony_ci				pe->pe_number, OPAL_IO_WINDOW_TYPE, 0, index);
22778c2ecf20Sopenharmony_ci			if (rc != OPAL_SUCCESS) {
22788c2ecf20Sopenharmony_ci				pr_err("%s: Error %lld mapping IO segment#%d to PE#%x\n",
22798c2ecf20Sopenharmony_ci				       __func__, rc, index, pe->pe_number);
22808c2ecf20Sopenharmony_ci				break;
22818c2ecf20Sopenharmony_ci			}
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ci			region.start += phb->ioda.io_segsize;
22848c2ecf20Sopenharmony_ci			index++;
22858c2ecf20Sopenharmony_ci		}
22868c2ecf20Sopenharmony_ci	} else if ((res->flags & IORESOURCE_MEM) &&
22878c2ecf20Sopenharmony_ci		   !pnv_pci_is_m64(phb, res)) {
22888c2ecf20Sopenharmony_ci		region.start = res->start -
22898c2ecf20Sopenharmony_ci			       phb->hose->mem_offset[0] -
22908c2ecf20Sopenharmony_ci			       phb->ioda.m32_pci_base;
22918c2ecf20Sopenharmony_ci		region.end   = res->end -
22928c2ecf20Sopenharmony_ci			       phb->hose->mem_offset[0] -
22938c2ecf20Sopenharmony_ci			       phb->ioda.m32_pci_base;
22948c2ecf20Sopenharmony_ci		index = region.start / phb->ioda.m32_segsize;
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_ci		while (index < phb->ioda.total_pe_num &&
22978c2ecf20Sopenharmony_ci		       region.start <= region.end) {
22988c2ecf20Sopenharmony_ci			phb->ioda.m32_segmap[index] = pe->pe_number;
22998c2ecf20Sopenharmony_ci			rc = opal_pci_map_pe_mmio_window(phb->opal_id,
23008c2ecf20Sopenharmony_ci				pe->pe_number, OPAL_M32_WINDOW_TYPE, 0, index);
23018c2ecf20Sopenharmony_ci			if (rc != OPAL_SUCCESS) {
23028c2ecf20Sopenharmony_ci				pr_err("%s: Error %lld mapping M32 segment#%d to PE#%x",
23038c2ecf20Sopenharmony_ci				       __func__, rc, index, pe->pe_number);
23048c2ecf20Sopenharmony_ci				break;
23058c2ecf20Sopenharmony_ci			}
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_ci			region.start += phb->ioda.m32_segsize;
23088c2ecf20Sopenharmony_ci			index++;
23098c2ecf20Sopenharmony_ci		}
23108c2ecf20Sopenharmony_ci	}
23118c2ecf20Sopenharmony_ci}
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_ci/*
23148c2ecf20Sopenharmony_ci * This function is supposed to be called on basis of PE from top
23158c2ecf20Sopenharmony_ci * to bottom style. So the the I/O or MMIO segment assigned to
23168c2ecf20Sopenharmony_ci * parent PE could be overridden by its child PEs if necessary.
23178c2ecf20Sopenharmony_ci */
23188c2ecf20Sopenharmony_cistatic void pnv_ioda_setup_pe_seg(struct pnv_ioda_pe *pe)
23198c2ecf20Sopenharmony_ci{
23208c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
23218c2ecf20Sopenharmony_ci	int i;
23228c2ecf20Sopenharmony_ci
23238c2ecf20Sopenharmony_ci	/*
23248c2ecf20Sopenharmony_ci	 * NOTE: We only care PCI bus based PE for now. For PCI
23258c2ecf20Sopenharmony_ci	 * device based PE, for example SRIOV sensitive VF should
23268c2ecf20Sopenharmony_ci	 * be figured out later.
23278c2ecf20Sopenharmony_ci	 */
23288c2ecf20Sopenharmony_ci	BUG_ON(!(pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL)));
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci	list_for_each_entry(pdev, &pe->pbus->devices, bus_list) {
23318c2ecf20Sopenharmony_ci		for (i = 0; i <= PCI_ROM_RESOURCE; i++)
23328c2ecf20Sopenharmony_ci			pnv_ioda_setup_pe_res(pe, &pdev->resource[i]);
23338c2ecf20Sopenharmony_ci
23348c2ecf20Sopenharmony_ci		/*
23358c2ecf20Sopenharmony_ci		 * If the PE contains all subordinate PCI buses, the
23368c2ecf20Sopenharmony_ci		 * windows of the child bridges should be mapped to
23378c2ecf20Sopenharmony_ci		 * the PE as well.
23388c2ecf20Sopenharmony_ci		 */
23398c2ecf20Sopenharmony_ci		if (!(pe->flags & PNV_IODA_PE_BUS_ALL) || !pci_is_bridge(pdev))
23408c2ecf20Sopenharmony_ci			continue;
23418c2ecf20Sopenharmony_ci		for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
23428c2ecf20Sopenharmony_ci			pnv_ioda_setup_pe_res(pe,
23438c2ecf20Sopenharmony_ci				&pdev->resource[PCI_BRIDGE_RESOURCES + i]);
23448c2ecf20Sopenharmony_ci	}
23458c2ecf20Sopenharmony_ci}
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
23488c2ecf20Sopenharmony_cistatic int pnv_pci_diag_data_set(void *data, u64 val)
23498c2ecf20Sopenharmony_ci{
23508c2ecf20Sopenharmony_ci	struct pnv_phb *phb = data;
23518c2ecf20Sopenharmony_ci	s64 ret;
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci	/* Retrieve the diag data from firmware */
23548c2ecf20Sopenharmony_ci	ret = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag_data,
23558c2ecf20Sopenharmony_ci					  phb->diag_data_size);
23568c2ecf20Sopenharmony_ci	if (ret != OPAL_SUCCESS)
23578c2ecf20Sopenharmony_ci		return -EIO;
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_ci	/* Print the diag data to the kernel log */
23608c2ecf20Sopenharmony_ci	pnv_pci_dump_phb_diag_data(phb->hose, phb->diag_data);
23618c2ecf20Sopenharmony_ci	return 0;
23628c2ecf20Sopenharmony_ci}
23638c2ecf20Sopenharmony_ci
23648c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(pnv_pci_diag_data_fops, NULL, pnv_pci_diag_data_set,
23658c2ecf20Sopenharmony_ci			 "%llu\n");
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_cistatic int pnv_pci_ioda_pe_dump(void *data, u64 val)
23688c2ecf20Sopenharmony_ci{
23698c2ecf20Sopenharmony_ci	struct pnv_phb *phb = data;
23708c2ecf20Sopenharmony_ci	int pe_num;
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ci	for (pe_num = 0; pe_num < phb->ioda.total_pe_num; pe_num++) {
23738c2ecf20Sopenharmony_ci		struct pnv_ioda_pe *pe = &phb->ioda.pe_array[pe_num];
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ci		if (!test_bit(pe_num, phb->ioda.pe_alloc))
23768c2ecf20Sopenharmony_ci			continue;
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_ci		pe_warn(pe, "rid: %04x dev count: %2d flags: %s%s%s%s%s%s\n",
23798c2ecf20Sopenharmony_ci			pe->rid, pe->device_count,
23808c2ecf20Sopenharmony_ci			(pe->flags & PNV_IODA_PE_DEV) ? "dev " : "",
23818c2ecf20Sopenharmony_ci			(pe->flags & PNV_IODA_PE_BUS) ? "bus " : "",
23828c2ecf20Sopenharmony_ci			(pe->flags & PNV_IODA_PE_BUS_ALL) ? "all " : "",
23838c2ecf20Sopenharmony_ci			(pe->flags & PNV_IODA_PE_MASTER) ? "master " : "",
23848c2ecf20Sopenharmony_ci			(pe->flags & PNV_IODA_PE_SLAVE) ? "slave " : "",
23858c2ecf20Sopenharmony_ci			(pe->flags & PNV_IODA_PE_VF) ? "vf " : "");
23868c2ecf20Sopenharmony_ci	}
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ci	return 0;
23898c2ecf20Sopenharmony_ci}
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(pnv_pci_ioda_pe_dump_fops, NULL,
23928c2ecf20Sopenharmony_ci			 pnv_pci_ioda_pe_dump, "%llu\n");
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_cistatic void pnv_pci_ioda_create_dbgfs(void)
23978c2ecf20Sopenharmony_ci{
23988c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
23998c2ecf20Sopenharmony_ci	struct pci_controller *hose, *tmp;
24008c2ecf20Sopenharmony_ci	struct pnv_phb *phb;
24018c2ecf20Sopenharmony_ci	char name[16];
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
24048c2ecf20Sopenharmony_ci		phb = hose->private_data;
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_ci		/* Notify initialization of PHB done */
24078c2ecf20Sopenharmony_ci		phb->initialized = 1;
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci		sprintf(name, "PCI%04x", hose->global_number);
24108c2ecf20Sopenharmony_ci		phb->dbgfs = debugfs_create_dir(name, powerpc_debugfs_root);
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci		debugfs_create_file_unsafe("dump_diag_regs", 0200, phb->dbgfs,
24138c2ecf20Sopenharmony_ci					   phb, &pnv_pci_diag_data_fops);
24148c2ecf20Sopenharmony_ci		debugfs_create_file_unsafe("dump_ioda_pe_state", 0200, phb->dbgfs,
24158c2ecf20Sopenharmony_ci					   phb, &pnv_pci_ioda_pe_dump_fops);
24168c2ecf20Sopenharmony_ci	}
24178c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */
24188c2ecf20Sopenharmony_ci}
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_cistatic void pnv_pci_enable_bridge(struct pci_bus *bus)
24218c2ecf20Sopenharmony_ci{
24228c2ecf20Sopenharmony_ci	struct pci_dev *dev = bus->self;
24238c2ecf20Sopenharmony_ci	struct pci_bus *child;
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	/* Empty bus ? bail */
24268c2ecf20Sopenharmony_ci	if (list_empty(&bus->devices))
24278c2ecf20Sopenharmony_ci		return;
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_ci	/*
24308c2ecf20Sopenharmony_ci	 * If there's a bridge associated with that bus enable it. This works
24318c2ecf20Sopenharmony_ci	 * around races in the generic code if the enabling is done during
24328c2ecf20Sopenharmony_ci	 * parallel probing. This can be removed once those races have been
24338c2ecf20Sopenharmony_ci	 * fixed.
24348c2ecf20Sopenharmony_ci	 */
24358c2ecf20Sopenharmony_ci	if (dev) {
24368c2ecf20Sopenharmony_ci		int rc = pci_enable_device(dev);
24378c2ecf20Sopenharmony_ci		if (rc)
24388c2ecf20Sopenharmony_ci			pci_err(dev, "Error enabling bridge (%d)\n", rc);
24398c2ecf20Sopenharmony_ci		pci_set_master(dev);
24408c2ecf20Sopenharmony_ci	}
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci	/* Perform the same to child busses */
24438c2ecf20Sopenharmony_ci	list_for_each_entry(child, &bus->children, node)
24448c2ecf20Sopenharmony_ci		pnv_pci_enable_bridge(child);
24458c2ecf20Sopenharmony_ci}
24468c2ecf20Sopenharmony_ci
24478c2ecf20Sopenharmony_cistatic void pnv_pci_enable_bridges(void)
24488c2ecf20Sopenharmony_ci{
24498c2ecf20Sopenharmony_ci	struct pci_controller *hose;
24508c2ecf20Sopenharmony_ci
24518c2ecf20Sopenharmony_ci	list_for_each_entry(hose, &hose_list, list_node)
24528c2ecf20Sopenharmony_ci		pnv_pci_enable_bridge(hose->bus);
24538c2ecf20Sopenharmony_ci}
24548c2ecf20Sopenharmony_ci
24558c2ecf20Sopenharmony_cistatic void pnv_pci_ioda_fixup(void)
24568c2ecf20Sopenharmony_ci{
24578c2ecf20Sopenharmony_ci	pnv_pci_ioda_setup_nvlink();
24588c2ecf20Sopenharmony_ci	pnv_pci_ioda_create_dbgfs();
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci	pnv_pci_enable_bridges();
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_ci#ifdef CONFIG_EEH
24638c2ecf20Sopenharmony_ci	pnv_eeh_post_init();
24648c2ecf20Sopenharmony_ci#endif
24658c2ecf20Sopenharmony_ci}
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci/*
24688c2ecf20Sopenharmony_ci * Returns the alignment for I/O or memory windows for P2P
24698c2ecf20Sopenharmony_ci * bridges. That actually depends on how PEs are segmented.
24708c2ecf20Sopenharmony_ci * For now, we return I/O or M32 segment size for PE sensitive
24718c2ecf20Sopenharmony_ci * P2P bridges. Otherwise, the default values (4KiB for I/O,
24728c2ecf20Sopenharmony_ci * 1MiB for memory) will be returned.
24738c2ecf20Sopenharmony_ci *
24748c2ecf20Sopenharmony_ci * The current PCI bus might be put into one PE, which was
24758c2ecf20Sopenharmony_ci * create against the parent PCI bridge. For that case, we
24768c2ecf20Sopenharmony_ci * needn't enlarge the alignment so that we can save some
24778c2ecf20Sopenharmony_ci * resources.
24788c2ecf20Sopenharmony_ci */
24798c2ecf20Sopenharmony_cistatic resource_size_t pnv_pci_window_alignment(struct pci_bus *bus,
24808c2ecf20Sopenharmony_ci						unsigned long type)
24818c2ecf20Sopenharmony_ci{
24828c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(bus);
24838c2ecf20Sopenharmony_ci	int num_pci_bridges = 0;
24848c2ecf20Sopenharmony_ci	struct pci_dev *bridge;
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci	bridge = bus->self;
24878c2ecf20Sopenharmony_ci	while (bridge) {
24888c2ecf20Sopenharmony_ci		if (pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE) {
24898c2ecf20Sopenharmony_ci			num_pci_bridges++;
24908c2ecf20Sopenharmony_ci			if (num_pci_bridges >= 2)
24918c2ecf20Sopenharmony_ci				return 1;
24928c2ecf20Sopenharmony_ci		}
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci		bridge = bridge->bus->self;
24958c2ecf20Sopenharmony_ci	}
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci	/*
24988c2ecf20Sopenharmony_ci	 * We fall back to M32 if M64 isn't supported. We enforce the M64
24998c2ecf20Sopenharmony_ci	 * alignment for any 64-bit resource, PCIe doesn't care and
25008c2ecf20Sopenharmony_ci	 * bridges only do 64-bit prefetchable anyway.
25018c2ecf20Sopenharmony_ci	 */
25028c2ecf20Sopenharmony_ci	if (phb->ioda.m64_segsize && pnv_pci_is_m64_flags(type))
25038c2ecf20Sopenharmony_ci		return phb->ioda.m64_segsize;
25048c2ecf20Sopenharmony_ci	if (type & IORESOURCE_MEM)
25058c2ecf20Sopenharmony_ci		return phb->ioda.m32_segsize;
25068c2ecf20Sopenharmony_ci
25078c2ecf20Sopenharmony_ci	return phb->ioda.io_segsize;
25088c2ecf20Sopenharmony_ci}
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ci/*
25118c2ecf20Sopenharmony_ci * We are updating root port or the upstream port of the
25128c2ecf20Sopenharmony_ci * bridge behind the root port with PHB's windows in order
25138c2ecf20Sopenharmony_ci * to accommodate the changes on required resources during
25148c2ecf20Sopenharmony_ci * PCI (slot) hotplug, which is connected to either root
25158c2ecf20Sopenharmony_ci * port or the downstream ports of PCIe switch behind the
25168c2ecf20Sopenharmony_ci * root port.
25178c2ecf20Sopenharmony_ci */
25188c2ecf20Sopenharmony_cistatic void pnv_pci_fixup_bridge_resources(struct pci_bus *bus,
25198c2ecf20Sopenharmony_ci					   unsigned long type)
25208c2ecf20Sopenharmony_ci{
25218c2ecf20Sopenharmony_ci	struct pci_controller *hose = pci_bus_to_host(bus);
25228c2ecf20Sopenharmony_ci	struct pnv_phb *phb = hose->private_data;
25238c2ecf20Sopenharmony_ci	struct pci_dev *bridge = bus->self;
25248c2ecf20Sopenharmony_ci	struct resource *r, *w;
25258c2ecf20Sopenharmony_ci	bool msi_region = false;
25268c2ecf20Sopenharmony_ci	int i;
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci	/* Check if we need apply fixup to the bridge's windows */
25298c2ecf20Sopenharmony_ci	if (!pci_is_root_bus(bridge->bus) &&
25308c2ecf20Sopenharmony_ci	    !pci_is_root_bus(bridge->bus->self->bus))
25318c2ecf20Sopenharmony_ci		return;
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ci	/* Fixup the resources */
25348c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
25358c2ecf20Sopenharmony_ci		r = &bridge->resource[PCI_BRIDGE_RESOURCES + i];
25368c2ecf20Sopenharmony_ci		if (!r->flags || !r->parent)
25378c2ecf20Sopenharmony_ci			continue;
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci		w = NULL;
25408c2ecf20Sopenharmony_ci		if (r->flags & type & IORESOURCE_IO)
25418c2ecf20Sopenharmony_ci			w = &hose->io_resource;
25428c2ecf20Sopenharmony_ci		else if (pnv_pci_is_m64(phb, r) &&
25438c2ecf20Sopenharmony_ci			 (type & IORESOURCE_PREFETCH) &&
25448c2ecf20Sopenharmony_ci			 phb->ioda.m64_segsize)
25458c2ecf20Sopenharmony_ci			w = &hose->mem_resources[1];
25468c2ecf20Sopenharmony_ci		else if (r->flags & type & IORESOURCE_MEM) {
25478c2ecf20Sopenharmony_ci			w = &hose->mem_resources[0];
25488c2ecf20Sopenharmony_ci			msi_region = true;
25498c2ecf20Sopenharmony_ci		}
25508c2ecf20Sopenharmony_ci
25518c2ecf20Sopenharmony_ci		r->start = w->start;
25528c2ecf20Sopenharmony_ci		r->end = w->end;
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_ci		/* The 64KB 32-bits MSI region shouldn't be included in
25558c2ecf20Sopenharmony_ci		 * the 32-bits bridge window. Otherwise, we can see strange
25568c2ecf20Sopenharmony_ci		 * issues. One of them is EEH error observed on Garrison.
25578c2ecf20Sopenharmony_ci		 *
25588c2ecf20Sopenharmony_ci		 * Exclude top 1MB region which is the minimal alignment of
25598c2ecf20Sopenharmony_ci		 * 32-bits bridge window.
25608c2ecf20Sopenharmony_ci		 */
25618c2ecf20Sopenharmony_ci		if (msi_region) {
25628c2ecf20Sopenharmony_ci			r->end += 0x10000;
25638c2ecf20Sopenharmony_ci			r->end -= 0x100000;
25648c2ecf20Sopenharmony_ci		}
25658c2ecf20Sopenharmony_ci	}
25668c2ecf20Sopenharmony_ci}
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_cistatic void pnv_pci_configure_bus(struct pci_bus *bus)
25698c2ecf20Sopenharmony_ci{
25708c2ecf20Sopenharmony_ci	struct pci_dev *bridge = bus->self;
25718c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe;
25728c2ecf20Sopenharmony_ci	bool all = (bridge && pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE);
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_ci	dev_info(&bus->dev, "Configuring PE for bus\n");
25758c2ecf20Sopenharmony_ci
25768c2ecf20Sopenharmony_ci	/* Don't assign PE to PCI bus, which doesn't have subordinate devices */
25778c2ecf20Sopenharmony_ci	if (WARN_ON(list_empty(&bus->devices)))
25788c2ecf20Sopenharmony_ci		return;
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci	/* Reserve PEs according to used M64 resources */
25818c2ecf20Sopenharmony_ci	pnv_ioda_reserve_m64_pe(bus, NULL, all);
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ci	/*
25848c2ecf20Sopenharmony_ci	 * Assign PE. We might run here because of partial hotplug.
25858c2ecf20Sopenharmony_ci	 * For the case, we just pick up the existing PE and should
25868c2ecf20Sopenharmony_ci	 * not allocate resources again.
25878c2ecf20Sopenharmony_ci	 */
25888c2ecf20Sopenharmony_ci	pe = pnv_ioda_setup_bus_PE(bus, all);
25898c2ecf20Sopenharmony_ci	if (!pe)
25908c2ecf20Sopenharmony_ci		return;
25918c2ecf20Sopenharmony_ci
25928c2ecf20Sopenharmony_ci	pnv_ioda_setup_pe_seg(pe);
25938c2ecf20Sopenharmony_ci}
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_cistatic resource_size_t pnv_pci_default_alignment(void)
25968c2ecf20Sopenharmony_ci{
25978c2ecf20Sopenharmony_ci	return PAGE_SIZE;
25988c2ecf20Sopenharmony_ci}
25998c2ecf20Sopenharmony_ci
26008c2ecf20Sopenharmony_ci/* Prevent enabling devices for which we couldn't properly
26018c2ecf20Sopenharmony_ci * assign a PE
26028c2ecf20Sopenharmony_ci */
26038c2ecf20Sopenharmony_cistatic bool pnv_pci_enable_device_hook(struct pci_dev *dev)
26048c2ecf20Sopenharmony_ci{
26058c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(dev->bus);
26068c2ecf20Sopenharmony_ci	struct pci_dn *pdn;
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci	/* The function is probably called while the PEs have
26098c2ecf20Sopenharmony_ci	 * not be created yet. For example, resource reassignment
26108c2ecf20Sopenharmony_ci	 * during PCI probe period. We just skip the check if
26118c2ecf20Sopenharmony_ci	 * PEs isn't ready.
26128c2ecf20Sopenharmony_ci	 */
26138c2ecf20Sopenharmony_ci	if (!phb->initialized)
26148c2ecf20Sopenharmony_ci		return true;
26158c2ecf20Sopenharmony_ci
26168c2ecf20Sopenharmony_ci	pdn = pci_get_pdn(dev);
26178c2ecf20Sopenharmony_ci	if (!pdn || pdn->pe_number == IODA_INVALID_PE)
26188c2ecf20Sopenharmony_ci		return false;
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ci	return true;
26218c2ecf20Sopenharmony_ci}
26228c2ecf20Sopenharmony_ci
26238c2ecf20Sopenharmony_cistatic bool pnv_ocapi_enable_device_hook(struct pci_dev *dev)
26248c2ecf20Sopenharmony_ci{
26258c2ecf20Sopenharmony_ci	struct pci_controller *hose = pci_bus_to_host(dev->bus);
26268c2ecf20Sopenharmony_ci	struct pnv_phb *phb = hose->private_data;
26278c2ecf20Sopenharmony_ci	struct pci_dn *pdn;
26288c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe;
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci	if (!phb->initialized)
26318c2ecf20Sopenharmony_ci		return true;
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_ci	pdn = pci_get_pdn(dev);
26348c2ecf20Sopenharmony_ci	if (!pdn)
26358c2ecf20Sopenharmony_ci		return false;
26368c2ecf20Sopenharmony_ci
26378c2ecf20Sopenharmony_ci	if (pdn->pe_number == IODA_INVALID_PE) {
26388c2ecf20Sopenharmony_ci		pe = pnv_ioda_setup_dev_PE(dev);
26398c2ecf20Sopenharmony_ci		if (!pe)
26408c2ecf20Sopenharmony_ci			return false;
26418c2ecf20Sopenharmony_ci	}
26428c2ecf20Sopenharmony_ci	return true;
26438c2ecf20Sopenharmony_ci}
26448c2ecf20Sopenharmony_ci
26458c2ecf20Sopenharmony_cistatic long pnv_pci_ioda1_unset_window(struct iommu_table_group *table_group,
26468c2ecf20Sopenharmony_ci				       int num)
26478c2ecf20Sopenharmony_ci{
26488c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe = container_of(table_group,
26498c2ecf20Sopenharmony_ci					      struct pnv_ioda_pe, table_group);
26508c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pe->phb;
26518c2ecf20Sopenharmony_ci	unsigned int idx;
26528c2ecf20Sopenharmony_ci	long rc;
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_ci	pe_info(pe, "Removing DMA window #%d\n", num);
26558c2ecf20Sopenharmony_ci	for (idx = 0; idx < phb->ioda.dma32_count; idx++) {
26568c2ecf20Sopenharmony_ci		if (phb->ioda.dma32_segmap[idx] != pe->pe_number)
26578c2ecf20Sopenharmony_ci			continue;
26588c2ecf20Sopenharmony_ci
26598c2ecf20Sopenharmony_ci		rc = opal_pci_map_pe_dma_window(phb->opal_id, pe->pe_number,
26608c2ecf20Sopenharmony_ci						idx, 0, 0ul, 0ul, 0ul);
26618c2ecf20Sopenharmony_ci		if (rc != OPAL_SUCCESS) {
26628c2ecf20Sopenharmony_ci			pe_warn(pe, "Failure %ld unmapping DMA32 segment#%d\n",
26638c2ecf20Sopenharmony_ci				rc, idx);
26648c2ecf20Sopenharmony_ci			return rc;
26658c2ecf20Sopenharmony_ci		}
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ci		phb->ioda.dma32_segmap[idx] = IODA_INVALID_PE;
26688c2ecf20Sopenharmony_ci	}
26698c2ecf20Sopenharmony_ci
26708c2ecf20Sopenharmony_ci	pnv_pci_unlink_table_and_group(table_group->tables[num], table_group);
26718c2ecf20Sopenharmony_ci	return OPAL_SUCCESS;
26728c2ecf20Sopenharmony_ci}
26738c2ecf20Sopenharmony_ci
26748c2ecf20Sopenharmony_cistatic void pnv_pci_ioda1_release_pe_dma(struct pnv_ioda_pe *pe)
26758c2ecf20Sopenharmony_ci{
26768c2ecf20Sopenharmony_ci	struct iommu_table *tbl = pe->table_group.tables[0];
26778c2ecf20Sopenharmony_ci	int64_t rc;
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_ci	if (!pe->dma_setup_done)
26808c2ecf20Sopenharmony_ci		return;
26818c2ecf20Sopenharmony_ci
26828c2ecf20Sopenharmony_ci	rc = pnv_pci_ioda1_unset_window(&pe->table_group, 0);
26838c2ecf20Sopenharmony_ci	if (rc != OPAL_SUCCESS)
26848c2ecf20Sopenharmony_ci		return;
26858c2ecf20Sopenharmony_ci
26868c2ecf20Sopenharmony_ci	pnv_pci_p7ioc_tce_invalidate(tbl, tbl->it_offset, tbl->it_size, false);
26878c2ecf20Sopenharmony_ci	if (pe->table_group.group) {
26888c2ecf20Sopenharmony_ci		iommu_group_put(pe->table_group.group);
26898c2ecf20Sopenharmony_ci		WARN_ON(pe->table_group.group);
26908c2ecf20Sopenharmony_ci	}
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_ci	free_pages(tbl->it_base, get_order(tbl->it_size << 3));
26938c2ecf20Sopenharmony_ci	iommu_tce_table_put(tbl);
26948c2ecf20Sopenharmony_ci}
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_civoid pnv_pci_ioda2_release_pe_dma(struct pnv_ioda_pe *pe)
26978c2ecf20Sopenharmony_ci{
26988c2ecf20Sopenharmony_ci	struct iommu_table *tbl = pe->table_group.tables[0];
26998c2ecf20Sopenharmony_ci	int64_t rc;
27008c2ecf20Sopenharmony_ci
27018c2ecf20Sopenharmony_ci	if (!pe->dma_setup_done)
27028c2ecf20Sopenharmony_ci		return;
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci	rc = pnv_pci_ioda2_unset_window(&pe->table_group, 0);
27058c2ecf20Sopenharmony_ci	if (rc)
27068c2ecf20Sopenharmony_ci		pe_warn(pe, "OPAL error %lld release DMA window\n", rc);
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci	pnv_pci_ioda2_set_bypass(pe, false);
27098c2ecf20Sopenharmony_ci	if (pe->table_group.group) {
27108c2ecf20Sopenharmony_ci		iommu_group_put(pe->table_group.group);
27118c2ecf20Sopenharmony_ci		WARN_ON(pe->table_group.group);
27128c2ecf20Sopenharmony_ci	}
27138c2ecf20Sopenharmony_ci
27148c2ecf20Sopenharmony_ci	iommu_tce_table_put(tbl);
27158c2ecf20Sopenharmony_ci}
27168c2ecf20Sopenharmony_ci
27178c2ecf20Sopenharmony_cistatic void pnv_ioda_free_pe_seg(struct pnv_ioda_pe *pe,
27188c2ecf20Sopenharmony_ci				 unsigned short win,
27198c2ecf20Sopenharmony_ci				 unsigned int *map)
27208c2ecf20Sopenharmony_ci{
27218c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pe->phb;
27228c2ecf20Sopenharmony_ci	int idx;
27238c2ecf20Sopenharmony_ci	int64_t rc;
27248c2ecf20Sopenharmony_ci
27258c2ecf20Sopenharmony_ci	for (idx = 0; idx < phb->ioda.total_pe_num; idx++) {
27268c2ecf20Sopenharmony_ci		if (map[idx] != pe->pe_number)
27278c2ecf20Sopenharmony_ci			continue;
27288c2ecf20Sopenharmony_ci
27298c2ecf20Sopenharmony_ci		rc = opal_pci_map_pe_mmio_window(phb->opal_id,
27308c2ecf20Sopenharmony_ci				phb->ioda.reserved_pe_idx, win, 0, idx);
27318c2ecf20Sopenharmony_ci
27328c2ecf20Sopenharmony_ci		if (rc != OPAL_SUCCESS)
27338c2ecf20Sopenharmony_ci			pe_warn(pe, "Error %lld unmapping (%d) segment#%d\n",
27348c2ecf20Sopenharmony_ci				rc, win, idx);
27358c2ecf20Sopenharmony_ci
27368c2ecf20Sopenharmony_ci		map[idx] = IODA_INVALID_PE;
27378c2ecf20Sopenharmony_ci	}
27388c2ecf20Sopenharmony_ci}
27398c2ecf20Sopenharmony_ci
27408c2ecf20Sopenharmony_cistatic void pnv_ioda_release_pe_seg(struct pnv_ioda_pe *pe)
27418c2ecf20Sopenharmony_ci{
27428c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pe->phb;
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_ci	if (phb->type == PNV_PHB_IODA1) {
27458c2ecf20Sopenharmony_ci		pnv_ioda_free_pe_seg(pe, OPAL_IO_WINDOW_TYPE,
27468c2ecf20Sopenharmony_ci				     phb->ioda.io_segmap);
27478c2ecf20Sopenharmony_ci		pnv_ioda_free_pe_seg(pe, OPAL_M32_WINDOW_TYPE,
27488c2ecf20Sopenharmony_ci				     phb->ioda.m32_segmap);
27498c2ecf20Sopenharmony_ci		/* M64 is pre-configured by pnv_ioda1_init_m64() */
27508c2ecf20Sopenharmony_ci	} else if (phb->type == PNV_PHB_IODA2) {
27518c2ecf20Sopenharmony_ci		pnv_ioda_free_pe_seg(pe, OPAL_M32_WINDOW_TYPE,
27528c2ecf20Sopenharmony_ci				     phb->ioda.m32_segmap);
27538c2ecf20Sopenharmony_ci	}
27548c2ecf20Sopenharmony_ci}
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_cistatic void pnv_ioda_release_pe(struct pnv_ioda_pe *pe)
27578c2ecf20Sopenharmony_ci{
27588c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pe->phb;
27598c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *slave, *tmp;
27608c2ecf20Sopenharmony_ci
27618c2ecf20Sopenharmony_ci	pe_info(pe, "Releasing PE\n");
27628c2ecf20Sopenharmony_ci
27638c2ecf20Sopenharmony_ci	mutex_lock(&phb->ioda.pe_list_mutex);
27648c2ecf20Sopenharmony_ci	list_del(&pe->list);
27658c2ecf20Sopenharmony_ci	mutex_unlock(&phb->ioda.pe_list_mutex);
27668c2ecf20Sopenharmony_ci
27678c2ecf20Sopenharmony_ci	switch (phb->type) {
27688c2ecf20Sopenharmony_ci	case PNV_PHB_IODA1:
27698c2ecf20Sopenharmony_ci		pnv_pci_ioda1_release_pe_dma(pe);
27708c2ecf20Sopenharmony_ci		break;
27718c2ecf20Sopenharmony_ci	case PNV_PHB_IODA2:
27728c2ecf20Sopenharmony_ci		pnv_pci_ioda2_release_pe_dma(pe);
27738c2ecf20Sopenharmony_ci		break;
27748c2ecf20Sopenharmony_ci	case PNV_PHB_NPU_OCAPI:
27758c2ecf20Sopenharmony_ci		break;
27768c2ecf20Sopenharmony_ci	default:
27778c2ecf20Sopenharmony_ci		WARN_ON(1);
27788c2ecf20Sopenharmony_ci	}
27798c2ecf20Sopenharmony_ci
27808c2ecf20Sopenharmony_ci	pnv_ioda_release_pe_seg(pe);
27818c2ecf20Sopenharmony_ci	pnv_ioda_deconfigure_pe(pe->phb, pe);
27828c2ecf20Sopenharmony_ci
27838c2ecf20Sopenharmony_ci	/* Release slave PEs in the compound PE */
27848c2ecf20Sopenharmony_ci	if (pe->flags & PNV_IODA_PE_MASTER) {
27858c2ecf20Sopenharmony_ci		list_for_each_entry_safe(slave, tmp, &pe->slaves, list) {
27868c2ecf20Sopenharmony_ci			list_del(&slave->list);
27878c2ecf20Sopenharmony_ci			pnv_ioda_free_pe(slave);
27888c2ecf20Sopenharmony_ci		}
27898c2ecf20Sopenharmony_ci	}
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	/*
27928c2ecf20Sopenharmony_ci	 * The PE for root bus can be removed because of hotplug in EEH
27938c2ecf20Sopenharmony_ci	 * recovery for fenced PHB error. We need to mark the PE dead so
27948c2ecf20Sopenharmony_ci	 * that it can be populated again in PCI hot add path. The PE
27958c2ecf20Sopenharmony_ci	 * shouldn't be destroyed as it's the global reserved resource.
27968c2ecf20Sopenharmony_ci	 */
27978c2ecf20Sopenharmony_ci	if (phb->ioda.root_pe_idx == pe->pe_number)
27988c2ecf20Sopenharmony_ci		return;
27998c2ecf20Sopenharmony_ci
28008c2ecf20Sopenharmony_ci	pnv_ioda_free_pe(pe);
28018c2ecf20Sopenharmony_ci}
28028c2ecf20Sopenharmony_ci
28038c2ecf20Sopenharmony_cistatic void pnv_pci_release_device(struct pci_dev *pdev)
28048c2ecf20Sopenharmony_ci{
28058c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(pdev->bus);
28068c2ecf20Sopenharmony_ci	struct pci_dn *pdn = pci_get_pdn(pdev);
28078c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe;
28088c2ecf20Sopenharmony_ci
28098c2ecf20Sopenharmony_ci	/* The VF PE state is torn down when sriov_disable() is called */
28108c2ecf20Sopenharmony_ci	if (pdev->is_virtfn)
28118c2ecf20Sopenharmony_ci		return;
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_ci	if (!pdn || pdn->pe_number == IODA_INVALID_PE)
28148c2ecf20Sopenharmony_ci		return;
28158c2ecf20Sopenharmony_ci
28168c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV
28178c2ecf20Sopenharmony_ci	/*
28188c2ecf20Sopenharmony_ci	 * FIXME: Try move this to sriov_disable(). It's here since we allocate
28198c2ecf20Sopenharmony_ci	 * the iov state at probe time since we need to fiddle with the IOV
28208c2ecf20Sopenharmony_ci	 * resources.
28218c2ecf20Sopenharmony_ci	 */
28228c2ecf20Sopenharmony_ci	if (pdev->is_physfn)
28238c2ecf20Sopenharmony_ci		kfree(pdev->dev.archdata.iov_data);
28248c2ecf20Sopenharmony_ci#endif
28258c2ecf20Sopenharmony_ci
28268c2ecf20Sopenharmony_ci	/*
28278c2ecf20Sopenharmony_ci	 * PCI hotplug can happen as part of EEH error recovery. The @pdn
28288c2ecf20Sopenharmony_ci	 * isn't removed and added afterwards in this scenario. We should
28298c2ecf20Sopenharmony_ci	 * set the PE number in @pdn to an invalid one. Otherwise, the PE's
28308c2ecf20Sopenharmony_ci	 * device count is decreased on removing devices while failing to
28318c2ecf20Sopenharmony_ci	 * be increased on adding devices. It leads to unbalanced PE's device
28328c2ecf20Sopenharmony_ci	 * count and eventually make normal PCI hotplug path broken.
28338c2ecf20Sopenharmony_ci	 */
28348c2ecf20Sopenharmony_ci	pe = &phb->ioda.pe_array[pdn->pe_number];
28358c2ecf20Sopenharmony_ci	pdn->pe_number = IODA_INVALID_PE;
28368c2ecf20Sopenharmony_ci
28378c2ecf20Sopenharmony_ci	WARN_ON(--pe->device_count < 0);
28388c2ecf20Sopenharmony_ci	if (pe->device_count == 0)
28398c2ecf20Sopenharmony_ci		pnv_ioda_release_pe(pe);
28408c2ecf20Sopenharmony_ci}
28418c2ecf20Sopenharmony_ci
28428c2ecf20Sopenharmony_cistatic void pnv_npu_disable_device(struct pci_dev *pdev)
28438c2ecf20Sopenharmony_ci{
28448c2ecf20Sopenharmony_ci	struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
28458c2ecf20Sopenharmony_ci	struct eeh_pe *eehpe = edev ? edev->pe : NULL;
28468c2ecf20Sopenharmony_ci
28478c2ecf20Sopenharmony_ci	if (eehpe && eeh_ops && eeh_ops->reset)
28488c2ecf20Sopenharmony_ci		eeh_ops->reset(eehpe, EEH_RESET_HOT);
28498c2ecf20Sopenharmony_ci}
28508c2ecf20Sopenharmony_ci
28518c2ecf20Sopenharmony_cistatic void pnv_pci_ioda_shutdown(struct pci_controller *hose)
28528c2ecf20Sopenharmony_ci{
28538c2ecf20Sopenharmony_ci	struct pnv_phb *phb = hose->private_data;
28548c2ecf20Sopenharmony_ci
28558c2ecf20Sopenharmony_ci	opal_pci_reset(phb->opal_id, OPAL_RESET_PCI_IODA_TABLE,
28568c2ecf20Sopenharmony_ci		       OPAL_ASSERT_RESET);
28578c2ecf20Sopenharmony_ci}
28588c2ecf20Sopenharmony_ci
28598c2ecf20Sopenharmony_cistatic void pnv_pci_ioda_dma_bus_setup(struct pci_bus *bus)
28608c2ecf20Sopenharmony_ci{
28618c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(bus);
28628c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *pe;
28638c2ecf20Sopenharmony_ci
28648c2ecf20Sopenharmony_ci	list_for_each_entry(pe, &phb->ioda.pe_list, list) {
28658c2ecf20Sopenharmony_ci		if (!(pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL)))
28668c2ecf20Sopenharmony_ci			continue;
28678c2ecf20Sopenharmony_ci
28688c2ecf20Sopenharmony_ci		if (!pe->pbus)
28698c2ecf20Sopenharmony_ci			continue;
28708c2ecf20Sopenharmony_ci
28718c2ecf20Sopenharmony_ci		if (bus->number == ((pe->rid >> 8) & 0xFF)) {
28728c2ecf20Sopenharmony_ci			pe->pbus = bus;
28738c2ecf20Sopenharmony_ci			break;
28748c2ecf20Sopenharmony_ci		}
28758c2ecf20Sopenharmony_ci	}
28768c2ecf20Sopenharmony_ci}
28778c2ecf20Sopenharmony_ci
28788c2ecf20Sopenharmony_cistatic const struct pci_controller_ops pnv_pci_ioda_controller_ops = {
28798c2ecf20Sopenharmony_ci	.dma_dev_setup		= pnv_pci_ioda_dma_dev_setup,
28808c2ecf20Sopenharmony_ci	.dma_bus_setup		= pnv_pci_ioda_dma_bus_setup,
28818c2ecf20Sopenharmony_ci	.iommu_bypass_supported	= pnv_pci_ioda_iommu_bypass_supported,
28828c2ecf20Sopenharmony_ci	.setup_msi_irqs		= pnv_setup_msi_irqs,
28838c2ecf20Sopenharmony_ci	.teardown_msi_irqs	= pnv_teardown_msi_irqs,
28848c2ecf20Sopenharmony_ci	.enable_device_hook	= pnv_pci_enable_device_hook,
28858c2ecf20Sopenharmony_ci	.release_device		= pnv_pci_release_device,
28868c2ecf20Sopenharmony_ci	.window_alignment	= pnv_pci_window_alignment,
28878c2ecf20Sopenharmony_ci	.setup_bridge		= pnv_pci_fixup_bridge_resources,
28888c2ecf20Sopenharmony_ci	.reset_secondary_bus	= pnv_pci_reset_secondary_bus,
28898c2ecf20Sopenharmony_ci	.shutdown		= pnv_pci_ioda_shutdown,
28908c2ecf20Sopenharmony_ci};
28918c2ecf20Sopenharmony_ci
28928c2ecf20Sopenharmony_cistatic const struct pci_controller_ops pnv_npu_ioda_controller_ops = {
28938c2ecf20Sopenharmony_ci	.setup_msi_irqs		= pnv_setup_msi_irqs,
28948c2ecf20Sopenharmony_ci	.teardown_msi_irqs	= pnv_teardown_msi_irqs,
28958c2ecf20Sopenharmony_ci	.enable_device_hook	= pnv_pci_enable_device_hook,
28968c2ecf20Sopenharmony_ci	.window_alignment	= pnv_pci_window_alignment,
28978c2ecf20Sopenharmony_ci	.reset_secondary_bus	= pnv_pci_reset_secondary_bus,
28988c2ecf20Sopenharmony_ci	.shutdown		= pnv_pci_ioda_shutdown,
28998c2ecf20Sopenharmony_ci	.disable_device		= pnv_npu_disable_device,
29008c2ecf20Sopenharmony_ci};
29018c2ecf20Sopenharmony_ci
29028c2ecf20Sopenharmony_cistatic const struct pci_controller_ops pnv_npu_ocapi_ioda_controller_ops = {
29038c2ecf20Sopenharmony_ci	.enable_device_hook	= pnv_ocapi_enable_device_hook,
29048c2ecf20Sopenharmony_ci	.release_device		= pnv_pci_release_device,
29058c2ecf20Sopenharmony_ci	.window_alignment	= pnv_pci_window_alignment,
29068c2ecf20Sopenharmony_ci	.reset_secondary_bus	= pnv_pci_reset_secondary_bus,
29078c2ecf20Sopenharmony_ci	.shutdown		= pnv_pci_ioda_shutdown,
29088c2ecf20Sopenharmony_ci};
29098c2ecf20Sopenharmony_ci
29108c2ecf20Sopenharmony_cistatic void __init pnv_pci_init_ioda_phb(struct device_node *np,
29118c2ecf20Sopenharmony_ci					 u64 hub_id, int ioda_type)
29128c2ecf20Sopenharmony_ci{
29138c2ecf20Sopenharmony_ci	struct pci_controller *hose;
29148c2ecf20Sopenharmony_ci	struct pnv_phb *phb;
29158c2ecf20Sopenharmony_ci	unsigned long size, m64map_off, m32map_off, pemap_off;
29168c2ecf20Sopenharmony_ci	unsigned long iomap_off = 0, dma32map_off = 0;
29178c2ecf20Sopenharmony_ci	struct pnv_ioda_pe *root_pe;
29188c2ecf20Sopenharmony_ci	struct resource r;
29198c2ecf20Sopenharmony_ci	const __be64 *prop64;
29208c2ecf20Sopenharmony_ci	const __be32 *prop32;
29218c2ecf20Sopenharmony_ci	int len;
29228c2ecf20Sopenharmony_ci	unsigned int segno;
29238c2ecf20Sopenharmony_ci	u64 phb_id;
29248c2ecf20Sopenharmony_ci	void *aux;
29258c2ecf20Sopenharmony_ci	long rc;
29268c2ecf20Sopenharmony_ci
29278c2ecf20Sopenharmony_ci	if (!of_device_is_available(np))
29288c2ecf20Sopenharmony_ci		return;
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_ci	pr_info("Initializing %s PHB (%pOF)\n",	pnv_phb_names[ioda_type], np);
29318c2ecf20Sopenharmony_ci
29328c2ecf20Sopenharmony_ci	prop64 = of_get_property(np, "ibm,opal-phbid", NULL);
29338c2ecf20Sopenharmony_ci	if (!prop64) {
29348c2ecf20Sopenharmony_ci		pr_err("  Missing \"ibm,opal-phbid\" property !\n");
29358c2ecf20Sopenharmony_ci		return;
29368c2ecf20Sopenharmony_ci	}
29378c2ecf20Sopenharmony_ci	phb_id = be64_to_cpup(prop64);
29388c2ecf20Sopenharmony_ci	pr_debug("  PHB-ID  : 0x%016llx\n", phb_id);
29398c2ecf20Sopenharmony_ci
29408c2ecf20Sopenharmony_ci	phb = memblock_alloc(sizeof(*phb), SMP_CACHE_BYTES);
29418c2ecf20Sopenharmony_ci	if (!phb)
29428c2ecf20Sopenharmony_ci		panic("%s: Failed to allocate %zu bytes\n", __func__,
29438c2ecf20Sopenharmony_ci		      sizeof(*phb));
29448c2ecf20Sopenharmony_ci
29458c2ecf20Sopenharmony_ci	/* Allocate PCI controller */
29468c2ecf20Sopenharmony_ci	phb->hose = hose = pcibios_alloc_controller(np);
29478c2ecf20Sopenharmony_ci	if (!phb->hose) {
29488c2ecf20Sopenharmony_ci		pr_err("  Can't allocate PCI controller for %pOF\n",
29498c2ecf20Sopenharmony_ci		       np);
29508c2ecf20Sopenharmony_ci		memblock_free(__pa(phb), sizeof(struct pnv_phb));
29518c2ecf20Sopenharmony_ci		return;
29528c2ecf20Sopenharmony_ci	}
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_ci	spin_lock_init(&phb->lock);
29558c2ecf20Sopenharmony_ci	prop32 = of_get_property(np, "bus-range", &len);
29568c2ecf20Sopenharmony_ci	if (prop32 && len == 8) {
29578c2ecf20Sopenharmony_ci		hose->first_busno = be32_to_cpu(prop32[0]);
29588c2ecf20Sopenharmony_ci		hose->last_busno = be32_to_cpu(prop32[1]);
29598c2ecf20Sopenharmony_ci	} else {
29608c2ecf20Sopenharmony_ci		pr_warn("  Broken <bus-range> on %pOF\n", np);
29618c2ecf20Sopenharmony_ci		hose->first_busno = 0;
29628c2ecf20Sopenharmony_ci		hose->last_busno = 0xff;
29638c2ecf20Sopenharmony_ci	}
29648c2ecf20Sopenharmony_ci	hose->private_data = phb;
29658c2ecf20Sopenharmony_ci	phb->hub_id = hub_id;
29668c2ecf20Sopenharmony_ci	phb->opal_id = phb_id;
29678c2ecf20Sopenharmony_ci	phb->type = ioda_type;
29688c2ecf20Sopenharmony_ci	mutex_init(&phb->ioda.pe_alloc_mutex);
29698c2ecf20Sopenharmony_ci
29708c2ecf20Sopenharmony_ci	/* Detect specific models for error handling */
29718c2ecf20Sopenharmony_ci	if (of_device_is_compatible(np, "ibm,p7ioc-pciex"))
29728c2ecf20Sopenharmony_ci		phb->model = PNV_PHB_MODEL_P7IOC;
29738c2ecf20Sopenharmony_ci	else if (of_device_is_compatible(np, "ibm,power8-pciex"))
29748c2ecf20Sopenharmony_ci		phb->model = PNV_PHB_MODEL_PHB3;
29758c2ecf20Sopenharmony_ci	else if (of_device_is_compatible(np, "ibm,power8-npu-pciex"))
29768c2ecf20Sopenharmony_ci		phb->model = PNV_PHB_MODEL_NPU;
29778c2ecf20Sopenharmony_ci	else if (of_device_is_compatible(np, "ibm,power9-npu-pciex"))
29788c2ecf20Sopenharmony_ci		phb->model = PNV_PHB_MODEL_NPU2;
29798c2ecf20Sopenharmony_ci	else
29808c2ecf20Sopenharmony_ci		phb->model = PNV_PHB_MODEL_UNKNOWN;
29818c2ecf20Sopenharmony_ci
29828c2ecf20Sopenharmony_ci	/* Initialize diagnostic data buffer */
29838c2ecf20Sopenharmony_ci	prop32 = of_get_property(np, "ibm,phb-diag-data-size", NULL);
29848c2ecf20Sopenharmony_ci	if (prop32)
29858c2ecf20Sopenharmony_ci		phb->diag_data_size = be32_to_cpup(prop32);
29868c2ecf20Sopenharmony_ci	else
29878c2ecf20Sopenharmony_ci		phb->diag_data_size = PNV_PCI_DIAG_BUF_SIZE;
29888c2ecf20Sopenharmony_ci
29898c2ecf20Sopenharmony_ci	phb->diag_data = memblock_alloc(phb->diag_data_size, SMP_CACHE_BYTES);
29908c2ecf20Sopenharmony_ci	if (!phb->diag_data)
29918c2ecf20Sopenharmony_ci		panic("%s: Failed to allocate %u bytes\n", __func__,
29928c2ecf20Sopenharmony_ci		      phb->diag_data_size);
29938c2ecf20Sopenharmony_ci
29948c2ecf20Sopenharmony_ci	/* Parse 32-bit and IO ranges (if any) */
29958c2ecf20Sopenharmony_ci	pci_process_bridge_OF_ranges(hose, np, !hose->global_number);
29968c2ecf20Sopenharmony_ci
29978c2ecf20Sopenharmony_ci	/* Get registers */
29988c2ecf20Sopenharmony_ci	if (!of_address_to_resource(np, 0, &r)) {
29998c2ecf20Sopenharmony_ci		phb->regs_phys = r.start;
30008c2ecf20Sopenharmony_ci		phb->regs = ioremap(r.start, resource_size(&r));
30018c2ecf20Sopenharmony_ci		if (phb->regs == NULL)
30028c2ecf20Sopenharmony_ci			pr_err("  Failed to map registers !\n");
30038c2ecf20Sopenharmony_ci	}
30048c2ecf20Sopenharmony_ci
30058c2ecf20Sopenharmony_ci	/* Initialize more IODA stuff */
30068c2ecf20Sopenharmony_ci	phb->ioda.total_pe_num = 1;
30078c2ecf20Sopenharmony_ci	prop32 = of_get_property(np, "ibm,opal-num-pes", NULL);
30088c2ecf20Sopenharmony_ci	if (prop32)
30098c2ecf20Sopenharmony_ci		phb->ioda.total_pe_num = be32_to_cpup(prop32);
30108c2ecf20Sopenharmony_ci	prop32 = of_get_property(np, "ibm,opal-reserved-pe", NULL);
30118c2ecf20Sopenharmony_ci	if (prop32)
30128c2ecf20Sopenharmony_ci		phb->ioda.reserved_pe_idx = be32_to_cpup(prop32);
30138c2ecf20Sopenharmony_ci
30148c2ecf20Sopenharmony_ci	/* Invalidate RID to PE# mapping */
30158c2ecf20Sopenharmony_ci	for (segno = 0; segno < ARRAY_SIZE(phb->ioda.pe_rmap); segno++)
30168c2ecf20Sopenharmony_ci		phb->ioda.pe_rmap[segno] = IODA_INVALID_PE;
30178c2ecf20Sopenharmony_ci
30188c2ecf20Sopenharmony_ci	/* Parse 64-bit MMIO range */
30198c2ecf20Sopenharmony_ci	pnv_ioda_parse_m64_window(phb);
30208c2ecf20Sopenharmony_ci
30218c2ecf20Sopenharmony_ci	phb->ioda.m32_size = resource_size(&hose->mem_resources[0]);
30228c2ecf20Sopenharmony_ci	/* FW Has already off top 64k of M32 space (MSI space) */
30238c2ecf20Sopenharmony_ci	phb->ioda.m32_size += 0x10000;
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	phb->ioda.m32_segsize = phb->ioda.m32_size / phb->ioda.total_pe_num;
30268c2ecf20Sopenharmony_ci	phb->ioda.m32_pci_base = hose->mem_resources[0].start - hose->mem_offset[0];
30278c2ecf20Sopenharmony_ci	phb->ioda.io_size = hose->pci_io_size;
30288c2ecf20Sopenharmony_ci	phb->ioda.io_segsize = phb->ioda.io_size / phb->ioda.total_pe_num;
30298c2ecf20Sopenharmony_ci	phb->ioda.io_pci_base = 0; /* XXX calculate this ? */
30308c2ecf20Sopenharmony_ci
30318c2ecf20Sopenharmony_ci	/* Calculate how many 32-bit TCE segments we have */
30328c2ecf20Sopenharmony_ci	phb->ioda.dma32_count = phb->ioda.m32_pci_base /
30338c2ecf20Sopenharmony_ci				PNV_IODA1_DMA32_SEGSIZE;
30348c2ecf20Sopenharmony_ci
30358c2ecf20Sopenharmony_ci	/* Allocate aux data & arrays. We don't have IO ports on PHB3 */
30368c2ecf20Sopenharmony_ci	size = ALIGN(max_t(unsigned, phb->ioda.total_pe_num, 8) / 8,
30378c2ecf20Sopenharmony_ci			sizeof(unsigned long));
30388c2ecf20Sopenharmony_ci	m64map_off = size;
30398c2ecf20Sopenharmony_ci	size += phb->ioda.total_pe_num * sizeof(phb->ioda.m64_segmap[0]);
30408c2ecf20Sopenharmony_ci	m32map_off = size;
30418c2ecf20Sopenharmony_ci	size += phb->ioda.total_pe_num * sizeof(phb->ioda.m32_segmap[0]);
30428c2ecf20Sopenharmony_ci	if (phb->type == PNV_PHB_IODA1) {
30438c2ecf20Sopenharmony_ci		iomap_off = size;
30448c2ecf20Sopenharmony_ci		size += phb->ioda.total_pe_num * sizeof(phb->ioda.io_segmap[0]);
30458c2ecf20Sopenharmony_ci		dma32map_off = size;
30468c2ecf20Sopenharmony_ci		size += phb->ioda.dma32_count *
30478c2ecf20Sopenharmony_ci			sizeof(phb->ioda.dma32_segmap[0]);
30488c2ecf20Sopenharmony_ci	}
30498c2ecf20Sopenharmony_ci	pemap_off = size;
30508c2ecf20Sopenharmony_ci	size += phb->ioda.total_pe_num * sizeof(struct pnv_ioda_pe);
30518c2ecf20Sopenharmony_ci	aux = memblock_alloc(size, SMP_CACHE_BYTES);
30528c2ecf20Sopenharmony_ci	if (!aux)
30538c2ecf20Sopenharmony_ci		panic("%s: Failed to allocate %lu bytes\n", __func__, size);
30548c2ecf20Sopenharmony_ci	phb->ioda.pe_alloc = aux;
30558c2ecf20Sopenharmony_ci	phb->ioda.m64_segmap = aux + m64map_off;
30568c2ecf20Sopenharmony_ci	phb->ioda.m32_segmap = aux + m32map_off;
30578c2ecf20Sopenharmony_ci	for (segno = 0; segno < phb->ioda.total_pe_num; segno++) {
30588c2ecf20Sopenharmony_ci		phb->ioda.m64_segmap[segno] = IODA_INVALID_PE;
30598c2ecf20Sopenharmony_ci		phb->ioda.m32_segmap[segno] = IODA_INVALID_PE;
30608c2ecf20Sopenharmony_ci	}
30618c2ecf20Sopenharmony_ci	if (phb->type == PNV_PHB_IODA1) {
30628c2ecf20Sopenharmony_ci		phb->ioda.io_segmap = aux + iomap_off;
30638c2ecf20Sopenharmony_ci		for (segno = 0; segno < phb->ioda.total_pe_num; segno++)
30648c2ecf20Sopenharmony_ci			phb->ioda.io_segmap[segno] = IODA_INVALID_PE;
30658c2ecf20Sopenharmony_ci
30668c2ecf20Sopenharmony_ci		phb->ioda.dma32_segmap = aux + dma32map_off;
30678c2ecf20Sopenharmony_ci		for (segno = 0; segno < phb->ioda.dma32_count; segno++)
30688c2ecf20Sopenharmony_ci			phb->ioda.dma32_segmap[segno] = IODA_INVALID_PE;
30698c2ecf20Sopenharmony_ci	}
30708c2ecf20Sopenharmony_ci	phb->ioda.pe_array = aux + pemap_off;
30718c2ecf20Sopenharmony_ci
30728c2ecf20Sopenharmony_ci	/*
30738c2ecf20Sopenharmony_ci	 * Choose PE number for root bus, which shouldn't have
30748c2ecf20Sopenharmony_ci	 * M64 resources consumed by its child devices. To pick
30758c2ecf20Sopenharmony_ci	 * the PE number adjacent to the reserved one if possible.
30768c2ecf20Sopenharmony_ci	 */
30778c2ecf20Sopenharmony_ci	pnv_ioda_reserve_pe(phb, phb->ioda.reserved_pe_idx);
30788c2ecf20Sopenharmony_ci	if (phb->ioda.reserved_pe_idx == 0) {
30798c2ecf20Sopenharmony_ci		phb->ioda.root_pe_idx = 1;
30808c2ecf20Sopenharmony_ci		pnv_ioda_reserve_pe(phb, phb->ioda.root_pe_idx);
30818c2ecf20Sopenharmony_ci	} else if (phb->ioda.reserved_pe_idx == (phb->ioda.total_pe_num - 1)) {
30828c2ecf20Sopenharmony_ci		phb->ioda.root_pe_idx = phb->ioda.reserved_pe_idx - 1;
30838c2ecf20Sopenharmony_ci		pnv_ioda_reserve_pe(phb, phb->ioda.root_pe_idx);
30848c2ecf20Sopenharmony_ci	} else {
30858c2ecf20Sopenharmony_ci		/* otherwise just allocate one */
30868c2ecf20Sopenharmony_ci		root_pe = pnv_ioda_alloc_pe(phb, 1);
30878c2ecf20Sopenharmony_ci		phb->ioda.root_pe_idx = root_pe->pe_number;
30888c2ecf20Sopenharmony_ci	}
30898c2ecf20Sopenharmony_ci
30908c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&phb->ioda.pe_list);
30918c2ecf20Sopenharmony_ci	mutex_init(&phb->ioda.pe_list_mutex);
30928c2ecf20Sopenharmony_ci
30938c2ecf20Sopenharmony_ci	/* Calculate how many 32-bit TCE segments we have */
30948c2ecf20Sopenharmony_ci	phb->ioda.dma32_count = phb->ioda.m32_pci_base /
30958c2ecf20Sopenharmony_ci				PNV_IODA1_DMA32_SEGSIZE;
30968c2ecf20Sopenharmony_ci
30978c2ecf20Sopenharmony_ci#if 0 /* We should really do that ... */
30988c2ecf20Sopenharmony_ci	rc = opal_pci_set_phb_mem_window(opal->phb_id,
30998c2ecf20Sopenharmony_ci					 window_type,
31008c2ecf20Sopenharmony_ci					 window_num,
31018c2ecf20Sopenharmony_ci					 starting_real_address,
31028c2ecf20Sopenharmony_ci					 starting_pci_address,
31038c2ecf20Sopenharmony_ci					 segment_size);
31048c2ecf20Sopenharmony_ci#endif
31058c2ecf20Sopenharmony_ci
31068c2ecf20Sopenharmony_ci	pr_info("  %03d (%03d) PE's M32: 0x%x [segment=0x%x]\n",
31078c2ecf20Sopenharmony_ci		phb->ioda.total_pe_num, phb->ioda.reserved_pe_idx,
31088c2ecf20Sopenharmony_ci		phb->ioda.m32_size, phb->ioda.m32_segsize);
31098c2ecf20Sopenharmony_ci	if (phb->ioda.m64_size)
31108c2ecf20Sopenharmony_ci		pr_info("                 M64: 0x%lx [segment=0x%lx]\n",
31118c2ecf20Sopenharmony_ci			phb->ioda.m64_size, phb->ioda.m64_segsize);
31128c2ecf20Sopenharmony_ci	if (phb->ioda.io_size)
31138c2ecf20Sopenharmony_ci		pr_info("                  IO: 0x%x [segment=0x%x]\n",
31148c2ecf20Sopenharmony_ci			phb->ioda.io_size, phb->ioda.io_segsize);
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci
31178c2ecf20Sopenharmony_ci	phb->hose->ops = &pnv_pci_ops;
31188c2ecf20Sopenharmony_ci	phb->get_pe_state = pnv_ioda_get_pe_state;
31198c2ecf20Sopenharmony_ci	phb->freeze_pe = pnv_ioda_freeze_pe;
31208c2ecf20Sopenharmony_ci	phb->unfreeze_pe = pnv_ioda_unfreeze_pe;
31218c2ecf20Sopenharmony_ci
31228c2ecf20Sopenharmony_ci	/* Setup MSI support */
31238c2ecf20Sopenharmony_ci	pnv_pci_init_ioda_msis(phb);
31248c2ecf20Sopenharmony_ci
31258c2ecf20Sopenharmony_ci	/*
31268c2ecf20Sopenharmony_ci	 * We pass the PCI probe flag PCI_REASSIGN_ALL_RSRC here
31278c2ecf20Sopenharmony_ci	 * to let the PCI core do resource assignment. It's supposed
31288c2ecf20Sopenharmony_ci	 * that the PCI core will do correct I/O and MMIO alignment
31298c2ecf20Sopenharmony_ci	 * for the P2P bridge bars so that each PCI bus (excluding
31308c2ecf20Sopenharmony_ci	 * the child P2P bridges) can form individual PE.
31318c2ecf20Sopenharmony_ci	 */
31328c2ecf20Sopenharmony_ci	ppc_md.pcibios_fixup = pnv_pci_ioda_fixup;
31338c2ecf20Sopenharmony_ci
31348c2ecf20Sopenharmony_ci	switch (phb->type) {
31358c2ecf20Sopenharmony_ci	case PNV_PHB_NPU_NVLINK:
31368c2ecf20Sopenharmony_ci		hose->controller_ops = pnv_npu_ioda_controller_ops;
31378c2ecf20Sopenharmony_ci		break;
31388c2ecf20Sopenharmony_ci	case PNV_PHB_NPU_OCAPI:
31398c2ecf20Sopenharmony_ci		hose->controller_ops = pnv_npu_ocapi_ioda_controller_ops;
31408c2ecf20Sopenharmony_ci		break;
31418c2ecf20Sopenharmony_ci	default:
31428c2ecf20Sopenharmony_ci		hose->controller_ops = pnv_pci_ioda_controller_ops;
31438c2ecf20Sopenharmony_ci	}
31448c2ecf20Sopenharmony_ci
31458c2ecf20Sopenharmony_ci	ppc_md.pcibios_default_alignment = pnv_pci_default_alignment;
31468c2ecf20Sopenharmony_ci
31478c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV
31488c2ecf20Sopenharmony_ci	ppc_md.pcibios_fixup_sriov = pnv_pci_ioda_fixup_iov;
31498c2ecf20Sopenharmony_ci	ppc_md.pcibios_iov_resource_alignment = pnv_pci_iov_resource_alignment;
31508c2ecf20Sopenharmony_ci	ppc_md.pcibios_sriov_enable = pnv_pcibios_sriov_enable;
31518c2ecf20Sopenharmony_ci	ppc_md.pcibios_sriov_disable = pnv_pcibios_sriov_disable;
31528c2ecf20Sopenharmony_ci#endif
31538c2ecf20Sopenharmony_ci
31548c2ecf20Sopenharmony_ci	pci_add_flags(PCI_REASSIGN_ALL_RSRC);
31558c2ecf20Sopenharmony_ci
31568c2ecf20Sopenharmony_ci	/* Reset IODA tables to a clean state */
31578c2ecf20Sopenharmony_ci	rc = opal_pci_reset(phb_id, OPAL_RESET_PCI_IODA_TABLE, OPAL_ASSERT_RESET);
31588c2ecf20Sopenharmony_ci	if (rc)
31598c2ecf20Sopenharmony_ci		pr_warn("  OPAL Error %ld performing IODA table reset !\n", rc);
31608c2ecf20Sopenharmony_ci
31618c2ecf20Sopenharmony_ci	/*
31628c2ecf20Sopenharmony_ci	 * If we're running in kdump kernel, the previous kernel never
31638c2ecf20Sopenharmony_ci	 * shutdown PCI devices correctly. We already got IODA table
31648c2ecf20Sopenharmony_ci	 * cleaned out. So we have to issue PHB reset to stop all PCI
31658c2ecf20Sopenharmony_ci	 * transactions from previous kernel. The ppc_pci_reset_phbs
31668c2ecf20Sopenharmony_ci	 * kernel parameter will force this reset too. Additionally,
31678c2ecf20Sopenharmony_ci	 * if the IODA reset above failed then use a bigger hammer.
31688c2ecf20Sopenharmony_ci	 * This can happen if we get a PHB fatal error in very early
31698c2ecf20Sopenharmony_ci	 * boot.
31708c2ecf20Sopenharmony_ci	 */
31718c2ecf20Sopenharmony_ci	if (is_kdump_kernel() || pci_reset_phbs || rc) {
31728c2ecf20Sopenharmony_ci		pr_info("  Issue PHB reset ...\n");
31738c2ecf20Sopenharmony_ci		pnv_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL);
31748c2ecf20Sopenharmony_ci		pnv_eeh_phb_reset(hose, EEH_RESET_DEACTIVATE);
31758c2ecf20Sopenharmony_ci	}
31768c2ecf20Sopenharmony_ci
31778c2ecf20Sopenharmony_ci	/* Remove M64 resource if we can't configure it successfully */
31788c2ecf20Sopenharmony_ci	if (!phb->init_m64 || phb->init_m64(phb))
31798c2ecf20Sopenharmony_ci		hose->mem_resources[1].flags = 0;
31808c2ecf20Sopenharmony_ci}
31818c2ecf20Sopenharmony_ci
31828c2ecf20Sopenharmony_civoid __init pnv_pci_init_ioda2_phb(struct device_node *np)
31838c2ecf20Sopenharmony_ci{
31848c2ecf20Sopenharmony_ci	pnv_pci_init_ioda_phb(np, 0, PNV_PHB_IODA2);
31858c2ecf20Sopenharmony_ci}
31868c2ecf20Sopenharmony_ci
31878c2ecf20Sopenharmony_civoid __init pnv_pci_init_npu_phb(struct device_node *np)
31888c2ecf20Sopenharmony_ci{
31898c2ecf20Sopenharmony_ci	pnv_pci_init_ioda_phb(np, 0, PNV_PHB_NPU_NVLINK);
31908c2ecf20Sopenharmony_ci}
31918c2ecf20Sopenharmony_ci
31928c2ecf20Sopenharmony_civoid __init pnv_pci_init_npu2_opencapi_phb(struct device_node *np)
31938c2ecf20Sopenharmony_ci{
31948c2ecf20Sopenharmony_ci	pnv_pci_init_ioda_phb(np, 0, PNV_PHB_NPU_OCAPI);
31958c2ecf20Sopenharmony_ci}
31968c2ecf20Sopenharmony_ci
31978c2ecf20Sopenharmony_cistatic void pnv_npu2_opencapi_cfg_size_fixup(struct pci_dev *dev)
31988c2ecf20Sopenharmony_ci{
31998c2ecf20Sopenharmony_ci	struct pnv_phb *phb = pci_bus_to_pnvhb(dev->bus);
32008c2ecf20Sopenharmony_ci
32018c2ecf20Sopenharmony_ci	if (!machine_is(powernv))
32028c2ecf20Sopenharmony_ci		return;
32038c2ecf20Sopenharmony_ci
32048c2ecf20Sopenharmony_ci	if (phb->type == PNV_PHB_NPU_OCAPI)
32058c2ecf20Sopenharmony_ci		dev->cfg_size = PCI_CFG_SPACE_EXP_SIZE;
32068c2ecf20Sopenharmony_ci}
32078c2ecf20Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, pnv_npu2_opencapi_cfg_size_fixup);
32088c2ecf20Sopenharmony_ci
32098c2ecf20Sopenharmony_civoid __init pnv_pci_init_ioda_hub(struct device_node *np)
32108c2ecf20Sopenharmony_ci{
32118c2ecf20Sopenharmony_ci	struct device_node *phbn;
32128c2ecf20Sopenharmony_ci	const __be64 *prop64;
32138c2ecf20Sopenharmony_ci	u64 hub_id;
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci	pr_info("Probing IODA IO-Hub %pOF\n", np);
32168c2ecf20Sopenharmony_ci
32178c2ecf20Sopenharmony_ci	prop64 = of_get_property(np, "ibm,opal-hubid", NULL);
32188c2ecf20Sopenharmony_ci	if (!prop64) {
32198c2ecf20Sopenharmony_ci		pr_err(" Missing \"ibm,opal-hubid\" property !\n");
32208c2ecf20Sopenharmony_ci		return;
32218c2ecf20Sopenharmony_ci	}
32228c2ecf20Sopenharmony_ci	hub_id = be64_to_cpup(prop64);
32238c2ecf20Sopenharmony_ci	pr_devel(" HUB-ID : 0x%016llx\n", hub_id);
32248c2ecf20Sopenharmony_ci
32258c2ecf20Sopenharmony_ci	/* Count child PHBs */
32268c2ecf20Sopenharmony_ci	for_each_child_of_node(np, phbn) {
32278c2ecf20Sopenharmony_ci		/* Look for IODA1 PHBs */
32288c2ecf20Sopenharmony_ci		if (of_device_is_compatible(phbn, "ibm,ioda-phb"))
32298c2ecf20Sopenharmony_ci			pnv_pci_init_ioda_phb(phbn, hub_id, PNV_PHB_IODA1);
32308c2ecf20Sopenharmony_ci	}
32318c2ecf20Sopenharmony_ci}
3232