xref: /openbsd/sys/arch/sparc64/dev/pci_machdep.c (revision 47c47fea)
1 /*	$OpenBSD: pci_machdep.c,v 1.52 2022/10/16 01:22:39 jsg Exp $	*/
2 /*	$NetBSD: pci_machdep.c,v 1.22 2001/07/20 00:07:13 eeh Exp $	*/
3 
4 /*
5  * Copyright (c) 1999, 2000 Matthew R. Green
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*
31  * functions expected by the MI PCI code.
32  */
33 
34 #ifdef DEBUG
35 #define SPDB_CONF	0x01
36 #define SPDB_INTR	0x04
37 #define SPDB_INTMAP	0x08
38 #define SPDB_PROBE	0x20
39 int sparc_pci_debug = 0x0;
40 #define DPRINTF(l, s)	do { if (sparc_pci_debug & l) printf s; } while (0)
41 #else
42 #define DPRINTF(l, s)	do { } while (0)
43 #endif
44 
45 #include <sys/param.h>
46 #include <sys/time.h>
47 #include <sys/systm.h>
48 #include <sys/errno.h>
49 #include <sys/device.h>
50 #include <sys/malloc.h>
51 
52 #define _SPARC_BUS_DMA_PRIVATE
53 #include <machine/bus.h>
54 #include <machine/autoconf.h>
55 #include <machine/openfirm.h>
56 #include <dev/pci/pcivar.h>
57 #include <dev/pci/pcireg.h>
58 #include <dev/pci/pcidevs.h>
59 
60 #include <dev/ofw/ofw_pci.h>
61 
62 #include <sparc64/dev/iommureg.h>
63 #include <sparc64/dev/iommuvar.h>
64 #include <sparc64/dev/psychoreg.h>
65 #include <sparc64/dev/psychovar.h>
66 #include <sparc64/sparc64/cache.h>
67 
68 /* this is a base to be copied */
69 struct sparc_pci_chipset _sparc_pci_chipset = {
70 	NULL,
71 };
72 
73 static int pci_bus_frequency(int node);
74 
75 /*
76  * functions provided to the MI code.
77  */
78 
79 void
pci_attach_hook(struct device * parent,struct device * self,struct pcibus_attach_args * pba)80 pci_attach_hook(struct device *parent, struct device *self,
81     struct pcibus_attach_args *pba)
82 {
83 	/* Don't do anything */
84 }
85 
86 int
pci_32bit_dmamap_create(bus_dma_tag_t dt,bus_dma_tag_t t0,bus_size_t size,int nsegments,bus_size_t maxsegsz,bus_size_t boundary,int flags,bus_dmamap_t * dmamp)87 pci_32bit_dmamap_create(bus_dma_tag_t dt, bus_dma_tag_t t0, bus_size_t size,
88     int nsegments, bus_size_t maxsegsz, bus_size_t boundary, int flags,
89     bus_dmamap_t *dmamp)
90 {
91 	bus_dma_tag_t pdt = dt->_parent;
92 
93 	CLR(flags, BUS_DMA_64BIT);
94 
95 	return ((*pdt->_dmamap_create)(pdt, t0, size, nsegments, maxsegsz,
96 	    boundary, flags, dmamp));
97 }
98 
99 int
pci_probe_device_hook(pci_chipset_tag_t pc,struct pci_attach_args * pa)100 pci_probe_device_hook(pci_chipset_tag_t pc, struct pci_attach_args *pa)
101 {
102 	bus_dma_tag_t dt, pdt;
103 
104 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_RCC &&
105 	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RCC_PCIE_PCIX) {
106 		/*
107 		 * These PCI bridges only support 40bit DVA, so intercept
108 		 * bus_dmamap_create so we can clear BUS_DMA_64BIT.
109 		 */
110 
111 		dt = malloc(sizeof(*dt), M_DEVBUF, M_NOWAIT | M_ZERO);
112 		if (dt == NULL)
113 			panic("%s: could not alloc dma tag", __func__);
114 
115 		pdt = pa->pa_dmat;
116 
117 		dt->_parent = pdt;
118 		dt->_dmamap_create = pci_32bit_dmamap_create;
119 
120 		pa->pa_dmat = dt;
121 	}
122 
123 	return (0);
124 }
125 
126 int
pci_bus_maxdevs(pci_chipset_tag_t pc,int busno)127 pci_bus_maxdevs(pci_chipset_tag_t pc, int busno)
128 {
129 
130 	return 32;
131 }
132 
133 pcitag_t
pci_make_tag(pci_chipset_tag_t pc,int b,int d,int f)134 pci_make_tag(pci_chipset_tag_t pc, int b, int d, int f)
135 {
136 	struct ofw_pci_register reg;
137 	pcitag_t tag;
138 	int busrange[2];
139 	int node, len;
140 #ifdef DEBUG
141 	char name[80];
142 	bzero(name, sizeof(name));
143 #endif
144 
145 	if (pc->busnode[b])
146 		return PCITAG_CREATE(0, b, d, f);
147 
148 	/*
149 	 * Hunt for the node that corresponds to this device
150 	 *
151 	 * We could cache this info in an array in the parent
152 	 * device... except then we have problems with devices
153 	 * attached below pci-pci bridges, and we would need to
154 	 * add special code to the pci-pci bridge to cache this
155 	 * info.
156 	 */
157 
158 	tag = PCITAG_CREATE(-1, b, d, f);
159 
160 	/*
161 	 * Traverse all peers until we find the node or we find
162 	 * the right bridge.
163 	 */
164 	for (node = pc->rootnode; node; node = OF_peer(node)) {
165 
166 #ifdef DEBUG
167 		if (sparc_pci_debug & SPDB_PROBE) {
168 			OF_getprop(node, "name", &name, sizeof(name));
169 			printf("checking node %x %s\n", node, name);
170 		}
171 #endif
172 
173 		/*
174 		 * Check for PCI-PCI bridges.  If the device we want is
175 		 * in the bus-range for that bridge, work our way down.
176 		 */
177 		while ((OF_getprop(node, "bus-range", (void *)&busrange,
178 			sizeof(busrange)) == sizeof(busrange)) &&
179 			(b >= busrange[0] && b <= busrange[1])) {
180 			/* Go down 1 level */
181 			node = OF_child(node);
182 #ifdef DEBUG
183 			if (sparc_pci_debug & SPDB_PROBE) {
184 				OF_getprop(node, "name", &name, sizeof(name));
185 				printf("going down to node %x %s\n",
186 					node, name);
187 			}
188 #endif
189 		}
190 
191 		/*
192 		 * We only really need the first `reg' property.
193 		 *
194 		 * For simplicity, we'll query the `reg' when we
195 		 * need it.  Otherwise we could malloc() it, but
196 		 * that gets more complicated.
197 		 */
198 		len = OF_getproplen(node, "reg");
199 		if (len < sizeof(reg))
200 			continue;
201 		if (OF_getprop(node, "reg", (void *)&reg, sizeof(reg)) != len)
202 			panic("pci_probe_bus: OF_getprop len botch");
203 
204 		if (b != OFW_PCI_PHYS_HI_BUS(reg.phys_hi))
205 			continue;
206 		if (d != OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi))
207 			continue;
208 		if (f != OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi))
209 			continue;
210 
211 		/* Got a match */
212 		tag = PCITAG_CREATE(node, b, d, f);
213 
214 		return (tag);
215 	}
216 	/* No device found -- return a dead tag */
217 	return (tag);
218 }
219 
220 void
pci_decompose_tag(pci_chipset_tag_t pc,pcitag_t tag,int * bp,int * dp,int * fp)221 pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, int *fp)
222 {
223 
224 	if (bp != NULL)
225 		*bp = PCITAG_BUS(tag);
226 	if (dp != NULL)
227 		*dp = PCITAG_DEV(tag);
228 	if (fp != NULL)
229 		*fp = PCITAG_FUN(tag);
230 }
231 
232 static int
pci_bus_frequency(int node)233 pci_bus_frequency(int node)
234 {
235 	int len, bus_frequency;
236 
237 	len = OF_getproplen(node, "clock-frequency");
238 	if (len < sizeof(bus_frequency)) {
239 		DPRINTF(SPDB_PROBE,
240 		    ("pci_bus_frequency: clock-frequency len %d too small\n",
241 		     len));
242 		return 33;
243 	}
244 	if (OF_getprop(node, "clock-frequency", &bus_frequency,
245 		       sizeof(bus_frequency)) != len) {
246 		DPRINTF(SPDB_PROBE,
247 		    ("pci_bus_frequency: could not read clock-frequency\n"));
248 		return 33;
249 	}
250 	return bus_frequency / 1000000;
251 }
252 
253 int
sparc64_pci_enumerate_bus(struct pci_softc * sc,int (* match)(struct pci_attach_args *),struct pci_attach_args * pap)254 sparc64_pci_enumerate_bus(struct pci_softc *sc,
255     int (*match)(struct pci_attach_args *), struct pci_attach_args *pap)
256 {
257 	struct ofw_pci_register reg;
258 	pci_chipset_tag_t pc = sc->sc_pc;
259 	pcitag_t tag;
260 	pcireg_t class, csr, bhlc, ic;
261 	int node, b, d, f, ret;
262 	int bus_frequency, lt, cl, cacheline;
263 	char name[30];
264 
265 	if (sc->sc_bridgetag)
266 		node = PCITAG_NODE(*sc->sc_bridgetag);
267 	else
268 		node = pc->rootnode;
269 
270 	bus_frequency = pci_bus_frequency(node);
271 
272 	/*
273 	 * Make sure the cache line size is at least as big as the
274 	 * ecache line and the streaming cache (64 byte).
275 	 */
276 	cacheline = max(cacheinfo.ec_linesize, 64);
277 
278 	for (node = OF_child(node); node != 0 && node != -1;
279 	     node = OF_peer(node)) {
280 		if (!checkstatus(node))
281 			continue;
282 
283 		name[0] = name[29] = 0;
284 		OF_getprop(node, "name", name, sizeof(name));
285 
286 		if (OF_getprop(node, "class-code", &class, sizeof(class)) !=
287 		    sizeof(class))
288 			continue;
289 		if (OF_getprop(node, "reg", &reg, sizeof(reg)) < sizeof(reg))
290 			panic("pci_enumerate_bus: \"%s\" regs too small", name);
291 
292 		b = OFW_PCI_PHYS_HI_BUS(reg.phys_hi);
293 		d = OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi);
294 		f = OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi);
295 
296 		if (sc->sc_bus != b) {
297 			printf("%s: WARNING: incorrect bus # for \"%s\" "
298 			"(%d/%d/%d)\n", sc->sc_dev.dv_xname, name, b, d, f);
299 			continue;
300 		}
301 
302 		tag = PCITAG_CREATE(node, b, d, f);
303 
304 		/*
305 		 * Turn on parity and fast-back-to-back for the device.
306 		 */
307 		csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
308 		if (csr & PCI_STATUS_BACKTOBACK_SUPPORT)
309 			csr |= PCI_COMMAND_BACKTOBACK_ENABLE;
310 		csr |= PCI_COMMAND_PARITY_ENABLE;
311 		pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
312 
313 		/*
314 		 * Initialize the latency timer register for busmaster
315 		 * devices to work properly.
316 		 *   latency-timer = min-grant * bus-freq / 4  (from FreeBSD)
317 		 * Also initialize the cache line size register.
318 		 * Solaris anytime sets this register to the value 0x10.
319 		 */
320 		bhlc = pci_conf_read(pc, tag, PCI_BHLC_REG);
321 		ic = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
322 
323 		lt = min(PCI_MIN_GNT(ic) * bus_frequency / 4, 255);
324 		if (lt == 0 || lt < PCI_LATTIMER(bhlc))
325 			lt = PCI_LATTIMER(bhlc);
326 
327 		cl = PCI_CACHELINE(bhlc);
328 		if (cl == 0)
329 			cl = cacheline;
330 
331 		bhlc &= ~((PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT) |
332 			  (PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT));
333 		bhlc |= (lt << PCI_LATTIMER_SHIFT) |
334 			(cl << PCI_CACHELINE_SHIFT);
335 		pci_conf_write(pc, tag, PCI_BHLC_REG, bhlc);
336 
337 		ret = pci_probe_device(sc, tag, match, pap);
338 		if (match != NULL && ret != 0)
339 			return (ret);
340 	}
341 
342 	return (0);
343 }
344 
345 int
pci_conf_size(pci_chipset_tag_t pc,pcitag_t tag)346 pci_conf_size(pci_chipset_tag_t pc, pcitag_t tag)
347 {
348 	int val = 0;
349 
350         if (PCITAG_NODE(tag) != -1)
351 		val = pc->conf_size(pc, tag);
352 
353         return (val);
354 }
355 
356 pcireg_t
pci_conf_read(pci_chipset_tag_t pc,pcitag_t tag,int reg)357 pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
358 {
359         pcireg_t val = (pcireg_t)~0;
360 
361         if (PCITAG_NODE(tag) != -1)
362 		val = pc->conf_read(pc, tag, reg);
363 
364         return (val);
365 }
366 
367 void
pci_conf_write(pci_chipset_tag_t pc,pcitag_t tag,int reg,pcireg_t data)368 pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
369 {
370         if (PCITAG_NODE(tag) != -1)
371 		pc->conf_write(pc, tag, reg, data);
372 }
373 
374 /*
375  * interrupt mapping foo.
376  * XXX: how does this deal with multiple interrupts for a device?
377  */
378 int
pci_intr_map(struct pci_attach_args * pa,pci_intr_handle_t * ihp)379 pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
380 {
381 	pcitag_t tag = pa->pa_tag;
382 	int interrupts[4], ninterrupts;
383 	int len, node = PCITAG_NODE(tag);
384 	char devtype[30];
385 
386 	len = OF_getproplen(node, "interrupts");
387 	if (len < 0 || len < sizeof(interrupts[0])) {
388 		DPRINTF(SPDB_INTMAP,
389 			("pci_intr_map: interrupts len %d too small\n", len));
390 		return (ENODEV);
391 	}
392 	if (OF_getprop(node, "interrupts", interrupts,
393 	    sizeof(interrupts)) != len) {
394 		DPRINTF(SPDB_INTMAP,
395 			("pci_intr_map: could not read interrupts\n"));
396 		return (ENODEV);
397 	}
398 
399 	/*
400 	 * If we have multiple interrupts for a device, choose the one
401 	 * that corresponds to the PCI function.  This makes the
402 	 * second PC Card slot on the UltraBook get the right interrupt.
403 	 */
404 	ninterrupts = len / sizeof(interrupts[0]);
405 	if (PCITAG_FUN(pa->pa_tag) < ninterrupts)
406 		interrupts[0] = interrupts[PCITAG_FUN(pa->pa_tag)];
407 
408 	if (OF_mapintr(node, &interrupts[0], sizeof(interrupts[0]),
409 	    sizeof(interrupts)) < 0) {
410 		interrupts[0] = -1;
411 	}
412 	/* Try to find an IPL for this type of device. */
413 	if (OF_getprop(node, "device_type", &devtype, sizeof(devtype)) > 0) {
414 		for (len = 0;  intrmap[len].in_class; len++)
415 			if (strcmp(intrmap[len].in_class, devtype) == 0) {
416 				interrupts[0] |= INTLEVENCODE(intrmap[len].in_lev);
417 				break;
418 			}
419 	}
420 
421 	/* XXXX -- we use the ino.  What if there is a valid IGN? */
422 	*ihp = interrupts[0];
423 
424 	if (pa->pa_pc->intr_map) {
425 		int rv = (*pa->pa_pc->intr_map)(pa, ihp);
426 		if (rv != 0)
427 			return (rv);
428 	}
429 
430 	KASSERT(PCI_INTR_TYPE(*ihp) == PCI_INTR_INTX);
431 
432 	return (0);
433 }
434 
435 int
pci_intr_map_msi(struct pci_attach_args * pa,pci_intr_handle_t * ihp)436 pci_intr_map_msi(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
437 {
438 	pci_chipset_tag_t pc = pa->pa_pc;
439 	pcitag_t tag = pa->pa_tag;
440 
441 	if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 ||
442 	    pci_get_capability(pc, tag, PCI_CAP_MSI, NULL, NULL) == 0)
443 		return (-1);
444 
445 	*ihp = PCITAG_OFFSET(pa->pa_tag) | PCI_INTR_MSI;
446 	return (0);
447 }
448 
449 int
pci_intr_map_msix(struct pci_attach_args * pa,int vec,pci_intr_handle_t * ihp)450 pci_intr_map_msix(struct pci_attach_args *pa, int vec, pci_intr_handle_t *ihp)
451 {
452 	pci_chipset_tag_t pc = pa->pa_pc;
453 	pcitag_t tag = pa->pa_tag;
454 	pcireg_t reg;
455 
456 	if (vec & ~PCI_INTR_VEC_MASK)
457 		return (-1);
458 
459 	if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 ||
460 	    pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, &reg) == 0)
461 		return (-1);
462 
463 	if (vec > PCI_MSIX_MC_TBLSZ(reg))
464 		return (-1);
465 
466 	KASSERT(!ISSET(pa->pa_tag, PCI_INTR_TYPE_MASK));
467 	KASSERT(!ISSET(pa->pa_tag, PCI_INTR_VEC_MASK));
468 
469 	*ihp = PCI_INTR_MSIX | PCITAG_OFFSET(pa->pa_tag) | vec;
470 	return (0);
471 }
472 
473 int
pci_intr_line(pci_chipset_tag_t pc,pci_intr_handle_t ih)474 pci_intr_line(pci_chipset_tag_t pc, pci_intr_handle_t ih)
475 {
476 	return (ih);
477 }
478 
479 const char *
pci_intr_string(pci_chipset_tag_t pc,pci_intr_handle_t ih)480 pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih)
481 {
482 	static char str[16];
483 	const char *rv = str;
484 
485 	DPRINTF(SPDB_INTR, ("pci_intr_string: ih %u", ih));
486 	switch (PCI_INTR_TYPE(ih)) {
487 	case PCI_INTR_MSIX:
488 		rv = "msix";
489 		break;
490 	case PCI_INTR_MSI:
491 		rv = "msi";
492 		break;
493 	case PCI_INTR_INTX:
494 		snprintf(str, sizeof str, "ivec 0x%llx", INTVEC(ih));
495 		break;
496 	}
497 	DPRINTF(SPDB_INTR, ("; returning %s\n", rv));
498 
499 	return (rv);
500 }
501 
502 void *
pci_intr_establish(pci_chipset_tag_t pc,pci_intr_handle_t ih,int level,int (* func)(void *),void * arg,const char * what)503 pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level,
504     int (*func)(void *), void *arg, const char *what)
505 {
506 	return (pci_intr_establish_cpu(pc, ih, level, NULL, func, arg, what));
507 }
508 
509 void *
pci_intr_establish_cpu(pci_chipset_tag_t pc,pci_intr_handle_t ih,int level,struct cpu_info * ci,int (* func)(void *),void * arg,const char * what)510 pci_intr_establish_cpu(pci_chipset_tag_t pc, pci_intr_handle_t ih,
511     int level, struct cpu_info *ci,
512     int (*func)(void *), void *arg, const char *what)
513 {
514 	void *cookie;
515 	int flags = 0;
516 
517 	if (level & IPL_MPSAFE) {
518 		flags |= BUS_INTR_ESTABLISH_MPSAFE;
519 		level &= ~IPL_MPSAFE;
520 	}
521 
522 	DPRINTF(SPDB_INTR, ("pci_intr_establish_cpu: ih %lu; level %d; ci %p",
523 	    (u_long)ih, level, ci));
524 	cookie = bus_intr_establish_cpu(pc->bustag, ih, level, flags,
525 	    ci, func, arg, what);
526 
527 	DPRINTF(SPDB_INTR, ("; returning handle %p\n", cookie));
528 	return (cookie);
529 }
530 
531 void
pci_intr_disestablish(pci_chipset_tag_t pc,void * cookie)532 pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
533 {
534 
535 	DPRINTF(SPDB_INTR, ("pci_intr_disestablish: cookie %p\n", cookie));
536 
537 	/* XXX */
538 	printf("can't disestablish PCI interrupts yet\n");
539 }
540 
541 void
pci_msi_enable(pci_chipset_tag_t pc,pcitag_t tag,bus_addr_t addr,int vec)542 pci_msi_enable(pci_chipset_tag_t pc, pcitag_t tag, bus_addr_t addr, int vec)
543 {
544 	pcireg_t reg;
545 	int off;
546 
547 	if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, &reg) == 0)
548 		panic("%s: no msi capability", __func__);
549 
550 	if (reg & PCI_MSI_MC_C64) {
551 		pci_conf_write(pc, tag, off + PCI_MSI_MA, addr);
552 		pci_conf_write(pc, tag, off + PCI_MSI_MAU32, 0);
553 		pci_conf_write(pc, tag, off + PCI_MSI_MD64, vec);
554 	} else {
555 		pci_conf_write(pc, tag, off + PCI_MSI_MA, addr);
556 		pci_conf_write(pc, tag, off + PCI_MSI_MD32, vec);
557 	}
558 	pci_conf_write(pc, tag, off, reg | PCI_MSI_MC_MSIE);
559 }
560 
561 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)562 pci_msix_enable(pci_chipset_tag_t pc, pcitag_t tag, bus_space_tag_t memt,
563     int vec, bus_addr_t addr, uint32_t data)
564 {
565 	bus_space_handle_t memh;
566 	bus_addr_t base;
567 	pcireg_t reg, table, type;
568 	uint32_t ctrl;
569 	int bir, offset;
570 	int off, tblsz;
571 
572 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, &reg) == 0)
573 		panic("%s: no msix capability", __func__);
574 
575 	table = pci_conf_read(pc, tag, off + PCI_MSIX_TABLE);
576 	bir = (table & PCI_MSIX_TABLE_BIR);
577 	offset = (table & PCI_MSIX_TABLE_OFF);
578 	tblsz = PCI_MSIX_MC_TBLSZ(reg) + 1;
579 
580 	bir = PCI_MAPREG_START + bir * 4;
581 	type = pci_mapreg_type(pc, tag, bir);
582 	if (pci_mapreg_info(pc, tag, bir, type, &base, NULL, NULL) ||
583 	    bus_space_map(memt, base + offset, tblsz * 16, 0, &memh))
584 		panic("%s: cannot map registers", __func__);
585 
586 	bus_space_write_4(memt, memh, PCI_MSIX_MA(vec), addr);
587 	bus_space_write_4(memt, memh, PCI_MSIX_MAU32(vec), addr >> 32);
588 	bus_space_write_4(memt, memh, PCI_MSIX_MD(vec), data);
589 	bus_space_barrier(memt, memh, PCI_MSIX_MA(vec), 16,
590 	    BUS_SPACE_BARRIER_WRITE);
591 	ctrl = bus_space_read_4(memt, memh, PCI_MSIX_VC(vec));
592 	bus_space_write_4(memt, memh, PCI_MSIX_VC(vec),
593 	    ctrl & ~PCI_MSIX_VC_MASK);
594 
595 	bus_space_unmap(memt, memh, tblsz * 16);
596 
597 	pci_conf_write(pc, tag, off, reg | PCI_MSIX_MC_MSIXE);
598 }
599 
600 int
pci_msix_table_map(pci_chipset_tag_t pc,pcitag_t tag,bus_space_tag_t memt,bus_space_handle_t * memh)601 pci_msix_table_map(pci_chipset_tag_t pc, pcitag_t tag,
602     bus_space_tag_t memt, bus_space_handle_t *memh)
603 {
604 	bus_addr_t base;
605 	pcireg_t reg, table, type;
606 	int bir, offset;
607 	int off, tblsz;
608 
609 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, &reg) == 0)
610 		panic("%s: no msix capability", __func__);
611 
612 	table = pci_conf_read(pc, tag, off + PCI_MSIX_TABLE);
613 	bir = (table & PCI_MSIX_TABLE_BIR);
614 	offset = (table & PCI_MSIX_TABLE_OFF);
615 	tblsz = PCI_MSIX_MC_TBLSZ(reg) + 1;
616 
617 	bir = PCI_MAPREG_START + bir * 4;
618 	type = pci_mapreg_type(pc, tag, bir);
619 	if (pci_mapreg_info(pc, tag, bir, type, &base, NULL, NULL) ||
620 	    bus_space_map(memt, base + offset, tblsz * 16, 0, memh))
621 		return (-1);
622 
623 	return (0);
624 }
625 
626 void
pci_msix_table_unmap(pci_chipset_tag_t pc,pcitag_t tag,bus_space_tag_t memt,bus_space_handle_t memh)627 pci_msix_table_unmap(pci_chipset_tag_t pc, pcitag_t tag,
628     bus_space_tag_t memt, bus_space_handle_t memh)
629 {
630 	pcireg_t reg;
631 	int tblsz;
632 
633 	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, &reg) == 0)
634 		panic("%s: no msix capability", __func__);
635 
636 	tblsz = PCI_MSIX_MC_TBLSZ(reg) + 1;
637 
638 	bus_space_unmap(memt, memh, tblsz * 16);
639 }
640