]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/pci/pci_host_generic.c
MFV r344063:
[FreeBSD/FreeBSD.git] / sys / dev / pci / pci_host_generic.c
1 /*-
2  * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
3  * Copyright (c) 2014 The FreeBSD Foundation
4  * All rights reserved.
5  *
6  * This software was developed by Semihalf under
7  * the sponsorship of the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 /* Generic ECAM PCIe driver */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include "opt_platform.h"
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/malloc.h>
41 #include <sys/kernel.h>
42 #include <sys/rman.h>
43 #include <sys/module.h>
44 #include <sys/bus.h>
45 #include <sys/endian.h>
46
47 #include <dev/pci/pcivar.h>
48 #include <dev/pci/pcireg.h>
49 #include <dev/pci/pcib_private.h>
50 #include <dev/pci/pci_host_generic.h>
51
52 #include <machine/bus.h>
53 #include <machine/intr.h>
54
55 #include "pcib_if.h"
56
57 /* Assembling ECAM Configuration Address */
58 #define PCIE_BUS_SHIFT          20
59 #define PCIE_SLOT_SHIFT         15
60 #define PCIE_FUNC_SHIFT         12
61 #define PCIE_BUS_MASK           0xFF
62 #define PCIE_SLOT_MASK          0x1F
63 #define PCIE_FUNC_MASK          0x07
64 #define PCIE_REG_MASK           0xFFF
65
66 #define PCIE_ADDR_OFFSET(bus, slot, func, reg)                  \
67         ((((bus) & PCIE_BUS_MASK) << PCIE_BUS_SHIFT)    |       \
68         (((slot) & PCIE_SLOT_MASK) << PCIE_SLOT_SHIFT)  |       \
69         (((func) & PCIE_FUNC_MASK) << PCIE_FUNC_SHIFT)  |       \
70         ((reg) & PCIE_REG_MASK))
71
72 /* Forward prototypes */
73
74 static uint32_t generic_pcie_read_config(device_t dev, u_int bus, u_int slot,
75     u_int func, u_int reg, int bytes);
76 static void generic_pcie_write_config(device_t dev, u_int bus, u_int slot,
77     u_int func, u_int reg, uint32_t val, int bytes);
78 static int generic_pcie_maxslots(device_t dev);
79 static int generic_pcie_read_ivar(device_t dev, device_t child, int index,
80     uintptr_t *result);
81 static int generic_pcie_write_ivar(device_t dev, device_t child, int index,
82     uintptr_t value);
83
84 int
85 pci_host_generic_core_attach(device_t dev)
86 {
87         struct generic_pcie_core_softc *sc;
88         int error;
89         int rid;
90
91         sc = device_get_softc(dev);
92         sc->dev = dev;
93
94         /* Create the parent DMA tag to pass down the coherent flag */
95         error = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
96             1, 0,                               /* alignment, bounds */
97             BUS_SPACE_MAXADDR,                  /* lowaddr */
98             BUS_SPACE_MAXADDR,                  /* highaddr */
99             NULL, NULL,                         /* filter, filterarg */
100             BUS_SPACE_MAXSIZE,                  /* maxsize */
101             BUS_SPACE_UNRESTRICTED,             /* nsegments */
102             BUS_SPACE_MAXSIZE,                  /* maxsegsize */
103             sc->coherent ? BUS_DMA_COHERENT : 0, /* flags */
104             NULL, NULL,                         /* lockfunc, lockarg */
105             &sc->dmat);
106         if (error != 0)
107                 return (error);
108
109         rid = 0;
110         sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
111         if (sc->res == NULL) {
112                 device_printf(dev, "could not map memory.\n");
113                 return (ENXIO);
114         }
115
116         sc->bst = rman_get_bustag(sc->res);
117         sc->bsh = rman_get_bushandle(sc->res);
118
119         sc->mem_rman.rm_type = RMAN_ARRAY;
120         sc->mem_rman.rm_descr = "PCIe Memory";
121         sc->io_rman.rm_type = RMAN_ARRAY;
122         sc->io_rman.rm_descr = "PCIe IO window";
123
124         /* Initialize rman and allocate memory regions */
125         error = rman_init(&sc->mem_rman);
126         if (error) {
127                 device_printf(dev, "rman_init() failed. error = %d\n", error);
128                 return (error);
129         }
130
131         error = rman_init(&sc->io_rman);
132         if (error) {
133                 device_printf(dev, "rman_init() failed. error = %d\n", error);
134                 return (error);
135         }
136
137         return (0);
138 }
139
140 static uint32_t
141 generic_pcie_read_config(device_t dev, u_int bus, u_int slot,
142     u_int func, u_int reg, int bytes)
143 {
144         struct generic_pcie_core_softc *sc;
145         bus_space_handle_t h;
146         bus_space_tag_t t;
147         uint64_t offset;
148         uint32_t data;
149
150         sc = device_get_softc(dev);
151         if ((bus < sc->bus_start) || (bus > sc->bus_end))
152                 return (~0U);
153         if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) ||
154             (reg > PCIE_REGMAX))
155                 return (~0U);
156
157         offset = PCIE_ADDR_OFFSET(bus - sc->bus_start, slot, func, reg);
158         t = sc->bst;
159         h = sc->bsh;
160
161         switch (bytes) {
162         case 1:
163                 data = bus_space_read_1(t, h, offset);
164                 break;
165         case 2:
166                 data = le16toh(bus_space_read_2(t, h, offset));
167                 break;
168         case 4:
169                 data = le32toh(bus_space_read_4(t, h, offset));
170                 break;
171         default:
172                 return (~0U);
173         }
174
175         return (data);
176 }
177
178 static void
179 generic_pcie_write_config(device_t dev, u_int bus, u_int slot,
180     u_int func, u_int reg, uint32_t val, int bytes)
181 {
182         struct generic_pcie_core_softc *sc;
183         bus_space_handle_t h;
184         bus_space_tag_t t;
185         uint64_t offset;
186
187         sc = device_get_softc(dev);
188         if ((bus < sc->bus_start) || (bus > sc->bus_end))
189                 return;
190         if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) ||
191             (reg > PCIE_REGMAX))
192                 return;
193
194         offset = PCIE_ADDR_OFFSET(bus - sc->bus_start, slot, func, reg);
195
196         t = sc->bst;
197         h = sc->bsh;
198
199         switch (bytes) {
200         case 1:
201                 bus_space_write_1(t, h, offset, val);
202                 break;
203         case 2:
204                 bus_space_write_2(t, h, offset, htole16(val));
205                 break;
206         case 4:
207                 bus_space_write_4(t, h, offset, htole32(val));
208                 break;
209         default:
210                 return;
211         }
212 }
213
214 static int
215 generic_pcie_maxslots(device_t dev)
216 {
217
218         return (31); /* max slots per bus acc. to standard */
219 }
220
221 static int
222 generic_pcie_read_ivar(device_t dev, device_t child, int index,
223     uintptr_t *result)
224 {
225         struct generic_pcie_core_softc *sc;
226
227         sc = device_get_softc(dev);
228
229         if (index == PCIB_IVAR_BUS) {
230                 *result = sc->bus_start;
231                 return (0);
232
233         }
234
235         if (index == PCIB_IVAR_DOMAIN) {
236                 *result = sc->ecam;
237                 return (0);
238         }
239
240         if (bootverbose)
241                 device_printf(dev, "ERROR: Unknown index %d.\n", index);
242         return (ENOENT);
243 }
244
245 static int
246 generic_pcie_write_ivar(device_t dev, device_t child, int index,
247     uintptr_t value)
248 {
249
250         return (ENOENT);
251 }
252
253 static struct rman *
254 generic_pcie_rman(struct generic_pcie_core_softc *sc, int type)
255 {
256
257         switch (type) {
258         case SYS_RES_IOPORT:
259                 return (&sc->io_rman);
260         case SYS_RES_MEMORY:
261                 return (&sc->mem_rman);
262         default:
263                 break;
264         }
265
266         return (NULL);
267 }
268
269 int
270 pci_host_generic_core_release_resource(device_t dev, device_t child, int type,
271     int rid, struct resource *res)
272 {
273         struct generic_pcie_core_softc *sc;
274         struct rman *rm;
275
276         sc = device_get_softc(dev);
277
278 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
279         if (type == PCI_RES_BUS) {
280                 return (pci_domain_release_bus(sc->ecam, child, rid, res));
281         }
282 #endif
283
284         rm = generic_pcie_rman(sc, type);
285         if (rm != NULL) {
286                 KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
287                 rman_release_resource(res);
288         }
289
290         return (bus_generic_release_resource(dev, child, type, rid, res));
291 }
292
293 struct resource *
294 pci_host_generic_core_alloc_resource(device_t dev, device_t child, int type,
295     int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
296 {
297         struct generic_pcie_core_softc *sc;
298         struct resource *res;
299         struct rman *rm;
300
301         sc = device_get_softc(dev);
302
303 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
304         if (type == PCI_RES_BUS) {
305                 return (pci_domain_alloc_bus(sc->ecam, child, rid, start, end,
306                     count, flags));
307         }
308 #endif
309
310         rm = generic_pcie_rman(sc, type);
311         if (rm == NULL)
312                 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
313                     type, rid, start, end, count, flags));
314
315         if (bootverbose) {
316                 device_printf(dev,
317                     "rman_reserve_resource: start=%#jx, end=%#jx, count=%#jx\n",
318                     start, end, count);
319         }
320
321         res = rman_reserve_resource(rm, start, end, count, flags, child);
322         if (res == NULL)
323                 goto fail;
324
325         rman_set_rid(res, *rid);
326
327         if (flags & RF_ACTIVE)
328                 if (bus_activate_resource(child, type, *rid, res)) {
329                         rman_release_resource(res);
330                         goto fail;
331                 }
332
333         return (res);
334
335 fail:
336         device_printf(dev, "%s FAIL: type=%d, rid=%d, "
337             "start=%016jx, end=%016jx, count=%016jx, flags=%x\n",
338             __func__, type, *rid, start, end, count, flags);
339
340         return (NULL);
341 }
342
343 static int
344 generic_pcie_activate_resource(device_t dev, device_t child, int type,
345     int rid, struct resource *r)
346 {
347         struct generic_pcie_core_softc *sc;
348         uint64_t phys_base;
349         uint64_t pci_base;
350         uint64_t size;
351         int found;
352         int res;
353         int i;
354
355         sc = device_get_softc(dev);
356
357         if ((res = rman_activate_resource(r)) != 0)
358                 return (res);
359
360         switch (type) {
361         case SYS_RES_IOPORT:
362                 found = 0;
363                 for (i = 0; i < MAX_RANGES_TUPLES; i++) {
364                         pci_base = sc->ranges[i].pci_base;
365                         phys_base = sc->ranges[i].phys_base;
366                         size = sc->ranges[i].size;
367
368                         if ((rid > pci_base) && (rid < (pci_base + size))) {
369                                 found = 1;
370                                 break;
371                         }
372                 }
373                 if (found) {
374                         rman_set_start(r, rman_get_start(r) + phys_base);
375                         rman_set_end(r, rman_get_end(r) + phys_base);
376                         res = BUS_ACTIVATE_RESOURCE(device_get_parent(dev),
377                             child, type, rid, r);
378                 } else {
379                         device_printf(dev,
380                             "Failed to activate IOPORT resource\n");
381                         res = 0;
382                 }
383                 break;
384         case SYS_RES_MEMORY:
385         case SYS_RES_IRQ:
386                 res = BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child,
387                     type, rid, r);
388                 break;
389         default:
390                 break;
391         }
392
393         return (res);
394 }
395
396 static int
397 generic_pcie_deactivate_resource(device_t dev, device_t child, int type,
398     int rid, struct resource *r)
399 {
400         int res;
401
402         if ((res = rman_deactivate_resource(r)) != 0)
403                 return (res);
404
405         switch (type) {
406         case SYS_RES_IOPORT:
407         case SYS_RES_MEMORY:
408         case SYS_RES_IRQ:
409                 res = BUS_DEACTIVATE_RESOURCE(device_get_parent(dev), child,
410                     type, rid, r);
411                 break;
412         default:
413                 break;
414         }
415
416         return (res);
417 }
418
419 static int
420 generic_pcie_adjust_resource(device_t dev, device_t child, int type,
421     struct resource *res, rman_res_t start, rman_res_t end)
422 {
423         struct generic_pcie_core_softc *sc;
424         struct rman *rm;
425
426         sc = device_get_softc(dev);
427 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
428         if (type == PCI_RES_BUS)
429                 return (pci_domain_adjust_bus(sc->ecam, child, res, start,
430                     end));
431 #endif
432
433         rm = generic_pcie_rman(sc, type);
434         if (rm != NULL)
435                 return (rman_adjust_resource(res, start, end));
436         return (bus_generic_adjust_resource(dev, child, type, res, start, end));
437 }
438
439 static bus_dma_tag_t
440 generic_pcie_get_dma_tag(device_t dev, device_t child)
441 {
442         struct generic_pcie_core_softc *sc;
443
444         sc = device_get_softc(dev);
445         return (sc->dmat);
446 }
447
448 static device_method_t generic_pcie_methods[] = {
449         DEVMETHOD(device_attach,                pci_host_generic_core_attach),
450         DEVMETHOD(bus_read_ivar,                generic_pcie_read_ivar),
451         DEVMETHOD(bus_write_ivar,               generic_pcie_write_ivar),
452         DEVMETHOD(bus_alloc_resource,           pci_host_generic_core_alloc_resource),
453         DEVMETHOD(bus_adjust_resource,          generic_pcie_adjust_resource),
454         DEVMETHOD(bus_activate_resource,        generic_pcie_activate_resource),
455         DEVMETHOD(bus_deactivate_resource,      generic_pcie_deactivate_resource),
456         DEVMETHOD(bus_release_resource,         pci_host_generic_core_release_resource),
457         DEVMETHOD(bus_setup_intr,               bus_generic_setup_intr),
458         DEVMETHOD(bus_teardown_intr,            bus_generic_teardown_intr),
459
460         DEVMETHOD(bus_get_dma_tag,              generic_pcie_get_dma_tag),
461
462         /* pcib interface */
463         DEVMETHOD(pcib_maxslots,                generic_pcie_maxslots),
464         DEVMETHOD(pcib_read_config,             generic_pcie_read_config),
465         DEVMETHOD(pcib_write_config,            generic_pcie_write_config),
466
467         DEVMETHOD_END
468 };
469
470 DEFINE_CLASS_0(pcib, generic_pcie_core_driver,
471     generic_pcie_methods, sizeof(struct generic_pcie_core_softc));