1 /* $OpenBSD: pci_machdep.c,v 1.5 2021/03/22 20:30:21 patrick Exp $ */ 2 3 /* 4 * Copyright (c) 2019 Mark Kettenis <kettenis@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 22 #include <machine/bus.h> 23 24 #include <dev/pci/pcivar.h> 25 #include <dev/pci/pcireg.h> 26 27 void 28 pci_msi_enable(pci_chipset_tag_t pc, pcitag_t tag, 29 bus_addr_t addr, uint32_t data) 30 { 31 pcireg_t reg; 32 int off; 33 34 if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, ®) == 0) 35 panic("%s: no msi capability", __func__); 36 37 if (reg & PCI_MSI_MC_C64) { 38 pci_conf_write(pc, tag, off + PCI_MSI_MA, addr); 39 pci_conf_write(pc, tag, off + PCI_MSI_MAU32, addr >> 32); 40 pci_conf_write(pc, tag, off + PCI_MSI_MD64, data); 41 } else { 42 pci_conf_write(pc, tag, off + PCI_MSI_MA, addr); 43 pci_conf_write(pc, tag, off + PCI_MSI_MD32, data); 44 } 45 pci_conf_write(pc, tag, off, reg | PCI_MSI_MC_MSIE); 46 } 47 48 int 49 pci_msix_table_map(pci_chipset_tag_t pc, pcitag_t tag, 50 bus_space_tag_t memt, bus_space_handle_t *memh) 51 { 52 bus_addr_t base; 53 pcireg_t reg, table, type; 54 int bir, offset; 55 int off, tblsz; 56 57 if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, ®) == 0) 58 panic("%s: no msix capability", __func__); 59 60 table = pci_conf_read(pc, tag, off + PCI_MSIX_TABLE); 61 bir = (table & PCI_MSIX_TABLE_BIR); 62 offset = (table & PCI_MSIX_TABLE_OFF); 63 tblsz = PCI_MSIX_MC_TBLSZ(reg) + 1; 64 65 bir = PCI_MAPREG_START + bir * 4; 66 type = pci_mapreg_type(pc, tag, bir); 67 if (pci_mapreg_info(pc, tag, bir, type, &base, NULL, NULL) || 68 bus_space_map(memt, base + offset, tblsz * 16, 0, memh)) 69 return -1; 70 71 return 0; 72 } 73 74 void 75 pci_msix_table_unmap(pci_chipset_tag_t pc, pcitag_t tag, 76 bus_space_tag_t memt, bus_space_handle_t memh) 77 { 78 pcireg_t reg; 79 int tblsz; 80 81 if (pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, ®) == 0) 82 panic("%s: no msix capability", __func__); 83 84 tblsz = PCI_MSIX_MC_TBLSZ(reg) + 1; 85 bus_space_unmap(memt, memh, tblsz * 16); 86 } 87 88 void 89 pci_msix_enable(pci_chipset_tag_t pc, pcitag_t tag, bus_space_tag_t memt, 90 int vec, bus_addr_t addr, uint32_t data) 91 { 92 bus_space_handle_t memh; 93 pcireg_t reg; 94 uint32_t ctrl; 95 int off; 96 97 if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, ®) == 0) 98 panic("%s: no msix capability", __func__); 99 100 KASSERT(vec <= PCI_MSIX_MC_TBLSZ(reg)); 101 102 if (pci_msix_table_map(pc, tag, memt, &memh)) 103 panic("%s: cannot map registers", __func__); 104 105 bus_space_write_4(memt, memh, PCI_MSIX_MA(vec), addr); 106 bus_space_write_4(memt, memh, PCI_MSIX_MAU32(vec), addr >> 32); 107 bus_space_write_4(memt, memh, PCI_MSIX_MD(vec), data); 108 bus_space_barrier(memt, memh, PCI_MSIX_MA(vec), 16, 109 BUS_SPACE_BARRIER_WRITE); 110 ctrl = bus_space_read_4(memt, memh, PCI_MSIX_VC(vec)); 111 bus_space_write_4(memt, memh, PCI_MSIX_VC(vec), 112 ctrl & ~PCI_MSIX_VC_MASK); 113 114 pci_msix_table_unmap(pc, tag, memt, memh); 115 116 pci_conf_write(pc, tag, off, reg | PCI_MSIX_MC_MSIXE); 117 } 118 119 int 120 _pci_intr_map_msi(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 121 { 122 pci_chipset_tag_t pc = pa->pa_pc; 123 pcitag_t tag = pa->pa_tag; 124 125 if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 || 126 pci_get_capability(pc, tag, PCI_CAP_MSI, NULL, NULL) == 0) 127 return -1; 128 129 ihp->ih_pc = pa->pa_pc; 130 ihp->ih_tag = pa->pa_tag; 131 ihp->ih_type = PCI_MSI; 132 ihp->ih_dmat = pa->pa_dmat; 133 134 return 0; 135 } 136 137 int 138 _pci_intr_map_msix(struct pci_attach_args *pa, int vec, 139 pci_intr_handle_t *ihp) 140 { 141 pci_chipset_tag_t pc = pa->pa_pc; 142 pcitag_t tag = pa->pa_tag; 143 pcireg_t reg, table, type; 144 int bir, off; 145 146 if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 || 147 pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, ®) == 0) 148 return -1; 149 150 if (vec > PCI_MSIX_MC_TBLSZ(reg)) 151 return -1; 152 153 table = pci_conf_read(pc, tag, off + PCI_MSIX_TABLE); 154 bir = PCI_MAPREG_START + (table & PCI_MSIX_TABLE_BIR) * 4; 155 type = pci_mapreg_type(pc, tag, bir); 156 if (pci_mapreg_assign(pa, bir, type, NULL, NULL)) 157 return -1; 158 159 ihp->ih_pc = pa->pa_pc; 160 ihp->ih_tag = pa->pa_tag; 161 ihp->ih_intrpin = vec; 162 ihp->ih_type = PCI_MSIX; 163 ihp->ih_dmat = pa->pa_dmat; 164 165 return 0; 166 } 167 168