]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/pci/pci_host_generic.c
Update ena-com HAL to v1.1.4.3 and update driver accordingly
[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         if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) ||
151             (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX))
152                 return (~0U);
153
154         sc = device_get_softc(dev);
155
156         offset = PCIE_ADDR_OFFSET(bus, slot, func, reg);
157         t = sc->bst;
158         h = sc->bsh;
159
160         switch (bytes) {
161         case 1:
162                 data = bus_space_read_1(t, h, offset);
163                 break;
164         case 2:
165                 data = le16toh(bus_space_read_2(t, h, offset));
166                 break;
167         case 4:
168                 data = le32toh(bus_space_read_4(t, h, offset));
169                 break;
170         default:
171                 return (~0U);
172         }
173
174         return (data);
175 }
176
177 static void
178 generic_pcie_write_config(device_t dev, u_int bus, u_int slot,
179     u_int func, u_int reg, uint32_t val, int bytes)
180 {
181         struct generic_pcie_core_softc *sc;
182         bus_space_handle_t h;
183         bus_space_tag_t t;
184         uint64_t offset;
185
186         if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) ||
187             (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX))
188                 return;
189
190         sc = device_get_softc(dev);
191
192         offset = PCIE_ADDR_OFFSET(bus, slot, func, reg);
193
194         t = sc->bst;
195         h = sc->bsh;
196
197         switch (bytes) {
198         case 1:
199                 bus_space_write_1(t, h, offset, val);
200                 break;
201         case 2:
202                 bus_space_write_2(t, h, offset, htole16(val));
203                 break;
204         case 4:
205                 bus_space_write_4(t, h, offset, htole32(val));
206                 break;
207         default:
208                 return;
209         }
210 }
211
212 static int
213 generic_pcie_maxslots(device_t dev)
214 {
215
216         return (31); /* max slots per bus acc. to standard */
217 }
218
219 static int
220 generic_pcie_read_ivar(device_t dev, device_t child, int index,
221     uintptr_t *result)
222 {
223         struct generic_pcie_core_softc *sc;
224         int secondary_bus;
225
226         sc = device_get_softc(dev);
227
228         if (index == PCIB_IVAR_BUS) {
229                 /* this pcib adds only pci bus 0 as child */
230                 secondary_bus = 0;
231                 *result = secondary_bus;
232                 return (0);
233
234         }
235
236         if (index == PCIB_IVAR_DOMAIN) {
237                 *result = sc->ecam;
238                 return (0);
239         }
240
241         if (bootverbose)
242                 device_printf(dev, "ERROR: Unknown index %d.\n", index);
243         return (ENOENT);
244 }
245
246 static int
247 generic_pcie_write_ivar(device_t dev, device_t child, int index,
248     uintptr_t value)
249 {
250
251         return (ENOENT);
252 }
253
254 static struct rman *
255 generic_pcie_rman(struct generic_pcie_core_softc *sc, int type)
256 {
257
258         switch (type) {
259         case SYS_RES_IOPORT:
260                 return (&sc->io_rman);
261         case SYS_RES_MEMORY:
262                 return (&sc->mem_rman);
263         default:
264                 break;
265         }
266
267         return (NULL);
268 }
269
270 int
271 pci_host_generic_core_release_resource(device_t dev, device_t child, int type,
272     int rid, struct resource *res)
273 {
274         struct generic_pcie_core_softc *sc;
275         struct rman *rm;
276
277         sc = device_get_softc(dev);
278
279 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
280         if (type == PCI_RES_BUS) {
281                 return (pci_domain_release_bus(sc->ecam, child, rid, res));
282         }
283 #endif
284
285         rm = generic_pcie_rman(sc, type);
286         if (rm != NULL) {
287                 KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
288                 rman_release_resource(res);
289         }
290
291         return (bus_generic_release_resource(dev, child, type, rid, res));
292 }
293
294 struct resource *
295 pci_host_generic_core_alloc_resource(device_t dev, device_t child, int type,
296     int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
297 {
298         struct generic_pcie_core_softc *sc;
299         struct resource *res;
300         struct rman *rm;
301
302         sc = device_get_softc(dev);
303
304 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
305         if (type == PCI_RES_BUS) {
306                 return (pci_domain_alloc_bus(sc->ecam, child, rid, start, end,
307                     count, flags));
308         }
309 #endif
310
311         rm = generic_pcie_rman(sc, type);
312         if (rm == NULL)
313                 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
314                     type, rid, start, end, count, flags));
315
316         if (bootverbose) {
317                 device_printf(dev,
318                     "rman_reserve_resource: start=%#jx, end=%#jx, count=%#jx\n",
319                     start, end, count);
320         }
321
322         res = rman_reserve_resource(rm, start, end, count, flags, child);
323         if (res == NULL)
324                 goto fail;
325
326         rman_set_rid(res, *rid);
327
328         if (flags & RF_ACTIVE)
329                 if (bus_activate_resource(child, type, *rid, res)) {
330                         rman_release_resource(res);
331                         goto fail;
332                 }
333
334         return (res);
335
336 fail:
337         device_printf(dev, "%s FAIL: type=%d, rid=%d, "
338             "start=%016jx, end=%016jx, count=%016jx, flags=%x\n",
339             __func__, type, *rid, start, end, count, flags);
340
341         return (NULL);
342 }
343
344 static int
345 generic_pcie_adjust_resource(device_t dev, device_t child, int type,
346     struct resource *res, rman_res_t start, rman_res_t end)
347 {
348         struct generic_pcie_core_softc *sc;
349         struct rman *rm;
350
351         sc = device_get_softc(dev);
352 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
353         if (type == PCI_RES_BUS)
354                 return (pci_domain_adjust_bus(sc->ecam, child, res, start,
355                     end));
356 #endif
357
358         rm = generic_pcie_rman(sc, type);
359         if (rm != NULL)
360                 return (rman_adjust_resource(res, start, end));
361         return (bus_generic_adjust_resource(dev, child, type, res, start, end));
362 }
363
364 static bus_dma_tag_t
365 generic_pcie_get_dma_tag(device_t dev, device_t child)
366 {
367         struct generic_pcie_core_softc *sc;
368
369         sc = device_get_softc(dev);
370         return (sc->dmat);
371 }
372
373 static device_method_t generic_pcie_methods[] = {
374         DEVMETHOD(device_attach,                pci_host_generic_core_attach),
375         DEVMETHOD(bus_read_ivar,                generic_pcie_read_ivar),
376         DEVMETHOD(bus_write_ivar,               generic_pcie_write_ivar),
377         DEVMETHOD(bus_alloc_resource,           pci_host_generic_core_alloc_resource),
378         DEVMETHOD(bus_adjust_resource,          generic_pcie_adjust_resource),
379         DEVMETHOD(bus_release_resource,         pci_host_generic_core_release_resource),
380         DEVMETHOD(bus_setup_intr,               bus_generic_setup_intr),
381         DEVMETHOD(bus_teardown_intr,            bus_generic_teardown_intr),
382
383         DEVMETHOD(bus_get_dma_tag,              generic_pcie_get_dma_tag),
384
385         /* pcib interface */
386         DEVMETHOD(pcib_maxslots,                generic_pcie_maxslots),
387         DEVMETHOD(pcib_read_config,             generic_pcie_read_config),
388         DEVMETHOD(pcib_write_config,            generic_pcie_write_config),
389
390         DEVMETHOD_END
391 };
392
393 DEFINE_CLASS_0(pcib, generic_pcie_core_driver,
394     generic_pcie_methods, sizeof(struct generic_pcie_core_softc));