FreeBSD kernel amd64 PCI device code
pci_n1sdp.c
Go to the documentation of this file.
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2019 Andrew Turner
5 * Copyright (c) 2019 Ruslan Bukin <br@bsdpad.com>
6 *
7 * This software was developed by SRI International and the University of
8 * Cambridge Computer Laboratory (Department of Computer Science and
9 * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
10 * DARPA SSITH research programme.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD$");
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/malloc.h>
40#include <sys/bus.h>
41#include <sys/endian.h>
42#include <sys/kernel.h>
43#include <sys/module.h>
44#include <sys/rman.h>
45
46#include <vm/vm.h>
47#include <vm/vm_extern.h>
48#include <vm/vm_page.h>
49#include <vm/vm_phys.h>
50
51#include <contrib/dev/acpica/include/acpi.h>
52#include <contrib/dev/acpica/include/accommon.h>
53
54#include <dev/acpica/acpivar.h>
55#include <dev/acpica/acpi_pcibvar.h>
56
57#include <dev/pci/pcivar.h>
58#include <dev/pci/pcireg.h>
62
63#include "pcib_if.h"
64
65#define AP_NS_SHARED_MEM_BASE 0x06000000
66#define N1SDP_MAX_SEGMENTS 2 /* Two PCIe root complex devices. */
67#define BDF_TABLE_SIZE (16 * 1024)
68#define PCI_CFG_SPACE_SIZE 0x1000
69
71 "pci_n1sdp.c assumes a 4k or 16k page size when mapping the shared data");
72
74 uint32_t rc_base_addr;
75 uint32_t nr_bdfs;
76 uint32_t valid_bdfs[0];
77};
78
82 bus_space_handle_t n1_bsh;
83};
84
85static int
87{
88 struct pcie_discovery_data *shared_data;
89 vm_offset_t vaddr;
90 vm_paddr_t paddr_rc;
91 vm_paddr_t paddr;
92 vm_page_t m[BDF_TABLE_SIZE / PAGE_SIZE];
93 int table_count;
94 int bdfs_size;
95 int error, i;
96
98 vm_phys_fictitious_reg_range(paddr, paddr + BDF_TABLE_SIZE,
99 VM_MEMATTR_UNCACHEABLE);
100
101 for (i = 0; i < nitems(m); i++) {
102 m[i] = PHYS_TO_VM_PAGE(paddr + i * PAGE_SIZE);
103 MPASS(m[i] != NULL);
104 }
105
106 vaddr = kva_alloc((vm_size_t)BDF_TABLE_SIZE);
107 if (vaddr == 0) {
108 printf("%s: Can't allocate KVA memory.", __func__);
109 error = ENXIO;
110 goto out;
111 }
112 pmap_qenter(vaddr, m, nitems(m));
113
114 shared_data = (struct pcie_discovery_data *)vaddr;
115 paddr_rc = (vm_offset_t)shared_data->rc_base_addr;
116 error = bus_space_map(sc->acpi.base.bst, paddr_rc, PCI_CFG_SPACE_SIZE,
117 0, &sc->n1_bsh);
118 if (error != 0)
119 goto out_pmap;
120
121 bdfs_size = sizeof(struct pcie_discovery_data) +
122 sizeof(uint32_t) * shared_data->nr_bdfs;
123 sc->n1_discovery_data = malloc(bdfs_size, M_DEVBUF,
124 M_WAITOK | M_ZERO);
125 memcpy(sc->n1_discovery_data, shared_data, bdfs_size);
126
127 if (bootverbose) {
128 table_count = sc->n1_discovery_data->nr_bdfs;
129 for (i = 0; i < table_count; i++)
130 printf("valid bdf %x\n",
132 }
133
134out_pmap:
135 pmap_qremove(vaddr, nitems(m));
136 kva_free(vaddr, (vm_size_t)BDF_TABLE_SIZE);
137
138out:
139 vm_phys_fictitious_unreg_range(paddr, paddr + BDF_TABLE_SIZE);
140 return (error);
141}
142
143static int
145 u_int bus, u_int slot, u_int func)
146{
147 int table_count;
148 int bdf;
149 int i;
150
151 bdf = PCIE_ADDR_OFFSET(bus, slot, func, 0);
152 if (bdf == 0)
153 return (1);
154
155 table_count = sc->n1_discovery_data->nr_bdfs;
156
157 for (i = 0; i < table_count; i++)
158 if (bdf == sc->n1_discovery_data->valid_bdfs[i])
159 return (1);
160
161 return (0);
162}
163
164static int
166{
167 ACPI_DEVICE_INFO *devinfo;
168 ACPI_TABLE_HEADER *hdr;
169 ACPI_STATUS status;
170 ACPI_HANDLE h;
171 int root;
172
173 if (acpi_disabled("pcib") || (h = acpi_get_handle(dev)) == NULL ||
174 ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo)))
175 return (ENXIO);
176
177 root = (devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) != 0;
178 AcpiOsFree(devinfo);
179 if (!root)
180 return (ENXIO);
181
182 /* TODO: Move this to an ACPI quirk? */
183 status = AcpiGetTable(ACPI_SIG_MCFG, 1, &hdr);
184 if (ACPI_FAILURE(status))
185 return (ENXIO);
186
187 if (memcmp(hdr->OemId, "ARMLTD", ACPI_OEM_ID_SIZE) != 0 ||
188 memcmp(hdr->OemTableId, "ARMN1SDP", ACPI_OEM_TABLE_ID_SIZE) != 0 ||
189 hdr->OemRevision != 0x20181101)
190 return (ENXIO);
191
192 device_set_desc(dev, "ARM N1SDP PCI host controller");
193 return (BUS_PROBE_DEFAULT);
194}
195
196static int
198{
199 struct generic_pcie_n1sdp_softc *sc;
200 ACPI_HANDLE handle;
201 ACPI_STATUS status;
202 int err;
203
205 if (err != 0)
206 return (err);
207
208 sc = device_get_softc(dev);
209 handle = acpi_get_handle(dev);
210
211 /* Get PCI Segment (domain) needed for IOMMU space remap. */
212 status = acpi_GetInteger(handle, "_SEG", &sc->acpi.segment);
213 if (ACPI_FAILURE(status)) {
214 device_printf(dev, "No _SEG for PCI Bus\n");
215 return (ENXIO);
216 }
217
218 if (sc->acpi.segment >= N1SDP_MAX_SEGMENTS) {
219 device_printf(dev, "Unknown PCI Bus segment (domain) %d\n",
220 sc->acpi.segment);
221 return (ENXIO);
222 }
223
224 err = n1sdp_init(sc);
225 if (err)
226 return (err);
227
228 device_add_child(dev, "pci", -1);
229 return (bus_generic_attach(dev));
230}
231
232static int
233n1sdp_get_bus_space(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
234 bus_space_tag_t *bst, bus_space_handle_t *bsh, bus_size_t *offset)
235{
236 struct generic_pcie_n1sdp_softc *sc;
237
238 sc = device_get_softc(dev);
239
240 if (n1sdp_check_bdf(sc, bus, slot, func) == 0)
241 return (EINVAL);
242
243 if (bus == sc->acpi.base.bus_start) {
244 if (slot != 0 || func != 0)
245 return (EINVAL);
246 *bsh = sc->n1_bsh;
247 } else {
248 *bsh = sc->acpi.base.bsh;
249 }
250
251 *bst = sc->acpi.base.bst;
252 *offset = PCIE_ADDR_OFFSET(bus - sc->acpi.base.bus_start, slot, func,
253 reg);
254
255 return (0);
256}
257
258static uint32_t
259n1sdp_pcie_read_config(device_t dev, u_int bus, u_int slot,
260 u_int func, u_int reg, int bytes)
261{
262 struct generic_pcie_n1sdp_softc *sc_n1sdp;
263 struct generic_pcie_acpi_softc *sc_acpi;
264 struct generic_pcie_core_softc *sc;
265 bus_space_handle_t h;
266 bus_space_tag_t t;
267 bus_size_t offset;
268 uint32_t data;
269
270 sc_n1sdp = device_get_softc(dev);
271 sc_acpi = &sc_n1sdp->acpi;
272 sc = &sc_acpi->base;
273
274 if ((bus < sc->bus_start) || (bus > sc->bus_end))
275 return (~0U);
276 if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) ||
277 (reg > PCIE_REGMAX))
278 return (~0U);
279
280 if (n1sdp_get_bus_space(dev, bus, slot, func, reg, &t, &h, &offset) !=0)
281 return (~0U);
282
283 data = bus_space_read_4(t, h, offset & ~3);
284
285 switch (bytes) {
286 case 1:
287 data >>= (offset & 3) * 8;
288 data &= 0xff;
289 break;
290 case 2:
291 data >>= (offset & 3) * 8;
292 data = le16toh(data);
293 break;
294 case 4:
295 data = le32toh(data);
296 break;
297 default:
298 return (~0U);
299 }
300
301 return (data);
302}
303
304static void
305n1sdp_pcie_write_config(device_t dev, u_int bus, u_int slot,
306 u_int func, u_int reg, uint32_t val, int bytes)
307{
308 struct generic_pcie_n1sdp_softc *sc_n1sdp;
309 struct generic_pcie_acpi_softc *sc_acpi;
310 struct generic_pcie_core_softc *sc;
311 bus_space_handle_t h;
312 bus_space_tag_t t;
313 bus_size_t offset;
314 uint32_t data;
315
316 sc_n1sdp = device_get_softc(dev);
317 sc_acpi = &sc_n1sdp->acpi;
318 sc = &sc_acpi->base;
319
320 if ((bus < sc->bus_start) || (bus > sc->bus_end))
321 return;
322 if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) ||
323 (reg > PCIE_REGMAX))
324 return;
325
326 if (n1sdp_get_bus_space(dev, bus, slot, func, reg, &t, &h, &offset) !=0)
327 return;
328
329 data = bus_space_read_4(t, h, offset & ~3);
330
331 switch (bytes) {
332 case 1:
333 data &= ~(0xff << ((offset & 3) * 8));
334 data |= (val & 0xff) << ((offset & 3) * 8);
335 break;
336 case 2:
337 data &= ~(0xffff << ((offset & 3) * 8));
338 data |= (val & 0xffff) << ((offset & 3) * 8);
339 break;
340 case 4:
341 data = val;
342 break;
343 default:
344 return;
345 }
346
347 bus_space_write_4(t, h, offset & ~3, data);
348}
349
350static device_method_t n1sdp_pcie_acpi_methods[] = {
351 DEVMETHOD(device_probe, n1sdp_pcie_acpi_probe),
352 DEVMETHOD(device_attach, n1sdp_pcie_acpi_attach),
353
354 /* pcib interface */
357
358 DEVMETHOD_END
359};
360
362 sizeof(struct generic_pcie_n1sdp_softc), generic_pcie_acpi_driver);
363
364static devclass_t n1sdp_pcie_acpi_devclass;
365
366DRIVER_MODULE(n1sdp_pcib, acpi, n1sdp_pcie_acpi_driver,
u_int reg
Definition: pci_dw_if.m:42
bool * status
Definition: pci_dw_if.m:72
#define PCIE_ADDR_OFFSET(bus, slot, func, reg)
int pci_host_generic_acpi_init(device_t dev)
uint16_t data
Definition: pci_if.m:198
u_int32_t val
Definition: pci_if.m:82
static int n1sdp_pcie_acpi_attach(device_t dev)
Definition: pci_n1sdp.c:197
static uint32_t n1sdp_pcie_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes)
Definition: pci_n1sdp.c:259
static int n1sdp_check_bdf(struct generic_pcie_n1sdp_softc *sc, u_int bus, u_int slot, u_int func)
Definition: pci_n1sdp.c:144
#define N1SDP_MAX_SEGMENTS
Definition: pci_n1sdp.c:66
static void n1sdp_pcie_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int bytes)
Definition: pci_n1sdp.c:305
DRIVER_MODULE(n1sdp_pcib, acpi, n1sdp_pcie_acpi_driver, n1sdp_pcie_acpi_devclass, 0, 0)
#define AP_NS_SHARED_MEM_BASE
Definition: pci_n1sdp.c:65
static int n1sdp_get_bus_space(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, bus_space_tag_t *bst, bus_space_handle_t *bsh, bus_size_t *offset)
Definition: pci_n1sdp.c:233
__FBSDID("$FreeBSD$")
_Static_assert(BDF_TABLE_SIZE >=PAGE_SIZE, "pci_n1sdp.c assumes a 4k or 16k page size when mapping the shared data")
static int n1sdp_pcie_acpi_probe(device_t dev)
Definition: pci_n1sdp.c:165
DEFINE_CLASS_1(pcib, n1sdp_pcie_acpi_driver, n1sdp_pcie_acpi_methods, sizeof(struct generic_pcie_n1sdp_softc), generic_pcie_acpi_driver)
#define BDF_TABLE_SIZE
Definition: pci_n1sdp.c:67
static device_method_t n1sdp_pcie_acpi_methods[]
Definition: pci_n1sdp.c:350
static devclass_t n1sdp_pcie_acpi_devclass
Definition: pci_n1sdp.c:364
static int n1sdp_init(struct generic_pcie_n1sdp_softc *sc)
Definition: pci_n1sdp.c:86
#define PCI_CFG_SPACE_SIZE
Definition: pci_n1sdp.c:68
static uint32_t pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width)
Definition: pci_pci.c:2698
static void pcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, uint32_t val, int width)
Definition: pci_pci.c:2721
u_int func
Definition: pcib_if.m:81
u_int bus
Definition: pcib_if.m:79
device_t dev
Definition: pcib_if.m:109
INTERFACE pcib
Definition: pcib_if.m:34
u_int slot
Definition: pcib_if.m:80
#define PCIE_REGMAX
Definition: pcireg.h:49
#define PCI_SLOTMAX
Definition: pcireg.h:46
#define PCI_FUNCMAX
Definition: pcireg.h:47
struct generic_pcie_core_softc base
bus_space_handle_t bsh
struct generic_pcie_acpi_softc acpi
Definition: pci_n1sdp.c:80
bus_space_handle_t n1_bsh
Definition: pci_n1sdp.c:82
struct pcie_discovery_data * n1_discovery_data
Definition: pci_n1sdp.c:81
uint32_t valid_bdfs[0]
Definition: pci_n1sdp.c:76
uint32_t rc_base_addr
Definition: pci_n1sdp.c:74
uint32_t nr_bdfs
Definition: pci_n1sdp.c:75