xref: /openbsd-src/sys/arch/amd64/pci/pci_machdep.c (revision eb3d9e2dd0357d3826bf04a6468e649c8525d43e)
1*eb3d9e2dSkettenis /*	$OpenBSD: pci_machdep.c,v 1.81 2025/01/23 11:24:34 kettenis Exp $	*/
2f5df1827Smickey /*	$NetBSD: pci_machdep.c,v 1.3 2003/05/07 21:33:58 fvdl Exp $	*/
3f5df1827Smickey 
4f5df1827Smickey /*-
5f5df1827Smickey  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
6f5df1827Smickey  * All rights reserved.
7f5df1827Smickey  *
8f5df1827Smickey  * This code is derived from software contributed to The NetBSD Foundation
9f5df1827Smickey  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10f5df1827Smickey  * NASA Ames Research Center.
11f5df1827Smickey  *
12f5df1827Smickey  * Redistribution and use in source and binary forms, with or without
13f5df1827Smickey  * modification, are permitted provided that the following conditions
14f5df1827Smickey  * are met:
15f5df1827Smickey  * 1. Redistributions of source code must retain the above copyright
16f5df1827Smickey  *    notice, this list of conditions and the following disclaimer.
17f5df1827Smickey  * 2. Redistributions in binary form must reproduce the above copyright
18f5df1827Smickey  *    notice, this list of conditions and the following disclaimer in the
19f5df1827Smickey  *    documentation and/or other materials provided with the distribution.
20f5df1827Smickey  *
21f5df1827Smickey  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22f5df1827Smickey  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23f5df1827Smickey  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24f5df1827Smickey  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25f5df1827Smickey  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26f5df1827Smickey  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27f5df1827Smickey  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28f5df1827Smickey  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29f5df1827Smickey  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30f5df1827Smickey  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31f5df1827Smickey  * POSSIBILITY OF SUCH DAMAGE.
32f5df1827Smickey  */
33f5df1827Smickey 
34f5df1827Smickey /*
35f5df1827Smickey  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
36f5df1827Smickey  * Copyright (c) 1994 Charles M. Hannum.  All rights reserved.
37f5df1827Smickey  *
38f5df1827Smickey  * Redistribution and use in source and binary forms, with or without
39f5df1827Smickey  * modification, are permitted provided that the following conditions
40f5df1827Smickey  * are met:
41f5df1827Smickey  * 1. Redistributions of source code must retain the above copyright
42f5df1827Smickey  *    notice, this list of conditions and the following disclaimer.
43f5df1827Smickey  * 2. Redistributions in binary form must reproduce the above copyright
44f5df1827Smickey  *    notice, this list of conditions and the following disclaimer in the
45f5df1827Smickey  *    documentation and/or other materials provided with the distribution.
46f5df1827Smickey  * 3. All advertising materials mentioning features or use of this software
47f5df1827Smickey  *    must display the following acknowledgement:
48f5df1827Smickey  *	This product includes software developed by Charles M. Hannum.
49f5df1827Smickey  * 4. The name of the author may not be used to endorse or promote products
50f5df1827Smickey  *    derived from this software without specific prior written permission.
51f5df1827Smickey  *
52f5df1827Smickey  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53f5df1827Smickey  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
54f5df1827Smickey  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
55f5df1827Smickey  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56f5df1827Smickey  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57f5df1827Smickey  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58f5df1827Smickey  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59f5df1827Smickey  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60f5df1827Smickey  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61f5df1827Smickey  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62f5df1827Smickey  */
63f5df1827Smickey 
64f5df1827Smickey /*
65f5df1827Smickey  * Machine-specific functions for PCI autoconfiguration.
66f5df1827Smickey  */
67f5df1827Smickey 
68f5df1827Smickey #include <sys/param.h>
69f5df1827Smickey #include <sys/systm.h>
70ea9b3ec9Skettenis #include <sys/extent.h>
71ea9b3ec9Skettenis #include <sys/malloc.h>
72f5df1827Smickey 
73f5df1827Smickey #include <machine/bus.h>
74f5df1827Smickey 
75f5df1827Smickey #include <machine/pio.h>
76f5df1827Smickey #include <machine/intr.h>
77ea9b3ec9Skettenis #include <machine/biosvar.h>
78f5df1827Smickey 
79f5df1827Smickey #include <dev/isa/isareg.h>
80f5df1827Smickey #include <dev/pci/pcivar.h>
81f5df1827Smickey #include <dev/pci/pcireg.h>
82f5df1827Smickey #include <dev/pci/pcidevs.h>
83b1d93e39Skettenis #include <dev/pci/ppbreg.h>
84f5df1827Smickey 
85f5df1827Smickey #include "ioapic.h"
86f5df1827Smickey 
87f5df1827Smickey #if NIOAPIC > 0
88f5df1827Smickey #include <machine/i82093var.h>
89f5df1827Smickey #include <machine/mpbiosvar.h>
90f5df1827Smickey #endif
91f5df1827Smickey 
9296940271Sjordan #include "acpi.h"
9396940271Sjordan 
9496940271Sjordan #include "acpidmar.h"
9596940271Sjordan #if NACPIDMAR > 0
9696940271Sjordan #include <dev/acpi/acpidmar.h>
9796940271Sjordan #endif
9896940271Sjordan 
99fd1ffd5dSkettenis /*
100fd1ffd5dSkettenis  * Memory Mapped Configuration space access.
101fd1ffd5dSkettenis  *
102fd1ffd5dSkettenis  * Since mapping the whole configuration space will cost us up to
10336fd90dcSjsg  * 256MB of kernel virtual memory, we use separate mappings per bus.
104fd1ffd5dSkettenis  * The mappings are created on-demand, such that we only use kernel
105fd1ffd5dSkettenis  * virtual memory for busses that are actually present.
106fd1ffd5dSkettenis  */
107fd1ffd5dSkettenis bus_addr_t pci_mcfg_addr;
108fd1ffd5dSkettenis int pci_mcfg_min_bus, pci_mcfg_max_bus;
1092c626a9bSkettenis bus_space_tag_t pci_mcfgt;
110fd1ffd5dSkettenis bus_space_handle_t pci_mcfgh[256];
111fd1ffd5dSkettenis 
112701c052aSoga struct mutex pci_conf_lock = MUTEX_INITIALIZER(IPL_HIGH);
113f5df1827Smickey 
114701c052aSoga #define	PCI_CONF_LOCK()						\
115f5df1827Smickey do {									\
116701c052aSoga 	mtx_enter(&pci_conf_lock);					\
117f5df1827Smickey } while (0)
118f5df1827Smickey 
119701c052aSoga #define	PCI_CONF_UNLOCK()						\
120f5df1827Smickey do {									\
121701c052aSoga 	mtx_leave(&pci_conf_lock);					\
122f5df1827Smickey } while (0)
123f5df1827Smickey 
124f5df1827Smickey #define	PCI_MODE1_ENABLE	0x80000000UL
125f5df1827Smickey #define	PCI_MODE1_ADDRESS_REG	0x0cf8
126f5df1827Smickey #define	PCI_MODE1_DATA_REG	0x0cfc
127f5df1827Smickey 
128f5df1827Smickey /*
129f5df1827Smickey  * PCI doesn't have any special needs; just use the generic versions
130f5df1827Smickey  * of these functions.
131f5df1827Smickey  */
13213fad3d0Soga struct bus_dma_tag pci_bus_dma_tag = {
133f5df1827Smickey 	NULL,			/* _may_bounce */
134f5df1827Smickey 	_bus_dmamap_create,
135f5df1827Smickey 	_bus_dmamap_destroy,
136f5df1827Smickey 	_bus_dmamap_load,
137f5df1827Smickey 	_bus_dmamap_load_mbuf,
138f5df1827Smickey 	_bus_dmamap_load_uio,
139f5df1827Smickey 	_bus_dmamap_load_raw,
140f5df1827Smickey 	_bus_dmamap_unload,
141bcc3a45bSkettenis 	_bus_dmamap_sync,
142f5df1827Smickey 	_bus_dmamem_alloc,
1433df3eb3bSkettenis 	_bus_dmamem_alloc_range,
144f5df1827Smickey 	_bus_dmamem_free,
145f5df1827Smickey 	_bus_dmamem_map,
146f5df1827Smickey 	_bus_dmamem_unmap,
147f5df1827Smickey 	_bus_dmamem_mmap,
148f5df1827Smickey };
149f5df1827Smickey 
150d6a1c66eSkettenis void
151d6a1c66eSkettenis pci_mcfg_init(bus_space_tag_t iot, bus_addr_t addr, int segment,
152d6a1c66eSkettenis     int min_bus, int max_bus)
1532c626a9bSkettenis {
154d6a1c66eSkettenis 	if (segment == 0) {
1552c626a9bSkettenis 		pci_mcfgt = iot;
1562c626a9bSkettenis 		pci_mcfg_addr = addr;
1572c626a9bSkettenis 		pci_mcfg_min_bus = min_bus;
1582c626a9bSkettenis 		pci_mcfg_max_bus = max_bus;
159d6a1c66eSkettenis 	}
160d6a1c66eSkettenis }
1612c626a9bSkettenis 
162d6a1c66eSkettenis pci_chipset_tag_t
163*eb3d9e2dSkettenis pci_lookup_segment(int segment, int bus)
164d6a1c66eSkettenis {
165d6a1c66eSkettenis 	KASSERT(segment == 0);
1662c626a9bSkettenis 	return NULL;
1672c626a9bSkettenis }
1682c626a9bSkettenis 
169f5df1827Smickey void
1702bb6026aSjsg pci_attach_hook(struct device *parent, struct device *self,
1712bb6026aSjsg     struct pcibus_attach_args *pba)
172f5df1827Smickey {
17357b2f8a1Sjason }
174f5df1827Smickey 
175f5df1827Smickey int
1762bb6026aSjsg pci_bus_maxdevs(pci_chipset_tag_t pc, int busno)
177f5df1827Smickey {
178f5df1827Smickey 	return (32);
179f5df1827Smickey }
180f5df1827Smickey 
181f5df1827Smickey pcitag_t
1822bb6026aSjsg pci_make_tag(pci_chipset_tag_t pc, int bus, int device, int function)
183f5df1827Smickey {
184f5df1827Smickey 	if (bus >= 256 || device >= 32 || function >= 8)
185f5df1827Smickey 		panic("pci_make_tag: bad request");
186f5df1827Smickey 
187cdb1eb42Skettenis 	return (PCI_MODE1_ENABLE |
188cdb1eb42Skettenis 	    (bus << 16) | (device << 11) | (function << 8));
189f5df1827Smickey }
190f5df1827Smickey 
191f5df1827Smickey void
1922bb6026aSjsg pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, int *fp)
193f5df1827Smickey {
194f5df1827Smickey 	if (bp != NULL)
195cdb1eb42Skettenis 		*bp = (tag >> 16) & 0xff;
196f5df1827Smickey 	if (dp != NULL)
197cdb1eb42Skettenis 		*dp = (tag >> 11) & 0x1f;
198f5df1827Smickey 	if (fp != NULL)
199cdb1eb42Skettenis 		*fp = (tag >> 8) & 0x7;
200f5df1827Smickey }
201f5df1827Smickey 
202b1926db3Smiod int
203b1926db3Smiod pci_conf_size(pci_chipset_tag_t pc, pcitag_t tag)
204b1926db3Smiod {
205d3b3aeffSkettenis 	int bus;
206d3b3aeffSkettenis 
207d3b3aeffSkettenis 	if (pci_mcfg_addr) {
208d3b3aeffSkettenis 		pci_decompose_tag(pc, tag, &bus, NULL, NULL);
209d3b3aeffSkettenis 		if (bus >= pci_mcfg_min_bus && bus <= pci_mcfg_max_bus)
210fd1ffd5dSkettenis 			return PCIE_CONFIG_SPACE_SIZE;
211d3b3aeffSkettenis 	}
212fd1ffd5dSkettenis 
213b1926db3Smiod 	return PCI_CONFIG_SPACE_SIZE;
214b1926db3Smiod }
215b1926db3Smiod 
216d3b3aeffSkettenis void
217d3b3aeffSkettenis pci_mcfg_map_bus(int bus)
218d3b3aeffSkettenis {
219d3b3aeffSkettenis 	if (pci_mcfgh[bus])
220d3b3aeffSkettenis 		return;
221d3b3aeffSkettenis 
222d3b3aeffSkettenis 	if (bus_space_map(pci_mcfgt, pci_mcfg_addr + (bus << 20), 1 << 20,
223d3b3aeffSkettenis 	    0, &pci_mcfgh[bus]))
224d3b3aeffSkettenis 		panic("pci_conf_read: cannot map mcfg space");
225d3b3aeffSkettenis }
226d3b3aeffSkettenis 
227f5df1827Smickey pcireg_t
2282bb6026aSjsg pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
229f5df1827Smickey {
230f5df1827Smickey 	pcireg_t data;
231fd1ffd5dSkettenis 	int bus;
232fd1ffd5dSkettenis 
23335fc78aeSkettenis 	KASSERT((reg & 0x3) == 0);
23435fc78aeSkettenis 
235ca91a0edSkettenis 	if (pci_mcfg_addr && reg >= PCI_CONFIG_SPACE_SIZE) {
236fd1ffd5dSkettenis 		pci_decompose_tag(pc, tag, &bus, NULL, NULL);
237d3b3aeffSkettenis 		if (bus >= pci_mcfg_min_bus && bus <= pci_mcfg_max_bus) {
238d3b3aeffSkettenis 			pci_mcfg_map_bus(bus);
239d3b3aeffSkettenis 			data = bus_space_read_4(pci_mcfgt, pci_mcfgh[bus],
240d3b3aeffSkettenis 			    (tag & 0x000ff00) << 4 | reg);
241d3b3aeffSkettenis 			return data;
242d3b3aeffSkettenis 		}
243fd1ffd5dSkettenis 	}
244f5df1827Smickey 
245701c052aSoga 	PCI_CONF_LOCK();
246cdb1eb42Skettenis 	outl(PCI_MODE1_ADDRESS_REG, tag | reg);
247f5df1827Smickey 	data = inl(PCI_MODE1_DATA_REG);
248f5df1827Smickey 	outl(PCI_MODE1_ADDRESS_REG, 0);
249701c052aSoga 	PCI_CONF_UNLOCK();
250c65c5fb2Sweingart 
251f5df1827Smickey 	return data;
252f5df1827Smickey }
253f5df1827Smickey 
254f5df1827Smickey void
2552bb6026aSjsg pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
256f5df1827Smickey {
257fd1ffd5dSkettenis 	int bus;
258fd1ffd5dSkettenis 
25935fc78aeSkettenis 	KASSERT((reg & 0x3) == 0);
26035fc78aeSkettenis 
261ca91a0edSkettenis 	if (pci_mcfg_addr && reg >= PCI_CONFIG_SPACE_SIZE) {
262fd1ffd5dSkettenis 		pci_decompose_tag(pc, tag, &bus, NULL, NULL);
263d3b3aeffSkettenis 		if (bus >= pci_mcfg_min_bus && bus <= pci_mcfg_max_bus) {
264d3b3aeffSkettenis 			pci_mcfg_map_bus(bus);
265fd1ffd5dSkettenis 			bus_space_write_4(pci_mcfgt, pci_mcfgh[bus],
266d3b3aeffSkettenis 			    (tag & 0x000ff00) << 4 | reg, data);
267fd1ffd5dSkettenis 			return;
268fd1ffd5dSkettenis 		}
269d3b3aeffSkettenis 	}
270fd1ffd5dSkettenis 
271701c052aSoga 	PCI_CONF_LOCK();
272cdb1eb42Skettenis 	outl(PCI_MODE1_ADDRESS_REG, tag | reg);
273f5df1827Smickey 	outl(PCI_MODE1_DATA_REG, data);
274f5df1827Smickey 	outl(PCI_MODE1_ADDRESS_REG, 0);
275701c052aSoga 	PCI_CONF_UNLOCK();
276f5df1827Smickey }
277f5df1827Smickey 
2784211e504Skettenis int
2794211e504Skettenis pci_msix_table_map(pci_chipset_tag_t pc, pcitag_t tag,
2804211e504Skettenis     bus_space_tag_t memt, bus_space_handle_t *memh)
2814211e504Skettenis {
2824211e504Skettenis 	bus_addr_t base;
2834211e504Skettenis 	pcireg_t reg, table, type;
2844211e504Skettenis 	int bir, offset;
2854211e504Skettenis 	int off, tblsz;
2864211e504Skettenis 
2874211e504Skettenis 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, &reg) == 0)
2884211e504Skettenis 		panic("%s: no msix capability", __func__);
2894211e504Skettenis 
2904211e504Skettenis 	table = pci_conf_read(pc, tag, off + PCI_MSIX_TABLE);
2914211e504Skettenis 	bir = (table & PCI_MSIX_TABLE_BIR);
2924211e504Skettenis 	offset = (table & PCI_MSIX_TABLE_OFF);
2934211e504Skettenis 	tblsz = PCI_MSIX_MC_TBLSZ(reg) + 1;
2944211e504Skettenis 
2954211e504Skettenis 	bir = PCI_MAPREG_START + bir * 4;
2964211e504Skettenis 	type = pci_mapreg_type(pc, tag, bir);
2974211e504Skettenis 	if (pci_mapreg_info(pc, tag, bir, type, &base, NULL, NULL) ||
2984211e504Skettenis 	    _bus_space_map(memt, base + offset, tblsz * 16, 0, memh))
2994211e504Skettenis 		return -1;
3004211e504Skettenis 
3014211e504Skettenis 	return 0;
3024211e504Skettenis }
3034211e504Skettenis 
3044211e504Skettenis void
3054211e504Skettenis pci_msix_table_unmap(pci_chipset_tag_t pc, pcitag_t tag,
3064211e504Skettenis     bus_space_tag_t memt, bus_space_handle_t memh)
3074211e504Skettenis {
3084211e504Skettenis 	pcireg_t reg;
3094211e504Skettenis 	int tblsz;
3104211e504Skettenis 
3114211e504Skettenis 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, &reg) == 0)
3124211e504Skettenis 		panic("%s: no msix capability", __func__);
3134211e504Skettenis 
3144211e504Skettenis 	tblsz = PCI_MSIX_MC_TBLSZ(reg) + 1;
3154211e504Skettenis 	_bus_space_unmap(memt, memh, tblsz * 16, NULL);
3164211e504Skettenis }
3174211e504Skettenis 
318fb432fadSkettenis /*
319fb432fadSkettenis  * We pack the MSI vector number into the lower 8 bits of the PCI tag
320fb432fadSkettenis  * and use that as the MSI/MSI-X "PIC" pin number.  This allows us to
321fb432fadSkettenis  * address 256 MSI vectors which ought to be enough for anybody.
322fb432fadSkettenis  */
323fb432fadSkettenis #define PCI_MSI_VEC_MASK	0xff
324fb432fadSkettenis #define PCI_MSI_VEC(pin)	((pin) & PCI_MSI_VEC_MASK)
325fb432fadSkettenis #define PCI_MSI_TAG(pin)	((pin) & ~PCI_MSI_VEC_MASK)
326fb432fadSkettenis #define PCI_MSI_PIN(tag, vec)	((tag) | (vec))
327fb432fadSkettenis 
328d132e815Skettenis void msi_hwmask(struct pic *, int);
329d132e815Skettenis void msi_hwunmask(struct pic *, int);
3305368f701Skettenis void msi_addroute(struct pic *, struct cpu_info *, int, int, int);
3315368f701Skettenis void msi_delroute(struct pic *, struct cpu_info *, int, int, int);
332fb432fadSkettenis int msi_allocidtvec(struct pic *, int, int, int);
333d132e815Skettenis 
334d132e815Skettenis struct pic msi_pic = {
335d132e815Skettenis 	{0, {NULL}, NULL, 0, "msi", NULL, 0, 0},
336d132e815Skettenis 	PIC_MSI,
337d132e815Skettenis #ifdef MULTIPROCESSOR
338d132e815Skettenis 	{},
339d132e815Skettenis #endif
340d132e815Skettenis 	msi_hwmask,
341d132e815Skettenis 	msi_hwunmask,
3425368f701Skettenis 	msi_addroute,
3435368f701Skettenis 	msi_delroute,
344fb432fadSkettenis 	msi_allocidtvec,
345d132e815Skettenis 	NULL,
346d132e815Skettenis 	ioapic_edge_stubs
347d132e815Skettenis };
348d132e815Skettenis 
349d132e815Skettenis void
350d132e815Skettenis msi_hwmask(struct pic *pic, int pin)
351d132e815Skettenis {
3523819a926Skettenis 	pci_chipset_tag_t pc = NULL; /* XXX */
3533819a926Skettenis 	pcitag_t tag = PCI_MSI_TAG(pin);
3543819a926Skettenis 	int vec = PCI_MSI_VEC(pin);
3553819a926Skettenis 	pcireg_t reg, mask;
3563819a926Skettenis 	int off;
3573819a926Skettenis 
3583819a926Skettenis 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, &reg) == 0)
3593819a926Skettenis 		return;
3603819a926Skettenis 
3613819a926Skettenis 	/* We can't mask if per-vector masking isn't implemented. */
3623819a926Skettenis 	if ((reg & PCI_MSI_MC_PVMASK) == 0)
3633819a926Skettenis 		return;
3643819a926Skettenis 
3653819a926Skettenis 	if (reg & PCI_MSI_MC_C64) {
3663819a926Skettenis 		mask = pci_conf_read(pc, tag, off + PCI_MSI_MASK64);
3673819a926Skettenis 		pci_conf_write(pc, tag, off + PCI_MSI_MASK64,
3683819a926Skettenis 		    mask | (1U << vec));
3693819a926Skettenis 	} else {
3703819a926Skettenis 		mask = pci_conf_read(pc, tag, off + PCI_MSI_MASK32);
3713819a926Skettenis 		pci_conf_write(pc, tag, off + PCI_MSI_MASK32,
3723819a926Skettenis 		    mask | (1U << vec));
3733819a926Skettenis 	}
374d132e815Skettenis }
375d132e815Skettenis 
376d132e815Skettenis void
377d132e815Skettenis msi_hwunmask(struct pic *pic, int pin)
378d132e815Skettenis {
3793819a926Skettenis 	pci_chipset_tag_t pc = NULL; /* XXX */
3803819a926Skettenis 	pcitag_t tag = PCI_MSI_TAG(pin);
3813819a926Skettenis 	int vec = PCI_MSI_VEC(pin);
3823819a926Skettenis 	pcireg_t reg, mask;
3833819a926Skettenis 	int off;
3843819a926Skettenis 
3853819a926Skettenis 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, &reg) == 0)
3863819a926Skettenis 		return;
3873819a926Skettenis 
3883819a926Skettenis 	/* We can't mask if per-vector masking isn't implemented. */
3893819a926Skettenis 	if ((reg & PCI_MSI_MC_PVMASK) == 0)
3903819a926Skettenis 		return;
3913819a926Skettenis 
3923819a926Skettenis 	if (reg & PCI_MSI_MC_C64) {
3933819a926Skettenis 		mask = pci_conf_read(pc, tag, off + PCI_MSI_MASK64);
3943819a926Skettenis 		pci_conf_write(pc, tag, off + PCI_MSI_MASK64,
3953819a926Skettenis 		    mask & ~(1U << vec));
3963819a926Skettenis 	} else {
3973819a926Skettenis 		mask = pci_conf_read(pc, tag, off + PCI_MSI_MASK32);
3983819a926Skettenis 		pci_conf_write(pc, tag, off + PCI_MSI_MASK32,
3993819a926Skettenis 		    mask & ~(1U << vec));
4003819a926Skettenis 	}
401d132e815Skettenis }
402d132e815Skettenis 
403d132e815Skettenis void
404fb432fadSkettenis msi_addroute(struct pic *pic, struct cpu_info *ci, int pin, int idtvec,
405fb432fadSkettenis     int type)
406d132e815Skettenis {
4075368f701Skettenis 	pci_chipset_tag_t pc = NULL; /* XXX */
408fb432fadSkettenis 	pcitag_t tag = PCI_MSI_TAG(pin);
409fb432fadSkettenis 	int vec = PCI_MSI_VEC(pin);
4105368f701Skettenis 	pcireg_t reg, addr;
4115368f701Skettenis 	int off;
4125368f701Skettenis 
4135368f701Skettenis 	if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg) == 0)
4145368f701Skettenis 		panic("%s: no msi capability", __func__);
4155368f701Skettenis 
416fb432fadSkettenis 	if (vec != 0)
417fb432fadSkettenis 		return;
418fb432fadSkettenis 
4195368f701Skettenis 	addr = 0xfee00000UL | (ci->ci_apicid << 12);
4205368f701Skettenis 
4215368f701Skettenis 	if (reg & PCI_MSI_MC_C64) {
4225368f701Skettenis 		pci_conf_write(pc, tag, off + PCI_MSI_MA, addr);
4235368f701Skettenis 		pci_conf_write(pc, tag, off + PCI_MSI_MAU32, 0);
424fb432fadSkettenis 		pci_conf_write(pc, tag, off + PCI_MSI_MD64, idtvec);
4255368f701Skettenis 	} else {
4265368f701Skettenis 		pci_conf_write(pc, tag, off + PCI_MSI_MA, addr);
427fb432fadSkettenis 		pci_conf_write(pc, tag, off + PCI_MSI_MD32, idtvec);
4285368f701Skettenis 	}
4295368f701Skettenis 	pci_conf_write(pc, tag, off, reg | PCI_MSI_MC_MSIE);
4305368f701Skettenis }
4315368f701Skettenis 
4325368f701Skettenis void
433fb432fadSkettenis msi_delroute(struct pic *pic, struct cpu_info *ci, int pin, int idtvec,
434fb432fadSkettenis     int type)
4355368f701Skettenis {
4365368f701Skettenis 	pci_chipset_tag_t pc = NULL; /* XXX */
437fb432fadSkettenis 	pcitag_t tag = PCI_MSI_TAG(pin);
438fb432fadSkettenis 	int vec = PCI_MSI_VEC(pin);
4395368f701Skettenis 	pcireg_t reg;
4405368f701Skettenis 	int off;
4415368f701Skettenis 
442fb432fadSkettenis 	if (vec != 0)
443fb432fadSkettenis 		return;
444fb432fadSkettenis 
4454f2f3591Skettenis 	if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg))
4465368f701Skettenis 		pci_conf_write(pc, tag, off, reg & ~PCI_MSI_MC_MSIE);
447d132e815Skettenis }
448d132e815Skettenis 
449d132e815Skettenis int
450fb432fadSkettenis msi_allocidtvec(struct pic *pic, int pin, int low, int high)
451fb432fadSkettenis {
452fb432fadSkettenis 	pci_chipset_tag_t pc = NULL; /* XXX */
453fb432fadSkettenis 	pcitag_t tag = PCI_MSI_TAG(pin);
454fb432fadSkettenis 	int vec = PCI_MSI_VEC(pin);
455fb432fadSkettenis 	int idtvec, mme, off;
456fb432fadSkettenis 	pcireg_t reg;
457fb432fadSkettenis 
458fb432fadSkettenis 	if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg) == 0)
459fb432fadSkettenis 		panic("%s: no msi capability", __func__);
460fb432fadSkettenis 
461fb432fadSkettenis 	reg = pci_conf_read(pc, tag, off);
462fb432fadSkettenis 	mme = ((reg & PCI_MSI_MC_MME_MASK) >> PCI_MSI_MC_MME_SHIFT);
463fb432fadSkettenis 	if (vec >= (1 << mme))
464fb432fadSkettenis 		return 0;
465fb432fadSkettenis 
466fb432fadSkettenis 	if (vec == 0) {
467fb432fadSkettenis 		idtvec = idt_vec_alloc_range(low, high, (1 << mme));
468fb432fadSkettenis 		if (reg & PCI_MSI_MC_C64)
469fb432fadSkettenis 			pci_conf_write(pc, tag, off + PCI_MSI_MD64, idtvec);
470fb432fadSkettenis 		else
471fb432fadSkettenis 			pci_conf_write(pc, tag, off + PCI_MSI_MD32, idtvec);
472fb432fadSkettenis 	} else {
473fb432fadSkettenis 		if (reg & PCI_MSI_MC_C64)
474fb432fadSkettenis 			reg = pci_conf_read(pc, tag, off + PCI_MSI_MD64);
475fb432fadSkettenis 		else
476fb432fadSkettenis 			reg = pci_conf_read(pc, tag, off + PCI_MSI_MD32);
477fb432fadSkettenis 		KASSERT(reg > 0);
478fb432fadSkettenis 		idtvec = reg + vec;
479fb432fadSkettenis 	}
480fb432fadSkettenis 
481fb432fadSkettenis 	return idtvec;
482fb432fadSkettenis }
483fb432fadSkettenis 
484fb432fadSkettenis int
485fb432fadSkettenis pci_intr_enable_msivec(struct pci_attach_args *pa, int num_vec)
486fb432fadSkettenis {
487fb432fadSkettenis 	pci_chipset_tag_t pc = pa->pa_pc;
488fb432fadSkettenis 	pcitag_t tag = pa->pa_tag;
489fb432fadSkettenis 	pcireg_t reg;
490fb432fadSkettenis 	int mmc, mme, off;
491fb432fadSkettenis 
492fb432fadSkettenis 	if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 || mp_busses == NULL ||
493fb432fadSkettenis 	    pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg) == 0)
494fb432fadSkettenis 		return 1;
495fb432fadSkettenis 
496fb432fadSkettenis 	mmc = ((reg & PCI_MSI_MC_MMC_MASK) >> PCI_MSI_MC_MMC_SHIFT);
497fb432fadSkettenis 	if (num_vec > (1 << mmc))
498fb432fadSkettenis 		return 1;
499fb432fadSkettenis 
500fb432fadSkettenis 	mme = ((reg & PCI_MSI_MC_MME_MASK) >> PCI_MSI_MC_MME_SHIFT);
501fb432fadSkettenis 	while ((1 << mme) < num_vec)
502fb432fadSkettenis 		mme++;
503fb432fadSkettenis 	reg &= ~PCI_MSI_MC_MME_MASK;
504fb432fadSkettenis 	reg |= (mme << PCI_MSI_MC_MME_SHIFT);
505fb432fadSkettenis 	pci_conf_write(pc, tag, off, reg);
506fb432fadSkettenis 
507fb432fadSkettenis 	return 0;
508fb432fadSkettenis }
509fb432fadSkettenis 
510fb432fadSkettenis int
511d132e815Skettenis pci_intr_map_msi(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
512d132e815Skettenis {
513d132e815Skettenis 	pci_chipset_tag_t pc = pa->pa_pc;
514d132e815Skettenis 	pcitag_t tag = pa->pa_tag;
515fb432fadSkettenis 	pcireg_t reg;
516fb432fadSkettenis 	int off;
517d132e815Skettenis 
518bcb3d2e7Skettenis 	if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 || mp_busses == NULL ||
519fb432fadSkettenis 	    pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg) == 0)
520d132e815Skettenis 		return 1;
521d132e815Skettenis 
522fb432fadSkettenis 	/* Make sure we only enable one MSI vector. */
523fb432fadSkettenis 	reg &= ~PCI_MSI_MC_MME_MASK;
524fb432fadSkettenis 	pci_conf_write(pc, tag, off, reg);
525fb432fadSkettenis 
526d132e815Skettenis 	ihp->tag = tag;
527d132e815Skettenis 	ihp->line = APIC_INT_VIA_MSG;
528d132e815Skettenis 	ihp->pin = 0;
529d132e815Skettenis 	return 0;
530d132e815Skettenis }
531d132e815Skettenis 
532fb432fadSkettenis int
533fb432fadSkettenis pci_intr_map_msivec(struct pci_attach_args *pa, int vec,
534fb432fadSkettenis     pci_intr_handle_t *ihp)
535fb432fadSkettenis {
536fb432fadSkettenis 	pci_chipset_tag_t pc = pa->pa_pc;
537fb432fadSkettenis 	pcitag_t tag = pa->pa_tag;
538fb432fadSkettenis 	pcireg_t reg;
539fb432fadSkettenis 	int mme, off;
540fb432fadSkettenis 
541fb432fadSkettenis 	if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 || mp_busses == NULL ||
542fb432fadSkettenis 	    pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg) == 0)
543fb432fadSkettenis 		return 1;
544fb432fadSkettenis 
545fb432fadSkettenis 	mme = ((reg & PCI_MSI_MC_MME_MASK) >> PCI_MSI_MC_MME_SHIFT);
54635b7f403Skettenis 	if (vec >= (1 << mme))
54735b7f403Skettenis 		return 1;
548fb432fadSkettenis 
549fb432fadSkettenis 	ihp->tag = PCI_MSI_PIN(tag, vec);
550fb432fadSkettenis 	ihp->line = APIC_INT_VIA_MSG;
551fb432fadSkettenis 	ihp->pin = 0;
552fb432fadSkettenis 	return 0;
553fb432fadSkettenis }
554fb432fadSkettenis 
555058ea912Skettenis void msix_hwmask(struct pic *, int);
556058ea912Skettenis void msix_hwunmask(struct pic *, int);
557058ea912Skettenis void msix_addroute(struct pic *, struct cpu_info *, int, int, int);
558058ea912Skettenis void msix_delroute(struct pic *, struct cpu_info *, int, int, int);
559058ea912Skettenis 
560058ea912Skettenis struct pic msix_pic = {
561058ea912Skettenis 	{0, {NULL}, NULL, 0, "msix", NULL, 0, 0},
562058ea912Skettenis 	PIC_MSI,
563058ea912Skettenis #ifdef MULTIPROCESSOR
564058ea912Skettenis 	{},
565058ea912Skettenis #endif
566058ea912Skettenis 	msix_hwmask,
567058ea912Skettenis 	msix_hwunmask,
568058ea912Skettenis 	msix_addroute,
569058ea912Skettenis 	msix_delroute,
570058ea912Skettenis 	NULL,
571fb432fadSkettenis 	NULL,
572058ea912Skettenis 	ioapic_edge_stubs
573058ea912Skettenis };
574058ea912Skettenis 
575058ea912Skettenis void
576058ea912Skettenis msix_hwmask(struct pic *pic, int pin)
577058ea912Skettenis {
5783819a926Skettenis 	pci_chipset_tag_t pc = NULL; /* XXX */
5793819a926Skettenis 	bus_space_tag_t memt = X86_BUS_SPACE_MEM; /* XXX */
5803819a926Skettenis 	bus_space_handle_t memh;
5813819a926Skettenis 	pcitag_t tag = PCI_MSI_TAG(pin);
5823819a926Skettenis 	int entry = PCI_MSI_VEC(pin);
5833819a926Skettenis 	pcireg_t reg;
5843819a926Skettenis 	uint32_t ctrl;
5853819a926Skettenis 
5863819a926Skettenis 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, &reg) == 0)
5873819a926Skettenis 		return;
5883819a926Skettenis 
5893819a926Skettenis 	KASSERT(entry <= PCI_MSIX_MC_TBLSZ(reg));
5903819a926Skettenis 
5913819a926Skettenis 	if (pci_msix_table_map(pc, tag, memt, &memh))
5923819a926Skettenis 		panic("%s: cannot map registers", __func__);
5933819a926Skettenis 
5943819a926Skettenis 	ctrl = bus_space_read_4(memt, memh, PCI_MSIX_VC(entry));
5953819a926Skettenis 	bus_space_write_4(memt, memh, PCI_MSIX_VC(entry),
5963819a926Skettenis 	    ctrl | PCI_MSIX_VC_MASK);
5973819a926Skettenis 
5983819a926Skettenis 	pci_msix_table_unmap(pc, tag, memt, memh);
599058ea912Skettenis }
600058ea912Skettenis 
601058ea912Skettenis void
602058ea912Skettenis msix_hwunmask(struct pic *pic, int pin)
603058ea912Skettenis {
6043819a926Skettenis 	pci_chipset_tag_t pc = NULL; /* XXX */
6053819a926Skettenis 	bus_space_tag_t memt = X86_BUS_SPACE_MEM; /* XXX */
6063819a926Skettenis 	bus_space_handle_t memh;
6073819a926Skettenis 	pcitag_t tag = PCI_MSI_TAG(pin);
6083819a926Skettenis 	int entry = PCI_MSI_VEC(pin);
6093819a926Skettenis 	pcireg_t reg;
6103819a926Skettenis 	uint32_t ctrl;
6113819a926Skettenis 
6123819a926Skettenis 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, &reg) == 0)
6133819a926Skettenis 		return;
6143819a926Skettenis 
6153819a926Skettenis 	if (pci_msix_table_map(pc, tag, memt, &memh))
6163819a926Skettenis 		panic("%s: cannot map registers", __func__);
6173819a926Skettenis 
6183819a926Skettenis 	ctrl = bus_space_read_4(memt, memh, PCI_MSIX_VC(entry));
6193819a926Skettenis 	bus_space_write_4(memt, memh, PCI_MSIX_VC(entry),
6203819a926Skettenis 	    ctrl & ~PCI_MSIX_VC_MASK);
6213819a926Skettenis 
6223819a926Skettenis 	pci_msix_table_unmap(pc, tag, memt, memh);
623058ea912Skettenis }
624058ea912Skettenis 
625058ea912Skettenis void
626fb432fadSkettenis msix_addroute(struct pic *pic, struct cpu_info *ci, int pin, int idtvec,
627fb432fadSkettenis     int type)
628058ea912Skettenis {
629058ea912Skettenis 	pci_chipset_tag_t pc = NULL; /* XXX */
630058ea912Skettenis 	bus_space_tag_t memt = X86_BUS_SPACE_MEM; /* XXX */
631058ea912Skettenis 	bus_space_handle_t memh;
632fb432fadSkettenis 	pcitag_t tag = PCI_MSI_TAG(pin);
633fb432fadSkettenis 	int entry = PCI_MSI_VEC(pin);
6344211e504Skettenis 	pcireg_t reg, addr;
635058ea912Skettenis 	uint32_t ctrl;
6364211e504Skettenis 	int off;
637058ea912Skettenis 
638058ea912Skettenis 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, &reg) == 0)
639058ea912Skettenis 		panic("%s: no msix capability", __func__);
640058ea912Skettenis 
6414211e504Skettenis 	KASSERT(entry <= PCI_MSIX_MC_TBLSZ(reg));
642058ea912Skettenis 
6434211e504Skettenis 	if (pci_msix_table_map(pc, tag, memt, &memh))
644058ea912Skettenis 		panic("%s: cannot map registers", __func__);
645058ea912Skettenis 
6464211e504Skettenis 	addr = 0xfee00000UL | (ci->ci_apicid << 12);
6474211e504Skettenis 
648912ed164Skettenis 	bus_space_write_4(memt, memh, PCI_MSIX_MA(entry), addr);
649912ed164Skettenis 	bus_space_write_4(memt, memh, PCI_MSIX_MAU32(entry), 0);
650fb432fadSkettenis 	bus_space_write_4(memt, memh, PCI_MSIX_MD(entry), idtvec);
651058ea912Skettenis 	bus_space_barrier(memt, memh, PCI_MSIX_MA(entry), 16,
652058ea912Skettenis 	    BUS_SPACE_BARRIER_WRITE);
653058ea912Skettenis 	ctrl = bus_space_read_4(memt, memh, PCI_MSIX_VC(entry));
654058ea912Skettenis 	bus_space_write_4(memt, memh, PCI_MSIX_VC(entry),
655058ea912Skettenis 	    ctrl & ~PCI_MSIX_VC_MASK);
656058ea912Skettenis 
6574211e504Skettenis 	pci_msix_table_unmap(pc, tag, memt, memh);
658058ea912Skettenis 
659058ea912Skettenis 	pci_conf_write(pc, tag, off, reg | PCI_MSIX_MC_MSIXE);
660058ea912Skettenis }
661058ea912Skettenis 
662058ea912Skettenis void
663fb432fadSkettenis msix_delroute(struct pic *pic, struct cpu_info *ci, int pin, int idtvec,
664fb432fadSkettenis     int type)
665058ea912Skettenis {
666058ea912Skettenis 	pci_chipset_tag_t pc = NULL; /* XXX */
667058ea912Skettenis 	bus_space_tag_t memt = X86_BUS_SPACE_MEM; /* XXX */
668058ea912Skettenis 	bus_space_handle_t memh;
669fb432fadSkettenis 	pcitag_t tag = PCI_MSI_TAG(pin);
670fb432fadSkettenis 	int entry = PCI_MSI_VEC(pin);
6714211e504Skettenis 	pcireg_t reg;
672058ea912Skettenis 	uint32_t ctrl;
673058ea912Skettenis 
6744211e504Skettenis 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, &reg) == 0)
675058ea912Skettenis 		return;
676058ea912Skettenis 
6774211e504Skettenis 	KASSERT(entry <= PCI_MSIX_MC_TBLSZ(reg));
678058ea912Skettenis 
6794211e504Skettenis 	if (pci_msix_table_map(pc, tag, memt, &memh))
6804211e504Skettenis 		return;
681058ea912Skettenis 
682058ea912Skettenis 	ctrl = bus_space_read_4(memt, memh, PCI_MSIX_VC(entry));
683058ea912Skettenis 	bus_space_write_4(memt, memh, PCI_MSIX_VC(entry),
684058ea912Skettenis 	    ctrl | PCI_MSIX_VC_MASK);
685058ea912Skettenis 
6864211e504Skettenis 	pci_msix_table_unmap(pc, tag, memt, memh);
687058ea912Skettenis }
688058ea912Skettenis 
689058ea912Skettenis int
690058ea912Skettenis pci_intr_map_msix(struct pci_attach_args *pa, int vec, pci_intr_handle_t *ihp)
691058ea912Skettenis {
692058ea912Skettenis 	pci_chipset_tag_t pc = pa->pa_pc;
693058ea912Skettenis 	pcitag_t tag = pa->pa_tag;
694058ea912Skettenis 	pcireg_t reg;
695058ea912Skettenis 
696fb432fadSkettenis 	KASSERT(PCI_MSI_VEC(vec) == vec);
697058ea912Skettenis 
698058ea912Skettenis 	if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 || mp_busses == NULL ||
699c8ed1699Skettenis 	    pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, &reg) == 0)
700058ea912Skettenis 		return 1;
701058ea912Skettenis 
702c8ed1699Skettenis 	if (vec > PCI_MSIX_MC_TBLSZ(reg))
703058ea912Skettenis 		return 1;
704058ea912Skettenis 
705fb432fadSkettenis 	ihp->tag = PCI_MSI_PIN(tag, vec);
706058ea912Skettenis 	ihp->line = APIC_INT_VIA_MSGX;
707058ea912Skettenis 	ihp->pin = 0;
708058ea912Skettenis 	return 0;
709058ea912Skettenis }
710058ea912Skettenis 
711f5df1827Smickey int
7122bb6026aSjsg pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
713f5df1827Smickey {
714127e340bSkettenis 	int pin = pa->pa_rawintrpin;
715f5df1827Smickey 	int line = pa->pa_intrline;
716adb2a0aeSkettenis #if NIOAPIC > 0
717cd9c0c40Skettenis 	struct mp_intr_map *mip;
718f5df1827Smickey 	int bus, dev, func;
719f5df1827Smickey #endif
720f5df1827Smickey 
721f5df1827Smickey 	if (pin == 0) {
722f5df1827Smickey 		/* No IRQ used. */
723f5df1827Smickey 		goto bad;
724f5df1827Smickey 	}
725f5df1827Smickey 
726f5df1827Smickey 	if (pin > PCI_INTERRUPT_PIN_MAX) {
727f5df1827Smickey 		printf("pci_intr_map: bad interrupt pin %d\n", pin);
728f5df1827Smickey 		goto bad;
729f5df1827Smickey 	}
730f5df1827Smickey 
731adb2a0aeSkettenis 	ihp->tag = pa->pa_tag;
732adb2a0aeSkettenis 	ihp->line = line;
733127e340bSkettenis 	ihp->pin = pin;
734adb2a0aeSkettenis 
735f5df1827Smickey #if NIOAPIC > 0
736127e340bSkettenis 	pci_decompose_tag(pa->pa_pc, pa->pa_tag, &bus, &dev, &func);
737cd9c0c40Skettenis 
738f5df1827Smickey 	if (mp_busses != NULL) {
739cd9c0c40Skettenis 		int mpspec_pin = (dev << 2) | (pin - 1);
740cd9c0c40Skettenis 
741cd9c0c40Skettenis 		if (bus < mp_nbusses) {
742cd9c0c40Skettenis 			for (mip = mp_busses[bus].mb_intrs;
743cd9c0c40Skettenis 			     mip != NULL; mip = mip->next) {
744cd9c0c40Skettenis 				if (&mp_busses[bus] == mp_isa_bus ||
745cd9c0c40Skettenis 				    &mp_busses[bus] == mp_eisa_bus)
746cd9c0c40Skettenis 					continue;
747cd9c0c40Skettenis 				if (mip->bus_pin == mpspec_pin) {
748cd9c0c40Skettenis 					ihp->line = mip->ioapic_ih | line;
749f5df1827Smickey 					return 0;
750f5df1827Smickey 				}
751cd9c0c40Skettenis 			}
752cd9c0c40Skettenis 		}
753cd9c0c40Skettenis 
754068fe21aSkettenis 		if (pa->pa_bridgetag) {
755127e340bSkettenis 			int swizpin = PPB_INTERRUPT_SWIZZLE(pin, dev);
756127e340bSkettenis 			if (pa->pa_bridgeih[swizpin - 1].line != -1) {
757127e340bSkettenis 				ihp->line = pa->pa_bridgeih[swizpin - 1].line;
758adb2a0aeSkettenis 				ihp->line |= line;
759068fe21aSkettenis 				return 0;
760068fe21aSkettenis 			}
761068fe21aSkettenis 		}
762f5df1827Smickey 		/*
763f5df1827Smickey 		 * No explicit PCI mapping found. This is not fatal,
764f5df1827Smickey 		 * we'll try the ISA (or possibly EISA) mappings next.
765f5df1827Smickey 		 */
766f5df1827Smickey 	}
767f5df1827Smickey #endif
768f5df1827Smickey 
769f5df1827Smickey 	/*
770f5df1827Smickey 	 * Section 6.2.4, `Miscellaneous Functions', says that 255 means
771f5df1827Smickey 	 * `unknown' or `no connection' on a PC.  We assume that a device with
772f5df1827Smickey 	 * `no connection' either doesn't have an interrupt (in which case the
773f5df1827Smickey 	 * pin number should be 0, and would have been noticed above), or
774f5df1827Smickey 	 * wasn't configured by the BIOS (in which case we punt, since there's
775f5df1827Smickey 	 * no real way we can know how the interrupt lines are mapped in the
776f5df1827Smickey 	 * hardware).
777f5df1827Smickey 	 *
778f5df1827Smickey 	 * XXX
779f5df1827Smickey 	 * Since IRQ 0 is only used by the clock, and we can't actually be sure
780f5df1827Smickey 	 * that the BIOS did its job, we also recognize that as meaning that
781f5df1827Smickey 	 * the BIOS has not configured the device.
782f5df1827Smickey 	 */
783b1d93e39Skettenis 	if (line == 0 || line == X86_PCI_INTERRUPT_LINE_NO_CONNECTION)
784f5df1827Smickey 		goto bad;
785b1d93e39Skettenis 
786f5df1827Smickey 	if (line >= NUM_LEGACY_IRQS) {
787f5df1827Smickey 		printf("pci_intr_map: bad interrupt line %d\n", line);
788f5df1827Smickey 		goto bad;
789f5df1827Smickey 	}
790f5df1827Smickey 	if (line == 2) {
791f5df1827Smickey 		printf("pci_intr_map: changed line 2 to line 9\n");
792f5df1827Smickey 		line = 9;
793f5df1827Smickey 	}
794b1d93e39Skettenis 
795f5df1827Smickey #if NIOAPIC > 0
796f5df1827Smickey 	if (mp_busses != NULL) {
797cd9c0c40Skettenis 		if (mip == NULL && mp_isa_bus) {
798cd9c0c40Skettenis 			for (mip = mp_isa_bus->mb_intrs; mip != NULL;
799cd9c0c40Skettenis 			    mip = mip->next) {
800cd9c0c40Skettenis 				if (mip->bus_pin == line) {
801cd9c0c40Skettenis 					ihp->line = mip->ioapic_ih | line;
802f5df1827Smickey 					return 0;
803f5df1827Smickey 				}
804cd9c0c40Skettenis 			}
805cd9c0c40Skettenis 		}
806f5df1827Smickey #if NEISA > 0
807cd9c0c40Skettenis 		if (mip == NULL && mp_eisa_bus) {
808cd9c0c40Skettenis 			for (mip = mp_eisa_bus->mb_intrs;  mip != NULL;
809cd9c0c40Skettenis 			    mip = mip->next) {
810cd9c0c40Skettenis 				if (mip->bus_pin == line) {
811cd9c0c40Skettenis 					ihp->line = mip->ioapic_ih | line;
812f5df1827Smickey 					return 0;
813f5df1827Smickey 				}
814cd9c0c40Skettenis 			}
815cd9c0c40Skettenis 		}
816f5df1827Smickey #endif
817cd9c0c40Skettenis 		if (mip == NULL) {
818cd9c0c40Skettenis 			printf("pci_intr_map: "
819cd9c0c40Skettenis 			    "bus %d dev %d func %d pin %d; line %d\n",
820f5df1827Smickey 			    bus, dev, func, pin, line);
821f5df1827Smickey 			printf("pci_intr_map: no MP mapping found\n");
822f5df1827Smickey 		}
823cd9c0c40Skettenis 	}
824f5df1827Smickey #endif
825f5df1827Smickey 
826f5df1827Smickey 	return 0;
827f5df1827Smickey 
828f5df1827Smickey bad:
829adb2a0aeSkettenis 	ihp->line = -1;
830f5df1827Smickey 	return 1;
831f5df1827Smickey }
832f5df1827Smickey 
833f5df1827Smickey const char *
8342bb6026aSjsg pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih)
835f5df1827Smickey {
836f5df1827Smickey 	static char irqstr[64];
837f5df1827Smickey 
838adb2a0aeSkettenis 	if (ih.line == 0)
839adb2a0aeSkettenis 		panic("pci_intr_string: bogus handle 0x%x", ih.line);
840f5df1827Smickey 
841d132e815Skettenis 	if (ih.line & APIC_INT_VIA_MSG)
842d132e815Skettenis 		return ("msi");
843058ea912Skettenis 	if (ih.line & APIC_INT_VIA_MSGX)
844058ea912Skettenis 		return ("msix");
845d132e815Skettenis 
846f5df1827Smickey #if NIOAPIC > 0
847adb2a0aeSkettenis 	if (ih.line & APIC_INT_VIA_APIC)
848662c4d21Skettenis 		snprintf(irqstr, sizeof(irqstr), "apic %d int %d",
849662c4d21Skettenis 		    APIC_IRQ_APIC(ih.line), APIC_IRQ_PIN(ih.line));
850f5df1827Smickey 	else
8511242d4e7Smiod 		snprintf(irqstr, sizeof(irqstr), "irq %d",
8521242d4e7Smiod 		    pci_intr_line(pc, ih));
853f5df1827Smickey #else
8541242d4e7Smiod 	snprintf(irqstr, sizeof(irqstr), "irq %d", pci_intr_line(pc, ih));
855f5df1827Smickey #endif
856f5df1827Smickey 	return (irqstr);
857f5df1827Smickey }
858f5df1827Smickey 
85949bbc65bSkettenis #include "acpiprt.h"
86049bbc65bSkettenis #if NACPIPRT > 0
86149bbc65bSkettenis void	acpiprt_route_interrupt(int bus, int dev, int pin);
86249bbc65bSkettenis #endif
86349bbc65bSkettenis 
864f5df1827Smickey void *
865992e7aa6Stedu pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level,
866c03b1b92Smk     int (*func)(void *), void *arg, const char *what)
867f5df1827Smickey {
86815db3095Sdlg 	return pci_intr_establish_cpu(pc, ih, level, NULL, func, arg, what);
86915db3095Sdlg }
87015db3095Sdlg 
87115db3095Sdlg void *
87215db3095Sdlg pci_intr_establish_cpu(pci_chipset_tag_t pc, pci_intr_handle_t ih,
87315db3095Sdlg     int level, struct cpu_info *ci,
87415db3095Sdlg     int (*func)(void *), void *arg, const char *what)
87515db3095Sdlg {
876f5df1827Smickey 	int pin, irq;
87749bbc65bSkettenis 	int bus, dev;
878d132e815Skettenis 	pcitag_t tag = ih.tag;
879f5df1827Smickey 	struct pic *pic;
880f5df1827Smickey 
881d132e815Skettenis 	if (ih.line & APIC_INT_VIA_MSG) {
8825368f701Skettenis 		return intr_establish(-1, &msi_pic, tag, IST_PULSE, level,
88315db3095Sdlg 		    ci, func, arg, what);
884d132e815Skettenis 	}
885058ea912Skettenis 	if (ih.line & APIC_INT_VIA_MSGX) {
886058ea912Skettenis 		return intr_establish(-1, &msix_pic, tag, IST_PULSE, level,
88715db3095Sdlg 		    ci, func, arg, what);
888058ea912Skettenis 	}
889d132e815Skettenis 
89049bbc65bSkettenis 	pci_decompose_tag(pc, ih.tag, &bus, &dev, NULL);
89149bbc65bSkettenis #if NACPIPRT > 0
89249bbc65bSkettenis 	acpiprt_route_interrupt(bus, dev, ih.pin);
89349bbc65bSkettenis #endif
89449bbc65bSkettenis 
895f5df1827Smickey 	pic = &i8259_pic;
896adb2a0aeSkettenis 	pin = irq = ih.line;
897f5df1827Smickey 
898f5df1827Smickey #if NIOAPIC > 0
899adb2a0aeSkettenis 	if (ih.line & APIC_INT_VIA_APIC) {
900adb2a0aeSkettenis 		pic = (struct pic *)ioapic_find(APIC_IRQ_APIC(ih.line));
901f5df1827Smickey 		if (pic == NULL) {
902f5df1827Smickey 			printf("pci_intr_establish: bad ioapic %d\n",
903adb2a0aeSkettenis 			    APIC_IRQ_APIC(ih.line));
904f5df1827Smickey 			return NULL;
905f5df1827Smickey 		}
906adb2a0aeSkettenis 		pin = APIC_IRQ_PIN(ih.line);
907adb2a0aeSkettenis 		irq = APIC_IRQ_LEGACY_IRQ(ih.line);
908f5df1827Smickey 		if (irq < 0 || irq >= NUM_LEGACY_IRQS)
909f5df1827Smickey 			irq = -1;
910f5df1827Smickey 	}
911f5df1827Smickey #endif
912f5df1827Smickey 
91315db3095Sdlg 	return intr_establish(irq, pic, pin, IST_LEVEL, level, ci,
91415db3095Sdlg 	    func, arg, what);
915f5df1827Smickey }
916f5df1827Smickey 
917f5df1827Smickey void
9182bb6026aSjsg pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
919f5df1827Smickey {
920f5df1827Smickey 	intr_disestablish(cookie);
921f5df1827Smickey }
922ea9b3ec9Skettenis 
923ea9b3ec9Skettenis struct extent *pciio_ex;
924ea9b3ec9Skettenis struct extent *pcimem_ex;
9250371ddceSkettenis struct extent *pcibus_ex;
926ea9b3ec9Skettenis 
927ea9b3ec9Skettenis void
928ea9b3ec9Skettenis pci_init_extents(void)
929ea9b3ec9Skettenis {
930ea9b3ec9Skettenis 	bios_memmap_t *bmp;
931ea9b3ec9Skettenis 	u_int64_t size;
932ea9b3ec9Skettenis 
933a2be259aSkettenis 	if (pciio_ex == NULL) {
934a2be259aSkettenis 		/*
935a2be259aSkettenis 		 * We only have 64K of addressable I/O space.
936a2be259aSkettenis 		 * However, since BARs may contain garbage, we cover
937a2be259aSkettenis 		 * the full 32-bit address space defined by PCI of
938a2be259aSkettenis 		 * which we only make the first 64K available.
939a2be259aSkettenis 		 */
940a2be259aSkettenis 		pciio_ex = extent_create("pciio", 0, 0xffffffff, M_DEVBUF,
941a2be259aSkettenis 		    NULL, 0, EX_NOWAIT | EX_FILLED);
942ea9b3ec9Skettenis 		if (pciio_ex == NULL)
943a2be259aSkettenis 			return;
9443e84add2Skettenis 		extent_free(pciio_ex, 0, 0x10000, EX_NOWAIT);
945a2be259aSkettenis 	}
946ea9b3ec9Skettenis 
947ea9b3ec9Skettenis 	if (pcimem_ex == NULL) {
94817be38f6Skettenis 		/*
94917be38f6Skettenis 		 * Cover the 36-bit address space addressable by PAE
95017be38f6Skettenis 		 * here.  As long as vendors continue to support
95117be38f6Skettenis 		 * 32-bit operating systems, we should never see BARs
95217be38f6Skettenis 		 * outside that region.
9539b96fbdeSjmatthew 		 *
9549b96fbdeSjmatthew 		 * Dell 13G servers have important devices outside the
9559b96fbdeSjmatthew 		 * 36-bit address space.  Until we can extract the address
9569b96fbdeSjmatthew 		 * ranges from ACPI, expand the allowed range to suit.
95717be38f6Skettenis 		 */
958e256c9dcSmikeb 		pcimem_ex = extent_create("pcimem", 0, 0xffffffffffffffffUL,
959e256c9dcSmikeb 		    M_DEVBUF, NULL, 0, EX_NOWAIT);
960ea9b3ec9Skettenis 		if (pcimem_ex == NULL)
961ea9b3ec9Skettenis 			return;
9629b96fbdeSjmatthew 		extent_alloc_region(pcimem_ex, 0x40000000000UL,
9639b96fbdeSjmatthew 		    0xfffffc0000000000UL, EX_NOWAIT);
964ea9b3ec9Skettenis 
965ea9b3ec9Skettenis 		for (bmp = bios_memmap; bmp->type != BIOS_MAP_END; bmp++) {
966ea9b3ec9Skettenis 			/*
967ea9b3ec9Skettenis 			 * Ignore address space beyond 4G.
968ea9b3ec9Skettenis 			 */
969ea9b3ec9Skettenis 			if (bmp->addr >= 0x100000000ULL)
970ea9b3ec9Skettenis 				continue;
971ea9b3ec9Skettenis 			size = bmp->size;
972ea9b3ec9Skettenis 			if (bmp->addr + size >= 0x100000000ULL)
973ea9b3ec9Skettenis 				size = 0x100000000ULL - bmp->addr;
974ea9b3ec9Skettenis 
975f1b7bdedSkettenis 			/* Ignore zero-sized regions. */
976f1b7bdedSkettenis 			if (size == 0)
977f1b7bdedSkettenis 				continue;
978f1b7bdedSkettenis 
979ea9b3ec9Skettenis 			if (extent_alloc_region(pcimem_ex, bmp->addr, size,
980ea9b3ec9Skettenis 			    EX_NOWAIT))
981ea9b3ec9Skettenis 				printf("memory map conflict 0x%llx/0x%llx\n",
982ea9b3ec9Skettenis 				    bmp->addr, bmp->size);
983ea9b3ec9Skettenis 		}
98418e560d4Skettenis 
98518e560d4Skettenis 		/* Take out the video buffer area and BIOS areas. */
98618e560d4Skettenis 		extent_alloc_region(pcimem_ex, IOM_BEGIN, IOM_SIZE,
98718e560d4Skettenis 		    EX_CONFLICTOK | EX_NOWAIT);
988ea9b3ec9Skettenis 	}
9890371ddceSkettenis 
9900371ddceSkettenis 	if (pcibus_ex == NULL) {
9910371ddceSkettenis 		pcibus_ex = extent_create("pcibus", 0, 0xff, M_DEVBUF,
9920371ddceSkettenis 		    NULL, 0, EX_NOWAIT);
9930371ddceSkettenis 	}
994ea9b3ec9Skettenis }
995ea14b1d7Sjordan 
99696940271Sjordan int
99796940271Sjordan pci_probe_device_hook(pci_chipset_tag_t pc, struct pci_attach_args *pa)
99896940271Sjordan {
99996940271Sjordan #if NACPIDMAR > 0
100096940271Sjordan 	acpidmar_pci_hook(pc, pa);
100196940271Sjordan #endif
100296940271Sjordan 	return 0;
100396940271Sjordan }
100496940271Sjordan 
1005ea14b1d7Sjordan #if NACPI > 0
1006ea14b1d7Sjordan void acpi_pci_match(struct device *, struct pci_attach_args *);
1007b08441edSmpi pcireg_t acpi_pci_min_powerstate(pci_chipset_tag_t, pcitag_t);
1008b08441edSmpi void acpi_pci_set_powerstate(pci_chipset_tag_t, pcitag_t, int, int);
1009ea14b1d7Sjordan #endif
1010ea14b1d7Sjordan 
1011ea14b1d7Sjordan void
1012ea14b1d7Sjordan pci_dev_postattach(struct device *dev, struct pci_attach_args *pa)
1013ea14b1d7Sjordan {
1014ea14b1d7Sjordan #if NACPI > 0
1015311c37bcSjordan 	acpi_pci_match(dev, pa);
1016ea14b1d7Sjordan #endif
1017ea14b1d7Sjordan }
10182d67ff8fSkettenis 
10192d67ff8fSkettenis pcireg_t
10202d67ff8fSkettenis pci_min_powerstate(pci_chipset_tag_t pc, pcitag_t tag)
10212d67ff8fSkettenis {
10222d67ff8fSkettenis #if NACPI > 0
10232d67ff8fSkettenis 	return acpi_pci_min_powerstate(pc, tag);
10242d67ff8fSkettenis #else
102559c12227Sderaadt 	return pci_get_powerstate(pc, tag);
10262d67ff8fSkettenis #endif
10272d67ff8fSkettenis }
1028b08441edSmpi 
1029b08441edSmpi void
1030b08441edSmpi pci_set_powerstate_md(pci_chipset_tag_t pc, pcitag_t tag, int state, int pre)
1031b08441edSmpi {
1032b08441edSmpi #if NACPI > 0
1033b08441edSmpi 	acpi_pci_set_powerstate(pc, tag, state, pre);
1034b08441edSmpi #endif
1035b08441edSmpi }
1036