xref: /openbmc/linux/arch/ia64/pci/pci.c (revision 02715e86b21955f107f376d84d165424ba9cd372)
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