11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * pci.c - Low-Level PCI Access in IA-64 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Derived from bios32.c of i386 tree. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * (c) Copyright 2002, 2005 Hewlett-Packard Development Company, L.P. 71da177e4SLinus Torvalds * David Mosberger-Tang <davidm@hpl.hp.com> 81da177e4SLinus Torvalds * Bjorn Helgaas <bjorn.helgaas@hp.com> 91da177e4SLinus Torvalds * Copyright (C) 2004 Silicon Graphics, Inc. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * Note: Above list of copyright holders is incomplete... 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include <linux/acpi.h> 151da177e4SLinus Torvalds #include <linux/types.h> 161da177e4SLinus Torvalds #include <linux/kernel.h> 171da177e4SLinus Torvalds #include <linux/pci.h> 18b02a4a19SJiang Liu #include <linux/pci-acpi.h> 191da177e4SLinus Torvalds #include <linux/init.h> 201da177e4SLinus Torvalds #include <linux/ioport.h> 211da177e4SLinus Torvalds #include <linux/slab.h> 221da177e4SLinus Torvalds #include <linux/spinlock.h> 23175add19SJohn Keller #include <linux/bootmem.h> 24bd3ff194SPaul Gortmaker #include <linux/export.h> 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #include <asm/machvec.h> 271da177e4SLinus Torvalds #include <asm/page.h> 281da177e4SLinus Torvalds #include <asm/io.h> 291da177e4SLinus Torvalds #include <asm/sal.h> 301da177e4SLinus Torvalds #include <asm/smp.h> 311da177e4SLinus Torvalds #include <asm/irq.h> 321da177e4SLinus Torvalds #include <asm/hw_irq.h> 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds /* 351da177e4SLinus Torvalds * Low-level SAL-based PCI configuration access functions. Note that SAL 361da177e4SLinus Torvalds * calls are already serialized (via sal_lock), so we don't need another 371da177e4SLinus Torvalds * synchronization mechanism here. 381da177e4SLinus Torvalds */ 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds #define PCI_SAL_ADDRESS(seg, bus, devfn, reg) \ 411da177e4SLinus Torvalds (((u64) seg << 24) | (bus << 16) | (devfn << 8) | (reg)) 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds /* SAL 3.2 adds support for extended config space. */ 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds #define PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg) \ 461da177e4SLinus Torvalds (((u64) seg << 28) | (bus << 20) | (devfn << 12) | (reg)) 471da177e4SLinus Torvalds 48b6ce068aSMatthew Wilcox int raw_pci_read(unsigned int seg, unsigned int bus, unsigned int devfn, 491da177e4SLinus Torvalds int reg, int len, u32 *value) 501da177e4SLinus Torvalds { 511da177e4SLinus Torvalds u64 addr, data = 0; 521da177e4SLinus Torvalds int mode, result; 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds if (!value || (seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095)) 551da177e4SLinus Torvalds return -EINVAL; 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds if ((seg | reg) <= 255) { 581da177e4SLinus Torvalds addr = PCI_SAL_ADDRESS(seg, bus, devfn, reg); 591da177e4SLinus Torvalds mode = 0; 60adcd7403SMatthew Wilcox } else if (sal_revision >= SAL_VERSION_CODE(3,2)) { 611da177e4SLinus Torvalds addr = PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg); 621da177e4SLinus Torvalds mode = 1; 63adcd7403SMatthew Wilcox } else { 64adcd7403SMatthew Wilcox return -EINVAL; 651da177e4SLinus Torvalds } 66adcd7403SMatthew Wilcox 671da177e4SLinus Torvalds result = ia64_sal_pci_config_read(addr, mode, len, &data); 681da177e4SLinus Torvalds if (result != 0) 691da177e4SLinus Torvalds return -EINVAL; 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds *value = (u32) data; 721da177e4SLinus Torvalds return 0; 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds 75b6ce068aSMatthew Wilcox int raw_pci_write(unsigned int seg, unsigned int bus, unsigned int devfn, 761da177e4SLinus Torvalds int reg, int len, u32 value) 771da177e4SLinus Torvalds { 781da177e4SLinus Torvalds u64 addr; 791da177e4SLinus Torvalds int mode, result; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095)) 821da177e4SLinus Torvalds return -EINVAL; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds if ((seg | reg) <= 255) { 851da177e4SLinus Torvalds addr = PCI_SAL_ADDRESS(seg, bus, devfn, reg); 861da177e4SLinus Torvalds mode = 0; 87adcd7403SMatthew Wilcox } else if (sal_revision >= SAL_VERSION_CODE(3,2)) { 881da177e4SLinus Torvalds addr = PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg); 891da177e4SLinus Torvalds mode = 1; 90adcd7403SMatthew Wilcox } else { 91adcd7403SMatthew Wilcox return -EINVAL; 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds result = ia64_sal_pci_config_write(addr, mode, len, value); 941da177e4SLinus Torvalds if (result != 0) 951da177e4SLinus Torvalds return -EINVAL; 961da177e4SLinus Torvalds return 0; 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds 99b6ce068aSMatthew Wilcox static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, 100b6ce068aSMatthew Wilcox int size, u32 *value) 1011da177e4SLinus Torvalds { 102b6ce068aSMatthew Wilcox return raw_pci_read(pci_domain_nr(bus), bus->number, 1031da177e4SLinus Torvalds devfn, where, size, value); 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds 106b6ce068aSMatthew Wilcox static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, 107b6ce068aSMatthew Wilcox int size, u32 value) 1081da177e4SLinus Torvalds { 109b6ce068aSMatthew Wilcox return raw_pci_write(pci_domain_nr(bus), bus->number, 1101da177e4SLinus Torvalds devfn, where, size, value); 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds struct pci_ops pci_root_ops = { 1141da177e4SLinus Torvalds .read = pci_read, 1151da177e4SLinus Torvalds .write = pci_write, 1161da177e4SLinus Torvalds }; 1171da177e4SLinus Torvalds 1184f41d5a4SBjorn Helgaas struct pci_root_info { 119*02715e86SJiang Liu struct acpi_pci_root_info common; 1203772aea7SJiang Liu struct pci_controller controller; 121c9e391cfSJiang Liu struct list_head io_resources; 1224f41d5a4SBjorn Helgaas }; 1234f41d5a4SBjorn Helgaas 124*02715e86SJiang Liu static unsigned int new_space(u64 phys_base, int sparse) 1251da177e4SLinus Torvalds { 1264f41d5a4SBjorn Helgaas u64 mmio_base; 1271da177e4SLinus Torvalds int i; 1281da177e4SLinus Torvalds 1294f41d5a4SBjorn Helgaas if (phys_base == 0) 1304f41d5a4SBjorn Helgaas return 0; /* legacy I/O port space */ 1311da177e4SLinus Torvalds 1324f41d5a4SBjorn Helgaas mmio_base = (u64) ioremap(phys_base, 0); 1331da177e4SLinus Torvalds for (i = 0; i < num_io_spaces; i++) 1344f41d5a4SBjorn Helgaas if (io_space[i].mmio_base == mmio_base && 1351da177e4SLinus Torvalds io_space[i].sparse == sparse) 1364f41d5a4SBjorn Helgaas return i; 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds if (num_io_spaces == MAX_IO_SPACES) { 139c4cbf6b9SYijing Wang pr_err("PCI: Too many IO port spaces " 1404f41d5a4SBjorn Helgaas "(MAX_IO_SPACES=%lu)\n", MAX_IO_SPACES); 1411da177e4SLinus Torvalds return ~0; 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds i = num_io_spaces++; 1454f41d5a4SBjorn Helgaas io_space[i].mmio_base = mmio_base; 1461da177e4SLinus Torvalds io_space[i].sparse = sparse; 1471da177e4SLinus Torvalds 1484f41d5a4SBjorn Helgaas return i; 1494f41d5a4SBjorn Helgaas } 1504f41d5a4SBjorn Helgaas 1513772aea7SJiang Liu static int add_io_space(struct device *dev, struct pci_root_info *info, 1523772aea7SJiang Liu struct resource_entry *entry) 1534f41d5a4SBjorn Helgaas { 1543f7abdefSJiang Liu struct resource_entry *iospace; 1553772aea7SJiang Liu struct resource *resource, *res = entry->res; 1564f41d5a4SBjorn Helgaas char *name; 157e088a4adSMatthew Wilcox unsigned long base, min, max, base_port; 1584f41d5a4SBjorn Helgaas unsigned int sparse = 0, space_nr, len; 1594f41d5a4SBjorn Helgaas 160*02715e86SJiang Liu len = strlen(info->common.name) + 32; 1613f7abdefSJiang Liu iospace = resource_list_create_entry(NULL, len); 162c9e391cfSJiang Liu if (!iospace) { 1633772aea7SJiang Liu dev_err(dev, "PCI: No memory for %s I/O port space\n", 164*02715e86SJiang Liu info->common.name); 1653772aea7SJiang Liu return -ENOMEM; 1664f41d5a4SBjorn Helgaas } 1674f41d5a4SBjorn Helgaas 1683772aea7SJiang Liu if (res->flags & IORESOURCE_IO_SPARSE) 1694f41d5a4SBjorn Helgaas sparse = 1; 1703772aea7SJiang Liu space_nr = new_space(entry->offset, sparse); 1714f41d5a4SBjorn Helgaas if (space_nr == ~0) 172c9e391cfSJiang Liu goto free_resource; 1734f41d5a4SBjorn Helgaas 1743772aea7SJiang Liu name = (char *)(iospace + 1); 1753772aea7SJiang Liu min = res->start - entry->offset; 1763772aea7SJiang Liu max = res->end - entry->offset; 1774f41d5a4SBjorn Helgaas base = __pa(io_space[space_nr].mmio_base); 1784f41d5a4SBjorn Helgaas base_port = IO_SPACE_BASE(space_nr); 179*02715e86SJiang Liu snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->common.name, 1804f41d5a4SBjorn Helgaas base_port + min, base_port + max); 1814f41d5a4SBjorn Helgaas 1824f41d5a4SBjorn Helgaas /* 1834f41d5a4SBjorn Helgaas * The SDM guarantees the legacy 0-64K space is sparse, but if the 1844f41d5a4SBjorn Helgaas * mapping is done by the processor (not the bridge), ACPI may not 1854f41d5a4SBjorn Helgaas * mark it as sparse. 1864f41d5a4SBjorn Helgaas */ 1874f41d5a4SBjorn Helgaas if (space_nr == 0) 1884f41d5a4SBjorn Helgaas sparse = 1; 1894f41d5a4SBjorn Helgaas 1903f7abdefSJiang Liu resource = iospace->res; 1914f41d5a4SBjorn Helgaas resource->name = name; 1924f41d5a4SBjorn Helgaas resource->flags = IORESOURCE_MEM; 1934f41d5a4SBjorn Helgaas resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min); 1944f41d5a4SBjorn Helgaas resource->end = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max); 195c9e391cfSJiang Liu if (insert_resource(&iomem_resource, resource)) { 1963772aea7SJiang Liu dev_err(dev, 197c9e391cfSJiang Liu "can't allocate host bridge io space resource %pR\n", 198c9e391cfSJiang Liu resource); 199c9e391cfSJiang Liu goto free_resource; 200c9e391cfSJiang Liu } 2014f41d5a4SBjorn Helgaas 2023772aea7SJiang Liu entry->offset = base_port; 2033772aea7SJiang Liu res->start = min + base_port; 2043772aea7SJiang Liu res->end = max + base_port; 2053f7abdefSJiang Liu resource_list_add_tail(iospace, &info->io_resources); 2063772aea7SJiang Liu 2073772aea7SJiang Liu return 0; 2084f41d5a4SBjorn Helgaas 2094f41d5a4SBjorn Helgaas free_resource: 2103f7abdefSJiang Liu resource_list_free_entry(iospace); 2113772aea7SJiang Liu return -ENOSPC; 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds 214463eb297SBjorn Helgaas /* 2153772aea7SJiang Liu * An IO port or MMIO resource assigned to a PCI host bridge may be 2163772aea7SJiang Liu * consumed by the host bridge itself or available to its child 2173772aea7SJiang Liu * bus/devices. The ACPI specification defines a bit (Producer/Consumer) 2183772aea7SJiang Liu * to tell whether the resource is consumed by the host bridge itself, 2193772aea7SJiang Liu * but firmware hasn't used that bit consistently, so we can't rely on it. 2203772aea7SJiang Liu * 2213772aea7SJiang Liu * On x86 and IA64 platforms, all IO port and MMIO resources are assumed 2223772aea7SJiang Liu * to be available to child bus/devices except one special case: 2233772aea7SJiang Liu * IO port [0xCF8-0xCFF] is consumed by the host bridge itself 2243772aea7SJiang Liu * to access PCI configuration space. 2253772aea7SJiang Liu * 2263772aea7SJiang Liu * So explicitly filter out PCI CFG IO ports[0xCF8-0xCFF]. 227463eb297SBjorn Helgaas */ 2283772aea7SJiang Liu static bool resource_is_pcicfg_ioport(struct resource *res) 2293772aea7SJiang Liu { 2303772aea7SJiang Liu return (res->flags & IORESOURCE_IO) && 2313772aea7SJiang Liu res->start == 0xCF8 && res->end == 0xCFF; 232463eb297SBjorn Helgaas } 233463eb297SBjorn Helgaas 234*02715e86SJiang Liu static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci) 2351da177e4SLinus Torvalds { 236*02715e86SJiang Liu struct device *dev = &ci->bridge->dev; 237*02715e86SJiang Liu struct pci_root_info *info; 238*02715e86SJiang Liu struct resource *res; 2393772aea7SJiang Liu struct resource_entry *entry, *tmp; 240*02715e86SJiang Liu int status; 2411da177e4SLinus Torvalds 242*02715e86SJiang Liu status = acpi_pci_probe_root_resources(ci); 243*02715e86SJiang Liu if (status > 0) { 244*02715e86SJiang Liu info = container_of(ci, struct pci_root_info, common); 245*02715e86SJiang Liu resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { 2463772aea7SJiang Liu res = entry->res; 2473772aea7SJiang Liu if (res->flags & IORESOURCE_MEM) { 2483772aea7SJiang Liu /* 249*02715e86SJiang Liu * HP's firmware has a hack to work around a 250*02715e86SJiang Liu * Windows bug. Ignore these tiny memory ranges. 2513772aea7SJiang Liu */ 2523772aea7SJiang Liu if (resource_size(res) <= 16) { 253*02715e86SJiang Liu resource_list_del(entry); 254*02715e86SJiang Liu insert_resource(&iomem_resource, 255*02715e86SJiang Liu entry->res); 256*02715e86SJiang Liu resource_list_add_tail(entry, 257*02715e86SJiang Liu &info->io_resources); 2583772aea7SJiang Liu } 2593772aea7SJiang Liu } else if (res->flags & IORESOURCE_IO) { 260*02715e86SJiang Liu if (resource_is_pcicfg_ioport(entry->res)) 2613772aea7SJiang Liu resource_list_destroy_entry(entry); 262*02715e86SJiang Liu else if (add_io_space(dev, info, entry)) 2633772aea7SJiang Liu resource_list_destroy_entry(entry); 2643772aea7SJiang Liu } 2653772aea7SJiang Liu } 266c9e391cfSJiang Liu } 267c9e391cfSJiang Liu 268*02715e86SJiang Liu return status; 269*02715e86SJiang Liu } 270*02715e86SJiang Liu 271*02715e86SJiang Liu static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci) 272c9e391cfSJiang Liu { 273*02715e86SJiang Liu struct pci_root_info *info; 274*02715e86SJiang Liu struct resource_entry *entry, *tmp; 275c9e391cfSJiang Liu 276*02715e86SJiang Liu info = container_of(ci, struct pci_root_info, common); 277*02715e86SJiang Liu resource_list_for_each_entry_safe(entry, tmp, &info->io_resources) { 2783f7abdefSJiang Liu release_resource(entry->res); 2793f7abdefSJiang Liu resource_list_destroy_entry(entry); 280c9e391cfSJiang Liu } 281c9e391cfSJiang Liu kfree(info); 282c9e391cfSJiang Liu } 283c9e391cfSJiang Liu 284*02715e86SJiang Liu static struct acpi_pci_root_ops pci_acpi_root_ops = { 285*02715e86SJiang Liu .pci_ops = &pci_root_ops, 286*02715e86SJiang Liu .release_info = pci_acpi_root_release_info, 287*02715e86SJiang Liu .prepare_resources = pci_acpi_root_prepare_resources, 288*02715e86SJiang Liu }; 2892932239fSYijing Wang 2905b5e76e9SGreg Kroah-Hartman struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) 2911da177e4SLinus Torvalds { 29257283776SBjorn Helgaas struct acpi_device *device = root->device; 2933772aea7SJiang Liu struct pci_root_info *info; 2941da177e4SLinus Torvalds 295429ac099SYijing Wang info = kzalloc(sizeof(*info), GFP_KERNEL); 296429ac099SYijing Wang if (!info) { 297c4cbf6b9SYijing Wang dev_err(&device->dev, 298429ac099SYijing Wang "pci_bus %04x:%02x: ignored (out of memory)\n", 299*02715e86SJiang Liu root->segment, (int)root->secondary.start); 3003a72af09SYijing Wang return NULL; 301429ac099SYijing Wang } 3021da177e4SLinus Torvalds 303*02715e86SJiang Liu info->controller.segment = root->segment; 3043772aea7SJiang Liu info->controller.companion = device; 3053772aea7SJiang Liu info->controller.node = acpi_get_node(device->handle); 3063772aea7SJiang Liu INIT_LIST_HEAD(&info->io_resources); 307*02715e86SJiang Liu return acpi_pci_root_create(root, &pci_acpi_root_ops, 308*02715e86SJiang Liu &info->common, &info->controller); 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds 3116c0cc950SRafael J. Wysocki int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) 3126c0cc950SRafael J. Wysocki { 313dc4fdaf0SRafael J. Wysocki /* 314dc4fdaf0SRafael J. Wysocki * We pass NULL as parent to pci_create_root_bus(), so if it is not NULL 315dc4fdaf0SRafael J. Wysocki * here, pci_create_root_bus() has been called by someone else and 316dc4fdaf0SRafael J. Wysocki * sysdata is likely to be different from what we expect. Let it go in 317dc4fdaf0SRafael J. Wysocki * that case. 318dc4fdaf0SRafael J. Wysocki */ 319dc4fdaf0SRafael J. Wysocki if (!bridge->dev.parent) { 3206c0cc950SRafael J. Wysocki struct pci_controller *controller = bridge->bus->sysdata; 3217b199811SRafael J. Wysocki ACPI_COMPANION_SET(&bridge->dev, controller->companion); 322dc4fdaf0SRafael J. Wysocki } 3236c0cc950SRafael J. Wysocki return 0; 3246c0cc950SRafael J. Wysocki } 3256c0cc950SRafael J. Wysocki 3265b5e76e9SGreg Kroah-Hartman void pcibios_fixup_device_resources(struct pci_dev *dev) 3277b9c8ba2SKenji Kaneshige { 328ce821ef0SYinghai Lu int idx; 329ce821ef0SYinghai Lu 330ce821ef0SYinghai Lu if (!dev->bus) 331ce821ef0SYinghai Lu return; 332ce821ef0SYinghai Lu 333ce821ef0SYinghai Lu for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) { 334ce821ef0SYinghai Lu struct resource *r = &dev->resource[idx]; 335ce821ef0SYinghai Lu 336ce821ef0SYinghai Lu if (!r->flags || r->parent || !r->start) 337ce821ef0SYinghai Lu continue; 338ce821ef0SYinghai Lu 339ce821ef0SYinghai Lu pci_claim_resource(dev, idx); 340ce821ef0SYinghai Lu } 3417b9c8ba2SKenji Kaneshige } 3428ea6091fSJohn Keller EXPORT_SYMBOL_GPL(pcibios_fixup_device_resources); 3437b9c8ba2SKenji Kaneshige 3445b5e76e9SGreg Kroah-Hartman static void pcibios_fixup_bridge_resources(struct pci_dev *dev) 3457b9c8ba2SKenji Kaneshige { 346ce821ef0SYinghai Lu int idx; 347ce821ef0SYinghai Lu 348ce821ef0SYinghai Lu if (!dev->bus) 349ce821ef0SYinghai Lu return; 350ce821ef0SYinghai Lu 351ce821ef0SYinghai Lu for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { 352ce821ef0SYinghai Lu struct resource *r = &dev->resource[idx]; 353ce821ef0SYinghai Lu 354ce821ef0SYinghai Lu if (!r->flags || r->parent || !r->start) 355ce821ef0SYinghai Lu continue; 356ce821ef0SYinghai Lu 357ce821ef0SYinghai Lu pci_claim_bridge_resource(dev, idx); 358ce821ef0SYinghai Lu } 3597b9c8ba2SKenji Kaneshige } 3607b9c8ba2SKenji Kaneshige 3611da177e4SLinus Torvalds /* 3621da177e4SLinus Torvalds * Called after each bus is probed, but before its children are examined. 3631da177e4SLinus Torvalds */ 3645b5e76e9SGreg Kroah-Hartman void pcibios_fixup_bus(struct pci_bus *b) 3651da177e4SLinus Torvalds { 3661da177e4SLinus Torvalds struct pci_dev *dev; 3671da177e4SLinus Torvalds 368237865f1SBjorn Helgaas if (b->self) { 369237865f1SBjorn Helgaas pci_read_bridge_bases(b); 3707b9c8ba2SKenji Kaneshige pcibios_fixup_bridge_resources(b->self); 371237865f1SBjorn Helgaas } 3721da177e4SLinus Torvalds list_for_each_entry(dev, &b->devices, bus_list) 3731da177e4SLinus Torvalds pcibios_fixup_device_resources(dev); 3748ea6091fSJohn Keller platform_pci_fixup_bus(b); 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 401bba6f6fcSEric W. Biederman if (!dev->msi_enabled) 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)); 410bba6f6fcSEric W. Biederman if (!dev->msi_enabled) 4111da177e4SLinus Torvalds acpi_pci_irq_disable(dev); 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 414b26b2d49SDominik Brodowski resource_size_t 4153b7a17fcSDominik Brodowski pcibios_align_resource (void *data, const struct resource *res, 416e31dd6e4SGreg Kroah-Hartman resource_size_t size, resource_size_t align) 4171da177e4SLinus Torvalds { 418b26b2d49SDominik Brodowski return res->start; 4191da177e4SLinus Torvalds } 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds int 4221da177e4SLinus Torvalds pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, 4231da177e4SLinus Torvalds enum pci_mmap_state mmap_state, int write_combine) 4241da177e4SLinus Torvalds { 425012b7105SAlex Chiang unsigned long size = vma->vm_end - vma->vm_start; 426012b7105SAlex Chiang pgprot_t prot; 427012b7105SAlex Chiang 4281da177e4SLinus Torvalds /* 4291da177e4SLinus Torvalds * I/O space cannot be accessed via normal processor loads and 4301da177e4SLinus Torvalds * stores on this platform. 4311da177e4SLinus Torvalds */ 4321da177e4SLinus Torvalds if (mmap_state == pci_mmap_io) 4331da177e4SLinus Torvalds /* 4341da177e4SLinus Torvalds * XXX we could relax this for I/O spaces for which ACPI 4351da177e4SLinus Torvalds * indicates that the space is 1-to-1 mapped. But at the 4361da177e4SLinus Torvalds * moment, we don't support multiple PCI address spaces and 4371da177e4SLinus Torvalds * the legacy I/O space is not 1-to-1 mapped, so this is moot. 4381da177e4SLinus Torvalds */ 4391da177e4SLinus Torvalds return -EINVAL; 4401da177e4SLinus Torvalds 441012b7105SAlex Chiang if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) 442012b7105SAlex Chiang return -EINVAL; 443012b7105SAlex Chiang 444012b7105SAlex Chiang prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size, 445012b7105SAlex Chiang vma->vm_page_prot); 446012b7105SAlex Chiang 4471da177e4SLinus Torvalds /* 448012b7105SAlex Chiang * If the user requested WC, the kernel uses UC or WC for this region, 449012b7105SAlex Chiang * and the chipset supports WC, we can use WC. Otherwise, we have to 450012b7105SAlex Chiang * use the same attribute the kernel uses. 4511da177e4SLinus Torvalds */ 452012b7105SAlex Chiang if (write_combine && 453012b7105SAlex Chiang ((pgprot_val(prot) & _PAGE_MA_MASK) == _PAGE_MA_UC || 454012b7105SAlex Chiang (pgprot_val(prot) & _PAGE_MA_MASK) == _PAGE_MA_WC) && 455012b7105SAlex Chiang efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start)) 4561da177e4SLinus Torvalds vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); 4571da177e4SLinus Torvalds else 458012b7105SAlex Chiang vma->vm_page_prot = prot; 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, 4611da177e4SLinus Torvalds vma->vm_end - vma->vm_start, vma->vm_page_prot)) 4621da177e4SLinus Torvalds return -EAGAIN; 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds return 0; 4651da177e4SLinus Torvalds } 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds /** 4681da177e4SLinus Torvalds * ia64_pci_get_legacy_mem - generic legacy mem routine 4691da177e4SLinus Torvalds * @bus: bus to get legacy memory base address for 4701da177e4SLinus Torvalds * 4711da177e4SLinus Torvalds * Find the base of legacy memory for @bus. This is typically the first 4721da177e4SLinus Torvalds * megabyte of bus address space for @bus or is simply 0 on platforms whose 4731da177e4SLinus Torvalds * chipsets support legacy I/O and memory routing. Returns the base address 4741da177e4SLinus Torvalds * or an error pointer if an error occurred. 4751da177e4SLinus Torvalds * 4761da177e4SLinus Torvalds * This is the ia64 generic version of this routine. Other platforms 4771da177e4SLinus Torvalds * are free to override it with a machine vector. 4781da177e4SLinus Torvalds */ 4791da177e4SLinus Torvalds char *ia64_pci_get_legacy_mem(struct pci_bus *bus) 4801da177e4SLinus Torvalds { 4811da177e4SLinus Torvalds return (char *)__IA64_UNCACHED_OFFSET; 4821da177e4SLinus Torvalds } 4831da177e4SLinus Torvalds 4841da177e4SLinus Torvalds /** 4851da177e4SLinus Torvalds * pci_mmap_legacy_page_range - map legacy memory space to userland 4861da177e4SLinus Torvalds * @bus: bus whose legacy space we're mapping 4871da177e4SLinus Torvalds * @vma: vma passed in by mmap 4881da177e4SLinus Torvalds * 4891da177e4SLinus Torvalds * Map legacy memory space for this device back to userspace using a machine 4901da177e4SLinus Torvalds * vector to get the base address. 4911da177e4SLinus Torvalds */ 4921da177e4SLinus Torvalds int 493f19aeb1fSBenjamin Herrenschmidt pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma, 494f19aeb1fSBenjamin Herrenschmidt enum pci_mmap_state mmap_state) 4951da177e4SLinus Torvalds { 49632e62c63SBjorn Helgaas unsigned long size = vma->vm_end - vma->vm_start; 49732e62c63SBjorn Helgaas pgprot_t prot; 4981da177e4SLinus Torvalds char *addr; 4991da177e4SLinus Torvalds 500f19aeb1fSBenjamin Herrenschmidt /* We only support mmap'ing of legacy memory space */ 501f19aeb1fSBenjamin Herrenschmidt if (mmap_state != pci_mmap_mem) 502f19aeb1fSBenjamin Herrenschmidt return -ENOSYS; 503f19aeb1fSBenjamin Herrenschmidt 50432e62c63SBjorn Helgaas /* 50532e62c63SBjorn Helgaas * Avoid attribute aliasing. See Documentation/ia64/aliasing.txt 50632e62c63SBjorn Helgaas * for more details. 50732e62c63SBjorn Helgaas */ 50806c67befSLennert Buytenhek if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) 50932e62c63SBjorn Helgaas return -EINVAL; 51032e62c63SBjorn Helgaas prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size, 51132e62c63SBjorn Helgaas vma->vm_page_prot); 51232e62c63SBjorn Helgaas 5131da177e4SLinus Torvalds addr = pci_get_legacy_mem(bus); 5141da177e4SLinus Torvalds if (IS_ERR(addr)) 5151da177e4SLinus Torvalds return PTR_ERR(addr); 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds vma->vm_pgoff += (unsigned long)addr >> PAGE_SHIFT; 51832e62c63SBjorn Helgaas vma->vm_page_prot = prot; 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, 52132e62c63SBjorn Helgaas size, vma->vm_page_prot)) 5221da177e4SLinus Torvalds return -EAGAIN; 5231da177e4SLinus Torvalds 5241da177e4SLinus Torvalds return 0; 5251da177e4SLinus Torvalds } 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds /** 5281da177e4SLinus Torvalds * ia64_pci_legacy_read - read from legacy I/O space 5291da177e4SLinus Torvalds * @bus: bus to read 5301da177e4SLinus Torvalds * @port: legacy port value 5311da177e4SLinus Torvalds * @val: caller allocated storage for returned value 5321da177e4SLinus Torvalds * @size: number of bytes to read 5331da177e4SLinus Torvalds * 5341da177e4SLinus Torvalds * Simply reads @size bytes from @port and puts the result in @val. 5351da177e4SLinus Torvalds * 5361da177e4SLinus Torvalds * Again, this (and the write routine) are generic versions that can be 5371da177e4SLinus Torvalds * overridden by the platform. This is necessary on platforms that don't 5381da177e4SLinus Torvalds * support legacy I/O routing or that hard fail on legacy I/O timeouts. 5391da177e4SLinus Torvalds */ 5401da177e4SLinus Torvalds int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size) 5411da177e4SLinus Torvalds { 5421da177e4SLinus Torvalds int ret = size; 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds switch (size) { 5451da177e4SLinus Torvalds case 1: 5461da177e4SLinus Torvalds *val = inb(port); 5471da177e4SLinus Torvalds break; 5481da177e4SLinus Torvalds case 2: 5491da177e4SLinus Torvalds *val = inw(port); 5501da177e4SLinus Torvalds break; 5511da177e4SLinus Torvalds case 4: 5521da177e4SLinus Torvalds *val = inl(port); 5531da177e4SLinus Torvalds break; 5541da177e4SLinus Torvalds default: 5551da177e4SLinus Torvalds ret = -EINVAL; 5561da177e4SLinus Torvalds break; 5571da177e4SLinus Torvalds } 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds return ret; 5601da177e4SLinus Torvalds } 5611da177e4SLinus Torvalds 5621da177e4SLinus Torvalds /** 5631da177e4SLinus Torvalds * ia64_pci_legacy_write - perform a legacy I/O write 5641da177e4SLinus Torvalds * @bus: bus pointer 5651da177e4SLinus Torvalds * @port: port to write 5661da177e4SLinus Torvalds * @val: value to write 5671da177e4SLinus Torvalds * @size: number of bytes to write from @val 5681da177e4SLinus Torvalds * 5691da177e4SLinus Torvalds * Simply writes @size bytes of @val to @port. 5701da177e4SLinus Torvalds */ 571a72391e4SSatoru Takeuchi int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size) 5721da177e4SLinus Torvalds { 573408045afSAlex Williamson int ret = size; 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds switch (size) { 5761da177e4SLinus Torvalds case 1: 5771da177e4SLinus Torvalds outb(val, port); 5781da177e4SLinus Torvalds break; 5791da177e4SLinus Torvalds case 2: 5801da177e4SLinus Torvalds outw(val, port); 5811da177e4SLinus Torvalds break; 5821da177e4SLinus Torvalds case 4: 5831da177e4SLinus Torvalds outl(val, port); 5841da177e4SLinus Torvalds break; 5851da177e4SLinus Torvalds default: 5861da177e4SLinus Torvalds ret = -EINVAL; 5871da177e4SLinus Torvalds break; 5881da177e4SLinus Torvalds } 5891da177e4SLinus Torvalds 5901da177e4SLinus Torvalds return ret; 5911da177e4SLinus Torvalds } 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds /** 5943efe2d84SMatthew Wilcox * set_pci_cacheline_size - determine cacheline size for PCI devices 5951da177e4SLinus Torvalds * 5961da177e4SLinus Torvalds * We want to use the line-size of the outer-most cache. We assume 5971da177e4SLinus Torvalds * that this line-size is the same for all CPUs. 5981da177e4SLinus Torvalds * 5991da177e4SLinus Torvalds * Code mostly taken from arch/ia64/kernel/palinfo.c:cache_info(). 6001da177e4SLinus Torvalds */ 601ac1aa47bSJesse Barnes static void __init set_pci_dfl_cacheline_size(void) 6021da177e4SLinus Torvalds { 603e088a4adSMatthew Wilcox unsigned long levels, unique_caches; 604e088a4adSMatthew Wilcox long status; 6051da177e4SLinus Torvalds pal_cache_config_info_t cci; 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds status = ia64_pal_cache_summary(&levels, &unique_caches); 6081da177e4SLinus Torvalds if (status != 0) { 609c4cbf6b9SYijing Wang pr_err("%s: ia64_pal_cache_summary() failed " 610d4ed8084SHarvey Harrison "(status=%ld)\n", __func__, status); 6113efe2d84SMatthew Wilcox return; 6121da177e4SLinus Torvalds } 6131da177e4SLinus Torvalds 6143efe2d84SMatthew Wilcox status = ia64_pal_cache_config_info(levels - 1, 6153efe2d84SMatthew Wilcox /* cache_type (data_or_unified)= */ 2, &cci); 6161da177e4SLinus Torvalds if (status != 0) { 617c4cbf6b9SYijing Wang pr_err("%s: ia64_pal_cache_config_info() failed " 618d4ed8084SHarvey Harrison "(status=%ld)\n", __func__, status); 6193efe2d84SMatthew Wilcox return; 6201da177e4SLinus Torvalds } 621ac1aa47bSJesse Barnes pci_dfl_cache_line_size = (1 << cci.pcci_line_size) / 4; 6221da177e4SLinus Torvalds } 6231da177e4SLinus Torvalds 624175add19SJohn Keller u64 ia64_dma_get_required_mask(struct device *dev) 625175add19SJohn Keller { 626175add19SJohn Keller u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT); 627175add19SJohn Keller u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT)); 628175add19SJohn Keller u64 mask; 629175add19SJohn Keller 630175add19SJohn Keller if (!high_totalram) { 631175add19SJohn Keller /* convert to mask just covering totalram */ 632175add19SJohn Keller low_totalram = (1 << (fls(low_totalram) - 1)); 633175add19SJohn Keller low_totalram += low_totalram - 1; 634175add19SJohn Keller mask = low_totalram; 635175add19SJohn Keller } else { 636175add19SJohn Keller high_totalram = (1 << (fls(high_totalram) - 1)); 637175add19SJohn Keller high_totalram += high_totalram - 1; 638175add19SJohn Keller mask = (((u64)high_totalram) << 32) + 0xffffffff; 639175add19SJohn Keller } 640175add19SJohn Keller return mask; 641175add19SJohn Keller } 642175add19SJohn Keller EXPORT_SYMBOL_GPL(ia64_dma_get_required_mask); 643175add19SJohn Keller 644175add19SJohn Keller u64 dma_get_required_mask(struct device *dev) 645175add19SJohn Keller { 646175add19SJohn Keller return platform_dma_get_required_mask(dev); 647175add19SJohn Keller } 648175add19SJohn Keller EXPORT_SYMBOL_GPL(dma_get_required_mask); 649175add19SJohn Keller 6503efe2d84SMatthew Wilcox static int __init pcibios_init(void) 6511da177e4SLinus Torvalds { 652ac1aa47bSJesse Barnes set_pci_dfl_cacheline_size(); 6533efe2d84SMatthew Wilcox return 0; 6543efe2d84SMatthew Wilcox } 6551da177e4SLinus Torvalds 6563efe2d84SMatthew Wilcox subsys_initcall(pcibios_init); 657