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, ®) == 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, ®) == 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, ®) == 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, ®) == 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, ®) == 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, ®)) 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, ®) == 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, ®) == 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, ®) == 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, ®) == 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, ®) == 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, ®) == 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, ®) == 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, ®) == 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, ®) == 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