1c0da6274SZhi-Jun Robin Fu /*
2c0da6274SZhi-Jun Robin Fu  * CDDL HEADER START
3c0da6274SZhi-Jun Robin Fu  *
4c0da6274SZhi-Jun Robin Fu  * The contents of this file are subject to the terms of the
5c0da6274SZhi-Jun Robin Fu  * Common Development and Distribution License (the "License").
6c0da6274SZhi-Jun Robin Fu  * You may not use this file except in compliance with the License.
7c0da6274SZhi-Jun Robin Fu  *
8c0da6274SZhi-Jun Robin Fu  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c0da6274SZhi-Jun Robin Fu  * or http://www.opensolaris.org/os/licensing.
10c0da6274SZhi-Jun Robin Fu  * See the License for the specific language governing permissions
11c0da6274SZhi-Jun Robin Fu  * and limitations under the License.
12c0da6274SZhi-Jun Robin Fu  *
13c0da6274SZhi-Jun Robin Fu  * When distributing Covered Code, include this CDDL HEADER in each
14c0da6274SZhi-Jun Robin Fu  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c0da6274SZhi-Jun Robin Fu  * If applicable, add the following below this CDDL HEADER, with the
16c0da6274SZhi-Jun Robin Fu  * fields enclosed by brackets "[]" replaced with your own identifying
17c0da6274SZhi-Jun Robin Fu  * information: Portions Copyright [yyyy] [name of copyright owner]
18c0da6274SZhi-Jun Robin Fu  *
19c0da6274SZhi-Jun Robin Fu  * CDDL HEADER END
20c0da6274SZhi-Jun Robin Fu  */
21c0da6274SZhi-Jun Robin Fu 
22c0da6274SZhi-Jun Robin Fu /*
238d7fafffSZhi-Jun Robin Fu  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24c0da6274SZhi-Jun Robin Fu  */
25c0da6274SZhi-Jun Robin Fu 
26c0da6274SZhi-Jun Robin Fu #include <sys/systm.h>
27c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc.h>
28c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgspace.h>
29c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgspace_impl.h>
30c0da6274SZhi-Jun Robin Fu #include <sys/sunddi.h>
31c0da6274SZhi-Jun Robin Fu #include <sys/sysmacros.h>
32c0da6274SZhi-Jun Robin Fu #include <sys/x86_archext.h>
33c0da6274SZhi-Jun Robin Fu #include <sys/pci.h>
348d7fafffSZhi-Jun Robin Fu #include <sys/cmn_err.h>
35c0da6274SZhi-Jun Robin Fu #include <vm/hat_i86.h>
36c0da6274SZhi-Jun Robin Fu #include <vm/seg_kmem.h>
37c0da6274SZhi-Jun Robin Fu #include <vm/kboot_mmu.h>
38c0da6274SZhi-Jun Robin Fu 
39c0da6274SZhi-Jun Robin Fu #define	PCIE_CFG_SPACE_SIZE	(PCI_CONF_HDR_SIZE << 4)
40c0da6274SZhi-Jun Robin Fu #define	PCI_BDF_BUS(bdf)	((((uint16_t)bdf) & 0xff00) >> 8)
41c0da6274SZhi-Jun Robin Fu #define	PCI_BDF_DEV(bdf)	((((uint16_t)bdf) & 0xf8) >> 3)
42c0da6274SZhi-Jun Robin Fu #define	PCI_BDF_FUNC(bdf)	(((uint16_t)bdf) & 0x7)
43c0da6274SZhi-Jun Robin Fu 
44c0da6274SZhi-Jun Robin Fu /* patchable variables */
45c0da6274SZhi-Jun Robin Fu volatile boolean_t pci_cfgacc_force_io = B_FALSE;
46c0da6274SZhi-Jun Robin Fu 
47c0da6274SZhi-Jun Robin Fu extern uintptr_t alloc_vaddr(size_t, paddr_t);
48c0da6274SZhi-Jun Robin Fu 
49c0da6274SZhi-Jun Robin Fu void pci_cfgacc_acc(pci_cfgacc_req_t *);
50c0da6274SZhi-Jun Robin Fu 
51c0da6274SZhi-Jun Robin Fu boolean_t pci_cfgacc_find_workaround(uint16_t);
52c0da6274SZhi-Jun Robin Fu /*
53c0da6274SZhi-Jun Robin Fu  * IS_P2ALIGNED() is used to make sure offset is 'size'-aligned, so
54c0da6274SZhi-Jun Robin Fu  * it's guaranteed that the access will not cross 4k page boundary.
55c0da6274SZhi-Jun Robin Fu  * Thus only 1 page is allocated for all config space access, and the
56c0da6274SZhi-Jun Robin Fu  * virtual address of that page is cached in pci_cfgacc_virt_base.
57c0da6274SZhi-Jun Robin Fu  */
58c0da6274SZhi-Jun Robin Fu static caddr_t pci_cfgacc_virt_base = NULL;
59c0da6274SZhi-Jun Robin Fu 
60c0da6274SZhi-Jun Robin Fu static caddr_t
pci_cfgacc_map(paddr_t phys_addr)61c0da6274SZhi-Jun Robin Fu pci_cfgacc_map(paddr_t phys_addr)
62c0da6274SZhi-Jun Robin Fu {
63c0da6274SZhi-Jun Robin Fu #ifdef __xpv
64c0da6274SZhi-Jun Robin Fu 	phys_addr = pfn_to_pa(xen_assign_pfn(mmu_btop(phys_addr))) |
65c0da6274SZhi-Jun Robin Fu 	    (phys_addr & MMU_PAGEOFFSET);
66c0da6274SZhi-Jun Robin Fu #endif
67c0da6274SZhi-Jun Robin Fu 	if (khat_running) {
68c0da6274SZhi-Jun Robin Fu 		pfn_t pfn = mmu_btop(phys_addr);
69c0da6274SZhi-Jun Robin Fu 		/*
70c0da6274SZhi-Jun Robin Fu 		 * pci_cfgacc_virt_base may hold address left from early
71c0da6274SZhi-Jun Robin Fu 		 * boot, which points to low mem. Realloc virtual address
72c0da6274SZhi-Jun Robin Fu 		 * in kernel space since it's already late in boot now.
73c0da6274SZhi-Jun Robin Fu 		 * Note: no need to unmap first, clear_boot_mappings() will
74c0da6274SZhi-Jun Robin Fu 		 * do that for us.
75c0da6274SZhi-Jun Robin Fu 		 */
768d7fafffSZhi-Jun Robin Fu 		if (pci_cfgacc_virt_base < (caddr_t)kernelbase)
778d7fafffSZhi-Jun Robin Fu 			pci_cfgacc_virt_base = vmem_alloc(heap_arena,
788d7fafffSZhi-Jun Robin Fu 			    MMU_PAGESIZE, VM_SLEEP);
798d7fafffSZhi-Jun Robin Fu 
80c0da6274SZhi-Jun Robin Fu 		hat_devload(kas.a_hat, pci_cfgacc_virt_base,
81c0da6274SZhi-Jun Robin Fu 		    MMU_PAGESIZE, pfn, PROT_READ | PROT_WRITE |
82c0da6274SZhi-Jun Robin Fu 		    HAT_STRICTORDER, HAT_LOAD_LOCK);
83c0da6274SZhi-Jun Robin Fu 	} else {
84c0da6274SZhi-Jun Robin Fu 		paddr_t	pa_base = P2ALIGN(phys_addr, MMU_PAGESIZE);
85c0da6274SZhi-Jun Robin Fu 
868d7fafffSZhi-Jun Robin Fu 		if (pci_cfgacc_virt_base == NULL)
878d7fafffSZhi-Jun Robin Fu 			pci_cfgacc_virt_base =
888d7fafffSZhi-Jun Robin Fu 			    (caddr_t)alloc_vaddr(MMU_PAGESIZE, MMU_PAGESIZE);
898d7fafffSZhi-Jun Robin Fu 
90c0da6274SZhi-Jun Robin Fu 		kbm_map((uintptr_t)pci_cfgacc_virt_base, pa_base, 0, 0);
91c0da6274SZhi-Jun Robin Fu 	}
92c0da6274SZhi-Jun Robin Fu 
93c0da6274SZhi-Jun Robin Fu 	return (pci_cfgacc_virt_base + (phys_addr & MMU_PAGEOFFSET));
94c0da6274SZhi-Jun Robin Fu }
95c0da6274SZhi-Jun Robin Fu 
96c0da6274SZhi-Jun Robin Fu static void
pci_cfgacc_unmap()97c0da6274SZhi-Jun Robin Fu pci_cfgacc_unmap()
98c0da6274SZhi-Jun Robin Fu {
99c0da6274SZhi-Jun Robin Fu 	if (khat_running)
100c0da6274SZhi-Jun Robin Fu 		hat_unload(kas.a_hat, pci_cfgacc_virt_base, MMU_PAGESIZE,
101c0da6274SZhi-Jun Robin Fu 		    HAT_UNLOAD_UNLOCK);
102c0da6274SZhi-Jun Robin Fu }
103c0da6274SZhi-Jun Robin Fu 
104c0da6274SZhi-Jun Robin Fu static void
pci_cfgacc_io(pci_cfgacc_req_t * req)105c0da6274SZhi-Jun Robin Fu pci_cfgacc_io(pci_cfgacc_req_t *req)
106c0da6274SZhi-Jun Robin Fu {
1078d7fafffSZhi-Jun Robin Fu 	uint8_t bus, dev, func;
1088d7fafffSZhi-Jun Robin Fu 	uint16_t ioacc_offset;	/* 4K config access with IO ECS */
109c0da6274SZhi-Jun Robin Fu 
110c0da6274SZhi-Jun Robin Fu 	bus = PCI_BDF_BUS(req->bdf);
111c0da6274SZhi-Jun Robin Fu 	dev = PCI_BDF_DEV(req->bdf);
112c0da6274SZhi-Jun Robin Fu 	func = PCI_BDF_FUNC(req->bdf);
113c0da6274SZhi-Jun Robin Fu 	ioacc_offset = req->offset;
1148d7fafffSZhi-Jun Robin Fu 
115c0da6274SZhi-Jun Robin Fu 	switch (req->size) {
116c0da6274SZhi-Jun Robin Fu 	case 1:
117c0da6274SZhi-Jun Robin Fu 		if (req->write)
118c0da6274SZhi-Jun Robin Fu 			(*pci_putb_func)(bus, dev, func,
119c0da6274SZhi-Jun Robin Fu 			    ioacc_offset, VAL8(req));
120c0da6274SZhi-Jun Robin Fu 		else
121c0da6274SZhi-Jun Robin Fu 			VAL8(req) = (*pci_getb_func)(bus, dev, func,
122c0da6274SZhi-Jun Robin Fu 			    ioacc_offset);
123c0da6274SZhi-Jun Robin Fu 		break;
124c0da6274SZhi-Jun Robin Fu 	case 2:
125c0da6274SZhi-Jun Robin Fu 		if (req->write)
126c0da6274SZhi-Jun Robin Fu 			(*pci_putw_func)(bus, dev, func,
127c0da6274SZhi-Jun Robin Fu 			    ioacc_offset, VAL16(req));
128c0da6274SZhi-Jun Robin Fu 		else
129c0da6274SZhi-Jun Robin Fu 			VAL16(req) = (*pci_getw_func)(bus, dev, func,
130c0da6274SZhi-Jun Robin Fu 			    ioacc_offset);
131c0da6274SZhi-Jun Robin Fu 		break;
132c0da6274SZhi-Jun Robin Fu 	case 4:
133c0da6274SZhi-Jun Robin Fu 		if (req->write)
134c0da6274SZhi-Jun Robin Fu 			(*pci_putl_func)(bus, dev, func,
135c0da6274SZhi-Jun Robin Fu 			    ioacc_offset, VAL32(req));
136c0da6274SZhi-Jun Robin Fu 		else
137c0da6274SZhi-Jun Robin Fu 			VAL32(req) = (*pci_getl_func)(bus, dev, func,
138c0da6274SZhi-Jun Robin Fu 			    ioacc_offset);
139c0da6274SZhi-Jun Robin Fu 		break;
1408d7fafffSZhi-Jun Robin Fu 	case 8:
1418d7fafffSZhi-Jun Robin Fu 		if (req->write) {
1428d7fafffSZhi-Jun Robin Fu 			(*pci_putl_func)(bus, dev, func,
1438d7fafffSZhi-Jun Robin Fu 			    ioacc_offset, VAL64(req) & 0xffffffff);
1448d7fafffSZhi-Jun Robin Fu 			(*pci_putl_func)(bus, dev, func,
1458d7fafffSZhi-Jun Robin Fu 			    ioacc_offset + 4, VAL64(req) >> 32);
1468d7fafffSZhi-Jun Robin Fu 		} else {
1478d7fafffSZhi-Jun Robin Fu 			VAL64(req) = (*pci_getl_func)(bus, dev, func,
1488d7fafffSZhi-Jun Robin Fu 			    ioacc_offset);
1498d7fafffSZhi-Jun Robin Fu 			VAL64(req) |= (uint64_t)(*pci_getl_func)(bus, dev, func,
1508d7fafffSZhi-Jun Robin Fu 			    ioacc_offset + 4) << 32;
1518d7fafffSZhi-Jun Robin Fu 		}
1528d7fafffSZhi-Jun Robin Fu 		break;
153c0da6274SZhi-Jun Robin Fu 	}
154c0da6274SZhi-Jun Robin Fu }
155c0da6274SZhi-Jun Robin Fu 
1568d7fafffSZhi-Jun Robin Fu static void
pci_cfgacc_mmio(pci_cfgacc_req_t * req)157c0da6274SZhi-Jun Robin Fu pci_cfgacc_mmio(pci_cfgacc_req_t *req)
158c0da6274SZhi-Jun Robin Fu {
159c0da6274SZhi-Jun Robin Fu 	caddr_t vaddr;
160c0da6274SZhi-Jun Robin Fu 	paddr_t paddr;
161c0da6274SZhi-Jun Robin Fu 
162c0da6274SZhi-Jun Robin Fu 	paddr = (paddr_t)req->bdf << 12;
163c0da6274SZhi-Jun Robin Fu 	paddr += mcfg_mem_base + req->offset;
164c0da6274SZhi-Jun Robin Fu 
16513763277SGuoli Shu 	mutex_enter(&pcicfg_mmio_mutex);
1668d7fafffSZhi-Jun Robin Fu 	vaddr = pci_cfgacc_map(paddr);
167c0da6274SZhi-Jun Robin Fu 
168c0da6274SZhi-Jun Robin Fu 	switch (req->size) {
169c0da6274SZhi-Jun Robin Fu 	case 1:
170c0da6274SZhi-Jun Robin Fu 		if (req->write)
171c0da6274SZhi-Jun Robin Fu 			*((uint8_t *)vaddr) = VAL8(req);
172c0da6274SZhi-Jun Robin Fu 		else
173c0da6274SZhi-Jun Robin Fu 			VAL8(req) = *((uint8_t *)vaddr);
174c0da6274SZhi-Jun Robin Fu 		break;
175c0da6274SZhi-Jun Robin Fu 	case 2:
176c0da6274SZhi-Jun Robin Fu 		if (req->write)
177c0da6274SZhi-Jun Robin Fu 			*((uint16_t *)vaddr) = VAL16(req);
178c0da6274SZhi-Jun Robin Fu 		else
179c0da6274SZhi-Jun Robin Fu 			VAL16(req) = *((uint16_t *)vaddr);
180c0da6274SZhi-Jun Robin Fu 		break;
181c0da6274SZhi-Jun Robin Fu 	case 4:
182c0da6274SZhi-Jun Robin Fu 		if (req->write)
183c0da6274SZhi-Jun Robin Fu 			*((uint32_t *)vaddr) = VAL32(req);
184c0da6274SZhi-Jun Robin Fu 		else
185c0da6274SZhi-Jun Robin Fu 			VAL32(req) = *((uint32_t *)vaddr);
186c0da6274SZhi-Jun Robin Fu 		break;
187c0da6274SZhi-Jun Robin Fu 	case 8:
188c0da6274SZhi-Jun Robin Fu 		if (req->write)
189c0da6274SZhi-Jun Robin Fu 			*((uint64_t *)vaddr) = VAL64(req);
190c0da6274SZhi-Jun Robin Fu 		else
191c0da6274SZhi-Jun Robin Fu 			VAL64(req) = *((uint64_t *)vaddr);
192c0da6274SZhi-Jun Robin Fu 		break;
193c0da6274SZhi-Jun Robin Fu 	}
194c0da6274SZhi-Jun Robin Fu 	pci_cfgacc_unmap();
19513763277SGuoli Shu 	mutex_exit(&pcicfg_mmio_mutex);
196c0da6274SZhi-Jun Robin Fu }
197c0da6274SZhi-Jun Robin Fu 
198c0da6274SZhi-Jun Robin Fu static boolean_t
pci_cfgacc_valid(pci_cfgacc_req_t * req,uint16_t cfgspc_size)199586fe2c2SZhi-Jun Robin Fu pci_cfgacc_valid(pci_cfgacc_req_t *req, uint16_t cfgspc_size)
200c0da6274SZhi-Jun Robin Fu {
2018d7fafffSZhi-Jun Robin Fu 	int sz = req->size;
2028d7fafffSZhi-Jun Robin Fu 
2038d7fafffSZhi-Jun Robin Fu 	if (IS_P2ALIGNED(req->offset, sz) &&
204586fe2c2SZhi-Jun Robin Fu 	    (req->offset + sz - 1 < cfgspc_size) &&
2058d7fafffSZhi-Jun Robin Fu 	    ((sz & 0xf) && ISP2(sz)))
2068d7fafffSZhi-Jun Robin Fu 		return (B_TRUE);
2078d7fafffSZhi-Jun Robin Fu 
2088d7fafffSZhi-Jun Robin Fu 	cmn_err(CE_WARN, "illegal PCI request: offset = %x, size = %d",
2098d7fafffSZhi-Jun Robin Fu 	    req->offset, sz);
2108d7fafffSZhi-Jun Robin Fu 	return (B_FALSE);
211c0da6274SZhi-Jun Robin Fu }
212c0da6274SZhi-Jun Robin Fu 
213c0da6274SZhi-Jun Robin Fu void
pci_cfgacc_check_io(pci_cfgacc_req_t * req)2148d7fafffSZhi-Jun Robin Fu pci_cfgacc_check_io(pci_cfgacc_req_t *req)
215c0da6274SZhi-Jun Robin Fu {
216c0da6274SZhi-Jun Robin Fu 	uint8_t bus;
217c0da6274SZhi-Jun Robin Fu 
218c0da6274SZhi-Jun Robin Fu 	bus = PCI_BDF_BUS(req->bdf);
219c0da6274SZhi-Jun Robin Fu 
220*4da99751SToomas Soome 	if (pci_cfgacc_force_io || (mcfg_mem_base == 0) ||
2218d7fafffSZhi-Jun Robin Fu 	    (bus < mcfg_bus_start) || (bus > mcfg_bus_end) ||
2228d7fafffSZhi-Jun Robin Fu 	    pci_cfgacc_find_workaround(req->bdf))
2238d7fafffSZhi-Jun Robin Fu 		req->ioacc = B_TRUE;
2248d7fafffSZhi-Jun Robin Fu }
225c0da6274SZhi-Jun Robin Fu 
2268d7fafffSZhi-Jun Robin Fu void
pci_cfgacc_acc(pci_cfgacc_req_t * req)2278d7fafffSZhi-Jun Robin Fu pci_cfgacc_acc(pci_cfgacc_req_t *req)
2288d7fafffSZhi-Jun Robin Fu {
2298d7fafffSZhi-Jun Robin Fu 	if (!req->write)
2308d7fafffSZhi-Jun Robin Fu 		VAL64(req) = (uint64_t)-1;
231c0da6274SZhi-Jun Robin Fu 
2328d7fafffSZhi-Jun Robin Fu 	pci_cfgacc_check_io(req);
233c0da6274SZhi-Jun Robin Fu 
2348d7fafffSZhi-Jun Robin Fu 	if (req->ioacc) {
235586fe2c2SZhi-Jun Robin Fu 		if (pci_cfgacc_valid(req, pci_iocfg_max_offset + 1))
2368d7fafffSZhi-Jun Robin Fu 			pci_cfgacc_io(req);
2378d7fafffSZhi-Jun Robin Fu 	} else {
2388d7fafffSZhi-Jun Robin Fu 		if (pci_cfgacc_valid(req, PCIE_CFG_SPACE_SIZE))
2398d7fafffSZhi-Jun Robin Fu 			pci_cfgacc_mmio(req);
2408d7fafffSZhi-Jun Robin Fu 	}
241c0da6274SZhi-Jun Robin Fu }
242c0da6274SZhi-Jun Robin Fu 
243c0da6274SZhi-Jun Robin Fu typedef	struct cfgacc_bus_range {
244c0da6274SZhi-Jun Robin Fu 	struct cfgacc_bus_range *next;
245c0da6274SZhi-Jun Robin Fu 	uint16_t bdf;
246c0da6274SZhi-Jun Robin Fu 	uchar_t	secbus;
247c0da6274SZhi-Jun Robin Fu 	uchar_t	subbus;
248c0da6274SZhi-Jun Robin Fu } cfgacc_bus_range_t;
249c0da6274SZhi-Jun Robin Fu 
250c0da6274SZhi-Jun Robin Fu cfgacc_bus_range_t *pci_cfgacc_bus_head = NULL;
251c0da6274SZhi-Jun Robin Fu 
252c0da6274SZhi-Jun Robin Fu #define	BUS_INSERT(prev, el) \
253c0da6274SZhi-Jun Robin Fu 	el->next = *prev; \
254c0da6274SZhi-Jun Robin Fu 	*prev = el;
255c0da6274SZhi-Jun Robin Fu 
256c0da6274SZhi-Jun Robin Fu #define	BUS_REMOVE(prev, el) \
257c0da6274SZhi-Jun Robin Fu 	*prev = el->next;
258c0da6274SZhi-Jun Robin Fu 
259c0da6274SZhi-Jun Robin Fu /*
260c0da6274SZhi-Jun Robin Fu  * This function is only supposed to be called in device tree setup time,
261c0da6274SZhi-Jun Robin Fu  * thus no lock is needed.
262c0da6274SZhi-Jun Robin Fu  */
263c0da6274SZhi-Jun Robin Fu void
pci_cfgacc_add_workaround(uint16_t bdf,uchar_t secbus,uchar_t subbus)264c0da6274SZhi-Jun Robin Fu pci_cfgacc_add_workaround(uint16_t bdf, uchar_t secbus, uchar_t subbus)
265c0da6274SZhi-Jun Robin Fu {
266c0da6274SZhi-Jun Robin Fu 	cfgacc_bus_range_t	*entry;
267c0da6274SZhi-Jun Robin Fu 
268c0da6274SZhi-Jun Robin Fu 	entry = kmem_zalloc(sizeof (cfgacc_bus_range_t), KM_SLEEP);
269c0da6274SZhi-Jun Robin Fu 	entry->bdf = bdf;
270c0da6274SZhi-Jun Robin Fu 	entry->secbus = secbus;
271c0da6274SZhi-Jun Robin Fu 	entry->subbus = subbus;
272c0da6274SZhi-Jun Robin Fu 	BUS_INSERT(&pci_cfgacc_bus_head, entry);
273c0da6274SZhi-Jun Robin Fu }
274c0da6274SZhi-Jun Robin Fu 
275c0da6274SZhi-Jun Robin Fu boolean_t
pci_cfgacc_find_workaround(uint16_t bdf)276c0da6274SZhi-Jun Robin Fu pci_cfgacc_find_workaround(uint16_t bdf)
277c0da6274SZhi-Jun Robin Fu {
278c0da6274SZhi-Jun Robin Fu 	cfgacc_bus_range_t	*entry;
279c0da6274SZhi-Jun Robin Fu 	uchar_t			bus;
280c0da6274SZhi-Jun Robin Fu 
281c0da6274SZhi-Jun Robin Fu 	for (entry = pci_cfgacc_bus_head; entry != NULL;
282c0da6274SZhi-Jun Robin Fu 	    entry = entry->next) {
283c0da6274SZhi-Jun Robin Fu 		if (bdf == entry->bdf) {
284c0da6274SZhi-Jun Robin Fu 			/* found a device which is known to be broken */
285c0da6274SZhi-Jun Robin Fu 			return (B_TRUE);
286c0da6274SZhi-Jun Robin Fu 		}
287c0da6274SZhi-Jun Robin Fu 
288c0da6274SZhi-Jun Robin Fu 		bus = PCI_BDF_BUS(bdf);
289c0da6274SZhi-Jun Robin Fu 		if ((bus != 0) && (bus >= entry->secbus) &&
290c0da6274SZhi-Jun Robin Fu 		    (bus <= entry->subbus)) {
291c0da6274SZhi-Jun Robin Fu 			/*
292c0da6274SZhi-Jun Robin Fu 			 * found a device whose parent/grandparent is
293c0da6274SZhi-Jun Robin Fu 			 * known to be broken.
294c0da6274SZhi-Jun Robin Fu 			 */
295c0da6274SZhi-Jun Robin Fu 			return (B_TRUE);
296c0da6274SZhi-Jun Robin Fu 		}
297c0da6274SZhi-Jun Robin Fu 	}
298c0da6274SZhi-Jun Robin Fu 
299c0da6274SZhi-Jun Robin Fu 	return (B_FALSE);
300c0da6274SZhi-Jun Robin Fu }
301