1 /* $OpenBSD: bcm2711_pcie.c,v 1.13 2024/03/27 15:15:00 patrick Exp $ */
2 /*
3 * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/extent.h>
22 #include <sys/malloc.h>
23
24 #include <machine/intr.h>
25 #include <machine/bus.h>
26 #include <machine/fdt.h>
27 #include <machine/simplebusvar.h>
28
29 #include <dev/pci/pcidevs.h>
30 #include <dev/pci/pcireg.h>
31 #include <dev/pci/pcivar.h>
32 #include <dev/pci/ppbreg.h>
33
34 #include <dev/ofw/openfirm.h>
35 #include <dev/ofw/fdt.h>
36
37 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c
38 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010
39 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070
40 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080
41 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084
42 #define PCIE_EXT_CFG_DATA 0x8000
43 #define PCIE_EXT_CFG_INDEX 0x9000
44 #define PCIE_RGR1_SW_INIT_1 0x9210
45 #define PCIE_RGR1_SW_INIT_1_PERST_MASK (1 << 0)
46 #define PCIE_RGR1_SW_INIT_1_INIT_MASK (1 << 1)
47
48 #define HREAD4(sc, reg) \
49 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
50 #define HWRITE4(sc, reg, val) \
51 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
52
53 struct bcmpcie_range {
54 uint32_t flags;
55 uint64_t pci_base;
56 uint64_t phys_base;
57 uint64_t size;
58 };
59
60 struct bcmpcie_softc {
61 struct simplebus_softc sc_sbus;
62 bus_space_tag_t sc_iot;
63 bus_space_handle_t sc_ioh;
64 bus_dma_tag_t sc_dmat;
65
66 int sc_node;
67 int sc_acells;
68 int sc_scells;
69 int sc_pacells;
70 int sc_pscells;
71 struct bcmpcie_range *sc_ranges;
72 int sc_nranges;
73 struct bcmpcie_range *sc_dmaranges;
74 int sc_ndmaranges;
75
76 struct bus_space sc_bus_iot;
77 struct bus_space sc_bus_memt;
78
79 struct machine_bus_dma_tag sc_dma;
80
81 struct machine_pci_chipset sc_pc;
82 int sc_bus;
83 };
84
85 int bcmpcie_match(struct device *, void *, void *);
86 void bcmpcie_attach(struct device *, struct device *, void *);
87
88 const struct cfattach bcmpcie_ca = {
89 sizeof (struct bcmpcie_softc), bcmpcie_match, bcmpcie_attach
90 };
91
92 struct cfdriver bcmpcie_cd = {
93 NULL, "bcmpcie", DV_DULL
94 };
95
96 int
bcmpcie_match(struct device * parent,void * match,void * aux)97 bcmpcie_match(struct device *parent, void *match, void *aux)
98 {
99 struct fdt_attach_args *faa = aux;
100
101 return OF_is_compatible(faa->fa_node, "brcm,bcm2711-pcie") ||
102 OF_is_compatible(faa->fa_node, "brcm,bcm2712-pcie");
103 }
104
105 int bcmpcie_submatch(struct device *, void *, void *);
106 void bcmpcie_attach_hook(struct device *, struct device *,
107 struct pcibus_attach_args *);
108 int bcmpcie_bus_maxdevs(void *, int);
109 pcitag_t bcmpcie_make_tag(void *, int, int, int);
110 void bcmpcie_decompose_tag(void *, pcitag_t, int *, int *, int *);
111 int bcmpcie_conf_size(void *, pcitag_t);
112 pcireg_t bcmpcie_conf_read(void *, pcitag_t, int);
113 void bcmpcie_conf_write(void *, pcitag_t, int, pcireg_t);
114 int bcmpcie_probe_device_hook(void *, struct pci_attach_args *);
115
116 int bcmpcie_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
117 const char *bcmpcie_intr_string(void *, pci_intr_handle_t);
118 void *bcmpcie_intr_establish(void *, pci_intr_handle_t, int,
119 struct cpu_info *, int (*)(void *), void *, char *);
120 void bcmpcie_intr_disestablish(void *, void *);
121
122 int bcmpcie_bs_iomap(bus_space_tag_t, bus_addr_t, bus_size_t, int,
123 bus_space_handle_t *);
124 int bcmpcie_bs_memmap(bus_space_tag_t, bus_addr_t, bus_size_t, int,
125 bus_space_handle_t *);
126 int bcmpcie_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *,
127 bus_size_t, struct proc *, int, paddr_t *, int *, int);
128 int bcmpcie_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
129 bus_dma_segment_t *, int, bus_size_t, int);
130
131 void
bcmpcie_attach(struct device * parent,struct device * self,void * aux)132 bcmpcie_attach(struct device *parent, struct device *self, void *aux)
133 {
134 struct bcmpcie_softc *sc = (struct bcmpcie_softc *)self;
135 struct fdt_attach_args *faa = aux;
136 struct pcibus_attach_args pba;
137 uint32_t *ranges;
138 int i, j, nranges, rangeslen;
139 uint32_t reg;
140
141 if (faa->fa_nreg < 1) {
142 printf(": no registers\n");
143 return;
144 }
145
146 sc->sc_iot = faa->fa_iot;
147 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
148 faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
149 printf(": can't map registers\n");
150 return;
151 }
152
153 reg = HREAD4(sc, PCIE_RGR1_SW_INIT_1);
154 if (reg & PCIE_RGR1_SW_INIT_1_INIT_MASK) {
155 printf(": disabled\n");
156 return;
157 }
158
159 sc->sc_node = faa->fa_node;
160 sc->sc_dmat = faa->fa_dmat;
161
162 sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells",
163 faa->fa_acells);
164 sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells",
165 faa->fa_scells);
166 sc->sc_pacells = faa->fa_acells;
167 sc->sc_pscells = faa->fa_scells;
168
169 /* Memory and IO space translations. */
170 rangeslen = OF_getproplen(sc->sc_node, "ranges");
171 if (rangeslen <= 0 || (rangeslen % sizeof(uint32_t)) ||
172 (rangeslen / sizeof(uint32_t)) % (sc->sc_acells +
173 sc->sc_pacells + sc->sc_scells)) {
174 printf(": invalid ranges property\n");
175 return;
176 }
177
178 ranges = malloc(rangeslen, M_TEMP, M_WAITOK);
179 OF_getpropintarray(sc->sc_node, "ranges", ranges,
180 rangeslen);
181
182 nranges = (rangeslen / sizeof(uint32_t)) /
183 (sc->sc_acells + sc->sc_pacells + sc->sc_scells);
184 sc->sc_ranges = mallocarray(nranges,
185 sizeof(struct bcmpcie_range), M_DEVBUF, M_WAITOK);
186 sc->sc_nranges = nranges;
187
188 for (i = 0, j = 0; i < sc->sc_nranges; i++) {
189 sc->sc_ranges[i].flags = ranges[j++];
190 sc->sc_ranges[i].pci_base = ranges[j++];
191 if (sc->sc_acells - 1 == 2) {
192 sc->sc_ranges[i].pci_base <<= 32;
193 sc->sc_ranges[i].pci_base |= ranges[j++];
194 }
195 sc->sc_ranges[i].phys_base = ranges[j++];
196 if (sc->sc_pacells == 2) {
197 sc->sc_ranges[i].phys_base <<= 32;
198 sc->sc_ranges[i].phys_base |= ranges[j++];
199 }
200 sc->sc_ranges[i].size = ranges[j++];
201 if (sc->sc_scells == 2) {
202 sc->sc_ranges[i].size <<= 32;
203 sc->sc_ranges[i].size |= ranges[j++];
204 }
205 }
206
207 free(ranges, M_TEMP, rangeslen);
208
209 /* DMA translations */
210 rangeslen = OF_getproplen(sc->sc_node, "dma-ranges");
211 if (rangeslen > 0) {
212 if ((rangeslen % sizeof(uint32_t)) ||
213 (rangeslen / sizeof(uint32_t)) % (sc->sc_acells +
214 sc->sc_pacells + sc->sc_scells)) {
215 printf(": invalid dma-ranges property\n");
216 free(sc->sc_ranges, M_DEVBUF,
217 sc->sc_nranges * sizeof(struct bcmpcie_range));
218 return;
219 }
220
221 ranges = malloc(rangeslen, M_TEMP, M_WAITOK);
222 OF_getpropintarray(sc->sc_node, "dma-ranges", ranges,
223 rangeslen);
224
225 nranges = (rangeslen / sizeof(uint32_t)) /
226 (sc->sc_acells + sc->sc_pacells + sc->sc_scells);
227 sc->sc_dmaranges = mallocarray(nranges,
228 sizeof(struct bcmpcie_range), M_DEVBUF, M_WAITOK);
229 sc->sc_ndmaranges = nranges;
230
231 for (i = 0, j = 0; i < sc->sc_ndmaranges; i++) {
232 sc->sc_dmaranges[i].flags = ranges[j++];
233 sc->sc_dmaranges[i].pci_base = ranges[j++];
234 if (sc->sc_acells - 1 == 2) {
235 sc->sc_dmaranges[i].pci_base <<= 32;
236 sc->sc_dmaranges[i].pci_base |= ranges[j++];
237 }
238 sc->sc_dmaranges[i].phys_base = ranges[j++];
239 if (sc->sc_pacells == 2) {
240 sc->sc_dmaranges[i].phys_base <<= 32;
241 sc->sc_dmaranges[i].phys_base |= ranges[j++];
242 }
243 sc->sc_dmaranges[i].size = ranges[j++];
244 if (sc->sc_scells == 2) {
245 sc->sc_dmaranges[i].size <<= 32;
246 sc->sc_dmaranges[i].size |= ranges[j++];
247 }
248 }
249
250 free(ranges, M_TEMP, rangeslen);
251 }
252
253 /*
254 * Reprogram the outbound window to match the configuration in
255 * the device tree. This is necessary since the EDK2-based
256 * UEFI firmware reprograms the window.
257 */
258 for (i = 0; i < sc->sc_nranges; i++) {
259 if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000) {
260 uint64_t cpu_base = sc->sc_ranges[i].phys_base;
261 uint64_t cpu_limit = sc->sc_ranges[i].phys_base +
262 sc->sc_ranges[i].size - 1;
263
264 HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO,
265 sc->sc_ranges[i].pci_base);
266 HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI,
267 sc->sc_ranges[i].pci_base >> 32);
268 HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT,
269 (cpu_base & PPB_MEM_MASK) >> PPB_MEM_SHIFT |
270 (cpu_limit & PPB_MEM_MASK));
271 HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI,
272 cpu_base >> 32);
273 HWRITE4(sc, PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI,
274 cpu_limit >> 32);
275 }
276 }
277
278 memcpy(&sc->sc_bus_iot, sc->sc_iot, sizeof(sc->sc_bus_iot));
279 sc->sc_bus_iot.bus_private = sc;
280 sc->sc_bus_iot._space_map = bcmpcie_bs_iomap;
281 memcpy(&sc->sc_bus_memt, sc->sc_iot, sizeof(sc->sc_bus_memt));
282 sc->sc_bus_memt.bus_private = sc;
283 sc->sc_bus_memt._space_map = bcmpcie_bs_memmap;
284
285 memcpy(&sc->sc_dma, sc->sc_dmat, sizeof(sc->sc_dma));
286 sc->sc_dma._dmamap_load_buffer = bcmpcie_dmamap_load_buffer;
287 sc->sc_dma._dmamap_load_raw = bcmpcie_dmamap_load_raw;
288 sc->sc_dma._cookie = sc;
289
290 sc->sc_pc.pc_conf_v = sc;
291 sc->sc_pc.pc_attach_hook = bcmpcie_attach_hook;
292 sc->sc_pc.pc_bus_maxdevs = bcmpcie_bus_maxdevs;
293 sc->sc_pc.pc_make_tag = bcmpcie_make_tag;
294 sc->sc_pc.pc_decompose_tag = bcmpcie_decompose_tag;
295 sc->sc_pc.pc_conf_size = bcmpcie_conf_size;
296 sc->sc_pc.pc_conf_read = bcmpcie_conf_read;
297 sc->sc_pc.pc_conf_write = bcmpcie_conf_write;
298 sc->sc_pc.pc_probe_device_hook = bcmpcie_probe_device_hook;
299
300 sc->sc_pc.pc_intr_v = sc;
301 sc->sc_pc.pc_intr_map = bcmpcie_intr_map;
302 sc->sc_pc.pc_intr_map_msi = _pci_intr_map_msi;
303 sc->sc_pc.pc_intr_map_msivec = _pci_intr_map_msivec;
304 sc->sc_pc.pc_intr_map_msix = _pci_intr_map_msix;
305 sc->sc_pc.pc_intr_string = bcmpcie_intr_string;
306 sc->sc_pc.pc_intr_establish = bcmpcie_intr_establish;
307 sc->sc_pc.pc_intr_disestablish = bcmpcie_intr_disestablish;
308
309 memset(&pba, 0, sizeof(pba));
310 pba.pba_busname = "pci";
311 pba.pba_iot = &sc->sc_bus_iot;
312 pba.pba_memt = &sc->sc_bus_memt;
313 pba.pba_dmat = &sc->sc_dma;
314 pba.pba_pc = &sc->sc_pc;
315 pba.pba_domain = pci_ndomains++;
316 pba.pba_bus = 0;
317
318 /* Attach device tree nodes enumerating PCIe bus */
319 simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa);
320
321 config_found_sm(self, &pba, NULL, bcmpcie_submatch);
322 }
323
324 int
bcmpcie_submatch(struct device * self,void * match,void * aux)325 bcmpcie_submatch(struct device *self, void *match, void *aux)
326 {
327 struct cfdata *cf = match;
328 struct pcibus_attach_args *pba = aux;
329
330 if (strcmp(pba->pba_busname, cf->cf_driver->cd_name) != 0)
331 return 0;
332
333 return (*cf->cf_attach->ca_match)(self, match, aux);
334 }
335
336 void
bcmpcie_attach_hook(struct device * parent,struct device * self,struct pcibus_attach_args * pba)337 bcmpcie_attach_hook(struct device *parent, struct device *self,
338 struct pcibus_attach_args *pba)
339 {
340 }
341
342 int
bcmpcie_bus_maxdevs(void * v,int bus)343 bcmpcie_bus_maxdevs(void *v, int bus)
344 {
345 struct bcmpcie_softc *sc = v;
346
347 if (bus == sc->sc_bus || bus == sc->sc_bus + 1)
348 return 1;
349 return 32;
350 }
351
352 pcitag_t
bcmpcie_make_tag(void * v,int bus,int device,int function)353 bcmpcie_make_tag(void *v, int bus, int device, int function)
354 {
355 /* Return ECAM address. */
356 return ((bus << 20) | (device << 15) | (function << 12));
357 }
358
359 void
bcmpcie_decompose_tag(void * v,pcitag_t tag,int * bp,int * dp,int * fp)360 bcmpcie_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp)
361 {
362 if (bp != NULL)
363 *bp = (tag >> 20) & 0xff;
364 if (dp != NULL)
365 *dp = (tag >> 15) & 0x1f;
366 if (fp != NULL)
367 *fp = (tag >> 12) & 0x7;
368 }
369
370 int
bcmpcie_conf_size(void * v,pcitag_t tag)371 bcmpcie_conf_size(void *v, pcitag_t tag)
372 {
373 return PCIE_CONFIG_SPACE_SIZE;
374 }
375
376 pcireg_t
bcmpcie_conf_read(void * v,pcitag_t tag,int reg)377 bcmpcie_conf_read(void *v, pcitag_t tag, int reg)
378 {
379 struct bcmpcie_softc *sc = v;
380 int bus, dev, fn;
381
382 bcmpcie_decompose_tag(sc, tag, &bus, &dev, &fn);
383 if (bus == 0) {
384 KASSERT(dev == 0);
385 return HREAD4(sc, tag | reg);
386 }
387
388 HWRITE4(sc, PCIE_EXT_CFG_INDEX, tag);
389 return HREAD4(sc, PCIE_EXT_CFG_DATA + reg);
390 }
391
392 void
bcmpcie_conf_write(void * v,pcitag_t tag,int reg,pcireg_t data)393 bcmpcie_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
394 {
395 struct bcmpcie_softc *sc = v;
396 int bus, dev, fn;
397
398 bcmpcie_decompose_tag(sc, tag, &bus, &dev, &fn);
399 if (bus == 0) {
400 KASSERT(dev == 0);
401 HWRITE4(sc, tag | reg, data);
402 return;
403 }
404
405 HWRITE4(sc, PCIE_EXT_CFG_INDEX, tag);
406 HWRITE4(sc, PCIE_EXT_CFG_DATA + reg, data);
407 }
408
409 int
bcmpcie_probe_device_hook(void * v,struct pci_attach_args * pa)410 bcmpcie_probe_device_hook(void *v, struct pci_attach_args *pa)
411 {
412 return 0;
413 }
414
415 int
bcmpcie_intr_map(struct pci_attach_args * pa,pci_intr_handle_t * ihp)416 bcmpcie_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
417 {
418 int pin = pa->pa_rawintrpin;
419
420 if (pin == 0 || pin > PCI_INTERRUPT_PIN_MAX)
421 return -1;
422
423 if (pa->pa_tag == 0)
424 return -1;
425
426 ihp->ih_pc = pa->pa_pc;
427 ihp->ih_tag = pa->pa_intrtag;
428 ihp->ih_intrpin = pa->pa_intrpin;
429 ihp->ih_type = PCI_INTX;
430
431 return 0;
432 }
433
434 const char *
bcmpcie_intr_string(void * v,pci_intr_handle_t ih)435 bcmpcie_intr_string(void *v, pci_intr_handle_t ih)
436 {
437 switch (ih.ih_type) {
438 case PCI_MSI:
439 return "msi";
440 case PCI_MSIX:
441 return "msix";
442 }
443
444 return "intx";
445 }
446
447 void *
bcmpcie_intr_establish(void * v,pci_intr_handle_t ih,int level,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)448 bcmpcie_intr_establish(void *v, pci_intr_handle_t ih, int level,
449 struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
450 {
451 struct bcmpcie_softc *sc = v;
452 int bus, dev, fn;
453 uint32_t reg[4];
454
455 KASSERT(ih.ih_type == PCI_INTX);
456 bcmpcie_decompose_tag(sc, ih.ih_tag, &bus, &dev, &fn);
457
458 reg[0] = bus << 16 | dev << 11 | fn << 8;
459 reg[1] = reg[2] = 0;
460 reg[3] = ih.ih_intrpin;
461
462 return fdt_intr_establish_imap_cpu(sc->sc_node, reg, sizeof(reg),
463 level, ci, func, arg, name);
464 }
465
466 void
bcmpcie_intr_disestablish(void * v,void * cookie)467 bcmpcie_intr_disestablish(void *v, void *cookie)
468 {
469 }
470
471 int
bcmpcie_bs_iomap(bus_space_tag_t t,bus_addr_t addr,bus_size_t size,int flags,bus_space_handle_t * bshp)472 bcmpcie_bs_iomap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
473 int flags, bus_space_handle_t *bshp)
474 {
475 struct bcmpcie_softc *sc = t->bus_private;
476 int i;
477
478 for (i = 0; i < sc->sc_nranges; i++) {
479 uint64_t pci_start = sc->sc_ranges[i].pci_base;
480 uint64_t pci_end = pci_start + sc->sc_ranges[i].size;
481 uint64_t phys_start = sc->sc_ranges[i].phys_base;
482
483 if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 &&
484 addr >= pci_start && addr + size <= pci_end) {
485 return bus_space_map(sc->sc_iot,
486 addr - pci_start + phys_start, size, flags, bshp);
487 }
488 }
489
490 return ENXIO;
491 }
492
493 int
bcmpcie_bs_memmap(bus_space_tag_t t,bus_addr_t addr,bus_size_t size,int flags,bus_space_handle_t * bshp)494 bcmpcie_bs_memmap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size,
495 int flags, bus_space_handle_t *bshp)
496 {
497 struct bcmpcie_softc *sc = t->bus_private;
498 int i;
499
500 for (i = 0; i < sc->sc_nranges; i++) {
501 uint64_t pci_start = sc->sc_ranges[i].pci_base;
502 uint64_t pci_end = pci_start + sc->sc_ranges[i].size;
503 uint64_t phys_start = sc->sc_ranges[i].phys_base;
504
505 if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000 &&
506 addr >= pci_start && addr + size <= pci_end) {
507 return bus_space_map(sc->sc_iot,
508 addr - pci_start + phys_start, size, flags, bshp);
509 }
510 }
511
512 return ENXIO;
513 }
514
515 int
bcmpcie_dmamap_load_buffer(bus_dma_tag_t t,bus_dmamap_t map,void * buf,bus_size_t buflen,struct proc * p,int flags,paddr_t * lastaddrp,int * segp,int first)516 bcmpcie_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
517 bus_size_t buflen, struct proc *p, int flags, paddr_t *lastaddrp,
518 int *segp, int first)
519 {
520 struct bcmpcie_softc *sc = t->_cookie;
521 int seg, firstseg = *segp;
522 int error;
523
524 error = sc->sc_dmat->_dmamap_load_buffer(sc->sc_dmat, map, buf, buflen,
525 p, flags, lastaddrp, segp, first);
526 if (error)
527 return error;
528
529 if (sc->sc_dmaranges == NULL)
530 return 0;
531
532 /* For each segment. */
533 for (seg = firstseg; seg <= *segp; seg++) {
534 uint64_t addr = map->dm_segs[seg].ds_addr;
535 uint64_t size = map->dm_segs[seg].ds_len;
536 int i;
537
538 /* For each range. */
539 for (i = 0; i < sc->sc_ndmaranges; i++) {
540 uint64_t pci_start = sc->sc_dmaranges[i].pci_base;
541 uint64_t phys_start = sc->sc_dmaranges[i].phys_base;
542 uint64_t phys_end = phys_start +
543 sc->sc_dmaranges[i].size;
544
545 if (addr >= phys_start && addr + size <= phys_end) {
546 map->dm_segs[seg].ds_addr -= phys_start;
547 map->dm_segs[seg].ds_addr += pci_start;
548 break;
549 }
550 }
551
552 if (i == sc->sc_ndmaranges)
553 return EINVAL;
554 }
555
556 return 0;
557 }
558
559 int
bcmpcie_dmamap_load_raw(bus_dma_tag_t t,bus_dmamap_t map,bus_dma_segment_t * segs,int nsegs,bus_size_t size,int flags)560 bcmpcie_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
561 bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
562 {
563 struct bcmpcie_softc *sc = t->_cookie;
564 int seg, error;
565
566 error = sc->sc_dmat->_dmamap_load_raw(sc->sc_dmat, map,
567 segs, nsegs, size, flags);
568 if (error)
569 return error;
570
571 if (sc->sc_dmaranges == NULL)
572 return 0;
573
574 /* For each segment. */
575 for (seg = 0; seg < map->dm_nsegs; seg++) {
576 uint64_t addr = map->dm_segs[seg].ds_addr;
577 uint64_t size = map->dm_segs[seg].ds_len;
578 int i;
579
580 /* For each range. */
581 for (i = 0; i < sc->sc_ndmaranges; i++) {
582 uint64_t pci_start = sc->sc_dmaranges[i].pci_base;
583 uint64_t phys_start = sc->sc_dmaranges[i].phys_base;
584 uint64_t phys_end = phys_start +
585 sc->sc_dmaranges[i].size;
586
587 if (addr >= phys_start && addr + size <= phys_end) {
588 map->dm_segs[seg].ds_addr -= phys_start;
589 map->dm_segs[seg].ds_addr += pci_start;
590 break;
591 }
592 }
593
594 if (i == sc->sc_ndmaranges)
595 return EINVAL;
596 }
597
598 return 0;
599 }
600