xref: /openbmc/linux/drivers/pci/bus.c (revision c845428b7a9157523103100806bc8130d64769c8)
17328c8f4SBjorn Helgaas // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * From setup-res.c, by:
41da177e4SLinus Torvalds  *	Dave Rusling (david.rusling@reo.mts.dec.com)
51da177e4SLinus Torvalds  *	David Mosberger (davidm@cs.arizona.edu)
61da177e4SLinus Torvalds  *	David Miller (davem@redhat.com)
71da177e4SLinus Torvalds  *	Ivan Kokshaysky (ink@jurassic.park.msu.ru)
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds #include <linux/module.h>
101da177e4SLinus Torvalds #include <linux/kernel.h>
111da177e4SLinus Torvalds #include <linux/pci.h>
121da177e4SLinus Torvalds #include <linux/errno.h>
131da177e4SLinus Torvalds #include <linux/ioport.h>
141a8c251cSVladimir Oltean #include <linux/of.h>
151da177e4SLinus Torvalds #include <linux/proc_fs.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds #include "pci.h"
191da177e4SLinus Torvalds 
pci_add_resource_offset(struct list_head * resources,struct resource * res,resource_size_t offset)200efd5aabSBjorn Helgaas void pci_add_resource_offset(struct list_head *resources, struct resource *res,
210efd5aabSBjorn Helgaas 			     resource_size_t offset)
2245ca9e97SBjorn Helgaas {
2314d76b68SJiang Liu 	struct resource_entry *entry;
2445ca9e97SBjorn Helgaas 
2514d76b68SJiang Liu 	entry = resource_list_create_entry(res, 0);
2614d76b68SJiang Liu 	if (!entry) {
2725da8dbaSMohan Kumar 		pr_err("PCI: can't add host bridge window %pR\n", res);
2845ca9e97SBjorn Helgaas 		return;
2945ca9e97SBjorn Helgaas 	}
3045ca9e97SBjorn Helgaas 
3114d76b68SJiang Liu 	entry->offset = offset;
3214d76b68SJiang Liu 	resource_list_add_tail(entry, resources);
330efd5aabSBjorn Helgaas }
340efd5aabSBjorn Helgaas EXPORT_SYMBOL(pci_add_resource_offset);
350efd5aabSBjorn Helgaas 
pci_add_resource(struct list_head * resources,struct resource * res)360efd5aabSBjorn Helgaas void pci_add_resource(struct list_head *resources, struct resource *res)
370efd5aabSBjorn Helgaas {
380efd5aabSBjorn Helgaas 	pci_add_resource_offset(resources, res, 0);
3945ca9e97SBjorn Helgaas }
4045ca9e97SBjorn Helgaas EXPORT_SYMBOL(pci_add_resource);
4145ca9e97SBjorn Helgaas 
pci_free_resource_list(struct list_head * resources)4245ca9e97SBjorn Helgaas void pci_free_resource_list(struct list_head *resources)
4345ca9e97SBjorn Helgaas {
4414d76b68SJiang Liu 	resource_list_free(resources);
4545ca9e97SBjorn Helgaas }
4645ca9e97SBjorn Helgaas EXPORT_SYMBOL(pci_free_resource_list);
4745ca9e97SBjorn Helgaas 
pci_bus_add_resource(struct pci_bus * bus,struct resource * res,unsigned int flags)482fe2abf8SBjorn Helgaas void pci_bus_add_resource(struct pci_bus *bus, struct resource *res,
492fe2abf8SBjorn Helgaas 			  unsigned int flags)
502fe2abf8SBjorn Helgaas {
512fe2abf8SBjorn Helgaas 	struct pci_bus_resource *bus_res;
522fe2abf8SBjorn Helgaas 
532fe2abf8SBjorn Helgaas 	bus_res = kzalloc(sizeof(struct pci_bus_resource), GFP_KERNEL);
542fe2abf8SBjorn Helgaas 	if (!bus_res) {
552fe2abf8SBjorn Helgaas 		dev_err(&bus->dev, "can't add %pR resource\n", res);
562fe2abf8SBjorn Helgaas 		return;
572fe2abf8SBjorn Helgaas 	}
582fe2abf8SBjorn Helgaas 
592fe2abf8SBjorn Helgaas 	bus_res->res = res;
602fe2abf8SBjorn Helgaas 	bus_res->flags = flags;
612fe2abf8SBjorn Helgaas 	list_add_tail(&bus_res->list, &bus->resources);
622fe2abf8SBjorn Helgaas }
632fe2abf8SBjorn Helgaas 
pci_bus_resource_n(const struct pci_bus * bus,int n)642fe2abf8SBjorn Helgaas struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n)
652fe2abf8SBjorn Helgaas {
662fe2abf8SBjorn Helgaas 	struct pci_bus_resource *bus_res;
672fe2abf8SBjorn Helgaas 
682fe2abf8SBjorn Helgaas 	if (n < PCI_BRIDGE_RESOURCE_NUM)
692fe2abf8SBjorn Helgaas 		return bus->resource[n];
702fe2abf8SBjorn Helgaas 
712fe2abf8SBjorn Helgaas 	n -= PCI_BRIDGE_RESOURCE_NUM;
722fe2abf8SBjorn Helgaas 	list_for_each_entry(bus_res, &bus->resources, list) {
732fe2abf8SBjorn Helgaas 		if (n-- == 0)
742fe2abf8SBjorn Helgaas 			return bus_res->res;
752fe2abf8SBjorn Helgaas 	}
762fe2abf8SBjorn Helgaas 	return NULL;
772fe2abf8SBjorn Helgaas }
782fe2abf8SBjorn Helgaas EXPORT_SYMBOL_GPL(pci_bus_resource_n);
792fe2abf8SBjorn Helgaas 
pci_bus_remove_resource(struct pci_bus * bus,struct resource * res)80ab909509SNiklas Schnelle void pci_bus_remove_resource(struct pci_bus *bus, struct resource *res)
81ab909509SNiklas Schnelle {
82ab909509SNiklas Schnelle 	struct pci_bus_resource *bus_res, *tmp;
83ab909509SNiklas Schnelle 	int i;
84ab909509SNiklas Schnelle 
85ab909509SNiklas Schnelle 	for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
86ab909509SNiklas Schnelle 		if (bus->resource[i] == res) {
87ab909509SNiklas Schnelle 			bus->resource[i] = NULL;
88ab909509SNiklas Schnelle 			return;
89ab909509SNiklas Schnelle 		}
90ab909509SNiklas Schnelle 	}
91ab909509SNiklas Schnelle 
92ab909509SNiklas Schnelle 	list_for_each_entry_safe(bus_res, tmp, &bus->resources, list) {
93ab909509SNiklas Schnelle 		if (bus_res->res == res) {
94ab909509SNiklas Schnelle 			list_del(&bus_res->list);
95ab909509SNiklas Schnelle 			kfree(bus_res);
96ab909509SNiklas Schnelle 			return;
97ab909509SNiklas Schnelle 		}
98ab909509SNiklas Schnelle 	}
99ab909509SNiklas Schnelle }
100ab909509SNiklas Schnelle 
pci_bus_remove_resources(struct pci_bus * bus)1012fe2abf8SBjorn Helgaas void pci_bus_remove_resources(struct pci_bus *bus)
1022fe2abf8SBjorn Helgaas {
1032fe2abf8SBjorn Helgaas 	int i;
104817a2685SYinghai Lu 	struct pci_bus_resource *bus_res, *tmp;
1052fe2abf8SBjorn Helgaas 
1062fe2abf8SBjorn Helgaas 	for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
1077736a05aSStephen Hemminger 		bus->resource[i] = NULL;
1082fe2abf8SBjorn Helgaas 
109817a2685SYinghai Lu 	list_for_each_entry_safe(bus_res, tmp, &bus->resources, list) {
110817a2685SYinghai Lu 		list_del(&bus_res->list);
111817a2685SYinghai Lu 		kfree(bus_res);
112817a2685SYinghai Lu 	}
1132fe2abf8SBjorn Helgaas }
1142fe2abf8SBjorn Helgaas 
devm_request_pci_bus_resources(struct device * dev,struct list_head * resources)115950334bcSBjorn Helgaas int devm_request_pci_bus_resources(struct device *dev,
116950334bcSBjorn Helgaas 				   struct list_head *resources)
117950334bcSBjorn Helgaas {
118950334bcSBjorn Helgaas 	struct resource_entry *win;
119950334bcSBjorn Helgaas 	struct resource *parent, *res;
120950334bcSBjorn Helgaas 	int err;
121950334bcSBjorn Helgaas 
122950334bcSBjorn Helgaas 	resource_list_for_each_entry(win, resources) {
123950334bcSBjorn Helgaas 		res = win->res;
124950334bcSBjorn Helgaas 		switch (resource_type(res)) {
125950334bcSBjorn Helgaas 		case IORESOURCE_IO:
126950334bcSBjorn Helgaas 			parent = &ioport_resource;
127950334bcSBjorn Helgaas 			break;
128950334bcSBjorn Helgaas 		case IORESOURCE_MEM:
129950334bcSBjorn Helgaas 			parent = &iomem_resource;
130950334bcSBjorn Helgaas 			break;
131950334bcSBjorn Helgaas 		default:
132950334bcSBjorn Helgaas 			continue;
133950334bcSBjorn Helgaas 		}
134950334bcSBjorn Helgaas 
135950334bcSBjorn Helgaas 		err = devm_request_resource(dev, parent, res);
136950334bcSBjorn Helgaas 		if (err)
137950334bcSBjorn Helgaas 			return err;
138950334bcSBjorn Helgaas 	}
139950334bcSBjorn Helgaas 
140950334bcSBjorn Helgaas 	return 0;
141950334bcSBjorn Helgaas }
142950334bcSBjorn Helgaas EXPORT_SYMBOL_GPL(devm_request_pci_bus_resources);
143950334bcSBjorn Helgaas 
144f75b99d5SYinghai Lu static struct pci_bus_region pci_32_bit = {0, 0xffffffffULL};
1458e639079SChristoph Hellwig #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
146f75b99d5SYinghai Lu static struct pci_bus_region pci_64_bit = {0,
1473a9ad0b4SYinghai Lu 				(pci_bus_addr_t) 0xffffffffffffffffULL};
1483a9ad0b4SYinghai Lu static struct pci_bus_region pci_high = {(pci_bus_addr_t) 0x100000000ULL,
1493a9ad0b4SYinghai Lu 				(pci_bus_addr_t) 0xffffffffffffffffULL};
150f75b99d5SYinghai Lu #endif
151f75b99d5SYinghai Lu 
152f75b99d5SYinghai Lu /*
153f75b99d5SYinghai Lu  * @res contains CPU addresses.  Clip it so the corresponding bus addresses
154f75b99d5SYinghai Lu  * on @bus are entirely within @region.  This is used to control the bus
155f75b99d5SYinghai Lu  * addresses of resources we allocate, e.g., we may need a resource that
156f75b99d5SYinghai Lu  * can be mapped by a 32-bit BAR.
1571da177e4SLinus Torvalds  */
pci_clip_resource_to_region(struct pci_bus * bus,struct resource * res,struct pci_bus_region * region)158f75b99d5SYinghai Lu static void pci_clip_resource_to_region(struct pci_bus *bus,
159f75b99d5SYinghai Lu 					struct resource *res,
160f75b99d5SYinghai Lu 					struct pci_bus_region *region)
161f75b99d5SYinghai Lu {
162f75b99d5SYinghai Lu 	struct pci_bus_region r;
163f75b99d5SYinghai Lu 
164f75b99d5SYinghai Lu 	pcibios_resource_to_bus(bus, &r, res);
165f75b99d5SYinghai Lu 	if (r.start < region->start)
166f75b99d5SYinghai Lu 		r.start = region->start;
167f75b99d5SYinghai Lu 	if (r.end > region->end)
168f75b99d5SYinghai Lu 		r.end = region->end;
169f75b99d5SYinghai Lu 
170f75b99d5SYinghai Lu 	if (r.end < r.start)
171f75b99d5SYinghai Lu 		res->end = res->start - 1;
172f75b99d5SYinghai Lu 	else
173f75b99d5SYinghai Lu 		pcibios_bus_to_resource(bus, res, &r);
174f75b99d5SYinghai Lu }
175f75b99d5SYinghai Lu 
pci_bus_alloc_from_region(struct pci_bus * bus,struct resource * res,resource_size_t size,resource_size_t align,resource_size_t min,unsigned long type_mask,resource_size_t (* alignf)(void *,const struct resource *,resource_size_t,resource_size_t),void * alignf_data,struct pci_bus_region * region)176f75b99d5SYinghai Lu static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
177e31dd6e4SGreg Kroah-Hartman 		resource_size_t size, resource_size_t align,
178664c2848SBjorn Helgaas 		resource_size_t min, unsigned long type_mask,
179b26b2d49SDominik Brodowski 		resource_size_t (*alignf)(void *,
1803b7a17fcSDominik Brodowski 					  const struct resource *,
181b26b2d49SDominik Brodowski 					  resource_size_t,
182e31dd6e4SGreg Kroah-Hartman 					  resource_size_t),
183f75b99d5SYinghai Lu 		void *alignf_data,
184f75b99d5SYinghai Lu 		struct pci_bus_region *region)
1851da177e4SLinus Torvalds {
186f75b99d5SYinghai Lu 	struct resource *r, avail;
187f75b99d5SYinghai Lu 	resource_size_t max;
18802992064SAndy Shevchenko 	int ret;
1891da177e4SLinus Torvalds 
190aa11fc58SBjorn Helgaas 	type_mask |= IORESOURCE_TYPE_BITS;
1911da177e4SLinus Torvalds 
19202992064SAndy Shevchenko 	pci_bus_for_each_resource(bus, r) {
1933460baa6SChristoph Biedl 		resource_size_t min_used = min;
1943460baa6SChristoph Biedl 
1956db45b76SBjorn Helgaas 		if (!r)
1966db45b76SBjorn Helgaas 			continue;
1976db45b76SBjorn Helgaas 
1981da177e4SLinus Torvalds 		/* type_mask must match */
1991da177e4SLinus Torvalds 		if ((res->flags ^ r->flags) & type_mask)
2001da177e4SLinus Torvalds 			continue;
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds 		/* We cannot allocate a non-prefetching resource
2031da177e4SLinus Torvalds 		   from a pre-fetching area */
2041da177e4SLinus Torvalds 		if ((r->flags & IORESOURCE_PREFETCH) &&
2051da177e4SLinus Torvalds 		    !(res->flags & IORESOURCE_PREFETCH))
2061da177e4SLinus Torvalds 			continue;
2071da177e4SLinus Torvalds 
208f75b99d5SYinghai Lu 		avail = *r;
209f75b99d5SYinghai Lu 		pci_clip_resource_to_region(bus, &avail, region);
210f75b99d5SYinghai Lu 
211f75b99d5SYinghai Lu 		/*
212f75b99d5SYinghai Lu 		 * "min" is typically PCIBIOS_MIN_IO or PCIBIOS_MIN_MEM to
213f75b99d5SYinghai Lu 		 * protect badly documented motherboard resources, but if
214f75b99d5SYinghai Lu 		 * this is an already-configured bridge window, its start
215f75b99d5SYinghai Lu 		 * overrides "min".
216f75b99d5SYinghai Lu 		 */
217f75b99d5SYinghai Lu 		if (avail.start)
2183460baa6SChristoph Biedl 			min_used = avail.start;
219f75b99d5SYinghai Lu 
220f75b99d5SYinghai Lu 		max = avail.end;
221f75b99d5SYinghai Lu 
2225c5fb3c3SBjorn Helgaas 		/* Don't bother if available space isn't large enough */
2235c5fb3c3SBjorn Helgaas 		if (size > max - min_used + 1)
2245c5fb3c3SBjorn Helgaas 			continue;
2255c5fb3c3SBjorn Helgaas 
2261da177e4SLinus Torvalds 		/* Ok, try it out.. */
2273460baa6SChristoph Biedl 		ret = allocate_resource(r, res, size, min_used, max,
228f75b99d5SYinghai Lu 					align, alignf, alignf_data);
2291da177e4SLinus Torvalds 		if (ret == 0)
230f75b99d5SYinghai Lu 			return 0;
2311da177e4SLinus Torvalds 	}
232f75b99d5SYinghai Lu 	return -ENOMEM;
233f75b99d5SYinghai Lu }
234f75b99d5SYinghai Lu 
2351da177e4SLinus Torvalds /**
2361da177e4SLinus Torvalds  * pci_bus_alloc_resource - allocate a resource from a parent bus
2371da177e4SLinus Torvalds  * @bus: PCI bus
2381da177e4SLinus Torvalds  * @res: resource to allocate
2391da177e4SLinus Torvalds  * @size: size of resource to allocate
2401da177e4SLinus Torvalds  * @align: alignment of resource to allocate
2411da177e4SLinus Torvalds  * @min: minimum /proc/iomem address to allocate
2421da177e4SLinus Torvalds  * @type_mask: IORESOURCE_* type flags
2431da177e4SLinus Torvalds  * @alignf: resource alignment function
2441da177e4SLinus Torvalds  * @alignf_data: data argument for resource alignment function
2451da177e4SLinus Torvalds  *
2461da177e4SLinus Torvalds  * Given the PCI bus a device resides on, the size, minimum address,
2471da177e4SLinus Torvalds  * alignment and type, try to find an acceptable resource allocation
2481da177e4SLinus Torvalds  * for a specific device resource.
2491da177e4SLinus Torvalds  */
pci_bus_alloc_resource(struct pci_bus * bus,struct resource * res,resource_size_t size,resource_size_t align,resource_size_t min,unsigned long type_mask,resource_size_t (* alignf)(void *,const struct resource *,resource_size_t,resource_size_t),void * alignf_data)250d56dbf5bSYinghai Lu int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
2511da177e4SLinus Torvalds 		resource_size_t size, resource_size_t align,
252664c2848SBjorn Helgaas 		resource_size_t min, unsigned long type_mask,
2531da177e4SLinus Torvalds 		resource_size_t (*alignf)(void *,
2541da177e4SLinus Torvalds 					  const struct resource *,
2551da177e4SLinus Torvalds 					  resource_size_t,
2561da177e4SLinus Torvalds 					  resource_size_t),
2571da177e4SLinus Torvalds 		void *alignf_data)
2581da177e4SLinus Torvalds {
2598e639079SChristoph Hellwig #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
260d56dbf5bSYinghai Lu 	int rc;
261d56dbf5bSYinghai Lu 
262d56dbf5bSYinghai Lu 	if (res->flags & IORESOURCE_MEM_64) {
263d56dbf5bSYinghai Lu 		rc = pci_bus_alloc_from_region(bus, res, size, align, min,
264d56dbf5bSYinghai Lu 					       type_mask, alignf, alignf_data,
265d56dbf5bSYinghai Lu 					       &pci_high);
266d56dbf5bSYinghai Lu 		if (rc == 0)
267d56dbf5bSYinghai Lu 			return 0;
268d56dbf5bSYinghai Lu 
269f75b99d5SYinghai Lu 		return pci_bus_alloc_from_region(bus, res, size, align, min,
270f75b99d5SYinghai Lu 						 type_mask, alignf, alignf_data,
271f75b99d5SYinghai Lu 						 &pci_64_bit);
272d56dbf5bSYinghai Lu 	}
273f75b99d5SYinghai Lu #endif
2741da177e4SLinus Torvalds 
275f75b99d5SYinghai Lu 	return pci_bus_alloc_from_region(bus, res, size, align, min,
276f75b99d5SYinghai Lu 					 type_mask, alignf, alignf_data,
277f75b99d5SYinghai Lu 					 &pci_32_bit);
2781da177e4SLinus Torvalds }
279b7fe9434SRyan Desfosses EXPORT_SYMBOL(pci_bus_alloc_resource);
2801da177e4SLinus Torvalds 
2810f7e7aeeSYinghai Lu /*
2820f7e7aeeSYinghai Lu  * The @idx resource of @dev should be a PCI-PCI bridge window.  If this
2830f7e7aeeSYinghai Lu  * resource fits inside a window of an upstream bridge, do nothing.  If it
2840f7e7aeeSYinghai Lu  * overlaps an upstream window but extends outside it, clip the resource so
2850f7e7aeeSYinghai Lu  * it fits completely inside.
2860f7e7aeeSYinghai Lu  */
pci_bus_clip_resource(struct pci_dev * dev,int idx)2870f7e7aeeSYinghai Lu bool pci_bus_clip_resource(struct pci_dev *dev, int idx)
2880f7e7aeeSYinghai Lu {
2890f7e7aeeSYinghai Lu 	struct pci_bus *bus = dev->bus;
2900f7e7aeeSYinghai Lu 	struct resource *res = &dev->resource[idx];
2910f7e7aeeSYinghai Lu 	struct resource orig_res = *res;
2920f7e7aeeSYinghai Lu 	struct resource *r;
2930f7e7aeeSYinghai Lu 
29402992064SAndy Shevchenko 	pci_bus_for_each_resource(bus, r) {
2950f7e7aeeSYinghai Lu 		resource_size_t start, end;
2960f7e7aeeSYinghai Lu 
2970f7e7aeeSYinghai Lu 		if (!r)
2980f7e7aeeSYinghai Lu 			continue;
2990f7e7aeeSYinghai Lu 
3000f7e7aeeSYinghai Lu 		if (resource_type(res) != resource_type(r))
3010f7e7aeeSYinghai Lu 			continue;
3020f7e7aeeSYinghai Lu 
3030f7e7aeeSYinghai Lu 		start = max(r->start, res->start);
3040f7e7aeeSYinghai Lu 		end = min(r->end, res->end);
3050f7e7aeeSYinghai Lu 
3060f7e7aeeSYinghai Lu 		if (start > end)
3070f7e7aeeSYinghai Lu 			continue;	/* no overlap */
3080f7e7aeeSYinghai Lu 
3090f7e7aeeSYinghai Lu 		if (res->start == start && res->end == end)
3100f7e7aeeSYinghai Lu 			return false;	/* no change */
3110f7e7aeeSYinghai Lu 
3120f7e7aeeSYinghai Lu 		res->start = start;
3130f7e7aeeSYinghai Lu 		res->end = end;
314b838b39eSBjorn Helgaas 		res->flags &= ~IORESOURCE_UNSET;
315b838b39eSBjorn Helgaas 		orig_res.flags &= ~IORESOURCE_UNSET;
31634c6b710SMohan Kumar 		pci_info(dev, "%pR clipped to %pR\n", &orig_res, res);
3170f7e7aeeSYinghai Lu 
3180f7e7aeeSYinghai Lu 		return true;
3190f7e7aeeSYinghai Lu 	}
3200f7e7aeeSYinghai Lu 
3210f7e7aeeSYinghai Lu 	return false;
3220f7e7aeeSYinghai Lu }
3230f7e7aeeSYinghai Lu 
pcibios_resource_survey_bus(struct pci_bus * bus)3243c449ed0SYinghai Lu void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { }
3253c449ed0SYinghai Lu 
pcibios_bus_add_device(struct pci_dev * pdev)3267b77061fSWei Yang void __weak pcibios_bus_add_device(struct pci_dev *pdev) { }
3277b77061fSWei Yang 
3281da177e4SLinus Torvalds /**
3294f535093SYinghai Lu  * pci_bus_add_device - start driver for a single device
3301da177e4SLinus Torvalds  * @dev: device to add
3311da177e4SLinus Torvalds  *
3324f535093SYinghai Lu  * This adds add sysfs entries and start device drivers
3331da177e4SLinus Torvalds  */
pci_bus_add_device(struct pci_dev * dev)334c893d133SYijing Wang void pci_bus_add_device(struct pci_dev *dev)
3351da177e4SLinus Torvalds {
3361a8c251cSVladimir Oltean 	struct device_node *dn = dev->dev.of_node;
337b19441afSGreg Kroah-Hartman 	int retval;
338735bff10SMyron Stowe 
3394f535093SYinghai Lu 	/*
3404f535093SYinghai Lu 	 * Can not put in pci_device_add yet because resources
3414f535093SYinghai Lu 	 * are not assigned yet for some devices.
3424f535093SYinghai Lu 	 */
3437b77061fSWei Yang 	pcibios_bus_add_device(dev);
344e253aaf0SYinghai Lu 	pci_fixup_device(pci_fixup_final, dev);
345407d1a51SLizhi Hou 	if (pci_is_bridge(dev))
346407d1a51SLizhi Hou 		of_pci_make_dev_node(dev);
3474f535093SYinghai Lu 	pci_create_sysfs_dev_files(dev);
348ef37702eSYinghai Lu 	pci_proc_attach_device(dev);
3491ed276a7SLukas Wunner 	pci_bridge_d3_update(dev);
3501da177e4SLinus Torvalds 
3511a8c251cSVladimir Oltean 	dev->match_driver = !dn || of_device_is_available(dn);
35258d9a38fSYinghai Lu 	retval = device_attach(&dev->dev);
3532194bc7cSRajat Jain 	if (retval < 0 && retval != -EPROBE_DEFER)
3547506dc79SFrederick Lawler 		pci_warn(dev, "device attach failed (%d)\n", retval);
35558d9a38fSYinghai Lu 
35644bda4b7SHari Vyas 	pci_dev_assign_added(dev, true);
3571da177e4SLinus Torvalds }
358b7fe9434SRyan Desfosses EXPORT_SYMBOL_GPL(pci_bus_add_device);
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds /**
3614f535093SYinghai Lu  * pci_bus_add_devices - start driver for PCI devices
3621da177e4SLinus Torvalds  * @bus: bus to check for new devices
3631da177e4SLinus Torvalds  *
3644f535093SYinghai Lu  * Start driver for PCI devices and add some sysfs entries.
3651da177e4SLinus Torvalds  */
pci_bus_add_devices(const struct pci_bus * bus)366c48f1670Sakpm@linux-foundation.org void pci_bus_add_devices(const struct pci_bus *bus)
3671da177e4SLinus Torvalds {
3681da177e4SLinus Torvalds 	struct pci_dev *dev;
3693fa16fdbSYu Zhao 	struct pci_bus *child;
3701da177e4SLinus Torvalds 
3711da177e4SLinus Torvalds 	list_for_each_entry(dev, &bus->devices, bus_list) {
3728a1bc901SGreg Kroah-Hartman 		/* Skip already-added devices */
37344bda4b7SHari Vyas 		if (pci_dev_is_added(dev))
3741da177e4SLinus Torvalds 			continue;
375c893d133SYijing Wang 		pci_bus_add_device(dev);
3761da177e4SLinus Torvalds 	}
3771da177e4SLinus Torvalds 
3781da177e4SLinus Torvalds 	list_for_each_entry(dev, &bus->devices, bus_list) {
3791e398eaeSLukas Wunner 		/* Skip if device attach failed */
38044bda4b7SHari Vyas 		if (!pci_dev_is_added(dev))
3811e398eaeSLukas Wunner 			continue;
3823fa16fdbSYu Zhao 		child = dev->subordinate;
383981cf9eaSJiang Liu 		if (child)
3843fa16fdbSYu Zhao 			pci_bus_add_devices(child);
3851da177e4SLinus Torvalds 	}
3861da177e4SLinus Torvalds }
387b7fe9434SRyan Desfosses EXPORT_SYMBOL(pci_bus_add_devices);
3881da177e4SLinus Torvalds 
__pci_walk_bus(struct pci_bus * top,int (* cb)(struct pci_dev *,void *),void * userdata,bool locked)389*b0f44788SJohan Hovold static void __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
390*b0f44788SJohan Hovold 			   void *userdata, bool locked)
391cecf4864SPaul Mackerras {
392cecf4864SPaul Mackerras 	struct pci_dev *dev;
393cecf4864SPaul Mackerras 	struct pci_bus *bus;
394cecf4864SPaul Mackerras 	struct list_head *next;
39570298c6eSZhang, Yanmin 	int retval;
396cecf4864SPaul Mackerras 
397cecf4864SPaul Mackerras 	bus = top;
398*b0f44788SJohan Hovold 	if (!locked)
399d71374daSZhang Yanmin 		down_read(&pci_bus_sem);
400cecf4864SPaul Mackerras 	next = top->devices.next;
401cecf4864SPaul Mackerras 	for (;;) {
402cecf4864SPaul Mackerras 		if (next == &bus->devices) {
403cecf4864SPaul Mackerras 			/* end of this bus, go up or finish */
404cecf4864SPaul Mackerras 			if (bus == top)
405cecf4864SPaul Mackerras 				break;
406cecf4864SPaul Mackerras 			next = bus->self->bus_list.next;
407cecf4864SPaul Mackerras 			bus = bus->self->bus;
408cecf4864SPaul Mackerras 			continue;
409cecf4864SPaul Mackerras 		}
410cecf4864SPaul Mackerras 		dev = list_entry(next, struct pci_dev, bus_list);
411cecf4864SPaul Mackerras 		if (dev->subordinate) {
412cecf4864SPaul Mackerras 			/* this is a pci-pci bridge, do its devices next */
413cecf4864SPaul Mackerras 			next = dev->subordinate->devices.next;
414cecf4864SPaul Mackerras 			bus = dev->subordinate;
415cecf4864SPaul Mackerras 		} else
416cecf4864SPaul Mackerras 			next = dev->bus_list.next;
417cecf4864SPaul Mackerras 
41870298c6eSZhang, Yanmin 		retval = cb(dev, userdata);
41970298c6eSZhang, Yanmin 		if (retval)
42070298c6eSZhang, Yanmin 			break;
421cecf4864SPaul Mackerras 	}
422*b0f44788SJohan Hovold 	if (!locked)
423d71374daSZhang Yanmin 		up_read(&pci_bus_sem);
424cecf4864SPaul Mackerras }
425*b0f44788SJohan Hovold 
426*b0f44788SJohan Hovold /**
427*b0f44788SJohan Hovold  *  pci_walk_bus - walk devices on/under bus, calling callback.
428*b0f44788SJohan Hovold  *  @top: bus whose devices should be walked
429*b0f44788SJohan Hovold  *  @cb: callback to be called for each device found
430*b0f44788SJohan Hovold  *  @userdata: arbitrary pointer to be passed to callback
431*b0f44788SJohan Hovold  *
432*b0f44788SJohan Hovold  *  Walk the given bus, including any bridged devices
433*b0f44788SJohan Hovold  *  on buses under this bus.  Call the provided callback
434*b0f44788SJohan Hovold  *  on each device found.
435*b0f44788SJohan Hovold  *
436*b0f44788SJohan Hovold  *  We check the return of @cb each time. If it returns anything
437*b0f44788SJohan Hovold  *  other than 0, we break out.
438*b0f44788SJohan Hovold  */
pci_walk_bus(struct pci_bus * top,int (* cb)(struct pci_dev *,void *),void * userdata)439*b0f44788SJohan Hovold void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata)
440*b0f44788SJohan Hovold {
441*b0f44788SJohan Hovold 	__pci_walk_bus(top, cb, userdata, false);
442*b0f44788SJohan Hovold }
4437c94def8SKonrad Rzeszutek Wilk EXPORT_SYMBOL_GPL(pci_walk_bus);
444cecf4864SPaul Mackerras 
pci_walk_bus_locked(struct pci_bus * top,int (* cb)(struct pci_dev *,void *),void * userdata)445*b0f44788SJohan Hovold void pci_walk_bus_locked(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata)
446*b0f44788SJohan Hovold {
447*b0f44788SJohan Hovold 	lockdep_assert_held(&pci_bus_sem);
448*b0f44788SJohan Hovold 
449*b0f44788SJohan Hovold 	__pci_walk_bus(top, cb, userdata, true);
450*b0f44788SJohan Hovold }
451*b0f44788SJohan Hovold EXPORT_SYMBOL_GPL(pci_walk_bus_locked);
452*b0f44788SJohan Hovold 
pci_bus_get(struct pci_bus * bus)453fe830ef6SJiang Liu struct pci_bus *pci_bus_get(struct pci_bus *bus)
454fe830ef6SJiang Liu {
455fe830ef6SJiang Liu 	if (bus)
456fe830ef6SJiang Liu 		get_device(&bus->dev);
457fe830ef6SJiang Liu 	return bus;
458fe830ef6SJiang Liu }
459fe830ef6SJiang Liu 
pci_bus_put(struct pci_bus * bus)460fe830ef6SJiang Liu void pci_bus_put(struct pci_bus *bus)
461fe830ef6SJiang Liu {
462fe830ef6SJiang Liu 	if (bus)
463fe830ef6SJiang Liu 		put_device(&bus->dev);
464fe830ef6SJiang Liu }
465