]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/beri/beri_iommu.c
Update Subversion to 1.14.0 LTS. See contrib/subversion/CHANGES for a
[FreeBSD/FreeBSD.git] / sys / mips / beri / beri_iommu.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2019 Ruslan Bukin <br@bsdpad.com>
5  *
6  * This software was developed by SRI International and the University of
7  * Cambridge Computer Laboratory (Department of Computer Science and
8  * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
9  * DARPA SSITH research programme.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bus.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/malloc.h>
42 #include <sys/rman.h>
43 #include <sys/timeet.h>
44 #include <sys/timetc.h>
45 #include <sys/conf.h>
46 #include <sys/uio.h>
47 #include <sys/endian.h>
48
49 #include <dev/ofw/openfirm.h>
50 #include <dev/ofw/ofw_bus.h>
51 #include <dev/ofw/ofw_bus_subr.h>
52
53 #include <machine/cache.h>
54 #include <machine/bus.h>
55 #include <machine/cpu.h>
56 #include <machine/intr.h>
57
58 #include <dev/xdma/xdma.h>
59
60 #include "xdma_if.h"
61
62 #define IOMMU_INVALIDATE        0x00
63 #define IOMMU_SET_BASE          0x08
64
65 struct beri_iommu_softc {
66         struct resource         *res[1];
67         device_t                dev;
68         bus_space_tag_t         bst_data;
69         bus_space_handle_t      bsh_data;
70         uint32_t                offs;
71 };
72
73 static struct resource_spec beri_iommu_spec[] = {
74         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
75         { -1, 0 }
76 };
77
78 static void
79 beri_iommu_invalidate(struct beri_iommu_softc *sc, vm_offset_t addr)
80 {
81
82         bus_write_8(sc->res[0], IOMMU_INVALIDATE, htole64(addr));
83 }
84
85 static void
86 beri_iommu_set_base(struct beri_iommu_softc *sc, vm_offset_t addr)
87 {
88
89         bus_write_8(sc->res[0], IOMMU_SET_BASE, htole64(addr));
90 }
91
92 static int
93 beri_iommu_release(device_t dev, struct xdma_iommu *xio)
94 {
95         struct beri_iommu_softc *sc;
96
97         sc = device_get_softc(dev);
98
99         beri_iommu_set_base(sc, 0);
100
101         return (0);
102 }
103
104 static int
105 beri_iommu_init(device_t dev, struct xdma_iommu *xio)
106 {
107         struct beri_iommu_softc *sc;
108
109         sc = device_get_softc(dev);
110
111         beri_iommu_set_base(sc, (uintptr_t)xio->p.pm_segtab);
112
113         return (0);
114 }
115
116 static int
117 beri_iommu_remove(device_t dev, struct xdma_iommu *xio, vm_offset_t va)
118 {
119         struct beri_iommu_softc *sc;
120
121         sc = device_get_softc(dev);
122
123         beri_iommu_invalidate(sc, va);
124
125         return (0);
126 }
127
128 static int
129 beri_iommu_enter(device_t dev, struct xdma_iommu *xio, vm_offset_t va,
130     vm_paddr_t pa)
131 {
132         struct beri_iommu_softc *sc;
133         pt_entry_t opte, npte;
134         pt_entry_t *pte;
135         pmap_t p;
136
137         sc = device_get_softc(dev);
138         p = &xio->p;
139
140         pte = pmap_pte(p, va);
141         if (pte == NULL)
142                 panic("pte is NULL\n");
143
144         /* Make pte uncacheable. */
145         opte = *pte;
146         npte = opte & ~PTE_C_MASK;
147         npte |= PTE_C(VM_MEMATTR_UNCACHEABLE);
148         *pte = npte;
149
150         /* Write back, invalidate pte. */
151         mips_dcache_wbinv_range((vm_offset_t)pte, sizeof(vm_offset_t));
152
153         /* Invalidate the entry. */
154         if (pte_test(&opte, PTE_V) && opte != npte)
155                 beri_iommu_invalidate(sc, va);
156
157         return (0);
158 }
159
160 static int
161 beri_iommu_probe(device_t dev)
162 {
163
164         if (!ofw_bus_status_okay(dev))
165                 return (ENXIO);
166
167         if (!ofw_bus_is_compatible(dev, "beri,iommu"))
168                 return (ENXIO);
169
170         device_set_desc(dev, "BERI IOMMU");
171
172         return (BUS_PROBE_DEFAULT);
173 }
174
175 static int
176 beri_iommu_attach(device_t dev)
177 {
178         struct beri_iommu_softc *sc;
179         phandle_t xref, node;
180
181         sc = device_get_softc(dev);
182         sc->dev = dev;
183
184         if (bus_alloc_resources(dev, beri_iommu_spec, sc->res)) {
185                 device_printf(dev, "could not allocate resources\n");
186                 return (ENXIO);
187         }
188
189         /* Memory interface */
190         sc->bst_data = rman_get_bustag(sc->res[0]);
191         sc->bsh_data = rman_get_bushandle(sc->res[0]);
192
193         node = ofw_bus_get_node(dev);
194         xref = OF_xref_from_node(node);
195         OF_device_register_xref(xref, dev);
196
197         return (0);
198 }
199
200 static int
201 beri_iommu_detach(device_t dev)
202 {
203         struct beri_iommu_softc *sc;
204
205         sc = device_get_softc(dev);
206
207         bus_release_resources(dev, beri_iommu_spec, sc->res);
208
209         return (0);
210 }
211
212 static device_method_t beri_iommu_methods[] = {
213
214         /* xDMA IOMMU interface */
215         DEVMETHOD(xdma_iommu_init,      beri_iommu_init),
216         DEVMETHOD(xdma_iommu_release,   beri_iommu_release),
217         DEVMETHOD(xdma_iommu_enter,     beri_iommu_enter),
218         DEVMETHOD(xdma_iommu_remove,    beri_iommu_remove),
219
220         /* Device interface */
221         DEVMETHOD(device_probe,         beri_iommu_probe),
222         DEVMETHOD(device_attach,        beri_iommu_attach),
223         DEVMETHOD(device_detach,        beri_iommu_detach),
224
225         { 0, 0 }
226 };
227
228 static driver_t beri_iommu_driver = {
229         "beri_iommu",
230         beri_iommu_methods,
231         sizeof(struct beri_iommu_softc),
232 };
233
234 static devclass_t beri_iommu_devclass;
235
236 DRIVER_MODULE(beri_iommu, simplebus, beri_iommu_driver,
237     beri_iommu_devclass, 0, 0);