xref: /openbsd/sys/arch/arm64/dev/pci_machdep.c (revision d415bd75)
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, &reg) == 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, &reg) == 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, &reg) == 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, &reg) == 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, &reg) == 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