1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * pci.c - Low-Level PCI Access in IA-64 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Derived from bios32.c of i386 tree. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * (c) Copyright 2002, 2005 Hewlett-Packard Development Company, L.P. 81da177e4SLinus Torvalds * David Mosberger-Tang <davidm@hpl.hp.com> 91da177e4SLinus Torvalds * Bjorn Helgaas <bjorn.helgaas@hp.com> 101da177e4SLinus Torvalds * Copyright (C) 2004 Silicon Graphics, Inc. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * Note: Above list of copyright holders is incomplete... 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds #include <linux/acpi.h> 161da177e4SLinus Torvalds #include <linux/types.h> 171da177e4SLinus Torvalds #include <linux/kernel.h> 181da177e4SLinus Torvalds #include <linux/pci.h> 19b02a4a19SJiang Liu #include <linux/pci-acpi.h> 201da177e4SLinus Torvalds #include <linux/init.h> 211da177e4SLinus Torvalds #include <linux/ioport.h> 221da177e4SLinus Torvalds #include <linux/slab.h> 231da177e4SLinus Torvalds #include <linux/spinlock.h> 2457c8a661SMike Rapoport #include <linux/memblock.h> 25bd3ff194SPaul Gortmaker #include <linux/export.h> 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds #include <asm/machvec.h> 281da177e4SLinus Torvalds #include <asm/page.h> 291da177e4SLinus Torvalds #include <asm/io.h> 301da177e4SLinus Torvalds #include <asm/sal.h> 311da177e4SLinus Torvalds #include <asm/smp.h> 321da177e4SLinus Torvalds #include <asm/irq.h> 331da177e4SLinus Torvalds #include <asm/hw_irq.h> 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds /* 361da177e4SLinus Torvalds * Low-level SAL-based PCI configuration access functions. Note that SAL 371da177e4SLinus Torvalds * calls are already serialized (via sal_lock), so we don't need another 381da177e4SLinus Torvalds * synchronization mechanism here. 391da177e4SLinus Torvalds */ 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds #define PCI_SAL_ADDRESS(seg, bus, devfn, reg) \ 421da177e4SLinus Torvalds (((u64) seg << 24) | (bus << 16) | (devfn << 8) | (reg)) 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds /* SAL 3.2 adds support for extended config space. */ 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds #define PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg) \ 471da177e4SLinus Torvalds (((u64) seg << 28) | (bus << 20) | (devfn << 12) | (reg)) 481da177e4SLinus Torvalds 49b6ce068aSMatthew Wilcox int raw_pci_read(unsigned int seg, unsigned int bus, unsigned int devfn, 501da177e4SLinus Torvalds int reg, int len, u32 *value) 511da177e4SLinus Torvalds { 521da177e4SLinus Torvalds u64 addr, data = 0; 531da177e4SLinus Torvalds int mode, result; 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds if (!value || (seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095)) 561da177e4SLinus Torvalds return -EINVAL; 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds if ((seg | reg) <= 255) { 591da177e4SLinus Torvalds addr = PCI_SAL_ADDRESS(seg, bus, devfn, reg); 601da177e4SLinus Torvalds mode = 0; 61adcd7403SMatthew Wilcox } else if (sal_revision >= SAL_VERSION_CODE(3,2)) { 621da177e4SLinus Torvalds addr = PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg); 631da177e4SLinus Torvalds mode = 1; 64adcd7403SMatthew Wilcox } else { 65adcd7403SMatthew Wilcox return -EINVAL; 661da177e4SLinus Torvalds } 67adcd7403SMatthew Wilcox 681da177e4SLinus Torvalds result = ia64_sal_pci_config_read(addr, mode, len, &data); 691da177e4SLinus Torvalds if (result != 0) 701da177e4SLinus Torvalds return -EINVAL; 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds *value = (u32) data; 731da177e4SLinus Torvalds return 0; 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 76b6ce068aSMatthew Wilcox int raw_pci_write(unsigned int seg, unsigned int bus, unsigned int devfn, 771da177e4SLinus Torvalds int reg, int len, u32 value) 781da177e4SLinus Torvalds { 791da177e4SLinus Torvalds u64 addr; 801da177e4SLinus Torvalds int mode, result; 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095)) 831da177e4SLinus Torvalds return -EINVAL; 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds if ((seg | reg) <= 255) { 861da177e4SLinus Torvalds addr = PCI_SAL_ADDRESS(seg, bus, devfn, reg); 871da177e4SLinus Torvalds mode = 0; 88adcd7403SMatthew Wilcox } else if (sal_revision >= SAL_VERSION_CODE(3,2)) { 891da177e4SLinus Torvalds addr = PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg); 901da177e4SLinus Torvalds mode = 1; 91adcd7403SMatthew Wilcox } else { 92adcd7403SMatthew Wilcox return -EINVAL; 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds result = ia64_sal_pci_config_write(addr, mode, len, value); 951da177e4SLinus Torvalds if (result != 0) 961da177e4SLinus Torvalds return -EINVAL; 971da177e4SLinus Torvalds return 0; 981da177e4SLinus Torvalds } 991da177e4SLinus Torvalds 100b6ce068aSMatthew Wilcox static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, 101b6ce068aSMatthew Wilcox int size, u32 *value) 1021da177e4SLinus Torvalds { 103b6ce068aSMatthew Wilcox return raw_pci_read(pci_domain_nr(bus), bus->number, 1041da177e4SLinus Torvalds devfn, where, size, value); 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 107b6ce068aSMatthew Wilcox static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, 108b6ce068aSMatthew Wilcox int size, u32 value) 1091da177e4SLinus Torvalds { 110b6ce068aSMatthew Wilcox return raw_pci_write(pci_domain_nr(bus), bus->number, 1111da177e4SLinus Torvalds devfn, where, size, value); 1121da177e4SLinus Torvalds } 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds struct pci_ops pci_root_ops = { 1151da177e4SLinus Torvalds .read = pci_read, 1161da177e4SLinus Torvalds .write = pci_write, 1171da177e4SLinus Torvalds }; 1181da177e4SLinus Torvalds 1194f41d5a4SBjorn Helgaas struct pci_root_info { 12002715e86SJiang Liu struct acpi_pci_root_info common; 1213772aea7SJiang Liu struct pci_controller controller; 122c9e391cfSJiang Liu struct list_head io_resources; 1234f41d5a4SBjorn Helgaas }; 1244f41d5a4SBjorn Helgaas 12502715e86SJiang Liu static unsigned int new_space(u64 phys_base, int sparse) 1261da177e4SLinus Torvalds { 1274f41d5a4SBjorn Helgaas u64 mmio_base; 1281da177e4SLinus Torvalds int i; 1291da177e4SLinus Torvalds 1304f41d5a4SBjorn Helgaas if (phys_base == 0) 1314f41d5a4SBjorn Helgaas return 0; /* legacy I/O port space */ 1321da177e4SLinus Torvalds 1334f41d5a4SBjorn Helgaas mmio_base = (u64) ioremap(phys_base, 0); 1341da177e4SLinus Torvalds for (i = 0; i < num_io_spaces; i++) 1354f41d5a4SBjorn Helgaas if (io_space[i].mmio_base == mmio_base && 1361da177e4SLinus Torvalds io_space[i].sparse == sparse) 1374f41d5a4SBjorn Helgaas return i; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds if (num_io_spaces == MAX_IO_SPACES) { 140c4cbf6b9SYijing Wang pr_err("PCI: Too many IO port spaces " 1414f41d5a4SBjorn Helgaas "(MAX_IO_SPACES=%lu)\n", MAX_IO_SPACES); 1421da177e4SLinus Torvalds return ~0; 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds i = num_io_spaces++; 1464f41d5a4SBjorn Helgaas io_space[i].mmio_base = mmio_base; 1471da177e4SLinus Torvalds io_space[i].sparse = sparse; 1481da177e4SLinus Torvalds 1494f41d5a4SBjorn Helgaas return i; 1504f41d5a4SBjorn Helgaas } 1514f41d5a4SBjorn Helgaas 1523772aea7SJiang Liu static int add_io_space(struct device *dev, struct pci_root_info *info, 1533772aea7SJiang Liu struct resource_entry *entry) 1544f41d5a4SBjorn Helgaas { 1553f7abdefSJiang Liu struct resource_entry *iospace; 1563772aea7SJiang Liu struct resource *resource, *res = entry->res; 1574f41d5a4SBjorn Helgaas char *name; 158e088a4adSMatthew Wilcox unsigned long base, min, max, base_port; 1594f41d5a4SBjorn Helgaas unsigned int sparse = 0, space_nr, len; 1604f41d5a4SBjorn Helgaas 16102715e86SJiang Liu len = strlen(info->common.name) + 32; 1623f7abdefSJiang Liu iospace = resource_list_create_entry(NULL, len); 163c9e391cfSJiang Liu if (!iospace) { 1643772aea7SJiang Liu dev_err(dev, "PCI: No memory for %s I/O port space\n", 16502715e86SJiang Liu info->common.name); 1663772aea7SJiang Liu return -ENOMEM; 1674f41d5a4SBjorn Helgaas } 1684f41d5a4SBjorn Helgaas 1693772aea7SJiang Liu if (res->flags & IORESOURCE_IO_SPARSE) 1704f41d5a4SBjorn Helgaas sparse = 1; 1713772aea7SJiang Liu space_nr = new_space(entry->offset, sparse); 1724f41d5a4SBjorn Helgaas if (space_nr == ~0) 173c9e391cfSJiang Liu goto free_resource; 1744f41d5a4SBjorn Helgaas 1753772aea7SJiang Liu name = (char *)(iospace + 1); 1763772aea7SJiang Liu min = res->start - entry->offset; 1773772aea7SJiang Liu max = res->end - entry->offset; 1784f41d5a4SBjorn Helgaas base = __pa(io_space[space_nr].mmio_base); 1794f41d5a4SBjorn Helgaas base_port = IO_SPACE_BASE(space_nr); 18002715e86SJiang Liu snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->common.name, 1814f41d5a4SBjorn Helgaas base_port + min, base_port + max); 1824f41d5a4SBjorn Helgaas 1834f41d5a4SBjorn Helgaas /* 1844f41d5a4SBjorn Helgaas * The SDM guarantees the legacy 0-64K space is sparse, but if the 1854f41d5a4SBjorn Helgaas * mapping is done by the processor (not the bridge), ACPI may not 1864f41d5a4SBjorn Helgaas * mark it as sparse. 1874f41d5a4SBjorn Helgaas */ 1884f41d5a4SBjorn Helgaas if (space_nr == 0) 1894f41d5a4SBjorn Helgaas sparse = 1; 1904f41d5a4SBjorn Helgaas 1913f7abdefSJiang Liu resource = iospace->res; 1924f41d5a4SBjorn Helgaas resource->name = name; 1934f41d5a4SBjorn Helgaas resource->flags = IORESOURCE_MEM; 1944f41d5a4SBjorn Helgaas resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min); 1954f41d5a4SBjorn Helgaas resource->end = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max); 196c9e391cfSJiang Liu if (insert_resource(&iomem_resource, resource)) { 1973772aea7SJiang Liu dev_err(dev, 198c9e391cfSJiang Liu "can't allocate host bridge io space resource %pR\n", 199c9e391cfSJiang Liu resource); 200c9e391cfSJiang Liu goto free_resource; 201c9e391cfSJiang Liu } 2024f41d5a4SBjorn Helgaas 2033772aea7SJiang Liu entry->offset = base_port; 2043772aea7SJiang Liu res->start = min + base_port; 2053772aea7SJiang Liu res->end = max + base_port; 2063f7abdefSJiang Liu resource_list_add_tail(iospace, &info->io_resources); 2073772aea7SJiang Liu 2083772aea7SJiang Liu return 0; 2094f41d5a4SBjorn Helgaas 2104f41d5a4SBjorn Helgaas free_resource: 2113f7abdefSJiang Liu resource_list_free_entry(iospace); 2123772aea7SJiang Liu return -ENOSPC; 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 215463eb297SBjorn Helgaas /* 2163772aea7SJiang Liu * An IO port or MMIO resource assigned to a PCI host bridge may be 2173772aea7SJiang Liu * consumed by the host bridge itself or available to its child 2183772aea7SJiang Liu * bus/devices. The ACPI specification defines a bit (Producer/Consumer) 2193772aea7SJiang Liu * to tell whether the resource is consumed by the host bridge itself, 2203772aea7SJiang Liu * but firmware hasn't used that bit consistently, so we can't rely on it. 2213772aea7SJiang Liu * 2223772aea7SJiang Liu * On x86 and IA64 platforms, all IO port and MMIO resources are assumed 2233772aea7SJiang Liu * to be available to child bus/devices except one special case: 2243772aea7SJiang Liu * IO port [0xCF8-0xCFF] is consumed by the host bridge itself 2253772aea7SJiang Liu * to access PCI configuration space. 2263772aea7SJiang Liu * 2273772aea7SJiang Liu * So explicitly filter out PCI CFG IO ports[0xCF8-0xCFF]. 228463eb297SBjorn Helgaas */ 2293772aea7SJiang Liu static bool resource_is_pcicfg_ioport(struct resource *res) 2303772aea7SJiang Liu { 2313772aea7SJiang Liu return (res->flags & IORESOURCE_IO) && 2323772aea7SJiang Liu res->start == 0xCF8 && res->end == 0xCFF; 233463eb297SBjorn Helgaas } 234463eb297SBjorn Helgaas 23502715e86SJiang Liu static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci) 2361da177e4SLinus Torvalds { 23702715e86SJiang Liu struct device *dev = &ci->bridge->dev; 23802715e86SJiang Liu struct pci_root_info *info; 23902715e86SJiang Liu struct resource *res; 2403772aea7SJiang Liu struct resource_entry *entry, *tmp; 24102715e86SJiang Liu int status; 2421da177e4SLinus Torvalds 24302715e86SJiang Liu status = acpi_pci_probe_root_resources(ci); 24402715e86SJiang Liu if (status > 0) { 24502715e86SJiang Liu info = container_of(ci, struct pci_root_info, common); 24602715e86SJiang Liu resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { 2473772aea7SJiang Liu res = entry->res; 2483772aea7SJiang Liu if (res->flags & IORESOURCE_MEM) { 2493772aea7SJiang Liu /* 25002715e86SJiang Liu * HP's firmware has a hack to work around a 25102715e86SJiang Liu * Windows bug. Ignore these tiny memory ranges. 2523772aea7SJiang Liu */ 2533772aea7SJiang Liu if (resource_size(res) <= 16) { 25402715e86SJiang Liu resource_list_del(entry); 25502715e86SJiang Liu insert_resource(&iomem_resource, 25602715e86SJiang Liu entry->res); 25702715e86SJiang Liu resource_list_add_tail(entry, 25802715e86SJiang Liu &info->io_resources); 2593772aea7SJiang Liu } 2603772aea7SJiang Liu } else if (res->flags & IORESOURCE_IO) { 26102715e86SJiang Liu if (resource_is_pcicfg_ioport(entry->res)) 2623772aea7SJiang Liu resource_list_destroy_entry(entry); 26302715e86SJiang Liu else if (add_io_space(dev, info, entry)) 2643772aea7SJiang Liu resource_list_destroy_entry(entry); 2653772aea7SJiang Liu } 2663772aea7SJiang Liu } 267c9e391cfSJiang Liu } 268c9e391cfSJiang Liu 26902715e86SJiang Liu return status; 27002715e86SJiang Liu } 27102715e86SJiang Liu 27202715e86SJiang Liu static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci) 273c9e391cfSJiang Liu { 27402715e86SJiang Liu struct pci_root_info *info; 27502715e86SJiang Liu struct resource_entry *entry, *tmp; 276c9e391cfSJiang Liu 27702715e86SJiang Liu info = container_of(ci, struct pci_root_info, common); 27802715e86SJiang Liu resource_list_for_each_entry_safe(entry, tmp, &info->io_resources) { 2793f7abdefSJiang Liu release_resource(entry->res); 2803f7abdefSJiang Liu resource_list_destroy_entry(entry); 281c9e391cfSJiang Liu } 282c9e391cfSJiang Liu kfree(info); 283c9e391cfSJiang Liu } 284c9e391cfSJiang Liu 28502715e86SJiang Liu static struct acpi_pci_root_ops pci_acpi_root_ops = { 28602715e86SJiang Liu .pci_ops = &pci_root_ops, 28702715e86SJiang Liu .release_info = pci_acpi_root_release_info, 28802715e86SJiang Liu .prepare_resources = pci_acpi_root_prepare_resources, 28902715e86SJiang Liu }; 2902932239fSYijing Wang 2915b5e76e9SGreg Kroah-Hartman struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) 2921da177e4SLinus Torvalds { 29357283776SBjorn Helgaas struct acpi_device *device = root->device; 2943772aea7SJiang Liu struct pci_root_info *info; 2951da177e4SLinus Torvalds 296429ac099SYijing Wang info = kzalloc(sizeof(*info), GFP_KERNEL); 297429ac099SYijing Wang if (!info) { 298c4cbf6b9SYijing Wang dev_err(&device->dev, 299429ac099SYijing Wang "pci_bus %04x:%02x: ignored (out of memory)\n", 30002715e86SJiang Liu root->segment, (int)root->secondary.start); 3013a72af09SYijing Wang return NULL; 302429ac099SYijing Wang } 3031da177e4SLinus Torvalds 30402715e86SJiang Liu info->controller.segment = root->segment; 3053772aea7SJiang Liu info->controller.companion = device; 3063772aea7SJiang Liu info->controller.node = acpi_get_node(device->handle); 3073772aea7SJiang Liu INIT_LIST_HEAD(&info->io_resources); 30802715e86SJiang Liu return acpi_pci_root_create(root, &pci_acpi_root_ops, 30902715e86SJiang Liu &info->common, &info->controller); 3101da177e4SLinus Torvalds } 3111da177e4SLinus Torvalds 3126c0cc950SRafael J. Wysocki int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) 3136c0cc950SRafael J. Wysocki { 314dc4fdaf0SRafael J. Wysocki /* 315dc4fdaf0SRafael J. Wysocki * We pass NULL as parent to pci_create_root_bus(), so if it is not NULL 316dc4fdaf0SRafael J. Wysocki * here, pci_create_root_bus() has been called by someone else and 317dc4fdaf0SRafael J. Wysocki * sysdata is likely to be different from what we expect. Let it go in 318dc4fdaf0SRafael J. Wysocki * that case. 319dc4fdaf0SRafael J. Wysocki */ 320dc4fdaf0SRafael J. Wysocki if (!bridge->dev.parent) { 3216c0cc950SRafael J. Wysocki struct pci_controller *controller = bridge->bus->sysdata; 3227b199811SRafael J. Wysocki ACPI_COMPANION_SET(&bridge->dev, controller->companion); 323dc4fdaf0SRafael J. Wysocki } 3246c0cc950SRafael J. Wysocki return 0; 3256c0cc950SRafael J. Wysocki } 3266c0cc950SRafael J. Wysocki 3275b5e76e9SGreg Kroah-Hartman void pcibios_fixup_device_resources(struct pci_dev *dev) 3287b9c8ba2SKenji Kaneshige { 329ce821ef0SYinghai Lu int idx; 330ce821ef0SYinghai Lu 331ce821ef0SYinghai Lu if (!dev->bus) 332ce821ef0SYinghai Lu return; 333ce821ef0SYinghai Lu 334ce821ef0SYinghai Lu for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) { 335ce821ef0SYinghai Lu struct resource *r = &dev->resource[idx]; 336ce821ef0SYinghai Lu 337ce821ef0SYinghai Lu if (!r->flags || r->parent || !r->start) 338ce821ef0SYinghai Lu continue; 339ce821ef0SYinghai Lu 340ce821ef0SYinghai Lu pci_claim_resource(dev, idx); 341ce821ef0SYinghai Lu } 3427b9c8ba2SKenji Kaneshige } 3438ea6091fSJohn Keller EXPORT_SYMBOL_GPL(pcibios_fixup_device_resources); 3447b9c8ba2SKenji Kaneshige 3455b5e76e9SGreg Kroah-Hartman static void pcibios_fixup_bridge_resources(struct pci_dev *dev) 3467b9c8ba2SKenji Kaneshige { 347ce821ef0SYinghai Lu int idx; 348ce821ef0SYinghai Lu 349ce821ef0SYinghai Lu if (!dev->bus) 350ce821ef0SYinghai Lu return; 351ce821ef0SYinghai Lu 352ce821ef0SYinghai Lu for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { 353ce821ef0SYinghai Lu struct resource *r = &dev->resource[idx]; 354ce821ef0SYinghai Lu 355ce821ef0SYinghai Lu if (!r->flags || r->parent || !r->start) 356ce821ef0SYinghai Lu continue; 357ce821ef0SYinghai Lu 358ce821ef0SYinghai Lu pci_claim_bridge_resource(dev, idx); 359ce821ef0SYinghai Lu } 3607b9c8ba2SKenji Kaneshige } 3617b9c8ba2SKenji Kaneshige 3621da177e4SLinus Torvalds /* 3631da177e4SLinus Torvalds * Called after each bus is probed, but before its children are examined. 3641da177e4SLinus Torvalds */ 3655b5e76e9SGreg Kroah-Hartman void pcibios_fixup_bus(struct pci_bus *b) 3661da177e4SLinus Torvalds { 3671da177e4SLinus Torvalds struct pci_dev *dev; 3681da177e4SLinus Torvalds 369237865f1SBjorn Helgaas if (b->self) { 370237865f1SBjorn Helgaas pci_read_bridge_bases(b); 3717b9c8ba2SKenji Kaneshige pcibios_fixup_bridge_resources(b->self); 372237865f1SBjorn Helgaas } 3731da177e4SLinus Torvalds list_for_each_entry(dev, &b->devices, bus_list) 3741da177e4SLinus Torvalds pcibios_fixup_device_resources(dev); 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds 377b02a4a19SJiang Liu void pcibios_add_bus(struct pci_bus *bus) 378b02a4a19SJiang Liu { 379b02a4a19SJiang Liu acpi_pci_add_bus(bus); 380b02a4a19SJiang Liu } 381b02a4a19SJiang Liu 382b02a4a19SJiang Liu void pcibios_remove_bus(struct pci_bus *bus) 383b02a4a19SJiang Liu { 384b02a4a19SJiang Liu acpi_pci_remove_bus(bus); 385b02a4a19SJiang Liu } 386b02a4a19SJiang Liu 38791e86df1SMyron Stowe void pcibios_set_master (struct pci_dev *dev) 38891e86df1SMyron Stowe { 38991e86df1SMyron Stowe /* No special bus mastering setup handling */ 39091e86df1SMyron Stowe } 39191e86df1SMyron Stowe 3921da177e4SLinus Torvalds int 3931da177e4SLinus Torvalds pcibios_enable_device (struct pci_dev *dev, int mask) 3941da177e4SLinus Torvalds { 3951da177e4SLinus Torvalds int ret; 3961da177e4SLinus Torvalds 397d981f163SBjorn Helgaas ret = pci_enable_resources(dev, mask); 3981da177e4SLinus Torvalds if (ret < 0) 3991da177e4SLinus Torvalds return ret; 4001da177e4SLinus Torvalds 4015a1e0baaSBjorn Helgaas if (!pci_dev_msi_enabled(dev)) 4021da177e4SLinus Torvalds return acpi_pci_irq_enable(dev); 403bba6f6fcSEric W. Biederman return 0; 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds void 4071da177e4SLinus Torvalds pcibios_disable_device (struct pci_dev *dev) 4081da177e4SLinus Torvalds { 409c7f570a5SPeter Chubb BUG_ON(atomic_read(&dev->enable_cnt)); 4105a1e0baaSBjorn Helgaas if (!pci_dev_msi_enabled(dev)) 4111da177e4SLinus Torvalds acpi_pci_irq_disable(dev); 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds /** 41505933aacSChristoph Hellwig * pci_get_legacy_mem - generic legacy mem routine 4161da177e4SLinus Torvalds * @bus: bus to get legacy memory base address for 4171da177e4SLinus Torvalds * 4181da177e4SLinus Torvalds * Find the base of legacy memory for @bus. This is typically the first 4191da177e4SLinus Torvalds * megabyte of bus address space for @bus or is simply 0 on platforms whose 4201da177e4SLinus Torvalds * chipsets support legacy I/O and memory routing. Returns the base address 4211da177e4SLinus Torvalds * or an error pointer if an error occurred. 4221da177e4SLinus Torvalds * 4231da177e4SLinus Torvalds * This is the ia64 generic version of this routine. Other platforms 4241da177e4SLinus Torvalds * are free to override it with a machine vector. 4251da177e4SLinus Torvalds */ 42605933aacSChristoph Hellwig char *pci_get_legacy_mem(struct pci_bus *bus) 4271da177e4SLinus Torvalds { 4281da177e4SLinus Torvalds return (char *)__IA64_UNCACHED_OFFSET; 4291da177e4SLinus Torvalds } 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds /** 4321da177e4SLinus Torvalds * pci_mmap_legacy_page_range - map legacy memory space to userland 4331da177e4SLinus Torvalds * @bus: bus whose legacy space we're mapping 4341da177e4SLinus Torvalds * @vma: vma passed in by mmap 4351da177e4SLinus Torvalds * 4361da177e4SLinus Torvalds * Map legacy memory space for this device back to userspace using a machine 4371da177e4SLinus Torvalds * vector to get the base address. 4381da177e4SLinus Torvalds */ 4391da177e4SLinus Torvalds int 440f19aeb1fSBenjamin Herrenschmidt pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma, 441f19aeb1fSBenjamin Herrenschmidt enum pci_mmap_state mmap_state) 4421da177e4SLinus Torvalds { 44332e62c63SBjorn Helgaas unsigned long size = vma->vm_end - vma->vm_start; 44432e62c63SBjorn Helgaas pgprot_t prot; 4451da177e4SLinus Torvalds char *addr; 4461da177e4SLinus Torvalds 447f19aeb1fSBenjamin Herrenschmidt /* We only support mmap'ing of legacy memory space */ 448f19aeb1fSBenjamin Herrenschmidt if (mmap_state != pci_mmap_mem) 449f19aeb1fSBenjamin Herrenschmidt return -ENOSYS; 450f19aeb1fSBenjamin Herrenschmidt 45132e62c63SBjorn Helgaas /* 452db9a0975SMauro Carvalho Chehab * Avoid attribute aliasing. See Documentation/ia64/aliasing.rst 45332e62c63SBjorn Helgaas * for more details. 45432e62c63SBjorn Helgaas */ 45506c67befSLennert Buytenhek if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) 45632e62c63SBjorn Helgaas return -EINVAL; 45732e62c63SBjorn Helgaas prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size, 45832e62c63SBjorn Helgaas vma->vm_page_prot); 45932e62c63SBjorn Helgaas 4601da177e4SLinus Torvalds addr = pci_get_legacy_mem(bus); 4611da177e4SLinus Torvalds if (IS_ERR(addr)) 4621da177e4SLinus Torvalds return PTR_ERR(addr); 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds vma->vm_pgoff += (unsigned long)addr >> PAGE_SHIFT; 46532e62c63SBjorn Helgaas vma->vm_page_prot = prot; 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, 46832e62c63SBjorn Helgaas size, vma->vm_page_prot)) 4691da177e4SLinus Torvalds return -EAGAIN; 4701da177e4SLinus Torvalds 4711da177e4SLinus Torvalds return 0; 4721da177e4SLinus Torvalds } 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds /** 47505933aacSChristoph Hellwig * pci_legacy_read - read from legacy I/O space 4761da177e4SLinus Torvalds * @bus: bus to read 4771da177e4SLinus Torvalds * @port: legacy port value 4781da177e4SLinus Torvalds * @val: caller allocated storage for returned value 4791da177e4SLinus Torvalds * @size: number of bytes to read 4801da177e4SLinus Torvalds * 4811da177e4SLinus Torvalds * Simply reads @size bytes from @port and puts the result in @val. 4821da177e4SLinus Torvalds * 4831da177e4SLinus Torvalds * Again, this (and the write routine) are generic versions that can be 4841da177e4SLinus Torvalds * overridden by the platform. This is necessary on platforms that don't 4851da177e4SLinus Torvalds * support legacy I/O routing or that hard fail on legacy I/O timeouts. 4861da177e4SLinus Torvalds */ 48705933aacSChristoph Hellwig int pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size) 4881da177e4SLinus Torvalds { 4891da177e4SLinus Torvalds int ret = size; 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds switch (size) { 4921da177e4SLinus Torvalds case 1: 4931da177e4SLinus Torvalds *val = inb(port); 4941da177e4SLinus Torvalds break; 4951da177e4SLinus Torvalds case 2: 4961da177e4SLinus Torvalds *val = inw(port); 4971da177e4SLinus Torvalds break; 4981da177e4SLinus Torvalds case 4: 4991da177e4SLinus Torvalds *val = inl(port); 5001da177e4SLinus Torvalds break; 5011da177e4SLinus Torvalds default: 5021da177e4SLinus Torvalds ret = -EINVAL; 5031da177e4SLinus Torvalds break; 5041da177e4SLinus Torvalds } 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds return ret; 5071da177e4SLinus Torvalds } 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds /** 51005933aacSChristoph Hellwig * pci_legacy_write - perform a legacy I/O write 5111da177e4SLinus Torvalds * @bus: bus pointer 5121da177e4SLinus Torvalds * @port: port to write 5131da177e4SLinus Torvalds * @val: value to write 5141da177e4SLinus Torvalds * @size: number of bytes to write from @val 5151da177e4SLinus Torvalds * 5161da177e4SLinus Torvalds * Simply writes @size bytes of @val to @port. 5171da177e4SLinus Torvalds */ 51805933aacSChristoph Hellwig int pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size) 5191da177e4SLinus Torvalds { 520408045afSAlex Williamson int ret = size; 5211da177e4SLinus Torvalds 5221da177e4SLinus Torvalds switch (size) { 5231da177e4SLinus Torvalds case 1: 5241da177e4SLinus Torvalds outb(val, port); 5251da177e4SLinus Torvalds break; 5261da177e4SLinus Torvalds case 2: 5271da177e4SLinus Torvalds outw(val, port); 5281da177e4SLinus Torvalds break; 5291da177e4SLinus Torvalds case 4: 5301da177e4SLinus Torvalds outl(val, port); 5311da177e4SLinus Torvalds break; 5321da177e4SLinus Torvalds default: 5331da177e4SLinus Torvalds ret = -EINVAL; 5341da177e4SLinus Torvalds break; 5351da177e4SLinus Torvalds } 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds return ret; 5381da177e4SLinus Torvalds } 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds /** 5413efe2d84SMatthew Wilcox * set_pci_cacheline_size - determine cacheline size for PCI devices 5421da177e4SLinus Torvalds * 5431da177e4SLinus Torvalds * We want to use the line-size of the outer-most cache. We assume 5441da177e4SLinus Torvalds * that this line-size is the same for all CPUs. 5451da177e4SLinus Torvalds * 5461da177e4SLinus Torvalds * Code mostly taken from arch/ia64/kernel/palinfo.c:cache_info(). 5471da177e4SLinus Torvalds */ 548ac1aa47bSJesse Barnes static void __init set_pci_dfl_cacheline_size(void) 5491da177e4SLinus Torvalds { 550e088a4adSMatthew Wilcox unsigned long levels, unique_caches; 551e088a4adSMatthew Wilcox long status; 5521da177e4SLinus Torvalds pal_cache_config_info_t cci; 5531da177e4SLinus Torvalds 5541da177e4SLinus Torvalds status = ia64_pal_cache_summary(&levels, &unique_caches); 5551da177e4SLinus Torvalds if (status != 0) { 556c4cbf6b9SYijing Wang pr_err("%s: ia64_pal_cache_summary() failed " 557d4ed8084SHarvey Harrison "(status=%ld)\n", __func__, status); 5583efe2d84SMatthew Wilcox return; 5591da177e4SLinus Torvalds } 5601da177e4SLinus Torvalds 5613efe2d84SMatthew Wilcox status = ia64_pal_cache_config_info(levels - 1, 5623efe2d84SMatthew Wilcox /* cache_type (data_or_unified)= */ 2, &cci); 5631da177e4SLinus Torvalds if (status != 0) { 564c4cbf6b9SYijing Wang pr_err("%s: ia64_pal_cache_config_info() failed " 565d4ed8084SHarvey Harrison "(status=%ld)\n", __func__, status); 5663efe2d84SMatthew Wilcox return; 5671da177e4SLinus Torvalds } 568ac1aa47bSJesse Barnes pci_dfl_cache_line_size = (1 << cci.pcci_line_size) / 4; 5691da177e4SLinus Torvalds } 5701da177e4SLinus Torvalds 5713efe2d84SMatthew Wilcox static int __init pcibios_init(void) 5721da177e4SLinus Torvalds { 573ac1aa47bSJesse Barnes set_pci_dfl_cacheline_size(); 5743efe2d84SMatthew Wilcox return 0; 5753efe2d84SMatthew Wilcox } 5761da177e4SLinus Torvalds 5773efe2d84SMatthew Wilcox subsys_initcall(pcibios_init); 578