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