18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2012
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author(s):
68c2ecf20Sopenharmony_ci *   Jan Glauber <jang@linux.vnet.ibm.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * The System z PCI code is a rewrite from a prototype by
98c2ecf20Sopenharmony_ci * the following people (Kudoz!):
108c2ecf20Sopenharmony_ci *   Alexander Schmidt
118c2ecf20Sopenharmony_ci *   Christoph Raisch
128c2ecf20Sopenharmony_ci *   Hannes Hering
138c2ecf20Sopenharmony_ci *   Hoang-Nam Nguyen
148c2ecf20Sopenharmony_ci *   Jan-Bernd Themann
158c2ecf20Sopenharmony_ci *   Stefan Roscher
168c2ecf20Sopenharmony_ci *   Thomas Klein
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "zpci"
208c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <linux/kernel.h>
238c2ecf20Sopenharmony_ci#include <linux/slab.h>
248c2ecf20Sopenharmony_ci#include <linux/err.h>
258c2ecf20Sopenharmony_ci#include <linux/export.h>
268c2ecf20Sopenharmony_ci#include <linux/delay.h>
278c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
288c2ecf20Sopenharmony_ci#include <linux/jump_label.h>
298c2ecf20Sopenharmony_ci#include <linux/pci.h>
308c2ecf20Sopenharmony_ci#include <linux/printk.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include <asm/isc.h>
338c2ecf20Sopenharmony_ci#include <asm/airq.h>
348c2ecf20Sopenharmony_ci#include <asm/facility.h>
358c2ecf20Sopenharmony_ci#include <asm/pci_insn.h>
368c2ecf20Sopenharmony_ci#include <asm/pci_clp.h>
378c2ecf20Sopenharmony_ci#include <asm/pci_dma.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#include "pci_bus.h"
408c2ecf20Sopenharmony_ci#include "pci_iov.h"
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* list of all detected zpci devices */
438c2ecf20Sopenharmony_cistatic LIST_HEAD(zpci_list);
448c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(zpci_list_lock);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic DECLARE_BITMAP(zpci_domain, ZPCI_DOMAIN_BITMAP_SIZE);
478c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(zpci_domain_lock);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define ZPCI_IOMAP_ENTRIES						\
508c2ecf20Sopenharmony_ci	min(((unsigned long) ZPCI_NR_DEVICES * PCI_STD_NUM_BARS / 2),	\
518c2ecf20Sopenharmony_ci	    ZPCI_IOMAP_MAX_ENTRIES)
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ciunsigned int s390_pci_no_rid;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(zpci_iomap_lock);
568c2ecf20Sopenharmony_cistatic unsigned long *zpci_iomap_bitmap;
578c2ecf20Sopenharmony_cistruct zpci_iomap_entry *zpci_iomap_start;
588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(zpci_iomap_start);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ciDEFINE_STATIC_KEY_FALSE(have_mio);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic struct kmem_cache *zdev_fmb_cache;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistruct zpci_dev *get_zdev_by_fid(u32 fid)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct zpci_dev *tmp, *zdev = NULL;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	spin_lock(&zpci_list_lock);
698c2ecf20Sopenharmony_ci	list_for_each_entry(tmp, &zpci_list, entry) {
708c2ecf20Sopenharmony_ci		if (tmp->fid == fid) {
718c2ecf20Sopenharmony_ci			zdev = tmp;
728c2ecf20Sopenharmony_ci			zpci_zdev_get(zdev);
738c2ecf20Sopenharmony_ci			break;
748c2ecf20Sopenharmony_ci		}
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci	spin_unlock(&zpci_list_lock);
778c2ecf20Sopenharmony_ci	return zdev;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_civoid zpci_remove_reserved_devices(void)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct zpci_dev *tmp, *zdev;
838c2ecf20Sopenharmony_ci	enum zpci_state state;
848c2ecf20Sopenharmony_ci	LIST_HEAD(remove);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	spin_lock(&zpci_list_lock);
878c2ecf20Sopenharmony_ci	list_for_each_entry_safe(zdev, tmp, &zpci_list, entry) {
888c2ecf20Sopenharmony_ci		if (zdev->state == ZPCI_FN_STATE_STANDBY &&
898c2ecf20Sopenharmony_ci		    !clp_get_state(zdev->fid, &state) &&
908c2ecf20Sopenharmony_ci		    state == ZPCI_FN_STATE_RESERVED)
918c2ecf20Sopenharmony_ci			list_move_tail(&zdev->entry, &remove);
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci	spin_unlock(&zpci_list_lock);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	list_for_each_entry_safe(zdev, tmp, &remove, entry)
968c2ecf20Sopenharmony_ci		zpci_device_reserved(zdev);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciint pci_domain_nr(struct pci_bus *bus)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	return ((struct zpci_bus *) bus->sysdata)->domain_nr;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_domain_nr);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ciint pci_proc_domain(struct pci_bus *bus)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	return pci_domain_nr(bus);
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_proc_domain);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/* Modify PCI: Register I/O address translation parameters */
1128c2ecf20Sopenharmony_ciint zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas,
1138c2ecf20Sopenharmony_ci		       u64 base, u64 limit, u64 iota)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	u64 req = ZPCI_CREATE_REQ(zdev->fh, dmaas, ZPCI_MOD_FC_REG_IOAT);
1168c2ecf20Sopenharmony_ci	struct zpci_fib fib = {0};
1178c2ecf20Sopenharmony_ci	u8 status;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	WARN_ON_ONCE(iota & 0x3fff);
1208c2ecf20Sopenharmony_ci	fib.pba = base;
1218c2ecf20Sopenharmony_ci	fib.pal = limit;
1228c2ecf20Sopenharmony_ci	fib.iota = iota | ZPCI_IOTA_RTTO_FLAG;
1238c2ecf20Sopenharmony_ci	return zpci_mod_fc(req, &fib, &status) ? -EIO : 0;
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci/* Modify PCI: Unregister I/O address translation parameters */
1278c2ecf20Sopenharmony_ciint zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	u64 req = ZPCI_CREATE_REQ(zdev->fh, dmaas, ZPCI_MOD_FC_DEREG_IOAT);
1308c2ecf20Sopenharmony_ci	struct zpci_fib fib = {0};
1318c2ecf20Sopenharmony_ci	u8 cc, status;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	cc = zpci_mod_fc(req, &fib, &status);
1348c2ecf20Sopenharmony_ci	if (cc == 3) /* Function already gone. */
1358c2ecf20Sopenharmony_ci		cc = 0;
1368c2ecf20Sopenharmony_ci	return cc ? -EIO : 0;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci/* Modify PCI: Set PCI function measurement parameters */
1408c2ecf20Sopenharmony_ciint zpci_fmb_enable_device(struct zpci_dev *zdev)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_SET_MEASURE);
1438c2ecf20Sopenharmony_ci	struct zpci_fib fib = {0};
1448c2ecf20Sopenharmony_ci	u8 cc, status;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	if (zdev->fmb || sizeof(*zdev->fmb) < zdev->fmb_length)
1478c2ecf20Sopenharmony_ci		return -EINVAL;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	zdev->fmb = kmem_cache_zalloc(zdev_fmb_cache, GFP_KERNEL);
1508c2ecf20Sopenharmony_ci	if (!zdev->fmb)
1518c2ecf20Sopenharmony_ci		return -ENOMEM;
1528c2ecf20Sopenharmony_ci	WARN_ON((u64) zdev->fmb & 0xf);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/* reset software counters */
1558c2ecf20Sopenharmony_ci	atomic64_set(&zdev->allocated_pages, 0);
1568c2ecf20Sopenharmony_ci	atomic64_set(&zdev->mapped_pages, 0);
1578c2ecf20Sopenharmony_ci	atomic64_set(&zdev->unmapped_pages, 0);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	fib.fmb_addr = virt_to_phys(zdev->fmb);
1608c2ecf20Sopenharmony_ci	cc = zpci_mod_fc(req, &fib, &status);
1618c2ecf20Sopenharmony_ci	if (cc) {
1628c2ecf20Sopenharmony_ci		kmem_cache_free(zdev_fmb_cache, zdev->fmb);
1638c2ecf20Sopenharmony_ci		zdev->fmb = NULL;
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci	return cc ? -EIO : 0;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci/* Modify PCI: Disable PCI function measurement */
1698c2ecf20Sopenharmony_ciint zpci_fmb_disable_device(struct zpci_dev *zdev)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_SET_MEASURE);
1728c2ecf20Sopenharmony_ci	struct zpci_fib fib = {0};
1738c2ecf20Sopenharmony_ci	u8 cc, status;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (!zdev->fmb)
1768c2ecf20Sopenharmony_ci		return -EINVAL;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	/* Function measurement is disabled if fmb address is zero */
1798c2ecf20Sopenharmony_ci	cc = zpci_mod_fc(req, &fib, &status);
1808c2ecf20Sopenharmony_ci	if (cc == 3) /* Function already gone. */
1818c2ecf20Sopenharmony_ci		cc = 0;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	if (!cc) {
1848c2ecf20Sopenharmony_ci		kmem_cache_free(zdev_fmb_cache, zdev->fmb);
1858c2ecf20Sopenharmony_ci		zdev->fmb = NULL;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci	return cc ? -EIO : 0;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	u64 req = ZPCI_CREATE_REQ(zdev->fh, ZPCI_PCIAS_CFGSPC, len);
1938c2ecf20Sopenharmony_ci	u64 data;
1948c2ecf20Sopenharmony_ci	int rc;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	rc = __zpci_load(&data, req, offset);
1978c2ecf20Sopenharmony_ci	if (!rc) {
1988c2ecf20Sopenharmony_ci		data = le64_to_cpu((__force __le64) data);
1998c2ecf20Sopenharmony_ci		data >>= (8 - len) * 8;
2008c2ecf20Sopenharmony_ci		*val = (u32) data;
2018c2ecf20Sopenharmony_ci	} else
2028c2ecf20Sopenharmony_ci		*val = 0xffffffff;
2038c2ecf20Sopenharmony_ci	return rc;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	u64 req = ZPCI_CREATE_REQ(zdev->fh, ZPCI_PCIAS_CFGSPC, len);
2098c2ecf20Sopenharmony_ci	u64 data = val;
2108c2ecf20Sopenharmony_ci	int rc;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	data <<= (8 - len) * 8;
2138c2ecf20Sopenharmony_ci	data = (__force u64) cpu_to_le64(data);
2148c2ecf20Sopenharmony_ci	rc = __zpci_store(data, req, offset);
2158c2ecf20Sopenharmony_ci	return rc;
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ciresource_size_t pcibios_align_resource(void *data, const struct resource *res,
2198c2ecf20Sopenharmony_ci				       resource_size_t size,
2208c2ecf20Sopenharmony_ci				       resource_size_t align)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	return 0;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci/* combine single writes by using store-block insn */
2268c2ecf20Sopenharmony_civoid __iowrite64_copy(void __iomem *to, const void *from, size_t count)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci       zpci_memcpy_toio(to, from, count);
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic void __iomem *__ioremap(phys_addr_t addr, size_t size, pgprot_t prot)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	unsigned long offset, vaddr;
2348c2ecf20Sopenharmony_ci	struct vm_struct *area;
2358c2ecf20Sopenharmony_ci	phys_addr_t last_addr;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	last_addr = addr + size - 1;
2388c2ecf20Sopenharmony_ci	if (!size || last_addr < addr)
2398c2ecf20Sopenharmony_ci		return NULL;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (!static_branch_unlikely(&have_mio))
2428c2ecf20Sopenharmony_ci		return (void __iomem *) addr;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	offset = addr & ~PAGE_MASK;
2458c2ecf20Sopenharmony_ci	addr &= PAGE_MASK;
2468c2ecf20Sopenharmony_ci	size = PAGE_ALIGN(size + offset);
2478c2ecf20Sopenharmony_ci	area = get_vm_area(size, VM_IOREMAP);
2488c2ecf20Sopenharmony_ci	if (!area)
2498c2ecf20Sopenharmony_ci		return NULL;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	vaddr = (unsigned long) area->addr;
2528c2ecf20Sopenharmony_ci	if (ioremap_page_range(vaddr, vaddr + size, addr, prot)) {
2538c2ecf20Sopenharmony_ci		free_vm_area(area);
2548c2ecf20Sopenharmony_ci		return NULL;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci	return (void __iomem *) ((unsigned long) area->addr + offset);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_civoid __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long prot)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	return __ioremap(addr, size, __pgprot(prot));
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ioremap_prot);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_civoid __iomem *ioremap(phys_addr_t addr, size_t size)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	return __ioremap(addr, size, PAGE_KERNEL);
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ioremap);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_civoid __iomem *ioremap_wc(phys_addr_t addr, size_t size)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	return __ioremap(addr, size, pgprot_writecombine(PAGE_KERNEL));
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ioremap_wc);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_civoid __iomem *ioremap_wt(phys_addr_t addr, size_t size)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	return __ioremap(addr, size, pgprot_writethrough(PAGE_KERNEL));
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ioremap_wt);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_civoid iounmap(volatile void __iomem *addr)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	if (static_branch_likely(&have_mio))
2868c2ecf20Sopenharmony_ci		vunmap((__force void *) ((unsigned long) addr & PAGE_MASK));
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ciEXPORT_SYMBOL(iounmap);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci/* Create a virtual mapping cookie for a PCI BAR */
2918c2ecf20Sopenharmony_cistatic void __iomem *pci_iomap_range_fh(struct pci_dev *pdev, int bar,
2928c2ecf20Sopenharmony_ci					unsigned long offset, unsigned long max)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct zpci_dev *zdev =	to_zpci(pdev);
2958c2ecf20Sopenharmony_ci	int idx;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	idx = zdev->bars[bar].map_idx;
2988c2ecf20Sopenharmony_ci	spin_lock(&zpci_iomap_lock);
2998c2ecf20Sopenharmony_ci	/* Detect overrun */
3008c2ecf20Sopenharmony_ci	WARN_ON(!++zpci_iomap_start[idx].count);
3018c2ecf20Sopenharmony_ci	zpci_iomap_start[idx].fh = zdev->fh;
3028c2ecf20Sopenharmony_ci	zpci_iomap_start[idx].bar = bar;
3038c2ecf20Sopenharmony_ci	spin_unlock(&zpci_iomap_lock);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	return (void __iomem *) ZPCI_ADDR(idx) + offset;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic void __iomem *pci_iomap_range_mio(struct pci_dev *pdev, int bar,
3098c2ecf20Sopenharmony_ci					 unsigned long offset,
3108c2ecf20Sopenharmony_ci					 unsigned long max)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	unsigned long barsize = pci_resource_len(pdev, bar);
3138c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(pdev);
3148c2ecf20Sopenharmony_ci	void __iomem *iova;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	iova = ioremap((unsigned long) zdev->bars[bar].mio_wt, barsize);
3178c2ecf20Sopenharmony_ci	return iova ? iova + offset : iova;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_civoid __iomem *pci_iomap_range(struct pci_dev *pdev, int bar,
3218c2ecf20Sopenharmony_ci			      unsigned long offset, unsigned long max)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	if (bar >= PCI_STD_NUM_BARS || !pci_resource_len(pdev, bar))
3248c2ecf20Sopenharmony_ci		return NULL;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (static_branch_likely(&have_mio))
3278c2ecf20Sopenharmony_ci		return pci_iomap_range_mio(pdev, bar, offset, max);
3288c2ecf20Sopenharmony_ci	else
3298c2ecf20Sopenharmony_ci		return pci_iomap_range_fh(pdev, bar, offset, max);
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_iomap_range);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_civoid __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	return pci_iomap_range(dev, bar, 0, maxlen);
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_iomap);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic void __iomem *pci_iomap_wc_range_mio(struct pci_dev *pdev, int bar,
3408c2ecf20Sopenharmony_ci					    unsigned long offset, unsigned long max)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	unsigned long barsize = pci_resource_len(pdev, bar);
3438c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(pdev);
3448c2ecf20Sopenharmony_ci	void __iomem *iova;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	iova = ioremap((unsigned long) zdev->bars[bar].mio_wb, barsize);
3478c2ecf20Sopenharmony_ci	return iova ? iova + offset : iova;
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_civoid __iomem *pci_iomap_wc_range(struct pci_dev *pdev, int bar,
3518c2ecf20Sopenharmony_ci				 unsigned long offset, unsigned long max)
3528c2ecf20Sopenharmony_ci{
3538c2ecf20Sopenharmony_ci	if (bar >= PCI_STD_NUM_BARS || !pci_resource_len(pdev, bar))
3548c2ecf20Sopenharmony_ci		return NULL;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (static_branch_likely(&have_mio))
3578c2ecf20Sopenharmony_ci		return pci_iomap_wc_range_mio(pdev, bar, offset, max);
3588c2ecf20Sopenharmony_ci	else
3598c2ecf20Sopenharmony_ci		return pci_iomap_range_fh(pdev, bar, offset, max);
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_iomap_wc_range);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_civoid __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long maxlen)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	return pci_iomap_wc_range(dev, bar, 0, maxlen);
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_iomap_wc);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic void pci_iounmap_fh(struct pci_dev *pdev, void __iomem *addr)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	unsigned int idx = ZPCI_IDX(addr);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	spin_lock(&zpci_iomap_lock);
3748c2ecf20Sopenharmony_ci	/* Detect underrun */
3758c2ecf20Sopenharmony_ci	WARN_ON(!zpci_iomap_start[idx].count);
3768c2ecf20Sopenharmony_ci	if (!--zpci_iomap_start[idx].count) {
3778c2ecf20Sopenharmony_ci		zpci_iomap_start[idx].fh = 0;
3788c2ecf20Sopenharmony_ci		zpci_iomap_start[idx].bar = 0;
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci	spin_unlock(&zpci_iomap_lock);
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic void pci_iounmap_mio(struct pci_dev *pdev, void __iomem *addr)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	iounmap(addr);
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_civoid pci_iounmap(struct pci_dev *pdev, void __iomem *addr)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	if (static_branch_likely(&have_mio))
3918c2ecf20Sopenharmony_ci		pci_iounmap_mio(pdev, addr);
3928c2ecf20Sopenharmony_ci	else
3938c2ecf20Sopenharmony_ci		pci_iounmap_fh(pdev, addr);
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_iounmap);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
3988c2ecf20Sopenharmony_ci		    int size, u32 *val)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = get_zdev_by_bus(bus, devfn);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	return (zdev) ? zpci_cfg_load(zdev, where, val, size) : -ENODEV;
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic int pci_write(struct pci_bus *bus, unsigned int devfn, int where,
4068c2ecf20Sopenharmony_ci		     int size, u32 val)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = get_zdev_by_bus(bus, devfn);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	return (zdev) ? zpci_cfg_store(zdev, where, val, size) : -ENODEV;
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic struct pci_ops pci_root_ops = {
4148c2ecf20Sopenharmony_ci	.read = pci_read,
4158c2ecf20Sopenharmony_ci	.write = pci_write,
4168c2ecf20Sopenharmony_ci};
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic void zpci_map_resources(struct pci_dev *pdev)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(pdev);
4218c2ecf20Sopenharmony_ci	resource_size_t len;
4228c2ecf20Sopenharmony_ci	int i;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
4258c2ecf20Sopenharmony_ci		len = pci_resource_len(pdev, i);
4268c2ecf20Sopenharmony_ci		if (!len)
4278c2ecf20Sopenharmony_ci			continue;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci		if (zpci_use_mio(zdev))
4308c2ecf20Sopenharmony_ci			pdev->resource[i].start =
4318c2ecf20Sopenharmony_ci				(resource_size_t __force) zdev->bars[i].mio_wt;
4328c2ecf20Sopenharmony_ci		else
4338c2ecf20Sopenharmony_ci			pdev->resource[i].start = (resource_size_t __force)
4348c2ecf20Sopenharmony_ci				pci_iomap_range_fh(pdev, i, 0, 0);
4358c2ecf20Sopenharmony_ci		pdev->resource[i].end = pdev->resource[i].start + len - 1;
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	zpci_iov_map_resources(pdev);
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_cistatic void zpci_unmap_resources(struct pci_dev *pdev)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(pdev);
4448c2ecf20Sopenharmony_ci	resource_size_t len;
4458c2ecf20Sopenharmony_ci	int i;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (zpci_use_mio(zdev))
4488c2ecf20Sopenharmony_ci		return;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
4518c2ecf20Sopenharmony_ci		len = pci_resource_len(pdev, i);
4528c2ecf20Sopenharmony_ci		if (!len)
4538c2ecf20Sopenharmony_ci			continue;
4548c2ecf20Sopenharmony_ci		pci_iounmap_fh(pdev, (void __iomem __force *)
4558c2ecf20Sopenharmony_ci			       pdev->resource[i].start);
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_cistatic int zpci_alloc_iomap(struct zpci_dev *zdev)
4608c2ecf20Sopenharmony_ci{
4618c2ecf20Sopenharmony_ci	unsigned long entry;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	spin_lock(&zpci_iomap_lock);
4648c2ecf20Sopenharmony_ci	entry = find_first_zero_bit(zpci_iomap_bitmap, ZPCI_IOMAP_ENTRIES);
4658c2ecf20Sopenharmony_ci	if (entry == ZPCI_IOMAP_ENTRIES) {
4668c2ecf20Sopenharmony_ci		spin_unlock(&zpci_iomap_lock);
4678c2ecf20Sopenharmony_ci		return -ENOSPC;
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci	set_bit(entry, zpci_iomap_bitmap);
4708c2ecf20Sopenharmony_ci	spin_unlock(&zpci_iomap_lock);
4718c2ecf20Sopenharmony_ci	return entry;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic void zpci_free_iomap(struct zpci_dev *zdev, int entry)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	spin_lock(&zpci_iomap_lock);
4778c2ecf20Sopenharmony_ci	memset(&zpci_iomap_start[entry], 0, sizeof(struct zpci_iomap_entry));
4788c2ecf20Sopenharmony_ci	clear_bit(entry, zpci_iomap_bitmap);
4798c2ecf20Sopenharmony_ci	spin_unlock(&zpci_iomap_lock);
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cistatic struct resource *__alloc_res(struct zpci_dev *zdev, unsigned long start,
4838c2ecf20Sopenharmony_ci				    unsigned long size, unsigned long flags)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	struct resource *r;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	r = kzalloc(sizeof(*r), GFP_KERNEL);
4888c2ecf20Sopenharmony_ci	if (!r)
4898c2ecf20Sopenharmony_ci		return NULL;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	r->start = start;
4928c2ecf20Sopenharmony_ci	r->end = r->start + size - 1;
4938c2ecf20Sopenharmony_ci	r->flags = flags;
4948c2ecf20Sopenharmony_ci	r->name = zdev->res_name;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if (request_resource(&iomem_resource, r)) {
4978c2ecf20Sopenharmony_ci		kfree(r);
4988c2ecf20Sopenharmony_ci		return NULL;
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci	return r;
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ciint zpci_setup_bus_resources(struct zpci_dev *zdev,
5048c2ecf20Sopenharmony_ci			     struct list_head *resources)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	unsigned long addr, size, flags;
5078c2ecf20Sopenharmony_ci	struct resource *res;
5088c2ecf20Sopenharmony_ci	int i, entry;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	snprintf(zdev->res_name, sizeof(zdev->res_name),
5118c2ecf20Sopenharmony_ci		 "PCI Bus %04x:%02x", zdev->uid, ZPCI_BUS_NR);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
5148c2ecf20Sopenharmony_ci		if (!zdev->bars[i].size)
5158c2ecf20Sopenharmony_ci			continue;
5168c2ecf20Sopenharmony_ci		entry = zpci_alloc_iomap(zdev);
5178c2ecf20Sopenharmony_ci		if (entry < 0)
5188c2ecf20Sopenharmony_ci			return entry;
5198c2ecf20Sopenharmony_ci		zdev->bars[i].map_idx = entry;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci		/* only MMIO is supported */
5228c2ecf20Sopenharmony_ci		flags = IORESOURCE_MEM;
5238c2ecf20Sopenharmony_ci		if (zdev->bars[i].val & 8)
5248c2ecf20Sopenharmony_ci			flags |= IORESOURCE_PREFETCH;
5258c2ecf20Sopenharmony_ci		if (zdev->bars[i].val & 4)
5268c2ecf20Sopenharmony_ci			flags |= IORESOURCE_MEM_64;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci		if (zpci_use_mio(zdev))
5298c2ecf20Sopenharmony_ci			addr = (unsigned long) zdev->bars[i].mio_wt;
5308c2ecf20Sopenharmony_ci		else
5318c2ecf20Sopenharmony_ci			addr = ZPCI_ADDR(entry);
5328c2ecf20Sopenharmony_ci		size = 1UL << zdev->bars[i].size;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci		res = __alloc_res(zdev, addr, size, flags);
5358c2ecf20Sopenharmony_ci		if (!res) {
5368c2ecf20Sopenharmony_ci			zpci_free_iomap(zdev, entry);
5378c2ecf20Sopenharmony_ci			return -ENOMEM;
5388c2ecf20Sopenharmony_ci		}
5398c2ecf20Sopenharmony_ci		zdev->bars[i].res = res;
5408c2ecf20Sopenharmony_ci		pci_add_resource(resources, res);
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	return 0;
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_cistatic void zpci_cleanup_bus_resources(struct zpci_dev *zdev)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	int i;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
5518c2ecf20Sopenharmony_ci		if (!zdev->bars[i].size || !zdev->bars[i].res)
5528c2ecf20Sopenharmony_ci			continue;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci		zpci_free_iomap(zdev, zdev->bars[i].map_idx);
5558c2ecf20Sopenharmony_ci		release_resource(zdev->bars[i].res);
5568c2ecf20Sopenharmony_ci		kfree(zdev->bars[i].res);
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ciint pcibios_add_device(struct pci_dev *pdev)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(pdev);
5638c2ecf20Sopenharmony_ci	struct resource *res;
5648c2ecf20Sopenharmony_ci	int i;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	/* The pdev has a reference to the zdev via its bus */
5678c2ecf20Sopenharmony_ci	zpci_zdev_get(zdev);
5688c2ecf20Sopenharmony_ci	if (pdev->is_physfn)
5698c2ecf20Sopenharmony_ci		pdev->no_vf_scan = 1;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	pdev->dev.groups = zpci_attr_groups;
5728c2ecf20Sopenharmony_ci	pdev->dev.dma_ops = &s390_pci_dma_ops;
5738c2ecf20Sopenharmony_ci	zpci_map_resources(pdev);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
5768c2ecf20Sopenharmony_ci		res = &pdev->resource[i];
5778c2ecf20Sopenharmony_ci		if (res->parent || !res->flags)
5788c2ecf20Sopenharmony_ci			continue;
5798c2ecf20Sopenharmony_ci		pci_claim_resource(pdev, i);
5808c2ecf20Sopenharmony_ci	}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	return 0;
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_civoid pcibios_release_device(struct pci_dev *pdev)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(pdev);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	zpci_unmap_resources(pdev);
5908c2ecf20Sopenharmony_ci	zpci_zdev_put(zdev);
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ciint pcibios_enable_device(struct pci_dev *pdev, int mask)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(pdev);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	zpci_debug_init_device(zdev, dev_name(&pdev->dev));
5988c2ecf20Sopenharmony_ci	zpci_fmb_enable_device(zdev);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	return pci_enable_resources(pdev, mask);
6018c2ecf20Sopenharmony_ci}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_civoid pcibios_disable_device(struct pci_dev *pdev)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(pdev);
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	zpci_fmb_disable_device(zdev);
6088c2ecf20Sopenharmony_ci	zpci_debug_exit_device(zdev);
6098c2ecf20Sopenharmony_ci}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_cistatic int __zpci_register_domain(int domain)
6128c2ecf20Sopenharmony_ci{
6138c2ecf20Sopenharmony_ci	spin_lock(&zpci_domain_lock);
6148c2ecf20Sopenharmony_ci	if (test_bit(domain, zpci_domain)) {
6158c2ecf20Sopenharmony_ci		spin_unlock(&zpci_domain_lock);
6168c2ecf20Sopenharmony_ci		pr_err("Domain %04x is already assigned\n", domain);
6178c2ecf20Sopenharmony_ci		return -EEXIST;
6188c2ecf20Sopenharmony_ci	}
6198c2ecf20Sopenharmony_ci	set_bit(domain, zpci_domain);
6208c2ecf20Sopenharmony_ci	spin_unlock(&zpci_domain_lock);
6218c2ecf20Sopenharmony_ci	return domain;
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_cistatic int __zpci_alloc_domain(void)
6258c2ecf20Sopenharmony_ci{
6268c2ecf20Sopenharmony_ci	int domain;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	spin_lock(&zpci_domain_lock);
6298c2ecf20Sopenharmony_ci	/*
6308c2ecf20Sopenharmony_ci	 * We can always auto allocate domains below ZPCI_NR_DEVICES.
6318c2ecf20Sopenharmony_ci	 * There is either a free domain or we have reached the maximum in
6328c2ecf20Sopenharmony_ci	 * which case we would have bailed earlier.
6338c2ecf20Sopenharmony_ci	 */
6348c2ecf20Sopenharmony_ci	domain = find_first_zero_bit(zpci_domain, ZPCI_NR_DEVICES);
6358c2ecf20Sopenharmony_ci	set_bit(domain, zpci_domain);
6368c2ecf20Sopenharmony_ci	spin_unlock(&zpci_domain_lock);
6378c2ecf20Sopenharmony_ci	return domain;
6388c2ecf20Sopenharmony_ci}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ciint zpci_alloc_domain(int domain)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	if (zpci_unique_uid) {
6438c2ecf20Sopenharmony_ci		if (domain)
6448c2ecf20Sopenharmony_ci			return __zpci_register_domain(domain);
6458c2ecf20Sopenharmony_ci		pr_warn("UID checking was active but no UID is provided: switching to automatic domain allocation\n");
6468c2ecf20Sopenharmony_ci		update_uid_checking(false);
6478c2ecf20Sopenharmony_ci	}
6488c2ecf20Sopenharmony_ci	return __zpci_alloc_domain();
6498c2ecf20Sopenharmony_ci}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_civoid zpci_free_domain(int domain)
6528c2ecf20Sopenharmony_ci{
6538c2ecf20Sopenharmony_ci	spin_lock(&zpci_domain_lock);
6548c2ecf20Sopenharmony_ci	clear_bit(domain, zpci_domain);
6558c2ecf20Sopenharmony_ci	spin_unlock(&zpci_domain_lock);
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ciint zpci_enable_device(struct zpci_dev *zdev)
6608c2ecf20Sopenharmony_ci{
6618c2ecf20Sopenharmony_ci	int rc;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	if (clp_enable_fh(zdev, ZPCI_NR_DMA_SPACES)) {
6648c2ecf20Sopenharmony_ci		rc = -EIO;
6658c2ecf20Sopenharmony_ci		goto out;
6668c2ecf20Sopenharmony_ci	}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	rc = zpci_dma_init_device(zdev);
6698c2ecf20Sopenharmony_ci	if (rc)
6708c2ecf20Sopenharmony_ci		goto out_dma;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	zdev->state = ZPCI_FN_STATE_ONLINE;
6738c2ecf20Sopenharmony_ci	return 0;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ciout_dma:
6768c2ecf20Sopenharmony_ci	clp_disable_fh(zdev);
6778c2ecf20Sopenharmony_ciout:
6788c2ecf20Sopenharmony_ci	return rc;
6798c2ecf20Sopenharmony_ci}
6808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(zpci_enable_device);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ciint zpci_disable_device(struct zpci_dev *zdev)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	zpci_dma_exit_device(zdev);
6858c2ecf20Sopenharmony_ci	/*
6868c2ecf20Sopenharmony_ci	 * The zPCI function may already be disabled by the platform, this is
6878c2ecf20Sopenharmony_ci	 * detected in clp_disable_fh() which becomes a no-op.
6888c2ecf20Sopenharmony_ci	 */
6898c2ecf20Sopenharmony_ci	return clp_disable_fh(zdev) ? -EIO : 0;
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(zpci_disable_device);
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci/* zpci_remove_device - Removes the given zdev from the PCI core
6948c2ecf20Sopenharmony_ci * @zdev: the zdev to be removed from the PCI core
6958c2ecf20Sopenharmony_ci * @set_error: if true the device's error state is set to permanent failure
6968c2ecf20Sopenharmony_ci *
6978c2ecf20Sopenharmony_ci * Sets a zPCI device to a configured but offline state; the zPCI
6988c2ecf20Sopenharmony_ci * device is still accessible through its hotplug slot and the zPCI
6998c2ecf20Sopenharmony_ci * API but is removed from the common code PCI bus, making it
7008c2ecf20Sopenharmony_ci * no longer available to drivers.
7018c2ecf20Sopenharmony_ci */
7028c2ecf20Sopenharmony_civoid zpci_remove_device(struct zpci_dev *zdev, bool set_error)
7038c2ecf20Sopenharmony_ci{
7048c2ecf20Sopenharmony_ci	struct zpci_bus *zbus = zdev->zbus;
7058c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	if (!zdev->zbus->bus)
7088c2ecf20Sopenharmony_ci		return;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	pdev = pci_get_slot(zbus->bus, zdev->devfn);
7118c2ecf20Sopenharmony_ci	if (pdev) {
7128c2ecf20Sopenharmony_ci		if (set_error)
7138c2ecf20Sopenharmony_ci			pdev->error_state = pci_channel_io_perm_failure;
7148c2ecf20Sopenharmony_ci		if (pdev->is_virtfn) {
7158c2ecf20Sopenharmony_ci			zpci_iov_remove_virtfn(pdev, zdev->vfn);
7168c2ecf20Sopenharmony_ci			/* balance pci_get_slot */
7178c2ecf20Sopenharmony_ci			pci_dev_put(pdev);
7188c2ecf20Sopenharmony_ci			return;
7198c2ecf20Sopenharmony_ci		}
7208c2ecf20Sopenharmony_ci		pci_stop_and_remove_bus_device_locked(pdev);
7218c2ecf20Sopenharmony_ci		/* balance pci_get_slot */
7228c2ecf20Sopenharmony_ci		pci_dev_put(pdev);
7238c2ecf20Sopenharmony_ci	}
7248c2ecf20Sopenharmony_ci}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci/**
7278c2ecf20Sopenharmony_ci * zpci_create_device() - Create a new zpci_dev and add it to the zbus
7288c2ecf20Sopenharmony_ci * @fid: Function ID of the device to be created
7298c2ecf20Sopenharmony_ci * @fh: Current Function Handle of the device to be created
7308c2ecf20Sopenharmony_ci * @state: Initial state after creation either Standby or Configured
7318c2ecf20Sopenharmony_ci *
7328c2ecf20Sopenharmony_ci * Creates a new zpci device and adds it to its, possibly newly created, zbus
7338c2ecf20Sopenharmony_ci * as well as zpci_list.
7348c2ecf20Sopenharmony_ci *
7358c2ecf20Sopenharmony_ci * Returns: 0 on success, an error value otherwise
7368c2ecf20Sopenharmony_ci */
7378c2ecf20Sopenharmony_ciint zpci_create_device(u32 fid, u32 fh, enum zpci_state state)
7388c2ecf20Sopenharmony_ci{
7398c2ecf20Sopenharmony_ci	struct zpci_dev *zdev;
7408c2ecf20Sopenharmony_ci	int rc;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	zpci_dbg(3, "add fid:%x, fh:%x, c:%d\n", fid, fh, state);
7438c2ecf20Sopenharmony_ci	zdev = kzalloc(sizeof(*zdev), GFP_KERNEL);
7448c2ecf20Sopenharmony_ci	if (!zdev)
7458c2ecf20Sopenharmony_ci		return -ENOMEM;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	/* FID and Function Handle are the static/dynamic identifiers */
7488c2ecf20Sopenharmony_ci	zdev->fid = fid;
7498c2ecf20Sopenharmony_ci	zdev->fh = fh;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	/* Query function properties and update zdev */
7528c2ecf20Sopenharmony_ci	rc = clp_query_pci_fn(zdev);
7538c2ecf20Sopenharmony_ci	if (rc)
7548c2ecf20Sopenharmony_ci		goto error;
7558c2ecf20Sopenharmony_ci	zdev->state =  state;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	kref_init(&zdev->kref);
7588c2ecf20Sopenharmony_ci	mutex_init(&zdev->lock);
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	rc = zpci_init_iommu(zdev);
7618c2ecf20Sopenharmony_ci	if (rc)
7628c2ecf20Sopenharmony_ci		goto error;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	if (zdev->state == ZPCI_FN_STATE_CONFIGURED) {
7658c2ecf20Sopenharmony_ci		rc = zpci_enable_device(zdev);
7668c2ecf20Sopenharmony_ci		if (rc)
7678c2ecf20Sopenharmony_ci			goto error_destroy_iommu;
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	rc = zpci_bus_device_register(zdev, &pci_root_ops);
7718c2ecf20Sopenharmony_ci	if (rc)
7728c2ecf20Sopenharmony_ci		goto error_disable;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	spin_lock(&zpci_list_lock);
7758c2ecf20Sopenharmony_ci	list_add_tail(&zdev->entry, &zpci_list);
7768c2ecf20Sopenharmony_ci	spin_unlock(&zpci_list_lock);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	return 0;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_cierror_disable:
7818c2ecf20Sopenharmony_ci	if (zdev->state == ZPCI_FN_STATE_ONLINE)
7828c2ecf20Sopenharmony_ci		zpci_disable_device(zdev);
7838c2ecf20Sopenharmony_cierror_destroy_iommu:
7848c2ecf20Sopenharmony_ci	zpci_destroy_iommu(zdev);
7858c2ecf20Sopenharmony_cierror:
7868c2ecf20Sopenharmony_ci	zpci_dbg(0, "add fid:%x, rc:%d\n", fid, rc);
7878c2ecf20Sopenharmony_ci	kfree(zdev);
7888c2ecf20Sopenharmony_ci	return rc;
7898c2ecf20Sopenharmony_ci}
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_cibool zpci_is_device_configured(struct zpci_dev *zdev)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	enum zpci_state state = zdev->state;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	return state != ZPCI_FN_STATE_RESERVED &&
7968c2ecf20Sopenharmony_ci		state != ZPCI_FN_STATE_STANDBY;
7978c2ecf20Sopenharmony_ci}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci/**
8008c2ecf20Sopenharmony_ci * zpci_device_reserved() - Mark device as resverved
8018c2ecf20Sopenharmony_ci * @zdev: the zpci_dev that was reserved
8028c2ecf20Sopenharmony_ci *
8038c2ecf20Sopenharmony_ci * Handle the case that a given zPCI function was reserved by another system.
8048c2ecf20Sopenharmony_ci * After a call to this function the zpci_dev can not be found via
8058c2ecf20Sopenharmony_ci * get_zdev_by_fid() anymore but may still be accessible via existing
8068c2ecf20Sopenharmony_ci * references though it will not be functional anymore.
8078c2ecf20Sopenharmony_ci */
8088c2ecf20Sopenharmony_civoid zpci_device_reserved(struct zpci_dev *zdev)
8098c2ecf20Sopenharmony_ci{
8108c2ecf20Sopenharmony_ci	if (zdev->has_hp_slot)
8118c2ecf20Sopenharmony_ci		zpci_exit_slot(zdev);
8128c2ecf20Sopenharmony_ci	/*
8138c2ecf20Sopenharmony_ci	 * Remove device from zpci_list as it is going away. This also
8148c2ecf20Sopenharmony_ci	 * makes sure we ignore subsequent zPCI events for this device.
8158c2ecf20Sopenharmony_ci	 */
8168c2ecf20Sopenharmony_ci	spin_lock(&zpci_list_lock);
8178c2ecf20Sopenharmony_ci	list_del(&zdev->entry);
8188c2ecf20Sopenharmony_ci	spin_unlock(&zpci_list_lock);
8198c2ecf20Sopenharmony_ci	zdev->state = ZPCI_FN_STATE_RESERVED;
8208c2ecf20Sopenharmony_ci	zpci_dbg(3, "rsv fid:%x\n", zdev->fid);
8218c2ecf20Sopenharmony_ci	zpci_zdev_put(zdev);
8228c2ecf20Sopenharmony_ci}
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_civoid zpci_release_device(struct kref *kref)
8258c2ecf20Sopenharmony_ci{
8268c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = container_of(kref, struct zpci_dev, kref);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	if (zdev->zbus->bus)
8298c2ecf20Sopenharmony_ci		zpci_remove_device(zdev, false);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	switch (zdev->state) {
8328c2ecf20Sopenharmony_ci	case ZPCI_FN_STATE_ONLINE:
8338c2ecf20Sopenharmony_ci	case ZPCI_FN_STATE_CONFIGURED:
8348c2ecf20Sopenharmony_ci		zpci_disable_device(zdev);
8358c2ecf20Sopenharmony_ci		fallthrough;
8368c2ecf20Sopenharmony_ci	case ZPCI_FN_STATE_STANDBY:
8378c2ecf20Sopenharmony_ci		if (zdev->has_hp_slot)
8388c2ecf20Sopenharmony_ci			zpci_exit_slot(zdev);
8398c2ecf20Sopenharmony_ci		spin_lock(&zpci_list_lock);
8408c2ecf20Sopenharmony_ci		list_del(&zdev->entry);
8418c2ecf20Sopenharmony_ci		spin_unlock(&zpci_list_lock);
8428c2ecf20Sopenharmony_ci		zpci_dbg(3, "rsv fid:%x\n", zdev->fid);
8438c2ecf20Sopenharmony_ci		fallthrough;
8448c2ecf20Sopenharmony_ci	case ZPCI_FN_STATE_RESERVED:
8458c2ecf20Sopenharmony_ci		zpci_cleanup_bus_resources(zdev);
8468c2ecf20Sopenharmony_ci		zpci_bus_device_unregister(zdev);
8478c2ecf20Sopenharmony_ci		zpci_destroy_iommu(zdev);
8488c2ecf20Sopenharmony_ci		fallthrough;
8498c2ecf20Sopenharmony_ci	default:
8508c2ecf20Sopenharmony_ci		break;
8518c2ecf20Sopenharmony_ci	}
8528c2ecf20Sopenharmony_ci	zpci_dbg(3, "rem fid:%x\n", zdev->fid);
8538c2ecf20Sopenharmony_ci	kfree(zdev);
8548c2ecf20Sopenharmony_ci}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ciint zpci_report_error(struct pci_dev *pdev,
8578c2ecf20Sopenharmony_ci		      struct zpci_report_error_header *report)
8588c2ecf20Sopenharmony_ci{
8598c2ecf20Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(pdev);
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	return sclp_pci_report(report, zdev->fh, zdev->fid);
8628c2ecf20Sopenharmony_ci}
8638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zpci_report_error);
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_cistatic int zpci_mem_init(void)
8668c2ecf20Sopenharmony_ci{
8678c2ecf20Sopenharmony_ci	BUILD_BUG_ON(!is_power_of_2(__alignof__(struct zpci_fmb)) ||
8688c2ecf20Sopenharmony_ci		     __alignof__(struct zpci_fmb) < sizeof(struct zpci_fmb));
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	zdev_fmb_cache = kmem_cache_create("PCI_FMB_cache", sizeof(struct zpci_fmb),
8718c2ecf20Sopenharmony_ci					   __alignof__(struct zpci_fmb), 0, NULL);
8728c2ecf20Sopenharmony_ci	if (!zdev_fmb_cache)
8738c2ecf20Sopenharmony_ci		goto error_fmb;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	zpci_iomap_start = kcalloc(ZPCI_IOMAP_ENTRIES,
8768c2ecf20Sopenharmony_ci				   sizeof(*zpci_iomap_start), GFP_KERNEL);
8778c2ecf20Sopenharmony_ci	if (!zpci_iomap_start)
8788c2ecf20Sopenharmony_ci		goto error_iomap;
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	zpci_iomap_bitmap = kcalloc(BITS_TO_LONGS(ZPCI_IOMAP_ENTRIES),
8818c2ecf20Sopenharmony_ci				    sizeof(*zpci_iomap_bitmap), GFP_KERNEL);
8828c2ecf20Sopenharmony_ci	if (!zpci_iomap_bitmap)
8838c2ecf20Sopenharmony_ci		goto error_iomap_bitmap;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	if (static_branch_likely(&have_mio))
8868c2ecf20Sopenharmony_ci		clp_setup_writeback_mio();
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	return 0;
8898c2ecf20Sopenharmony_cierror_iomap_bitmap:
8908c2ecf20Sopenharmony_ci	kfree(zpci_iomap_start);
8918c2ecf20Sopenharmony_cierror_iomap:
8928c2ecf20Sopenharmony_ci	kmem_cache_destroy(zdev_fmb_cache);
8938c2ecf20Sopenharmony_cierror_fmb:
8948c2ecf20Sopenharmony_ci	return -ENOMEM;
8958c2ecf20Sopenharmony_ci}
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_cistatic void zpci_mem_exit(void)
8988c2ecf20Sopenharmony_ci{
8998c2ecf20Sopenharmony_ci	kfree(zpci_iomap_bitmap);
9008c2ecf20Sopenharmony_ci	kfree(zpci_iomap_start);
9018c2ecf20Sopenharmony_ci	kmem_cache_destroy(zdev_fmb_cache);
9028c2ecf20Sopenharmony_ci}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_cistatic unsigned int s390_pci_probe __initdata = 1;
9058c2ecf20Sopenharmony_ciunsigned int s390_pci_force_floating __initdata;
9068c2ecf20Sopenharmony_cistatic unsigned int s390_pci_initialized;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_cichar * __init pcibios_setup(char *str)
9098c2ecf20Sopenharmony_ci{
9108c2ecf20Sopenharmony_ci	if (!strcmp(str, "off")) {
9118c2ecf20Sopenharmony_ci		s390_pci_probe = 0;
9128c2ecf20Sopenharmony_ci		return NULL;
9138c2ecf20Sopenharmony_ci	}
9148c2ecf20Sopenharmony_ci	if (!strcmp(str, "nomio")) {
9158c2ecf20Sopenharmony_ci		S390_lowcore.machine_flags &= ~MACHINE_FLAG_PCI_MIO;
9168c2ecf20Sopenharmony_ci		return NULL;
9178c2ecf20Sopenharmony_ci	}
9188c2ecf20Sopenharmony_ci	if (!strcmp(str, "force_floating")) {
9198c2ecf20Sopenharmony_ci		s390_pci_force_floating = 1;
9208c2ecf20Sopenharmony_ci		return NULL;
9218c2ecf20Sopenharmony_ci	}
9228c2ecf20Sopenharmony_ci	if (!strcmp(str, "norid")) {
9238c2ecf20Sopenharmony_ci		s390_pci_no_rid = 1;
9248c2ecf20Sopenharmony_ci		return NULL;
9258c2ecf20Sopenharmony_ci	}
9268c2ecf20Sopenharmony_ci	return str;
9278c2ecf20Sopenharmony_ci}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_cibool zpci_is_enabled(void)
9308c2ecf20Sopenharmony_ci{
9318c2ecf20Sopenharmony_ci	return s390_pci_initialized;
9328c2ecf20Sopenharmony_ci}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_cistatic int __init pci_base_init(void)
9358c2ecf20Sopenharmony_ci{
9368c2ecf20Sopenharmony_ci	int rc;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	if (!s390_pci_probe)
9398c2ecf20Sopenharmony_ci		return 0;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	if (!test_facility(69) || !test_facility(71))
9428c2ecf20Sopenharmony_ci		return 0;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	if (MACHINE_HAS_PCI_MIO) {
9458c2ecf20Sopenharmony_ci		static_branch_enable(&have_mio);
9468c2ecf20Sopenharmony_ci		ctl_set_bit(2, 5);
9478c2ecf20Sopenharmony_ci	}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	rc = zpci_debug_init();
9508c2ecf20Sopenharmony_ci	if (rc)
9518c2ecf20Sopenharmony_ci		goto out;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	rc = zpci_mem_init();
9548c2ecf20Sopenharmony_ci	if (rc)
9558c2ecf20Sopenharmony_ci		goto out_mem;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	rc = zpci_irq_init();
9588c2ecf20Sopenharmony_ci	if (rc)
9598c2ecf20Sopenharmony_ci		goto out_irq;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	rc = zpci_dma_init();
9628c2ecf20Sopenharmony_ci	if (rc)
9638c2ecf20Sopenharmony_ci		goto out_dma;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	rc = clp_scan_pci_devices();
9668c2ecf20Sopenharmony_ci	if (rc)
9678c2ecf20Sopenharmony_ci		goto out_find;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	s390_pci_initialized = 1;
9708c2ecf20Sopenharmony_ci	return 0;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ciout_find:
9738c2ecf20Sopenharmony_ci	zpci_dma_exit();
9748c2ecf20Sopenharmony_ciout_dma:
9758c2ecf20Sopenharmony_ci	zpci_irq_exit();
9768c2ecf20Sopenharmony_ciout_irq:
9778c2ecf20Sopenharmony_ci	zpci_mem_exit();
9788c2ecf20Sopenharmony_ciout_mem:
9798c2ecf20Sopenharmony_ci	zpci_debug_exit();
9808c2ecf20Sopenharmony_ciout:
9818c2ecf20Sopenharmony_ci	return rc;
9828c2ecf20Sopenharmony_ci}
9838c2ecf20Sopenharmony_cisubsys_initcall_sync(pci_base_init);
984