xref: /openbsd/sys/arch/arm64/dev/pci_machdep.c (revision 35ee0dc2)
1 /*	$OpenBSD: pci_machdep.c,v 1.7 2024/07/05 22:53:57 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 int
pci_intr_enable_msivec(struct pci_attach_args * pa,int num_vec)28 pci_intr_enable_msivec(struct pci_attach_args *pa, int num_vec)
29 {
30 	pci_chipset_tag_t pc = pa->pa_pc;
31 	pcitag_t tag = pa->pa_tag;
32 	pcireg_t reg;
33 	int mmc, mme, off;
34 
35 	if ((pa->pa_flags & PCI_FLAGS_MSIVEC_ENABLED) == 0 ||
36 	    pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg) == 0)
37 		return 1;
38 
39 	mmc = ((reg & PCI_MSI_MC_MMC_MASK) >> PCI_MSI_MC_MMC_SHIFT);
40 	if (num_vec > (1 << mmc))
41 		return 1;
42 
43 	mme = ((reg & PCI_MSI_MC_MME_MASK) >> PCI_MSI_MC_MME_SHIFT);
44 	while ((1 << mme) < num_vec)
45 		mme++;
46 	reg &= ~PCI_MSI_MC_MME_MASK;
47 	reg |= (mme << PCI_MSI_MC_MME_SHIFT);
48 	pci_conf_write(pc, tag, off, reg);
49 
50 	return 0;
51 }
52 
53 void
pci_msi_enable(pci_chipset_tag_t pc,pcitag_t tag,bus_addr_t addr,uint32_t data)54 pci_msi_enable(pci_chipset_tag_t pc, pcitag_t tag,
55     bus_addr_t addr, uint32_t data)
56 {
57 	pcireg_t reg;
58 	int mme, off;
59 
60 	if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg) == 0)
61 		panic("%s: no msi capability", __func__);
62 
63 	mme = ((reg & PCI_MSI_MC_MME_MASK) >> PCI_MSI_MC_MME_SHIFT);
64 	data &= ~((1 << mme) - 1);
65 
66 	if (reg & PCI_MSI_MC_C64) {
67 		pci_conf_write(pc, tag, off + PCI_MSI_MA, addr);
68 		pci_conf_write(pc, tag, off + PCI_MSI_MAU32, addr >> 32);
69 		pci_conf_write(pc, tag, off + PCI_MSI_MD64, data);
70 	} else {
71 		pci_conf_write(pc, tag, off + PCI_MSI_MA, addr);
72 		pci_conf_write(pc, tag, off + PCI_MSI_MD32, data);
73 	}
74 	pci_conf_write(pc, tag, off, reg | PCI_MSI_MC_MSIE);
75 }
76 
77 int
pci_msix_table_map(pci_chipset_tag_t pc,pcitag_t tag,bus_space_tag_t memt,bus_space_handle_t * memh)78 pci_msix_table_map(pci_chipset_tag_t pc, pcitag_t tag,
79     bus_space_tag_t memt, bus_space_handle_t *memh)
80 {
81 	bus_addr_t base;
82 	pcireg_t reg, table, type;
83 	int bir, offset;
84 	int off, tblsz;
85 
86 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, &reg) == 0)
87 		panic("%s: no msix capability", __func__);
88 
89 	table = pci_conf_read(pc, tag, off + PCI_MSIX_TABLE);
90 	bir = (table & PCI_MSIX_TABLE_BIR);
91 	offset = (table & PCI_MSIX_TABLE_OFF);
92 	tblsz = PCI_MSIX_MC_TBLSZ(reg) + 1;
93 
94 	bir = PCI_MAPREG_START + bir * 4;
95 	type = pci_mapreg_type(pc, tag, bir);
96 	if (pci_mapreg_info(pc, tag, bir, type, &base, NULL, NULL) ||
97 	    bus_space_map(memt, base + offset, tblsz * 16, 0, memh))
98 		return -1;
99 
100 	return 0;
101 }
102 
103 void
pci_msix_table_unmap(pci_chipset_tag_t pc,pcitag_t tag,bus_space_tag_t memt,bus_space_handle_t memh)104 pci_msix_table_unmap(pci_chipset_tag_t pc, pcitag_t tag,
105     bus_space_tag_t memt, bus_space_handle_t memh)
106 {
107 	pcireg_t reg;
108 	int tblsz;
109 
110 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, &reg) == 0)
111 		panic("%s: no msix capability", __func__);
112 
113 	tblsz = PCI_MSIX_MC_TBLSZ(reg) + 1;
114 	bus_space_unmap(memt, memh, tblsz * 16);
115 }
116 
117 void
pci_msix_enable(pci_chipset_tag_t pc,pcitag_t tag,bus_space_tag_t memt,int vec,bus_addr_t addr,uint32_t data)118 pci_msix_enable(pci_chipset_tag_t pc, pcitag_t tag, bus_space_tag_t memt,
119     int vec, bus_addr_t addr, uint32_t data)
120 {
121 	bus_space_handle_t memh;
122 	pcireg_t reg;
123 	uint32_t ctrl;
124 	int off;
125 
126 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, &reg) == 0)
127 		panic("%s: no msix capability", __func__);
128 
129 	KASSERT(vec <= PCI_MSIX_MC_TBLSZ(reg));
130 
131 	if (pci_msix_table_map(pc, tag, memt, &memh))
132 		panic("%s: cannot map registers", __func__);
133 
134 	bus_space_write_4(memt, memh, PCI_MSIX_MA(vec), addr);
135 	bus_space_write_4(memt, memh, PCI_MSIX_MAU32(vec), addr >> 32);
136 	bus_space_write_4(memt, memh, PCI_MSIX_MD(vec), data);
137 	bus_space_barrier(memt, memh, PCI_MSIX_MA(vec), 16,
138 	    BUS_SPACE_BARRIER_WRITE);
139 	ctrl = bus_space_read_4(memt, memh, PCI_MSIX_VC(vec));
140 	bus_space_write_4(memt, memh, PCI_MSIX_VC(vec),
141 	    ctrl & ~PCI_MSIX_VC_MASK);
142 
143 	pci_msix_table_unmap(pc, tag, memt, memh);
144 
145 	pci_conf_write(pc, tag, off, reg | PCI_MSIX_MC_MSIXE);
146 }
147 
148 int
_pci_intr_map_msi(struct pci_attach_args * pa,pci_intr_handle_t * ihp)149 _pci_intr_map_msi(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
150 {
151 	pci_chipset_tag_t pc = pa->pa_pc;
152 	pcitag_t tag = pa->pa_tag;
153 
154 	if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 ||
155 	    pci_get_capability(pc, tag, PCI_CAP_MSI, NULL, NULL) == 0)
156 		return -1;
157 
158 	ihp->ih_pc = pa->pa_pc;
159 	ihp->ih_tag = pa->pa_tag;
160 	ihp->ih_intrpin = 0;
161 	ihp->ih_type = PCI_MSI;
162 	ihp->ih_dmat = pa->pa_dmat;
163 
164 	return 0;
165 }
166 
167 int
_pci_intr_map_msivec(struct pci_attach_args * pa,int vec,pci_intr_handle_t * ihp)168 _pci_intr_map_msivec(struct pci_attach_args *pa, int vec,
169     pci_intr_handle_t *ihp)
170 {
171 	pci_chipset_tag_t pc = pa->pa_pc;
172 	pcitag_t tag = pa->pa_tag;
173 	pcireg_t reg;
174 	int mme, off;
175 
176 	if ((pa->pa_flags & PCI_FLAGS_MSIVEC_ENABLED) == 0 ||
177 	    pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg) == 0)
178 		return -1;
179 
180 	mme = ((reg & PCI_MSI_MC_MME_MASK) >> PCI_MSI_MC_MME_SHIFT);
181 	if (vec >= (1 << mme))
182 		return -1;
183 
184 	ihp->ih_pc = pa->pa_pc;
185 	ihp->ih_tag = pa->pa_tag;
186 	ihp->ih_intrpin = vec;
187 	ihp->ih_type = PCI_MSI;
188 	ihp->ih_dmat = pa->pa_dmat;
189 
190 	return 0;
191 }
192 
193 int
_pci_intr_map_msix(struct pci_attach_args * pa,int vec,pci_intr_handle_t * ihp)194 _pci_intr_map_msix(struct pci_attach_args *pa, int vec,
195     pci_intr_handle_t *ihp)
196 {
197 	pci_chipset_tag_t pc = pa->pa_pc;
198 	pcitag_t tag = pa->pa_tag;
199 	pcireg_t reg, table, type;
200 	int bir, off;
201 
202 	if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 ||
203 	    pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, &reg) == 0)
204 		return -1;
205 
206 	if (vec > PCI_MSIX_MC_TBLSZ(reg))
207 		return -1;
208 
209 	table = pci_conf_read(pc, tag, off + PCI_MSIX_TABLE);
210 	bir = PCI_MAPREG_START + (table & PCI_MSIX_TABLE_BIR) * 4;
211 	type = pci_mapreg_type(pc, tag, bir);
212 	if (pci_mapreg_assign(pa, bir, type, NULL, NULL))
213 		return -1;
214 
215 	ihp->ih_pc = pa->pa_pc;
216 	ihp->ih_tag = pa->pa_tag;
217 	ihp->ih_intrpin = vec;
218 	ihp->ih_type = PCI_MSIX;
219 	ihp->ih_dmat = pa->pa_dmat;
220 
221 	return 0;
222 }
223