xref: /netbsd-src/sys/external/bsd/drm2/linux/linux_pci.c (revision 5bb9ef1957ce74f08767c459589e9635fa83d097)
1*5bb9ef19Sriastradh /*	$NetBSD: linux_pci.c,v 1.30 2024/06/24 21:23:53 riastradh Exp $	*/
2bee2274fSriastradh 
3bee2274fSriastradh /*-
4bee2274fSriastradh  * Copyright (c) 2013 The NetBSD Foundation, Inc.
5bee2274fSriastradh  * All rights reserved.
6bee2274fSriastradh  *
7bee2274fSriastradh  * This code is derived from software contributed to The NetBSD Foundation
8bee2274fSriastradh  * by Taylor R. Campbell.
9bee2274fSriastradh  *
10bee2274fSriastradh  * Redistribution and use in source and binary forms, with or without
11bee2274fSriastradh  * modification, are permitted provided that the following conditions
12bee2274fSriastradh  * are met:
13bee2274fSriastradh  * 1. Redistributions of source code must retain the above copyright
14bee2274fSriastradh  *    notice, this list of conditions and the following disclaimer.
15bee2274fSriastradh  * 2. Redistributions in binary form must reproduce the above copyright
16bee2274fSriastradh  *    notice, this list of conditions and the following disclaimer in the
17bee2274fSriastradh  *    documentation and/or other materials provided with the distribution.
18bee2274fSriastradh  *
19bee2274fSriastradh  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20bee2274fSriastradh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21bee2274fSriastradh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22bee2274fSriastradh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23bee2274fSriastradh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24bee2274fSriastradh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25bee2274fSriastradh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26bee2274fSriastradh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27bee2274fSriastradh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28bee2274fSriastradh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29bee2274fSriastradh  * POSSIBILITY OF SUCH DAMAGE.
30bee2274fSriastradh  */
31bee2274fSriastradh 
32d3e2e38eSjmcneill #ifdef _KERNEL_OPT
3303ec3320Sriastradh #include "acpica.h"
34d3e2e38eSjmcneill #include "opt_pci.h"
35d3e2e38eSjmcneill #endif
36d3e2e38eSjmcneill 
37bee2274fSriastradh #include <sys/cdefs.h>
38*5bb9ef19Sriastradh __KERNEL_RCSID(0, "$NetBSD: linux_pci.c,v 1.30 2024/06/24 21:23:53 riastradh Exp $");
3933fe66daSriastradh 
4033fe66daSriastradh #if NACPICA > 0
4133fe66daSriastradh #include <dev/acpi/acpivar.h>
4233fe66daSriastradh #include <dev/acpi/acpi_pci.h>
4333fe66daSriastradh #endif
44bee2274fSriastradh 
45bee2274fSriastradh #include <linux/pci.h>
46bee2274fSriastradh 
4771276a2cSriastradh #include <drm/drm_agp_netbsd.h>
4871276a2cSriastradh 
49bee2274fSriastradh device_t
pci_dev_dev(struct pci_dev * pdev)50bee2274fSriastradh pci_dev_dev(struct pci_dev *pdev)
51bee2274fSriastradh {
52bee2274fSriastradh 
53bee2274fSriastradh 	return pdev->pd_dev;
54bee2274fSriastradh }
55bee2274fSriastradh 
5611bf911fSriastradh void
pci_set_drvdata(struct pci_dev * pdev,void * drvdata)5711bf911fSriastradh pci_set_drvdata(struct pci_dev *pdev, void *drvdata)
5811bf911fSriastradh {
5911bf911fSriastradh 	pdev->pd_drvdata = drvdata;
6011bf911fSriastradh }
6111bf911fSriastradh 
6211bf911fSriastradh void *
pci_get_drvdata(struct pci_dev * pdev)63bee2274fSriastradh pci_get_drvdata(struct pci_dev *pdev)
64bee2274fSriastradh {
6511bf911fSriastradh 	return pdev->pd_drvdata;
66bee2274fSriastradh }
67bee2274fSriastradh 
688a88a9efSriastradh const char *
pci_name(struct pci_dev * pdev)698a88a9efSriastradh pci_name(struct pci_dev *pdev)
708a88a9efSriastradh {
718a88a9efSriastradh 
728a88a9efSriastradh 	/* XXX not sure this has the right format */
738a88a9efSriastradh 	return device_xname(pci_dev_dev(pdev));
748a88a9efSriastradh }
758a88a9efSriastradh 
76cb8e3c86Smrg /*
77cb8e3c86Smrg  * Setup enough of a parent that we can access config space.
78cb8e3c86Smrg  * This is gross and grovels pci(4) and ppb(4) internals.
79cb8e3c86Smrg  */
80cb8e3c86Smrg static struct pci_dev *
alloc_fake_parent_device(device_t parent,const struct pci_attach_args * pa)81cb8e3c86Smrg alloc_fake_parent_device(device_t parent, const struct pci_attach_args *pa)
82cb8e3c86Smrg {
83cb8e3c86Smrg 
84cb8e3c86Smrg 	if (parent == NULL || !device_is_a(parent, "pci"))
85cb8e3c86Smrg 		return NULL;
86cb8e3c86Smrg 
87cb8e3c86Smrg 	device_t pparent = device_parent(parent);
88cb8e3c86Smrg 	if (pparent == NULL || !device_is_a(pparent, "ppb"))
89cb8e3c86Smrg 		return NULL;
90cb8e3c86Smrg 
91cb8e3c86Smrg 	struct pci_softc *pcisc = device_private(parent);
92cb8e3c86Smrg 	struct ppb_softc *ppbsc = device_private(pparent);
93cb8e3c86Smrg 
94cb8e3c86Smrg 	struct pci_dev *parentdev = kmem_zalloc(sizeof(*parentdev), KM_SLEEP);
95cb8e3c86Smrg 
96cb8e3c86Smrg 	/* Copy this device's pci_attach_args{} as a base-line. */
97cb8e3c86Smrg 	struct pci_attach_args *npa = &parentdev->pd_pa;
98cb8e3c86Smrg 	*npa = *pa;
99cb8e3c86Smrg 
100cb8e3c86Smrg 	/* Now update with stuff found in parent. */
101cb8e3c86Smrg 	npa->pa_iot = pcisc->sc_iot;
102cb8e3c86Smrg 	npa->pa_memt = pcisc->sc_memt;
103cb8e3c86Smrg 	npa->pa_dmat = pcisc->sc_dmat;
104cb8e3c86Smrg 	npa->pa_dmat64 = pcisc->sc_dmat64;
105cb8e3c86Smrg 	npa->pa_pc = pcisc->sc_pc;
106cb8e3c86Smrg 	npa->pa_flags = 0;	/* XXX? */
107cb8e3c86Smrg 
108cb8e3c86Smrg 	/* Copy the parent tag, and read some info about it. */
109cb8e3c86Smrg 	npa->pa_tag = ppbsc->sc_tag;
110cb8e3c86Smrg 	pcireg_t id = pci_conf_read(npa->pa_pc, npa->pa_tag, PCI_ID_REG);
111cb8e3c86Smrg 	pcireg_t subid = pci_conf_read(npa->pa_pc, npa->pa_tag,
112cb8e3c86Smrg 	    PCI_SUBSYS_ID_REG);
113cb8e3c86Smrg 	pcireg_t class = pci_conf_read(npa->pa_pc, npa->pa_tag, PCI_CLASS_REG);
114cb8e3c86Smrg 
115cb8e3c86Smrg 	/*
116cb8e3c86Smrg 	 * Fill in as much of pci_attach_args and pci_dev as reasonably possible.
117cb8e3c86Smrg 	 * Most of this is not used currently.
118cb8e3c86Smrg 	 */
119cb8e3c86Smrg 	int bus, device, function;
120cb8e3c86Smrg 	pci_decompose_tag(npa->pa_pc, npa->pa_tag, &bus, &device, &function);
121cb8e3c86Smrg 	npa->pa_device = device;
122cb8e3c86Smrg 	npa->pa_function = function;
123cb8e3c86Smrg 	npa->pa_bus = bus;
124cb8e3c86Smrg 	npa->pa_id = id;
125cb8e3c86Smrg 	npa->pa_class = class;
126cb8e3c86Smrg 	npa->pa_intrswiz = pcisc->sc_intrswiz;
127cb8e3c86Smrg 	npa->pa_intrtag = pcisc->sc_intrtag;
128cb8e3c86Smrg 	npa->pa_intrpin = PCI_INTERRUPT_PIN_NONE;
129cb8e3c86Smrg 
130cb8e3c86Smrg 	parentdev->pd_dev = parent;
131cb8e3c86Smrg 
132cb8e3c86Smrg 	parentdev->bus = NULL;
133cb8e3c86Smrg 	parentdev->devfn = device << 3 | function;
134cb8e3c86Smrg 	parentdev->vendor = PCI_VENDOR(id);
135cb8e3c86Smrg 	parentdev->device = PCI_PRODUCT(id);
136cb8e3c86Smrg 	parentdev->subsystem_vendor = PCI_SUBSYS_VENDOR(subid);
137cb8e3c86Smrg 	parentdev->subsystem_device = PCI_SUBSYS_ID(subid);
138cb8e3c86Smrg 	parentdev->revision = PCI_REVISION(class);
139cb8e3c86Smrg 	parentdev->class = __SHIFTOUT(class, 0xffffff00UL); /* ? */
140cb8e3c86Smrg 
141cb8e3c86Smrg 	return parentdev;
142cb8e3c86Smrg }
143cb8e3c86Smrg 
144bee2274fSriastradh void
linux_pci_dev_init(struct pci_dev * pdev,device_t dev,device_t parent,const struct pci_attach_args * pa,int kludges)145bee2274fSriastradh linux_pci_dev_init(struct pci_dev *pdev, device_t dev, device_t parent,
146bee2274fSriastradh     const struct pci_attach_args *pa, int kludges)
147bee2274fSriastradh {
148bee2274fSriastradh 	const uint32_t subsystem_id = pci_conf_read(pa->pa_pc, pa->pa_tag,
149bee2274fSriastradh 	    PCI_SUBSYS_ID_REG);
150bee2274fSriastradh 	unsigned i;
151bee2274fSriastradh 
1526465a4feSriastradh 	memset(pdev, 0, sizeof(*pdev)); /* paranoia */
1536465a4feSriastradh 
154bee2274fSriastradh 	pdev->pd_pa = *pa;
155bee2274fSriastradh 	pdev->pd_kludges = kludges;
156bee2274fSriastradh 	pdev->pd_rom_vaddr = NULL;
157bee2274fSriastradh 	pdev->pd_dev = dev;
158bee2274fSriastradh #if (NACPICA > 0)
159d3e2e38eSjmcneill 	const int seg = pci_get_segment(pa->pa_pc);
160d3e2e38eSjmcneill 	pdev->pd_ad = acpi_pcidev_find(seg, pa->pa_bus,
161bee2274fSriastradh 	    pa->pa_device, pa->pa_function);
162bee2274fSriastradh #else
163bee2274fSriastradh 	pdev->pd_ad = NULL;
164bee2274fSriastradh #endif
165bee2274fSriastradh 	pdev->pd_saved_state = NULL;
166bee2274fSriastradh 	pdev->pd_intr_handles = NULL;
16711bf911fSriastradh 	pdev->pd_drvdata = NULL;
168bee2274fSriastradh 	pdev->bus = kmem_zalloc(sizeof(*pdev->bus), KM_NOSLEEP);
169bee2274fSriastradh 	pdev->bus->pb_pc = pa->pa_pc;
170bee2274fSriastradh 	pdev->bus->pb_dev = parent;
171bee2274fSriastradh 	pdev->bus->number = pa->pa_bus;
17200c5a72cSmrg 	/*
17300c5a72cSmrg 	 * NetBSD doesn't have an easy "am I PCIe" or "give me PCIe speed
17400c5a72cSmrg 	 * from capability" function, but we already emulate the Linux
17500c5a72cSmrg 	 * versions that do.
17600c5a72cSmrg 	 */
17700c5a72cSmrg 	if (pci_is_pcie(pdev)) {
17800c5a72cSmrg 		pdev->bus->max_bus_speed = pcie_get_speed_cap(pdev);
17900c5a72cSmrg 	} else {
18000c5a72cSmrg 		/* XXX: Do AGP/PCI-X, etc.? */
18100c5a72cSmrg 		pdev->bus->max_bus_speed = PCI_SPEED_UNKNOWN;
18200c5a72cSmrg 	}
183cb8e3c86Smrg 	pdev->bus->self = alloc_fake_parent_device(parent, pa);
184bee2274fSriastradh 	pdev->devfn = PCI_DEVFN(pa->pa_device, pa->pa_function);
185bee2274fSriastradh 	pdev->vendor = PCI_VENDOR(pa->pa_id);
186bee2274fSriastradh 	pdev->device = PCI_PRODUCT(pa->pa_id);
187bee2274fSriastradh 	pdev->subsystem_vendor = PCI_SUBSYS_VENDOR(subsystem_id);
188bee2274fSriastradh 	pdev->subsystem_device = PCI_SUBSYS_ID(subsystem_id);
189bee2274fSriastradh 	pdev->revision = PCI_REVISION(pa->pa_class);
190bee2274fSriastradh 	pdev->class = __SHIFTOUT(pa->pa_class, 0xffffff00UL); /* ? */
191bee2274fSriastradh 
192bee2274fSriastradh 	CTASSERT(__arraycount(pdev->pd_resources) == PCI_NUM_RESOURCES);
193bee2274fSriastradh 	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
194bee2274fSriastradh 		const int reg = PCI_BAR(i);
195bee2274fSriastradh 
196bee2274fSriastradh 		pdev->pd_resources[i].type = pci_mapreg_type(pa->pa_pc,
197bee2274fSriastradh 		    pa->pa_tag, reg);
198bee2274fSriastradh 		if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, reg,
199bee2274fSriastradh 			pdev->pd_resources[i].type,
200bee2274fSriastradh 			&pdev->pd_resources[i].addr,
201bee2274fSriastradh 			&pdev->pd_resources[i].size,
202bee2274fSriastradh 			&pdev->pd_resources[i].flags)) {
203bee2274fSriastradh 			pdev->pd_resources[i].addr = 0;
204bee2274fSriastradh 			pdev->pd_resources[i].size = 0;
205bee2274fSriastradh 			pdev->pd_resources[i].flags = 0;
206bee2274fSriastradh 		}
207bee2274fSriastradh 		pdev->pd_resources[i].kva = NULL;
208c9b0fb12Sriastradh 		pdev->pd_resources[i].mapped = false;
209bee2274fSriastradh 	}
210bee2274fSriastradh }
211bee2274fSriastradh 
212bee2274fSriastradh int
pci_find_capability(struct pci_dev * pdev,int cap)213bee2274fSriastradh pci_find_capability(struct pci_dev *pdev, int cap)
214bee2274fSriastradh {
215bee2274fSriastradh 
216bee2274fSriastradh 	return pci_get_capability(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, cap,
217bee2274fSriastradh 	    NULL, NULL);
218bee2274fSriastradh }
219bee2274fSriastradh 
220bee2274fSriastradh int
pci_read_config_dword(struct pci_dev * pdev,int reg,uint32_t * valuep)221bee2274fSriastradh pci_read_config_dword(struct pci_dev *pdev, int reg, uint32_t *valuep)
222bee2274fSriastradh {
223bee2274fSriastradh 
224bee2274fSriastradh 	KASSERT(!ISSET(reg, 3));
225bee2274fSriastradh 	*valuep = pci_conf_read(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, reg);
226bee2274fSriastradh 	return 0;
227bee2274fSriastradh }
228bee2274fSriastradh 
229bee2274fSriastradh int
pci_read_config_word(struct pci_dev * pdev,int reg,uint16_t * valuep)230bee2274fSriastradh pci_read_config_word(struct pci_dev *pdev, int reg, uint16_t *valuep)
231bee2274fSriastradh {
232bee2274fSriastradh 
233bee2274fSriastradh 	KASSERT(!ISSET(reg, 1));
234bee2274fSriastradh 	*valuep = pci_conf_read(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag,
235bee2274fSriastradh 	    (reg &~ 2)) >> (8 * (reg & 2));
236bee2274fSriastradh 	return 0;
237bee2274fSriastradh }
238bee2274fSriastradh 
239bee2274fSriastradh int
pci_read_config_byte(struct pci_dev * pdev,int reg,uint8_t * valuep)240bee2274fSriastradh pci_read_config_byte(struct pci_dev *pdev, int reg, uint8_t *valuep)
241bee2274fSriastradh {
242bee2274fSriastradh 
243bee2274fSriastradh 	*valuep = pci_conf_read(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag,
244bee2274fSriastradh 	    (reg &~ 3)) >> (8 * (reg & 3));
245bee2274fSriastradh 	return 0;
246bee2274fSriastradh }
247bee2274fSriastradh 
248bee2274fSriastradh int
pci_write_config_dword(struct pci_dev * pdev,int reg,uint32_t value)249bee2274fSriastradh pci_write_config_dword(struct pci_dev *pdev, int reg, uint32_t value)
250bee2274fSriastradh {
251bee2274fSriastradh 
252bee2274fSriastradh 	KASSERT(!ISSET(reg, 3));
253bee2274fSriastradh 	pci_conf_write(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, reg, value);
254bee2274fSriastradh 	return 0;
255bee2274fSriastradh }
256bee2274fSriastradh 
257bee2274fSriastradh int
pci_bus_read_config_dword(struct pci_bus * bus,unsigned devfn,int reg,uint32_t * valuep)258bee2274fSriastradh pci_bus_read_config_dword(struct pci_bus *bus, unsigned devfn, int reg,
259bee2274fSriastradh     uint32_t *valuep)
260bee2274fSriastradh {
261bee2274fSriastradh 	pcitag_t tag = pci_make_tag(bus->pb_pc, bus->number, PCI_SLOT(devfn),
262bee2274fSriastradh 	    PCI_FUNC(devfn));
263bee2274fSriastradh 
264bee2274fSriastradh 	KASSERT(!ISSET(reg, 1));
265bee2274fSriastradh 	*valuep = pci_conf_read(bus->pb_pc, tag, reg & ~3) >> (8 * (reg & 3));
266bee2274fSriastradh 	return 0;
267bee2274fSriastradh }
268bee2274fSriastradh 
269bee2274fSriastradh int
pci_bus_read_config_word(struct pci_bus * bus,unsigned devfn,int reg,uint16_t * valuep)270bee2274fSriastradh pci_bus_read_config_word(struct pci_bus *bus, unsigned devfn, int reg,
271bee2274fSriastradh     uint16_t *valuep)
272bee2274fSriastradh {
273bee2274fSriastradh 	pcitag_t tag = pci_make_tag(bus->pb_pc, bus->number, PCI_SLOT(devfn),
274bee2274fSriastradh 	    PCI_FUNC(devfn));
275bee2274fSriastradh 
276bee2274fSriastradh 	KASSERT(!ISSET(reg, 1));
277bee2274fSriastradh 	*valuep = pci_conf_read(bus->pb_pc, tag, reg &~ 2) >> (8 * (reg & 2));
278bee2274fSriastradh 	return 0;
279bee2274fSriastradh }
280bee2274fSriastradh 
281bee2274fSriastradh int
pci_bus_read_config_byte(struct pci_bus * bus,unsigned devfn,int reg,uint8_t * valuep)282bee2274fSriastradh pci_bus_read_config_byte(struct pci_bus *bus, unsigned devfn, int reg,
283bee2274fSriastradh     uint8_t *valuep)
284bee2274fSriastradh {
285bee2274fSriastradh 	pcitag_t tag = pci_make_tag(bus->pb_pc, bus->number, PCI_SLOT(devfn),
286bee2274fSriastradh 	    PCI_FUNC(devfn));
287bee2274fSriastradh 
288bee2274fSriastradh 	*valuep = pci_conf_read(bus->pb_pc, tag, reg &~ 3) >> (8 * (reg & 3));
289bee2274fSriastradh 	return 0;
290bee2274fSriastradh }
291bee2274fSriastradh 
292bee2274fSriastradh int
pci_bus_write_config_dword(struct pci_bus * bus,unsigned devfn,int reg,uint32_t value)293bee2274fSriastradh pci_bus_write_config_dword(struct pci_bus *bus, unsigned devfn, int reg,
294bee2274fSriastradh     uint32_t value)
295bee2274fSriastradh {
296bee2274fSriastradh 	pcitag_t tag = pci_make_tag(bus->pb_pc, bus->number, PCI_SLOT(devfn),
297bee2274fSriastradh 	    PCI_FUNC(devfn));
298bee2274fSriastradh 
299bee2274fSriastradh 	KASSERT(!ISSET(reg, 3));
300bee2274fSriastradh 	pci_conf_write(bus->pb_pc, tag, reg, value);
301bee2274fSriastradh 	return 0;
302bee2274fSriastradh }
303bee2274fSriastradh 
304bee2274fSriastradh static void
pci_rmw_config(pci_chipset_tag_t pc,pcitag_t tag,int reg,unsigned int bytes,uint32_t value)305bee2274fSriastradh pci_rmw_config(pci_chipset_tag_t pc, pcitag_t tag, int reg, unsigned int bytes,
306bee2274fSriastradh     uint32_t value)
307bee2274fSriastradh {
308bee2274fSriastradh 	const uint32_t mask = ~((~0UL) << (8 * bytes));
309bee2274fSriastradh 	const int reg32 = (reg &~ 3);
310bee2274fSriastradh 	const unsigned int shift = (8 * (reg & 3));
311bee2274fSriastradh 	uint32_t value32;
312bee2274fSriastradh 
313bee2274fSriastradh 	KASSERT(bytes <= 4);
314bee2274fSriastradh 	KASSERT(!ISSET(value, ~mask));
315bee2274fSriastradh 	value32 = pci_conf_read(pc, tag, reg32);
316bee2274fSriastradh 	value32 &=~ (mask << shift);
317bee2274fSriastradh 	value32 |= (value << shift);
318bee2274fSriastradh 	pci_conf_write(pc, tag, reg32, value32);
319bee2274fSriastradh }
320bee2274fSriastradh 
321bee2274fSriastradh int
pci_write_config_word(struct pci_dev * pdev,int reg,uint16_t value)322bee2274fSriastradh pci_write_config_word(struct pci_dev *pdev, int reg, uint16_t value)
323bee2274fSriastradh {
324bee2274fSriastradh 
325bee2274fSriastradh 	KASSERT(!ISSET(reg, 1));
326bee2274fSriastradh 	pci_rmw_config(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, reg, 2, value);
327bee2274fSriastradh 	return 0;
328bee2274fSriastradh }
329bee2274fSriastradh 
330bee2274fSriastradh int
pci_write_config_byte(struct pci_dev * pdev,int reg,uint8_t value)331bee2274fSriastradh pci_write_config_byte(struct pci_dev *pdev, int reg, uint8_t value)
332bee2274fSriastradh {
333bee2274fSriastradh 
334bee2274fSriastradh 	pci_rmw_config(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag, reg, 1, value);
335bee2274fSriastradh 	return 0;
336bee2274fSriastradh }
337bee2274fSriastradh 
338bee2274fSriastradh int
pci_bus_write_config_word(struct pci_bus * bus,unsigned devfn,int reg,uint16_t value)339bee2274fSriastradh pci_bus_write_config_word(struct pci_bus *bus, unsigned devfn, int reg,
340bee2274fSriastradh     uint16_t value)
341bee2274fSriastradh {
342bee2274fSriastradh 	pcitag_t tag = pci_make_tag(bus->pb_pc, bus->number, PCI_SLOT(devfn),
343bee2274fSriastradh 	    PCI_FUNC(devfn));
344bee2274fSriastradh 
345bee2274fSriastradh 	KASSERT(!ISSET(reg, 1));
346bee2274fSriastradh 	pci_rmw_config(bus->pb_pc, tag, reg, 2, value);
347bee2274fSriastradh 	return 0;
348bee2274fSriastradh }
349bee2274fSriastradh 
350bee2274fSriastradh int
pci_bus_write_config_byte(struct pci_bus * bus,unsigned devfn,int reg,uint8_t value)351bee2274fSriastradh pci_bus_write_config_byte(struct pci_bus *bus, unsigned devfn, int reg,
352bee2274fSriastradh     uint8_t value)
353bee2274fSriastradh {
354bee2274fSriastradh 	pcitag_t tag = pci_make_tag(bus->pb_pc, bus->number, PCI_SLOT(devfn),
355bee2274fSriastradh 	    PCI_FUNC(devfn));
356bee2274fSriastradh 
357bee2274fSriastradh 	pci_rmw_config(bus->pb_pc, tag, reg, 1, value);
358bee2274fSriastradh 	return 0;
359bee2274fSriastradh }
360bee2274fSriastradh 
361bee2274fSriastradh int
pci_enable_msi(struct pci_dev * pdev)362bee2274fSriastradh pci_enable_msi(struct pci_dev *pdev)
363bee2274fSriastradh {
364bee2274fSriastradh 	const struct pci_attach_args *const pa = &pdev->pd_pa;
365bee2274fSriastradh 
366bee2274fSriastradh 	if (pci_msi_alloc_exact(pa, &pdev->pd_intr_handles, 1))
367bee2274fSriastradh 		return -EINVAL;
368bee2274fSriastradh 
369bee2274fSriastradh 	pdev->msi_enabled = 1;
370bee2274fSriastradh 	return 0;
371bee2274fSriastradh }
372bee2274fSriastradh 
373bee2274fSriastradh void
pci_disable_msi(struct pci_dev * pdev __unused)374bee2274fSriastradh pci_disable_msi(struct pci_dev *pdev __unused)
375bee2274fSriastradh {
376bee2274fSriastradh 	const struct pci_attach_args *const pa = &pdev->pd_pa;
377bee2274fSriastradh 
378bee2274fSriastradh 	if (pdev->pd_intr_handles != NULL) {
379bee2274fSriastradh 		pci_intr_release(pa->pa_pc, pdev->pd_intr_handles, 1);
380bee2274fSriastradh 		pdev->pd_intr_handles = NULL;
381bee2274fSriastradh 	}
382bee2274fSriastradh 	pdev->msi_enabled = 0;
383bee2274fSriastradh }
384bee2274fSriastradh 
385bee2274fSriastradh void
pci_set_master(struct pci_dev * pdev)386bee2274fSriastradh pci_set_master(struct pci_dev *pdev)
387bee2274fSriastradh {
388bee2274fSriastradh 	pcireg_t csr;
389bee2274fSriastradh 
390bee2274fSriastradh 	csr = pci_conf_read(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag,
391bee2274fSriastradh 	    PCI_COMMAND_STATUS_REG);
392bee2274fSriastradh 	csr |= PCI_COMMAND_MASTER_ENABLE;
393bee2274fSriastradh 	pci_conf_write(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag,
394bee2274fSriastradh 	    PCI_COMMAND_STATUS_REG, csr);
395bee2274fSriastradh }
396bee2274fSriastradh 
397bee2274fSriastradh void
pci_clear_master(struct pci_dev * pdev)398bee2274fSriastradh pci_clear_master(struct pci_dev *pdev)
399bee2274fSriastradh {
400bee2274fSriastradh 	pcireg_t csr;
401bee2274fSriastradh 
402bee2274fSriastradh 	csr = pci_conf_read(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag,
403bee2274fSriastradh 	    PCI_COMMAND_STATUS_REG);
404bee2274fSriastradh 	csr &= ~(pcireg_t)PCI_COMMAND_MASTER_ENABLE;
405bee2274fSriastradh 	pci_conf_write(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag,
406bee2274fSriastradh 	    PCI_COMMAND_STATUS_REG, csr);
407bee2274fSriastradh }
408bee2274fSriastradh 
409cb8e3c86Smrg int
pcie_capability_read_dword(struct pci_dev * pdev,int reg,uint32_t * valuep)410cb8e3c86Smrg pcie_capability_read_dword(struct pci_dev *pdev, int reg, uint32_t *valuep)
411cb8e3c86Smrg {
412cb8e3c86Smrg 	pci_chipset_tag_t pc = pdev->pd_pa.pa_pc;
413cb8e3c86Smrg 	pcitag_t tag = pdev->pd_pa.pa_tag;
414cb8e3c86Smrg 	int off;
415cb8e3c86Smrg 
416cb8e3c86Smrg 	*valuep = 0;
417cb8e3c86Smrg 
418cb8e3c86Smrg 	/* Must have capabilities. */
419cb8e3c86Smrg 	if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0)
420cb8e3c86Smrg 		return 1;
421cb8e3c86Smrg 
422cb8e3c86Smrg 	*valuep = pci_conf_read(pc, tag, off + reg);
423cb8e3c86Smrg 
424cb8e3c86Smrg 	return 0;
425cb8e3c86Smrg }
426cb8e3c86Smrg 
427cb8e3c86Smrg int
pcie_capability_read_word(struct pci_dev * pdev,int reg,uint16_t * valuep)428cb8e3c86Smrg pcie_capability_read_word(struct pci_dev *pdev, int reg, uint16_t *valuep)
429cb8e3c86Smrg {
430cb8e3c86Smrg 	pci_chipset_tag_t pc = pdev->pd_pa.pa_pc;
431cb8e3c86Smrg 	pcitag_t tag = pdev->pd_pa.pa_tag;
432cb8e3c86Smrg 	int off;
433cb8e3c86Smrg 
434cb8e3c86Smrg 	*valuep = 0;
435cb8e3c86Smrg 
436cb8e3c86Smrg 	/* Must have capabilities. */
437cb8e3c86Smrg 	if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0)
438cb8e3c86Smrg 		return 1;
439cb8e3c86Smrg 
440cb8e3c86Smrg 	*valuep = pci_conf_read(pc, tag, off + (reg &~ 2)) >> (8 * (reg & 2));
441cb8e3c86Smrg 
442cb8e3c86Smrg 	return 0;
443cb8e3c86Smrg }
444cb8e3c86Smrg 
445cb8e3c86Smrg int
pcie_capability_write_dword(struct pci_dev * pdev,int reg,uint32_t value)446cb8e3c86Smrg pcie_capability_write_dword(struct pci_dev *pdev, int reg, uint32_t value)
447cb8e3c86Smrg {
448cb8e3c86Smrg 	pci_chipset_tag_t pc = pdev->pd_pa.pa_pc;
449cb8e3c86Smrg 	pcitag_t tag = pdev->pd_pa.pa_tag;
450cb8e3c86Smrg 	int off;
451cb8e3c86Smrg 
452cb8e3c86Smrg 	/* Must have capabilities. */
453cb8e3c86Smrg 	if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0)
454cb8e3c86Smrg 		return 1;
455cb8e3c86Smrg 
456cb8e3c86Smrg 	pci_conf_write(pc, tag, off + reg, value);
457cb8e3c86Smrg 
458cb8e3c86Smrg 	return 0;
459cb8e3c86Smrg }
460cb8e3c86Smrg 
461cb8e3c86Smrg int
pcie_capability_write_word(struct pci_dev * pdev,int reg,uint16_t value)462cb8e3c86Smrg pcie_capability_write_word(struct pci_dev *pdev, int reg, uint16_t value)
463cb8e3c86Smrg {
464cb8e3c86Smrg 	pci_chipset_tag_t pc = pdev->pd_pa.pa_pc;
465cb8e3c86Smrg 	pcitag_t tag = pdev->pd_pa.pa_tag;
466cb8e3c86Smrg 	int off;
467cb8e3c86Smrg 
468cb8e3c86Smrg 	/* Must have capabilities. */
469cb8e3c86Smrg 	if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0)
470cb8e3c86Smrg 		return 1;
471cb8e3c86Smrg 
472cb8e3c86Smrg 	pci_rmw_config(pc, tag, off + reg, 2, value);
473cb8e3c86Smrg 
474cb8e3c86Smrg 	return 0;
475cb8e3c86Smrg }
476cb8e3c86Smrg 
477cb8e3c86Smrg /* From PCIe 5.0 7.5.3.4 "Device Control Register" */
478cb8e3c86Smrg static const unsigned readrqmax[] = {
479cb8e3c86Smrg 	128,
480cb8e3c86Smrg 	256,
481cb8e3c86Smrg 	512,
482cb8e3c86Smrg 	1024,
483cb8e3c86Smrg 	2048,
484cb8e3c86Smrg 	4096,
485cb8e3c86Smrg };
486cb8e3c86Smrg 
487cb8e3c86Smrg int
pcie_get_readrq(struct pci_dev * pdev)488cb8e3c86Smrg pcie_get_readrq(struct pci_dev *pdev)
489cb8e3c86Smrg {
490cb8e3c86Smrg 	pci_chipset_tag_t pc = pdev->pd_pa.pa_pc;
491cb8e3c86Smrg 	pcitag_t tag = pdev->pd_pa.pa_tag;
492cb8e3c86Smrg 	unsigned val;
493cb8e3c86Smrg 	int off;
494cb8e3c86Smrg 
495cb8e3c86Smrg 	if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0)
496cb8e3c86Smrg 		return -EINVAL; /* XXX NetBSD->Linux */
497cb8e3c86Smrg 
498cb8e3c86Smrg 	val = __SHIFTOUT(pci_conf_read(pc, tag, off + PCIE_DCSR),
499cb8e3c86Smrg 	    PCIE_DCSR_MAX_READ_REQ);
500cb8e3c86Smrg 
501cb8e3c86Smrg 	if (val >= __arraycount(readrqmax))
502cb8e3c86Smrg 		val = 0;
503cb8e3c86Smrg 	return readrqmax[val];
504cb8e3c86Smrg }
505cb8e3c86Smrg 
506cb8e3c86Smrg int
pcie_set_readrq(struct pci_dev * pdev,int val)507cb8e3c86Smrg pcie_set_readrq(struct pci_dev *pdev, int val)
508cb8e3c86Smrg {
509cb8e3c86Smrg 	pci_chipset_tag_t pc = pdev->pd_pa.pa_pc;
510cb8e3c86Smrg 	pcitag_t tag = pdev->pd_pa.pa_tag;
511cb8e3c86Smrg 	pcireg_t reg, newval = 0;
512cb8e3c86Smrg 	unsigned i;
513cb8e3c86Smrg 	int off;
514cb8e3c86Smrg 
515cb8e3c86Smrg 	for (i = 0; i < __arraycount(readrqmax); i++) {
516cb8e3c86Smrg 		if (readrqmax[i] == val) {
517cb8e3c86Smrg 			newval = i;
518cb8e3c86Smrg 			break;
519cb8e3c86Smrg 		}
520cb8e3c86Smrg 	}
521cb8e3c86Smrg 
522cb8e3c86Smrg 	if (i == __arraycount(readrqmax))
523cb8e3c86Smrg 		return -EINVAL;
524cb8e3c86Smrg 
525cb8e3c86Smrg 	if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0)
526cb8e3c86Smrg 		return -EINVAL; /* XXX NetBSD->Linux */
527cb8e3c86Smrg 
528cb8e3c86Smrg 	reg = pci_conf_read(pc, tag, off + PCIE_DCSR);
529cb8e3c86Smrg 	reg &= ~PCIE_DCSR_MAX_READ_REQ | (newval << 12);
530cb8e3c86Smrg 	pci_conf_write(pc, tag, off + PCIE_DCSR, reg);
531cb8e3c86Smrg 
532cb8e3c86Smrg 	return 0;
533cb8e3c86Smrg }
534cb8e3c86Smrg 
535bee2274fSriastradh bus_addr_t
pcibios_align_resource(void * p,const struct resource * resource,bus_addr_t addr,bus_size_t size)536bee2274fSriastradh pcibios_align_resource(void *p, const struct resource *resource,
537bee2274fSriastradh     bus_addr_t addr, bus_size_t size)
538bee2274fSriastradh {
539bee2274fSriastradh 	panic("pcibios_align_resource has accessed unaligned neurons!");
540bee2274fSriastradh }
541bee2274fSriastradh 
542bee2274fSriastradh int
pci_bus_alloc_resource(struct pci_bus * bus,struct resource * resource,bus_size_t size,bus_size_t align,bus_addr_t start,int type __unused,bus_addr_t (* align_fn)(void *,const struct resource *,bus_addr_t,bus_size_t)__unused,struct pci_dev * pdev)543bee2274fSriastradh pci_bus_alloc_resource(struct pci_bus *bus, struct resource *resource,
544bee2274fSriastradh     bus_size_t size, bus_size_t align, bus_addr_t start, int type __unused,
545bee2274fSriastradh     bus_addr_t (*align_fn)(void *, const struct resource *, bus_addr_t,
546bee2274fSriastradh 	bus_size_t) __unused,
547bee2274fSriastradh     struct pci_dev *pdev)
548bee2274fSriastradh {
549bee2274fSriastradh 	const struct pci_attach_args *const pa = &pdev->pd_pa;
550bee2274fSriastradh 	bus_space_tag_t bst;
551bee2274fSriastradh 	int error;
552bee2274fSriastradh 
553bee2274fSriastradh 	switch (resource->flags) {
554bee2274fSriastradh 	case IORESOURCE_MEM:
555bee2274fSriastradh 		bst = pa->pa_memt;
556bee2274fSriastradh 		break;
557bee2274fSriastradh 
558bee2274fSriastradh 	case IORESOURCE_IO:
559bee2274fSriastradh 		bst = pa->pa_iot;
560bee2274fSriastradh 		break;
561bee2274fSriastradh 
562bee2274fSriastradh 	default:
563bee2274fSriastradh 		panic("I don't know what kind of resource you want!");
564bee2274fSriastradh 	}
565bee2274fSriastradh 
566bee2274fSriastradh 	resource->r_bst = bst;
567bee2274fSriastradh 	error = bus_space_alloc(bst, start, __type_max(bus_addr_t),
568bee2274fSriastradh 	    size, align, 0, 0, &resource->start, &resource->r_bsh);
569bee2274fSriastradh 	if (error)
570bee2274fSriastradh 		return error;
571bee2274fSriastradh 
572b0ecd478Sriastradh 	resource->end = start + (size - 1);
573bee2274fSriastradh 	return 0;
574bee2274fSriastradh }
575bee2274fSriastradh 
576d5a34bf3Sriastradh struct pci_domain_bus_and_slot {
577d5a34bf3Sriastradh 	int domain, bus, slot;
578d5a34bf3Sriastradh };
579bee2274fSriastradh 
580bee2274fSriastradh static int
pci_match_domain_bus_and_slot(void * cookie,const struct pci_attach_args * pa)581d5a34bf3Sriastradh pci_match_domain_bus_and_slot(void *cookie, const struct pci_attach_args *pa)
582bee2274fSriastradh {
583d5a34bf3Sriastradh 	const struct pci_domain_bus_and_slot *C = cookie;
584bee2274fSriastradh 
585d5a34bf3Sriastradh 	if (pci_get_segment(pa->pa_pc) != C->domain)
586bee2274fSriastradh 		return 0;
587d5a34bf3Sriastradh 	if (pa->pa_bus != C->bus)
588bee2274fSriastradh 		return 0;
589d5a34bf3Sriastradh 	if (PCI_DEVFN(pa->pa_device, pa->pa_function) != C->slot)
590bee2274fSriastradh 		return 0;
591bee2274fSriastradh 
592bee2274fSriastradh 	return 1;
593bee2274fSriastradh }
594bee2274fSriastradh 
595bee2274fSriastradh struct pci_dev *
pci_get_domain_bus_and_slot(int domain,int bus,int slot)596d09c8680Sriastradh pci_get_domain_bus_and_slot(int domain, int bus, int slot)
597bee2274fSriastradh {
598bee2274fSriastradh 	struct pci_attach_args pa;
599d5a34bf3Sriastradh 	struct pci_domain_bus_and_slot context = {domain, bus, slot},
600d5a34bf3Sriastradh 	    *C = &context;
601bee2274fSriastradh 
602d5a34bf3Sriastradh 	if (!pci_find_device1(&pa, &pci_match_domain_bus_and_slot, C))
603bee2274fSriastradh 		return NULL;
604bee2274fSriastradh 
605bee2274fSriastradh 	struct pci_dev *const pdev = kmem_zalloc(sizeof(*pdev), KM_SLEEP);
606bee2274fSriastradh 	linux_pci_dev_init(pdev, NULL, NULL, &pa, NBPCI_KLUDGE_GET_MUMBLE);
607bee2274fSriastradh 
608bee2274fSriastradh 	return pdev;
609bee2274fSriastradh }
610bee2274fSriastradh 
611bee2274fSriastradh void
pci_dev_put(struct pci_dev * pdev)612bee2274fSriastradh pci_dev_put(struct pci_dev *pdev)
613bee2274fSriastradh {
614bee2274fSriastradh 
615bee2274fSriastradh 	if (pdev == NULL)
616bee2274fSriastradh 		return;
617bee2274fSriastradh 
618bee2274fSriastradh 	KASSERT(ISSET(pdev->pd_kludges, NBPCI_KLUDGE_GET_MUMBLE));
619bee2274fSriastradh 	kmem_free(pdev->bus, sizeof(*pdev->bus));
620bee2274fSriastradh 	kmem_free(pdev, sizeof(*pdev));
621bee2274fSriastradh }
622bee2274fSriastradh 
623d5a34bf3Sriastradh struct pci_get_class_state {
624*5bb9ef19Sriastradh 	uint32_t		class_subclass_interface;
625d5a34bf3Sriastradh 	const struct pci_dev	*from;
626d5a34bf3Sriastradh };
627d5a34bf3Sriastradh 
628d5a34bf3Sriastradh static int
pci_get_class_match(void * cookie,const struct pci_attach_args * pa)629d5a34bf3Sriastradh pci_get_class_match(void *cookie, const struct pci_attach_args *pa)
630d5a34bf3Sriastradh {
631d5a34bf3Sriastradh 	struct pci_get_class_state *C = cookie;
632d5a34bf3Sriastradh 
633d5a34bf3Sriastradh 	if (C->from) {
634d5a34bf3Sriastradh 		if ((pci_get_segment(C->from->pd_pa.pa_pc) ==
635d5a34bf3Sriastradh 			pci_get_segment(pa->pa_pc)) &&
636d5a34bf3Sriastradh 		    C->from->pd_pa.pa_bus == pa->pa_bus &&
637d5a34bf3Sriastradh 		    C->from->pd_pa.pa_device == pa->pa_device &&
638d5a34bf3Sriastradh 		    C->from->pd_pa.pa_function == pa->pa_function)
639d5a34bf3Sriastradh 			C->from = NULL;
640d5a34bf3Sriastradh 		return 0;
641d5a34bf3Sriastradh 	}
642*5bb9ef19Sriastradh 	if (C->class_subclass_interface !=
643*5bb9ef19Sriastradh 	    (PCI_CLASS(pa->pa_class) << 16 |
644*5bb9ef19Sriastradh 		PCI_SUBCLASS(pa->pa_class) << 8 |
645*5bb9ef19Sriastradh 		PCI_INTERFACE(pa->pa_class)))
646d5a34bf3Sriastradh 		return 0;
647d5a34bf3Sriastradh 
648d5a34bf3Sriastradh 	return 1;
649d5a34bf3Sriastradh }
650d5a34bf3Sriastradh 
651d5a34bf3Sriastradh struct pci_dev *
pci_get_class(uint32_t class_subclass_interface,struct pci_dev * from)652*5bb9ef19Sriastradh pci_get_class(uint32_t class_subclass_interface, struct pci_dev *from)
653bee2274fSriastradh {
654*5bb9ef19Sriastradh 	struct pci_get_class_state context = {class_subclass_interface, from},
655d5a34bf3Sriastradh 	    *C = &context;
656bee2274fSriastradh 	struct pci_attach_args pa;
657d5a34bf3Sriastradh 	struct pci_dev *pdev = NULL;
658bee2274fSriastradh 
659d5a34bf3Sriastradh 	if (!pci_find_device1(&pa, &pci_get_class_match, C))
660d5a34bf3Sriastradh 		goto out;
661d5a34bf3Sriastradh 	pdev = kmem_zalloc(sizeof(*pdev), KM_SLEEP);
662bee2274fSriastradh 	linux_pci_dev_init(pdev, NULL, NULL, &pa, NBPCI_KLUDGE_GET_MUMBLE);
663bee2274fSriastradh 
664d5a34bf3Sriastradh out:	if (from)
665d5a34bf3Sriastradh 		pci_dev_put(from);
666bee2274fSriastradh 	return pdev;
667bee2274fSriastradh }
668bee2274fSriastradh 
669dfa0e026Sriastradh int
pci_dev_present(const struct pci_device_id * ids)670dfa0e026Sriastradh pci_dev_present(const struct pci_device_id *ids)
671dfa0e026Sriastradh {
672dfa0e026Sriastradh 
673dfa0e026Sriastradh 	/* XXX implement me -- pci_find_device doesn't pass a cookie */
674dfa0e026Sriastradh 	return 0;
675dfa0e026Sriastradh }
676dfa0e026Sriastradh 
677bee2274fSriastradh void
pci_unmap_rom(struct pci_dev * pdev,void __pci_rom_iomem * vaddr __unused)678bee2274fSriastradh pci_unmap_rom(struct pci_dev *pdev, void __pci_rom_iomem *vaddr __unused)
679bee2274fSriastradh {
680bee2274fSriastradh 
681bee2274fSriastradh 	/* XXX Disable the ROM address decoder.  */
682bee2274fSriastradh 	KASSERT(ISSET(pdev->pd_kludges, NBPCI_KLUDGE_MAP_ROM));
683bee2274fSriastradh 	KASSERT(vaddr == pdev->pd_rom_vaddr);
684bee2274fSriastradh 	bus_space_unmap(pdev->pd_rom_bst, pdev->pd_rom_bsh, pdev->pd_rom_size);
685bee2274fSriastradh 	pdev->pd_kludges &= ~NBPCI_KLUDGE_MAP_ROM;
686bee2274fSriastradh 	pdev->pd_rom_vaddr = NULL;
687bee2274fSriastradh }
688bee2274fSriastradh 
689bee2274fSriastradh /* XXX Whattakludge!  Should move this in sys/arch/.  */
690bee2274fSriastradh static int
pci_map_rom_md(struct pci_dev * pdev)691bee2274fSriastradh pci_map_rom_md(struct pci_dev *pdev)
692bee2274fSriastradh {
693bee2274fSriastradh #if defined(__i386__) || defined(__x86_64__) || defined(__ia64__)
694bee2274fSriastradh 	const bus_addr_t rom_base = 0xc0000;
695bee2274fSriastradh 	const bus_size_t rom_size = 0x20000;
696bee2274fSriastradh 	bus_space_handle_t rom_bsh;
697bee2274fSriastradh 	int error;
698bee2274fSriastradh 
699bee2274fSriastradh 	if (PCI_CLASS(pdev->pd_pa.pa_class) != PCI_CLASS_DISPLAY)
700bee2274fSriastradh 		return ENXIO;
701bee2274fSriastradh 	if (PCI_SUBCLASS(pdev->pd_pa.pa_class) != PCI_SUBCLASS_DISPLAY_VGA)
702bee2274fSriastradh 		return ENXIO;
703bee2274fSriastradh 	/* XXX Check whether this is the primary VGA card?  */
704bee2274fSriastradh 	error = bus_space_map(pdev->pd_pa.pa_memt, rom_base, rom_size,
705bee2274fSriastradh 	    (BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE), &rom_bsh);
706bee2274fSriastradh 	if (error)
707bee2274fSriastradh 		return ENXIO;
708bee2274fSriastradh 
709bee2274fSriastradh 	pdev->pd_rom_bst = pdev->pd_pa.pa_memt;
710bee2274fSriastradh 	pdev->pd_rom_bsh = rom_bsh;
711bee2274fSriastradh 	pdev->pd_rom_size = rom_size;
712bee2274fSriastradh 	pdev->pd_kludges |= NBPCI_KLUDGE_MAP_ROM;
713bee2274fSriastradh 
714bee2274fSriastradh 	return 0;
715bee2274fSriastradh #else
716bee2274fSriastradh 	return ENXIO;
717bee2274fSriastradh #endif
718bee2274fSriastradh }
719bee2274fSriastradh 
720bee2274fSriastradh void __pci_rom_iomem *
pci_map_rom(struct pci_dev * pdev,size_t * sizep)721bee2274fSriastradh pci_map_rom(struct pci_dev *pdev, size_t *sizep)
722bee2274fSriastradh {
723bee2274fSriastradh 
724bee2274fSriastradh 	KASSERT(!ISSET(pdev->pd_kludges, NBPCI_KLUDGE_MAP_ROM));
725bee2274fSriastradh 
726bee2274fSriastradh 	if (pci_mapreg_map(&pdev->pd_pa, PCI_MAPREG_ROM, PCI_MAPREG_TYPE_ROM,
727bee2274fSriastradh 		(BUS_SPACE_MAP_PREFETCHABLE | BUS_SPACE_MAP_LINEAR),
728bee2274fSriastradh 		&pdev->pd_rom_bst, &pdev->pd_rom_bsh, NULL, &pdev->pd_rom_size)
729bee2274fSriastradh 	    != 0)
730bee2274fSriastradh 		goto fail_mi;
731bee2274fSriastradh 	pdev->pd_kludges |= NBPCI_KLUDGE_MAP_ROM;
732bee2274fSriastradh 
733bee2274fSriastradh 	/* XXX This type is obviously wrong in general...  */
734bee2274fSriastradh 	if (pci_find_rom(&pdev->pd_pa, pdev->pd_rom_bst, pdev->pd_rom_bsh,
735bee2274fSriastradh 		pdev->pd_rom_size, PCI_ROM_CODE_TYPE_X86,
736bee2274fSriastradh 		&pdev->pd_rom_found_bsh, &pdev->pd_rom_found_size)) {
737bee2274fSriastradh 		pci_unmap_rom(pdev, NULL);
738bee2274fSriastradh 		goto fail_mi;
739bee2274fSriastradh 	}
740bee2274fSriastradh 	goto success;
741bee2274fSriastradh 
742bee2274fSriastradh fail_mi:
743bee2274fSriastradh 	if (pci_map_rom_md(pdev) != 0)
744bee2274fSriastradh 		goto fail_md;
745bee2274fSriastradh 
746bee2274fSriastradh 	/* XXX This type is obviously wrong in general...  */
747bee2274fSriastradh 	if (pci_find_rom(&pdev->pd_pa, pdev->pd_rom_bst, pdev->pd_rom_bsh,
748bee2274fSriastradh 		pdev->pd_rom_size, PCI_ROM_CODE_TYPE_X86,
749bee2274fSriastradh 		&pdev->pd_rom_found_bsh, &pdev->pd_rom_found_size)) {
750bee2274fSriastradh 		pci_unmap_rom(pdev, NULL);
751bee2274fSriastradh 		goto fail_md;
752bee2274fSriastradh 	}
753bee2274fSriastradh 
754bee2274fSriastradh success:
755bee2274fSriastradh 	KASSERT(pdev->pd_rom_found_size <= SIZE_T_MAX);
756bee2274fSriastradh 	*sizep = pdev->pd_rom_found_size;
757bee2274fSriastradh 	pdev->pd_rom_vaddr = bus_space_vaddr(pdev->pd_rom_bst,
758bee2274fSriastradh 	    pdev->pd_rom_found_bsh);
759bee2274fSriastradh 	return pdev->pd_rom_vaddr;
760bee2274fSriastradh 
761bee2274fSriastradh fail_md:
762bee2274fSriastradh 	return NULL;
763bee2274fSriastradh }
764bee2274fSriastradh 
765bee2274fSriastradh void __pci_rom_iomem *
pci_platform_rom(struct pci_dev * pdev __unused,size_t * sizep)766bee2274fSriastradh pci_platform_rom(struct pci_dev *pdev __unused, size_t *sizep)
767bee2274fSriastradh {
768bee2274fSriastradh 
769bee2274fSriastradh 	*sizep = 0;
770bee2274fSriastradh 	return NULL;
771bee2274fSriastradh }
772bee2274fSriastradh 
773bee2274fSriastradh int
pci_enable_rom(struct pci_dev * pdev)774bee2274fSriastradh pci_enable_rom(struct pci_dev *pdev)
775bee2274fSriastradh {
776bee2274fSriastradh 	const pci_chipset_tag_t pc = pdev->pd_pa.pa_pc;
777bee2274fSriastradh 	const pcitag_t tag = pdev->pd_pa.pa_tag;
778bee2274fSriastradh 	pcireg_t addr;
779bee2274fSriastradh 	int s;
780bee2274fSriastradh 
781bee2274fSriastradh 	/* XXX Don't do anything if the ROM isn't there.  */
782bee2274fSriastradh 
783bee2274fSriastradh 	s = splhigh();
784bee2274fSriastradh 	addr = pci_conf_read(pc, tag, PCI_MAPREG_ROM);
785bee2274fSriastradh 	addr |= PCI_MAPREG_ROM_ENABLE;
786bee2274fSriastradh 	pci_conf_write(pc, tag, PCI_MAPREG_ROM, addr);
787bee2274fSriastradh 	splx(s);
788bee2274fSriastradh 
789bee2274fSriastradh 	return 0;
790bee2274fSriastradh }
791bee2274fSriastradh 
792bee2274fSriastradh void
pci_disable_rom(struct pci_dev * pdev)793bee2274fSriastradh pci_disable_rom(struct pci_dev *pdev)
794bee2274fSriastradh {
795bee2274fSriastradh 	const pci_chipset_tag_t pc = pdev->pd_pa.pa_pc;
796bee2274fSriastradh 	const pcitag_t tag = pdev->pd_pa.pa_tag;
797bee2274fSriastradh 	pcireg_t addr;
798bee2274fSriastradh 	int s;
799bee2274fSriastradh 
800bee2274fSriastradh 	s = splhigh();
801bee2274fSriastradh 	addr = pci_conf_read(pc, tag, PCI_MAPREG_ROM);
802bee2274fSriastradh 	addr &= ~(pcireg_t)PCI_MAPREG_ROM_ENABLE;
803bee2274fSriastradh 	pci_conf_write(pc, tag, PCI_MAPREG_ROM, addr);
804bee2274fSriastradh 	splx(s);
805bee2274fSriastradh }
806bee2274fSriastradh 
807bee2274fSriastradh bus_addr_t
pci_resource_start(struct pci_dev * pdev,unsigned i)808bee2274fSriastradh pci_resource_start(struct pci_dev *pdev, unsigned i)
809bee2274fSriastradh {
810bee2274fSriastradh 
8117cb953c8Smrg 	if (i >= PCI_NUM_RESOURCES)
8127cb953c8Smrg 		panic("resource %d >= max %d", i, PCI_NUM_RESOURCES);
813bee2274fSriastradh 	return pdev->pd_resources[i].addr;
814bee2274fSriastradh }
815bee2274fSriastradh 
816bee2274fSriastradh bus_size_t
pci_resource_len(struct pci_dev * pdev,unsigned i)817bee2274fSriastradh pci_resource_len(struct pci_dev *pdev, unsigned i)
818bee2274fSriastradh {
819bee2274fSriastradh 
8207cb953c8Smrg 	if (i >= PCI_NUM_RESOURCES)
8217cb953c8Smrg 		panic("resource %d >= max %d", i, PCI_NUM_RESOURCES);
822bee2274fSriastradh 	return pdev->pd_resources[i].size;
823bee2274fSriastradh }
824bee2274fSriastradh 
825bee2274fSriastradh bus_addr_t
pci_resource_end(struct pci_dev * pdev,unsigned i)826bee2274fSriastradh pci_resource_end(struct pci_dev *pdev, unsigned i)
827bee2274fSriastradh {
828bee2274fSriastradh 
829bee2274fSriastradh 	return pci_resource_start(pdev, i) + (pci_resource_len(pdev, i) - 1);
830bee2274fSriastradh }
831bee2274fSriastradh 
832bee2274fSriastradh int
pci_resource_flags(struct pci_dev * pdev,unsigned i)833bee2274fSriastradh pci_resource_flags(struct pci_dev *pdev, unsigned i)
834bee2274fSriastradh {
835bee2274fSriastradh 
8367cb953c8Smrg 	if (i >= PCI_NUM_RESOURCES)
8377cb953c8Smrg 		panic("resource %d >= max %d", i, PCI_NUM_RESOURCES);
838bee2274fSriastradh 	return pdev->pd_resources[i].flags;
839bee2274fSriastradh }
840bee2274fSriastradh 
841bee2274fSriastradh void __pci_iomem *
pci_iomap(struct pci_dev * pdev,unsigned i,bus_size_t size)842bee2274fSriastradh pci_iomap(struct pci_dev *pdev, unsigned i, bus_size_t size)
843bee2274fSriastradh {
844bee2274fSriastradh 	int error;
845bee2274fSriastradh 
846bee2274fSriastradh 	KASSERT(i < PCI_NUM_RESOURCES);
847bee2274fSriastradh 	KASSERT(pdev->pd_resources[i].kva == NULL);
848bee2274fSriastradh 
849bee2274fSriastradh 	if (PCI_MAPREG_TYPE(pdev->pd_resources[i].type) != PCI_MAPREG_TYPE_MEM)
850bee2274fSriastradh 		return NULL;
851bee2274fSriastradh 	if (pdev->pd_resources[i].size < size)
852bee2274fSriastradh 		return NULL;
853bee2274fSriastradh 	error = bus_space_map(pdev->pd_pa.pa_memt, pdev->pd_resources[i].addr,
854bee2274fSriastradh 	    size, BUS_SPACE_MAP_LINEAR | pdev->pd_resources[i].flags,
855bee2274fSriastradh 	    &pdev->pd_resources[i].bsh);
856d46aeca2Sriastradh 	if (error)
857bee2274fSriastradh 		return NULL;
858bee2274fSriastradh 	pdev->pd_resources[i].bst = pdev->pd_pa.pa_memt;
859bee2274fSriastradh 	pdev->pd_resources[i].kva = bus_space_vaddr(pdev->pd_resources[i].bst,
860bee2274fSriastradh 	    pdev->pd_resources[i].bsh);
861bee2274fSriastradh 	pdev->pd_resources[i].mapped = true;
862bee2274fSriastradh 
863bee2274fSriastradh 	return pdev->pd_resources[i].kva;
864bee2274fSriastradh }
865bee2274fSriastradh 
866bee2274fSriastradh void
pci_iounmap(struct pci_dev * pdev,void __pci_iomem * kva)867bee2274fSriastradh pci_iounmap(struct pci_dev *pdev, void __pci_iomem *kva)
868bee2274fSriastradh {
869bee2274fSriastradh 	unsigned i;
870bee2274fSriastradh 
871bee2274fSriastradh 	CTASSERT(__arraycount(pdev->pd_resources) == PCI_NUM_RESOURCES);
872bee2274fSriastradh 	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
873bee2274fSriastradh 		if (pdev->pd_resources[i].kva == kva)
874bee2274fSriastradh 			break;
875bee2274fSriastradh 	}
876bee2274fSriastradh 	KASSERT(i < PCI_NUM_RESOURCES);
877bee2274fSriastradh 
878bee2274fSriastradh 	pdev->pd_resources[i].kva = NULL;
879bee2274fSriastradh 	bus_space_unmap(pdev->pd_resources[i].bst, pdev->pd_resources[i].bsh,
880bee2274fSriastradh 	    pdev->pd_resources[i].size);
881bee2274fSriastradh }
882bee2274fSriastradh 
883bee2274fSriastradh void
pci_save_state(struct pci_dev * pdev)884bee2274fSriastradh pci_save_state(struct pci_dev *pdev)
885bee2274fSriastradh {
886bee2274fSriastradh 
887bee2274fSriastradh 	KASSERT(pdev->pd_saved_state == NULL);
888bee2274fSriastradh 	pdev->pd_saved_state = kmem_alloc(sizeof(*pdev->pd_saved_state),
889bee2274fSriastradh 	    KM_SLEEP);
890bee2274fSriastradh 	pci_conf_capture(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag,
891bee2274fSriastradh 	    pdev->pd_saved_state);
892bee2274fSriastradh }
893bee2274fSriastradh 
894bee2274fSriastradh void
pci_restore_state(struct pci_dev * pdev)895bee2274fSriastradh pci_restore_state(struct pci_dev *pdev)
896bee2274fSriastradh {
897bee2274fSriastradh 
898bee2274fSriastradh 	KASSERT(pdev->pd_saved_state != NULL);
899bee2274fSriastradh 	pci_conf_restore(pdev->pd_pa.pa_pc, pdev->pd_pa.pa_tag,
900bee2274fSriastradh 	    pdev->pd_saved_state);
901bee2274fSriastradh 	kmem_free(pdev->pd_saved_state, sizeof(*pdev->pd_saved_state));
902bee2274fSriastradh 	pdev->pd_saved_state = NULL;
903bee2274fSriastradh }
904bee2274fSriastradh 
905bee2274fSriastradh bool
pci_is_pcie(struct pci_dev * pdev)906bee2274fSriastradh pci_is_pcie(struct pci_dev *pdev)
907bee2274fSriastradh {
908bee2274fSriastradh 
909bee2274fSriastradh 	return (pci_find_capability(pdev, PCI_CAP_PCIEXPRESS) != 0);
910bee2274fSriastradh }
911bee2274fSriastradh 
912bee2274fSriastradh bool
pci_dma_supported(struct pci_dev * pdev,uintmax_t mask)913bee2274fSriastradh pci_dma_supported(struct pci_dev *pdev, uintmax_t mask)
914bee2274fSriastradh {
915bee2274fSriastradh 
916bee2274fSriastradh 	/* XXX Cop-out.  */
917bee2274fSriastradh 	if (mask > DMA_BIT_MASK(32))
918bee2274fSriastradh 		return pci_dma64_available(&pdev->pd_pa);
919bee2274fSriastradh 	else
920bee2274fSriastradh 		return true;
921bee2274fSriastradh }
922bee2274fSriastradh 
923bee2274fSriastradh bool
pci_is_thunderbolt_attached(struct pci_dev * pdev)924edb5cae2Sriastradh pci_is_thunderbolt_attached(struct pci_dev *pdev)
925edb5cae2Sriastradh {
926edb5cae2Sriastradh 
927edb5cae2Sriastradh 	/* XXX Cop-out.  */
928edb5cae2Sriastradh 	return false;
929edb5cae2Sriastradh }
930edb5cae2Sriastradh 
931edb5cae2Sriastradh bool
pci_is_root_bus(struct pci_bus * bus)932bee2274fSriastradh pci_is_root_bus(struct pci_bus *bus)
933bee2274fSriastradh {
934bee2274fSriastradh 
93516e2f9f2Smrg 	return bus->number == 0;
936bee2274fSriastradh }
937bee2274fSriastradh 
938bee2274fSriastradh int
pci_domain_nr(struct pci_bus * bus)939bee2274fSriastradh pci_domain_nr(struct pci_bus *bus)
940bee2274fSriastradh {
941bee2274fSriastradh 
94286a0f5fdSriastradh 	return pci_get_segment(bus->pb_pc);
943bee2274fSriastradh }
944bee2274fSriastradh 
945bee2274fSriastradh /*
946bee2274fSriastradh  * We explicitly rename pci_enable/disable_device so that you have to
947bee2274fSriastradh  * review each use of them, since NetBSD's PCI API does _not_ respect
948bee2274fSriastradh  * our local enablecnt here, but there are different parts of NetBSD
949bee2274fSriastradh  * that automatically enable/disable like PMF, so you have to decide
950bee2274fSriastradh  * for each one whether to call it or not.
951bee2274fSriastradh  */
952bee2274fSriastradh 
953bee2274fSriastradh int
linux_pci_enable_device(struct pci_dev * pdev)954bee2274fSriastradh linux_pci_enable_device(struct pci_dev *pdev)
955bee2274fSriastradh {
956bee2274fSriastradh 	const struct pci_attach_args *pa = &pdev->pd_pa;
957bee2274fSriastradh 	pcireg_t csr;
958bee2274fSriastradh 	int s;
959bee2274fSriastradh 
960bee2274fSriastradh 	if (pdev->pd_enablecnt++)
961bee2274fSriastradh 		return 0;
962bee2274fSriastradh 
963bee2274fSriastradh 	s = splhigh();
964bee2274fSriastradh 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
965702caa99Sriastradh 	/* If someone else (firmware) already enabled it, credit them.  */
966702caa99Sriastradh 	if (csr & (PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE))
967702caa99Sriastradh 		pdev->pd_enablecnt++;
968bee2274fSriastradh 	csr |= PCI_COMMAND_IO_ENABLE;
969bee2274fSriastradh 	csr |= PCI_COMMAND_MEM_ENABLE;
970bee2274fSriastradh 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
971bee2274fSriastradh 	splx(s);
972bee2274fSriastradh 
973bee2274fSriastradh 	return 0;
974bee2274fSriastradh }
975bee2274fSriastradh 
976bee2274fSriastradh void
linux_pci_disable_device(struct pci_dev * pdev)977bee2274fSriastradh linux_pci_disable_device(struct pci_dev *pdev)
978bee2274fSriastradh {
979bee2274fSriastradh 	const struct pci_attach_args *pa = &pdev->pd_pa;
980bee2274fSriastradh 	pcireg_t csr;
981bee2274fSriastradh 	int s;
982bee2274fSriastradh 
983bee2274fSriastradh 	if (--pdev->pd_enablecnt)
984bee2274fSriastradh 		return;
985bee2274fSriastradh 
986bee2274fSriastradh 	s = splhigh();
987bee2274fSriastradh 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
988bee2274fSriastradh 	csr &= ~PCI_COMMAND_IO_ENABLE;
989bee2274fSriastradh 	csr &= ~PCI_COMMAND_MEM_ENABLE;
990bee2274fSriastradh 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
991bee2274fSriastradh 	splx(s);
992bee2274fSriastradh }
993bee2274fSriastradh 
994bee2274fSriastradh void
linux_pci_dev_destroy(struct pci_dev * pdev)995bee2274fSriastradh linux_pci_dev_destroy(struct pci_dev *pdev)
996bee2274fSriastradh {
997bee2274fSriastradh 	unsigned i;
998bee2274fSriastradh 
999cb8e3c86Smrg 	if (pdev->bus->self != NULL) {
1000cb8e3c86Smrg 		kmem_free(pdev->bus->self, sizeof(*pdev->bus->self));
1001cb8e3c86Smrg 	}
1002bee2274fSriastradh 	if (pdev->bus != NULL) {
1003bee2274fSriastradh 		kmem_free(pdev->bus, sizeof(*pdev->bus));
1004bee2274fSriastradh 		pdev->bus = NULL;
1005bee2274fSriastradh 	}
1006bee2274fSriastradh 	if (ISSET(pdev->pd_kludges, NBPCI_KLUDGE_MAP_ROM)) {
1007bee2274fSriastradh 		pci_unmap_rom(pdev, pdev->pd_rom_vaddr);
1008bee2274fSriastradh 		pdev->pd_rom_vaddr = 0;
1009bee2274fSriastradh 	}
1010bee2274fSriastradh 	for (i = 0; i < __arraycount(pdev->pd_resources); i++) {
1011bee2274fSriastradh 		if (!pdev->pd_resources[i].mapped)
1012bee2274fSriastradh 			continue;
1013bee2274fSriastradh 		bus_space_unmap(pdev->pd_resources[i].bst,
1014bee2274fSriastradh 		    pdev->pd_resources[i].bsh, pdev->pd_resources[i].size);
1015bee2274fSriastradh 	}
1016bee2274fSriastradh 
1017bee2274fSriastradh 	/* There is no way these should be still in use.  */
1018bee2274fSriastradh 	KASSERT(pdev->pd_saved_state == NULL);
1019bee2274fSriastradh 	KASSERT(pdev->pd_intr_handles == NULL);
1020bee2274fSriastradh }
102116e2f9f2Smrg 
102216e2f9f2Smrg enum pci_bus_speed
pcie_get_speed_cap(struct pci_dev * dev)102316e2f9f2Smrg pcie_get_speed_cap(struct pci_dev *dev)
102416e2f9f2Smrg {
102516e2f9f2Smrg 	pci_chipset_tag_t pc = dev->pd_pa.pa_pc;
102616e2f9f2Smrg 	pcitag_t tag = dev->pd_pa.pa_tag;
102716e2f9f2Smrg 	pcireg_t lcap, lcap2, xcap;
102816e2f9f2Smrg 	int off;
102916e2f9f2Smrg 
103016e2f9f2Smrg 	/* Must have capabilities. */
103116e2f9f2Smrg 	if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0)
103216e2f9f2Smrg 		return PCI_SPEED_UNKNOWN;
103316e2f9f2Smrg 
103416e2f9f2Smrg 	/* Only PCIe 3.x has LCAP2. */
103516e2f9f2Smrg 	xcap = pci_conf_read(pc, tag, off + PCIE_XCAP);
103616e2f9f2Smrg 	if (__SHIFTOUT(xcap, PCIE_XCAP_VER_MASK) >= 2) {
103716e2f9f2Smrg 		lcap2 = pci_conf_read(pc, tag, off + PCIE_LCAP2);
103816e2f9f2Smrg 		if (lcap2) {
103916e2f9f2Smrg 			if ((lcap2 & PCIE_LCAP2_SUP_LNKS64) != 0) {
104016e2f9f2Smrg 				return PCIE_SPEED_64_0GT;
104116e2f9f2Smrg 			}
104216e2f9f2Smrg 			if ((lcap2 & PCIE_LCAP2_SUP_LNKS32) != 0) {
104316e2f9f2Smrg 				return PCIE_SPEED_32_0GT;
104416e2f9f2Smrg 			}
104516e2f9f2Smrg 			if ((lcap2 & PCIE_LCAP2_SUP_LNKS16) != 0) {
104616e2f9f2Smrg 				return PCIE_SPEED_16_0GT;
104716e2f9f2Smrg 			}
104816e2f9f2Smrg 			if ((lcap2 & PCIE_LCAP2_SUP_LNKS8) != 0) {
104916e2f9f2Smrg 				return PCIE_SPEED_8_0GT;
105016e2f9f2Smrg 			}
105116e2f9f2Smrg 			if ((lcap2 & PCIE_LCAP2_SUP_LNKS5) != 0) {
105216e2f9f2Smrg 				return PCIE_SPEED_5_0GT;
105316e2f9f2Smrg 			}
105416e2f9f2Smrg 			if ((lcap2 & PCIE_LCAP2_SUP_LNKS2) != 0) {
105516e2f9f2Smrg 				return PCIE_SPEED_2_5GT;
105616e2f9f2Smrg 			}
105716e2f9f2Smrg 		}
105816e2f9f2Smrg 	}
105916e2f9f2Smrg 
106016e2f9f2Smrg 	lcap = pci_conf_read(pc, tag, off + PCIE_LCAP);
106116e2f9f2Smrg 	if ((lcap & PCIE_LCAP_MAX_SPEED) == PCIE_LCAP_MAX_SPEED_64) {
106216e2f9f2Smrg 		return PCIE_SPEED_64_0GT;
106316e2f9f2Smrg 	}
106416e2f9f2Smrg 	if ((lcap & PCIE_LCAP_MAX_SPEED) == PCIE_LCAP_MAX_SPEED_32) {
106516e2f9f2Smrg 		return PCIE_SPEED_32_0GT;
106616e2f9f2Smrg 	}
106716e2f9f2Smrg 	if ((lcap & PCIE_LCAP_MAX_SPEED) == PCIE_LCAP_MAX_SPEED_16) {
106816e2f9f2Smrg 		return PCIE_SPEED_16_0GT;
106916e2f9f2Smrg 	}
107016e2f9f2Smrg 	if ((lcap & PCIE_LCAP_MAX_SPEED) == PCIE_LCAP_MAX_SPEED_8) {
107116e2f9f2Smrg 		return PCIE_SPEED_8_0GT;
107216e2f9f2Smrg 	}
107316e2f9f2Smrg 	if ((lcap & PCIE_LCAP_MAX_SPEED) == PCIE_LCAP_MAX_SPEED_5) {
107416e2f9f2Smrg 		return PCIE_SPEED_5_0GT;
107516e2f9f2Smrg 	}
107616e2f9f2Smrg 	if ((lcap & PCIE_LCAP_MAX_SPEED) == PCIE_LCAP_MAX_SPEED_2) {
107716e2f9f2Smrg 		return PCIE_SPEED_2_5GT;
107816e2f9f2Smrg 	}
107916e2f9f2Smrg 
108016e2f9f2Smrg 	return PCI_SPEED_UNKNOWN;
108116e2f9f2Smrg }
108216e2f9f2Smrg 
108316e2f9f2Smrg /*
108416e2f9f2Smrg  * This should walk the tree, it only checks this device currently.
108516e2f9f2Smrg  * It also does not write to limiting_dev (the only caller in drm2
108616e2f9f2Smrg  * currently does not use it.)
108716e2f9f2Smrg  */
108816e2f9f2Smrg unsigned
pcie_bandwidth_available(struct pci_dev * dev,struct pci_dev ** limiting_dev,enum pci_bus_speed * speed,enum pcie_link_width * width)108916e2f9f2Smrg pcie_bandwidth_available(struct pci_dev *dev,
109016e2f9f2Smrg     struct pci_dev **limiting_dev,
109116e2f9f2Smrg     enum pci_bus_speed *speed,
109216e2f9f2Smrg     enum pcie_link_width *width)
109316e2f9f2Smrg {
109416e2f9f2Smrg 	pci_chipset_tag_t pc = dev->pd_pa.pa_pc;
109516e2f9f2Smrg 	pcitag_t tag = dev->pd_pa.pa_tag;
109616e2f9f2Smrg 	pcireg_t lcsr;
109716e2f9f2Smrg 	unsigned per_line_speed, num_lanes;
109816e2f9f2Smrg 	int off;
109916e2f9f2Smrg 
110016e2f9f2Smrg 	/* Must have capabilities. */
110116e2f9f2Smrg 	if (pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, &off, NULL) == 0)
110216e2f9f2Smrg 		return 0;
110316e2f9f2Smrg 
110416e2f9f2Smrg 	if (speed)
110516e2f9f2Smrg 		*speed = PCI_SPEED_UNKNOWN;
110616e2f9f2Smrg 	if (width)
110716e2f9f2Smrg 		*width = 0;
110816e2f9f2Smrg 
110916e2f9f2Smrg 	lcsr = pci_conf_read(pc, tag, off + PCIE_LCSR);
111016e2f9f2Smrg 
111116e2f9f2Smrg 	switch (lcsr & PCIE_LCSR_NLW) {
111216e2f9f2Smrg 	case PCIE_LCSR_NLW_X1:
111316e2f9f2Smrg 	case PCIE_LCSR_NLW_X2:
111416e2f9f2Smrg 	case PCIE_LCSR_NLW_X4:
111516e2f9f2Smrg 	case PCIE_LCSR_NLW_X8:
111616e2f9f2Smrg 	case PCIE_LCSR_NLW_X12:
111716e2f9f2Smrg 	case PCIE_LCSR_NLW_X16:
111816e2f9f2Smrg 	case PCIE_LCSR_NLW_X32:
111916e2f9f2Smrg 		num_lanes = __SHIFTOUT(lcsr, PCIE_LCSR_NLW);
112016e2f9f2Smrg 		if (width)
112116e2f9f2Smrg 			*width = num_lanes;
112216e2f9f2Smrg 		break;
112316e2f9f2Smrg 	default:
112416e2f9f2Smrg 		num_lanes = 0;
112516e2f9f2Smrg 		break;
112616e2f9f2Smrg 	}
112716e2f9f2Smrg 
112816e2f9f2Smrg 	switch (__SHIFTOUT(lcsr, PCIE_LCSR_LINKSPEED)) {
112916e2f9f2Smrg 	case PCIE_LCSR_LINKSPEED_2:
113016e2f9f2Smrg 		*speed = PCIE_SPEED_2_5GT;
113116e2f9f2Smrg 		per_line_speed = 2500 * 8 / 10;
113216e2f9f2Smrg 		break;
113316e2f9f2Smrg 	case PCIE_LCSR_LINKSPEED_5:
113416e2f9f2Smrg 		*speed = PCIE_SPEED_5_0GT;
113516e2f9f2Smrg 		per_line_speed = 5000 * 8 / 10;
113616e2f9f2Smrg 		break;
113716e2f9f2Smrg 	case PCIE_LCSR_LINKSPEED_8:
113816e2f9f2Smrg 		*speed = PCIE_SPEED_8_0GT;
113916e2f9f2Smrg 		per_line_speed = 8000 * 128 / 130;
114016e2f9f2Smrg 		break;
114116e2f9f2Smrg 	case PCIE_LCSR_LINKSPEED_16:
114216e2f9f2Smrg 		*speed = PCIE_SPEED_16_0GT;
114316e2f9f2Smrg 		per_line_speed = 16000 * 128 / 130;
114416e2f9f2Smrg 		break;
114516e2f9f2Smrg 	case PCIE_LCSR_LINKSPEED_32:
114616e2f9f2Smrg 		*speed = PCIE_SPEED_32_0GT;
114716e2f9f2Smrg 		per_line_speed = 32000 * 128 / 130;
114816e2f9f2Smrg 		break;
114916e2f9f2Smrg 	case PCIE_LCSR_LINKSPEED_64:
115016e2f9f2Smrg 		*speed = PCIE_SPEED_64_0GT;
115116e2f9f2Smrg 		per_line_speed = 64000 * 128 / 130;
115216e2f9f2Smrg 		break;
115316e2f9f2Smrg 	default:
115416e2f9f2Smrg 		per_line_speed = 0;
115516e2f9f2Smrg 	}
115616e2f9f2Smrg 
115716e2f9f2Smrg 	return num_lanes * per_line_speed;
115816e2f9f2Smrg }
1159