18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2020 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author(s): 68c2ecf20Sopenharmony_ci * Pierre Morel <pmorel@linux.ibm.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "zpci" 118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/err.h> 168c2ecf20Sopenharmony_ci#include <linux/export.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 198c2ecf20Sopenharmony_ci#include <linux/jump_label.h> 208c2ecf20Sopenharmony_ci#include <linux/pci.h> 218c2ecf20Sopenharmony_ci#include <linux/printk.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <asm/pci_clp.h> 248c2ecf20Sopenharmony_ci#include <asm/pci_dma.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "pci_bus.h" 278c2ecf20Sopenharmony_ci#include "pci_iov.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic LIST_HEAD(zbus_list); 308c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(zbus_list_lock); 318c2ecf20Sopenharmony_cistatic int zpci_nb_devices; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* zpci_bus_scan 348c2ecf20Sopenharmony_ci * @zbus: the zbus holding the zdevices 358c2ecf20Sopenharmony_ci * @ops: the pci operations 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * The domain number must be set before pci_scan_root_bus is called. 388c2ecf20Sopenharmony_ci * This function can be called once the domain is known, hence 398c2ecf20Sopenharmony_ci * when the function_0 is dicovered. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_cistatic int zpci_bus_scan(struct zpci_bus *zbus, int domain, struct pci_ops *ops) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct pci_bus *bus; 448c2ecf20Sopenharmony_ci int rc; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci rc = zpci_alloc_domain(domain); 478c2ecf20Sopenharmony_ci if (rc < 0) 488c2ecf20Sopenharmony_ci return rc; 498c2ecf20Sopenharmony_ci zbus->domain_nr = rc; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, ops, zbus, &zbus->resources); 528c2ecf20Sopenharmony_ci if (!bus) { 538c2ecf20Sopenharmony_ci zpci_free_domain(zbus->domain_nr); 548c2ecf20Sopenharmony_ci return -EFAULT; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci zbus->bus = bus; 588c2ecf20Sopenharmony_ci pci_bus_add_devices(bus); 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void zpci_bus_release(struct kref *kref) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct zpci_bus *zbus = container_of(kref, struct zpci_bus, kref); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (zbus->bus) { 678c2ecf20Sopenharmony_ci pci_lock_rescan_remove(); 688c2ecf20Sopenharmony_ci pci_stop_root_bus(zbus->bus); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci zpci_free_domain(zbus->domain_nr); 718c2ecf20Sopenharmony_ci pci_free_resource_list(&zbus->resources); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci pci_remove_root_bus(zbus->bus); 748c2ecf20Sopenharmony_ci pci_unlock_rescan_remove(); 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci spin_lock(&zbus_list_lock); 788c2ecf20Sopenharmony_ci list_del(&zbus->bus_next); 798c2ecf20Sopenharmony_ci spin_unlock(&zbus_list_lock); 808c2ecf20Sopenharmony_ci kfree(zbus); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic void zpci_bus_put(struct zpci_bus *zbus) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci kref_put(&zbus->kref, zpci_bus_release); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic struct zpci_bus *zpci_bus_get(int pchid) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct zpci_bus *zbus; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci spin_lock(&zbus_list_lock); 938c2ecf20Sopenharmony_ci list_for_each_entry(zbus, &zbus_list, bus_next) { 948c2ecf20Sopenharmony_ci if (pchid == zbus->pchid) { 958c2ecf20Sopenharmony_ci kref_get(&zbus->kref); 968c2ecf20Sopenharmony_ci goto out_unlock; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci zbus = NULL; 1008c2ecf20Sopenharmony_ciout_unlock: 1018c2ecf20Sopenharmony_ci spin_unlock(&zbus_list_lock); 1028c2ecf20Sopenharmony_ci return zbus; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic struct zpci_bus *zpci_bus_alloc(int pchid) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct zpci_bus *zbus; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci zbus = kzalloc(sizeof(*zbus), GFP_KERNEL); 1108c2ecf20Sopenharmony_ci if (!zbus) 1118c2ecf20Sopenharmony_ci return NULL; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci zbus->pchid = pchid; 1148c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&zbus->bus_next); 1158c2ecf20Sopenharmony_ci spin_lock(&zbus_list_lock); 1168c2ecf20Sopenharmony_ci list_add_tail(&zbus->bus_next, &zbus_list); 1178c2ecf20Sopenharmony_ci spin_unlock(&zbus_list_lock); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci kref_init(&zbus->kref); 1208c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&zbus->resources); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci zbus->bus_resource.start = 0; 1238c2ecf20Sopenharmony_ci zbus->bus_resource.end = ZPCI_BUS_NR; 1248c2ecf20Sopenharmony_ci zbus->bus_resource.flags = IORESOURCE_BUS; 1258c2ecf20Sopenharmony_ci pci_add_resource(&zbus->resources, &zbus->bus_resource); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return zbus; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_civoid pcibios_bus_add_device(struct pci_dev *pdev) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct zpci_dev *zdev = to_zpci(pdev); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* 1358c2ecf20Sopenharmony_ci * With pdev->no_vf_scan the common PCI probing code does not 1368c2ecf20Sopenharmony_ci * perform PF/VF linking. 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_ci if (zdev->vfn) { 1398c2ecf20Sopenharmony_ci zpci_iov_setup_virtfn(zdev->zbus, pdev, zdev->vfn); 1408c2ecf20Sopenharmony_ci pdev->no_command_memory = 1; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int zpci_bus_add_device(struct zpci_bus *zbus, struct zpci_dev *zdev) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct pci_bus *bus; 1478c2ecf20Sopenharmony_ci struct resource_entry *window, *n; 1488c2ecf20Sopenharmony_ci struct resource *res; 1498c2ecf20Sopenharmony_ci struct pci_dev *pdev; 1508c2ecf20Sopenharmony_ci int rc; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci bus = zbus->bus; 1538c2ecf20Sopenharmony_ci if (!bus) 1548c2ecf20Sopenharmony_ci return -EINVAL; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci pdev = pci_get_slot(bus, zdev->devfn); 1578c2ecf20Sopenharmony_ci if (pdev) { 1588c2ecf20Sopenharmony_ci /* Device is already known. */ 1598c2ecf20Sopenharmony_ci pci_dev_put(pdev); 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci rc = zpci_init_slot(zdev); 1648c2ecf20Sopenharmony_ci if (rc) 1658c2ecf20Sopenharmony_ci return rc; 1668c2ecf20Sopenharmony_ci zdev->has_hp_slot = 1; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci resource_list_for_each_entry_safe(window, n, &zbus->resources) { 1698c2ecf20Sopenharmony_ci res = window->res; 1708c2ecf20Sopenharmony_ci pci_bus_add_resource(bus, res, 0); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci pdev = pci_scan_single_device(bus, zdev->devfn); 1748c2ecf20Sopenharmony_ci if (pdev) 1758c2ecf20Sopenharmony_ci pci_bus_add_device(pdev); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic void zpci_bus_add_devices(struct zpci_bus *zbus) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci int i; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci for (i = 1; i < ZPCI_FUNCTIONS_PER_BUS; i++) 1858c2ecf20Sopenharmony_ci if (zbus->function[i]) 1868c2ecf20Sopenharmony_ci zpci_bus_add_device(zbus, zbus->function[i]); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci pci_lock_rescan_remove(); 1898c2ecf20Sopenharmony_ci pci_bus_add_devices(zbus->bus); 1908c2ecf20Sopenharmony_ci pci_unlock_rescan_remove(); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ciint zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct zpci_bus *zbus = NULL; 1968c2ecf20Sopenharmony_ci int rc = -EBADF; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (zpci_nb_devices == ZPCI_NR_DEVICES) { 1998c2ecf20Sopenharmony_ci pr_warn("Adding PCI function %08x failed because the configured limit of %d is reached\n", 2008c2ecf20Sopenharmony_ci zdev->fid, ZPCI_NR_DEVICES); 2018c2ecf20Sopenharmony_ci return -ENOSPC; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci zpci_nb_devices++; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (zdev->devfn >= ZPCI_FUNCTIONS_PER_BUS) 2068c2ecf20Sopenharmony_ci return -EINVAL; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (!s390_pci_no_rid && zdev->rid_available) 2098c2ecf20Sopenharmony_ci zbus = zpci_bus_get(zdev->pchid); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (!zbus) { 2128c2ecf20Sopenharmony_ci zbus = zpci_bus_alloc(zdev->pchid); 2138c2ecf20Sopenharmony_ci if (!zbus) 2148c2ecf20Sopenharmony_ci return -ENOMEM; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci zdev->zbus = zbus; 2188c2ecf20Sopenharmony_ci if (zbus->function[zdev->devfn]) { 2198c2ecf20Sopenharmony_ci pr_err("devfn %04x is already assigned\n", zdev->devfn); 2208c2ecf20Sopenharmony_ci goto error; /* rc already set */ 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci zbus->function[zdev->devfn] = zdev; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci zpci_setup_bus_resources(zdev, &zbus->resources); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (zbus->bus) { 2278c2ecf20Sopenharmony_ci if (!zbus->multifunction) { 2288c2ecf20Sopenharmony_ci WARN_ONCE(1, "zbus is not multifunction\n"); 2298c2ecf20Sopenharmony_ci goto error_bus; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci if (!zdev->rid_available) { 2328c2ecf20Sopenharmony_ci WARN_ONCE(1, "rid_available not set for multifunction\n"); 2338c2ecf20Sopenharmony_ci goto error_bus; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci rc = zpci_bus_add_device(zbus, zdev); 2368c2ecf20Sopenharmony_ci if (rc) 2378c2ecf20Sopenharmony_ci goto error_bus; 2388c2ecf20Sopenharmony_ci } else if (zdev->devfn == 0) { 2398c2ecf20Sopenharmony_ci if (zbus->multifunction && !zdev->rid_available) { 2408c2ecf20Sopenharmony_ci WARN_ONCE(1, "rid_available not set on function 0 for multifunction\n"); 2418c2ecf20Sopenharmony_ci goto error_bus; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci rc = zpci_bus_scan(zbus, (u16)zdev->uid, ops); 2448c2ecf20Sopenharmony_ci if (rc) 2458c2ecf20Sopenharmony_ci goto error_bus; 2468c2ecf20Sopenharmony_ci zpci_bus_add_devices(zbus); 2478c2ecf20Sopenharmony_ci rc = zpci_init_slot(zdev); 2488c2ecf20Sopenharmony_ci if (rc) 2498c2ecf20Sopenharmony_ci goto error_bus; 2508c2ecf20Sopenharmony_ci zdev->has_hp_slot = 1; 2518c2ecf20Sopenharmony_ci zbus->multifunction = zdev->rid_available; 2528c2ecf20Sopenharmony_ci zbus->max_bus_speed = zdev->max_bus_speed; 2538c2ecf20Sopenharmony_ci } else { 2548c2ecf20Sopenharmony_ci zbus->multifunction = 1; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cierror_bus: 2608c2ecf20Sopenharmony_ci zpci_nb_devices--; 2618c2ecf20Sopenharmony_ci zbus->function[zdev->devfn] = NULL; 2628c2ecf20Sopenharmony_cierror: 2638c2ecf20Sopenharmony_ci pr_err("Adding PCI function %08x failed\n", zdev->fid); 2648c2ecf20Sopenharmony_ci zpci_bus_put(zbus); 2658c2ecf20Sopenharmony_ci return rc; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_civoid zpci_bus_device_unregister(struct zpci_dev *zdev) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci struct zpci_bus *zbus = zdev->zbus; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci zpci_nb_devices--; 2738c2ecf20Sopenharmony_ci zbus->function[zdev->devfn] = NULL; 2748c2ecf20Sopenharmony_ci zpci_bus_put(zbus); 2758c2ecf20Sopenharmony_ci} 276