1*2ed98337SAymeric Wibo /*-
2*2ed98337SAymeric Wibo * SPDX-License-Identifier: BSD-2-Clause
3*2ed98337SAymeric Wibo *
4*2ed98337SAymeric Wibo * Copyright (c) 2022 Scott Long
5*2ed98337SAymeric Wibo * All rights reserved.
6*2ed98337SAymeric Wibo *
7*2ed98337SAymeric Wibo * Redistribution and use in source and binary forms, with or without
8*2ed98337SAymeric Wibo * modification, are permitted provided that the following conditions
9*2ed98337SAymeric Wibo * are met:
10*2ed98337SAymeric Wibo * 1. Redistributions of source code must retain the above copyright
11*2ed98337SAymeric Wibo * notice, this list of conditions and the following disclaimer.
12*2ed98337SAymeric Wibo * 2. Redistributions in binary form must reproduce the above copyright
13*2ed98337SAymeric Wibo * notice, this list of conditions and the following disclaimer in the
14*2ed98337SAymeric Wibo * documentation and/or other materials provided with the distribution.
15*2ed98337SAymeric Wibo *
16*2ed98337SAymeric Wibo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*2ed98337SAymeric Wibo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*2ed98337SAymeric Wibo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*2ed98337SAymeric Wibo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*2ed98337SAymeric Wibo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*2ed98337SAymeric Wibo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*2ed98337SAymeric Wibo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*2ed98337SAymeric Wibo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*2ed98337SAymeric Wibo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*2ed98337SAymeric Wibo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*2ed98337SAymeric Wibo * SUCH DAMAGE.
27*2ed98337SAymeric Wibo */
28*2ed98337SAymeric Wibo
29*2ed98337SAymeric Wibo #include "opt_thunderbolt.h"
30*2ed98337SAymeric Wibo
31*2ed98337SAymeric Wibo /* Userspace control device for USB4 / TB3 */
32*2ed98337SAymeric Wibo #include <sys/types.h>
33*2ed98337SAymeric Wibo #include <sys/param.h>
34*2ed98337SAymeric Wibo #include <sys/systm.h>
35*2ed98337SAymeric Wibo #include <sys/kernel.h>
36*2ed98337SAymeric Wibo #include <sys/module.h>
37*2ed98337SAymeric Wibo #include <sys/bus.h>
38*2ed98337SAymeric Wibo #include <sys/conf.h>
39*2ed98337SAymeric Wibo #include <sys/malloc.h>
40*2ed98337SAymeric Wibo #include <sys/queue.h>
41*2ed98337SAymeric Wibo #include <sys/sysctl.h>
42*2ed98337SAymeric Wibo #include <sys/lock.h>
43*2ed98337SAymeric Wibo #include <sys/mutex.h>
44*2ed98337SAymeric Wibo #include <sys/nv.h>
45*2ed98337SAymeric Wibo #include <sys/taskqueue.h>
46*2ed98337SAymeric Wibo #include <sys/gsb_crc32.h>
47*2ed98337SAymeric Wibo #include <sys/endian.h>
48*2ed98337SAymeric Wibo #include <vm/vm.h>
49*2ed98337SAymeric Wibo #include <vm/pmap.h>
50*2ed98337SAymeric Wibo
51*2ed98337SAymeric Wibo #include <machine/bus.h>
52*2ed98337SAymeric Wibo #include <machine/stdarg.h>
53*2ed98337SAymeric Wibo
54*2ed98337SAymeric Wibo #include <dev/thunderbolt/nhi_reg.h>
55*2ed98337SAymeric Wibo #include <dev/thunderbolt/nhi_var.h>
56*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_reg.h>
57*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_var.h>
58*2ed98337SAymeric Wibo #include <dev/thunderbolt/tbcfg_reg.h>
59*2ed98337SAymeric Wibo #include <dev/thunderbolt/router_var.h>
60*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_debug.h>
61*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_dev.h>
62*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_ioctl.h>
63*2ed98337SAymeric Wibo
64*2ed98337SAymeric Wibo struct tbdev_if;
65*2ed98337SAymeric Wibo struct tbdev_dm;
66*2ed98337SAymeric Wibo struct tbdev_rt;
67*2ed98337SAymeric Wibo
68*2ed98337SAymeric Wibo struct tbdev_if {
69*2ed98337SAymeric Wibo TAILQ_ENTRY(tbdev_if) dev_next;
70*2ed98337SAymeric Wibo char name[SPECNAMELEN];
71*2ed98337SAymeric Wibo };
72*2ed98337SAymeric Wibo
73*2ed98337SAymeric Wibo struct tbdev_dm {
74*2ed98337SAymeric Wibo TAILQ_ENTRY(tbdev_dm) dev_next;
75*2ed98337SAymeric Wibo char uid[16];
76*2ed98337SAymeric Wibo };
77*2ed98337SAymeric Wibo
78*2ed98337SAymeric Wibo struct tbdev_rt {
79*2ed98337SAymeric Wibo TAILQ_ENTRY(tbdev_rt) dev_next;
80*2ed98337SAymeric Wibo uint64_t route;
81*2ed98337SAymeric Wibo };
82*2ed98337SAymeric Wibo
83*2ed98337SAymeric Wibo static int tbdev_static_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td);
84*2ed98337SAymeric Wibo
85*2ed98337SAymeric Wibo static struct cdevsw tbdev_static_devsw = {
86*2ed98337SAymeric Wibo .d_version = D_VERSION,
87*2ed98337SAymeric Wibo .d_ioctl = tbdev_static_ioctl,
88*2ed98337SAymeric Wibo .d_name = "tbt"
89*2ed98337SAymeric Wibo };
90*2ed98337SAymeric Wibo static struct cdev *tb_dev = NULL;
91*2ed98337SAymeric Wibo
92*2ed98337SAymeric Wibo static TAILQ_HEAD(, tbdev_if) tbdev_head = TAILQ_HEAD_INITIALIZER(tbdev_head);
93*2ed98337SAymeric Wibo static TAILQ_HEAD(, tbdev_dm) tbdomain_head = TAILQ_HEAD_INITIALIZER(tbdomain_head);
94*2ed98337SAymeric Wibo static TAILQ_HEAD(, tbdev_rt) tbrouter_head = TAILQ_HEAD_INITIALIZER(tbrouter_head);
95*2ed98337SAymeric Wibo
96*2ed98337SAymeric Wibo static struct mtx tbdev_mtx;
97*2ed98337SAymeric Wibo MTX_SYSINIT(tbdev_mtx, &tbdev_mtx, "TBT Device Mutex", MTX_DEF);
98*2ed98337SAymeric Wibo
99*2ed98337SAymeric Wibo MALLOC_DEFINE(M_THUNDERBOLT, "thunderbolt", "memory for thunderbolt");
100*2ed98337SAymeric Wibo
101*2ed98337SAymeric Wibo static void
tbdev_init(void * arg)102*2ed98337SAymeric Wibo tbdev_init(void *arg)
103*2ed98337SAymeric Wibo {
104*2ed98337SAymeric Wibo
105*2ed98337SAymeric Wibo tb_dev = make_dev(&tbdev_static_devsw, 0, UID_ROOT, GID_OPERATOR,
106*2ed98337SAymeric Wibo 0644, TBT_DEVICE_NAME);
107*2ed98337SAymeric Wibo if (tb_dev == NULL)
108*2ed98337SAymeric Wibo printf("Cannot create Thunderbolt system device\n");
109*2ed98337SAymeric Wibo
110*2ed98337SAymeric Wibo return;
111*2ed98337SAymeric Wibo }
112*2ed98337SAymeric Wibo
113*2ed98337SAymeric Wibo SYSINIT(tbdev_init, SI_SUB_KICK_SCHEDULER, SI_ORDER_FIRST, tbdev_init, NULL);
114*2ed98337SAymeric Wibo
115*2ed98337SAymeric Wibo static void
tbdev_uninit(void * arg)116*2ed98337SAymeric Wibo tbdev_uninit(void *arg)
117*2ed98337SAymeric Wibo {
118*2ed98337SAymeric Wibo if (tb_dev != NULL) {
119*2ed98337SAymeric Wibo destroy_dev(tb_dev);
120*2ed98337SAymeric Wibo tb_dev = NULL;
121*2ed98337SAymeric Wibo }
122*2ed98337SAymeric Wibo }
123*2ed98337SAymeric Wibo
124*2ed98337SAymeric Wibo SYSUNINIT(tbdev_uninit, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, tbdev_uninit, NULL);
125*2ed98337SAymeric Wibo
126*2ed98337SAymeric Wibo int
tbdev_add_interface(struct nhi_softc * nhi)127*2ed98337SAymeric Wibo tbdev_add_interface(struct nhi_softc *nhi)
128*2ed98337SAymeric Wibo {
129*2ed98337SAymeric Wibo struct tbdev_if *ifce;
130*2ed98337SAymeric Wibo
131*2ed98337SAymeric Wibo ifce = malloc(sizeof(struct tbdev_if), M_THUNDERBOLT, M_ZERO|M_NOWAIT);
132*2ed98337SAymeric Wibo if (ifce == NULL)
133*2ed98337SAymeric Wibo return (ENOMEM);
134*2ed98337SAymeric Wibo
135*2ed98337SAymeric Wibo strlcpy(ifce->name, device_get_nameunit(nhi->dev), SPECNAMELEN);
136*2ed98337SAymeric Wibo mtx_lock(&tbdev_mtx);
137*2ed98337SAymeric Wibo TAILQ_INSERT_TAIL(&tbdev_head, ifce, dev_next);
138*2ed98337SAymeric Wibo mtx_unlock(&tbdev_mtx);
139*2ed98337SAymeric Wibo
140*2ed98337SAymeric Wibo return (0);
141*2ed98337SAymeric Wibo }
142*2ed98337SAymeric Wibo
143*2ed98337SAymeric Wibo int
tbdev_remove_interface(struct nhi_softc * nhi)144*2ed98337SAymeric Wibo tbdev_remove_interface(struct nhi_softc *nhi)
145*2ed98337SAymeric Wibo {
146*2ed98337SAymeric Wibo struct tbdev_if *ifce = NULL, *if_back;
147*2ed98337SAymeric Wibo const char *name;
148*2ed98337SAymeric Wibo
149*2ed98337SAymeric Wibo name = device_get_nameunit(nhi->dev);
150*2ed98337SAymeric Wibo mtx_lock(&tbdev_mtx);
151*2ed98337SAymeric Wibo TAILQ_FOREACH_SAFE(ifce, &tbdev_head, dev_next, if_back) {
152*2ed98337SAymeric Wibo if (strncmp(name, ifce->name, SPECNAMELEN) == 0) {
153*2ed98337SAymeric Wibo TAILQ_REMOVE(&tbdev_head, ifce, dev_next);
154*2ed98337SAymeric Wibo break;
155*2ed98337SAymeric Wibo }
156*2ed98337SAymeric Wibo }
157*2ed98337SAymeric Wibo mtx_unlock(&tbdev_mtx);
158*2ed98337SAymeric Wibo
159*2ed98337SAymeric Wibo if (ifce != NULL)
160*2ed98337SAymeric Wibo free(ifce, M_THUNDERBOLT);
161*2ed98337SAymeric Wibo
162*2ed98337SAymeric Wibo return (0);
163*2ed98337SAymeric Wibo }
164*2ed98337SAymeric Wibo
165*2ed98337SAymeric Wibo int
tbdev_add_domain(void * domain)166*2ed98337SAymeric Wibo tbdev_add_domain(void *domain)
167*2ed98337SAymeric Wibo {
168*2ed98337SAymeric Wibo
169*2ed98337SAymeric Wibo return (0);
170*2ed98337SAymeric Wibo }
171*2ed98337SAymeric Wibo
172*2ed98337SAymeric Wibo int
tbdev_remove_domain(void * domain)173*2ed98337SAymeric Wibo tbdev_remove_domain(void *domain)
174*2ed98337SAymeric Wibo {
175*2ed98337SAymeric Wibo
176*2ed98337SAymeric Wibo return (0);
177*2ed98337SAymeric Wibo }
178*2ed98337SAymeric Wibo
179*2ed98337SAymeric Wibo int
tbdev_add_router(struct router_softc * rt)180*2ed98337SAymeric Wibo tbdev_add_router(struct router_softc *rt)
181*2ed98337SAymeric Wibo {
182*2ed98337SAymeric Wibo
183*2ed98337SAymeric Wibo return (0);
184*2ed98337SAymeric Wibo }
185*2ed98337SAymeric Wibo
186*2ed98337SAymeric Wibo int
tbdev_remove_router(struct router_softc * rt)187*2ed98337SAymeric Wibo tbdev_remove_router(struct router_softc *rt)
188*2ed98337SAymeric Wibo {
189*2ed98337SAymeric Wibo
190*2ed98337SAymeric Wibo return (0);
191*2ed98337SAymeric Wibo }
192*2ed98337SAymeric Wibo
193*2ed98337SAymeric Wibo static int
tbdev_discover(caddr_t addr)194*2ed98337SAymeric Wibo tbdev_discover(caddr_t addr)
195*2ed98337SAymeric Wibo {
196*2ed98337SAymeric Wibo nvlist_t *nvl = NULL;
197*2ed98337SAymeric Wibo struct tbt_ioc *ioc = (struct tbt_ioc *)addr;
198*2ed98337SAymeric Wibo struct tbdev_if *dev;
199*2ed98337SAymeric Wibo struct tbdev_dm *dm;
200*2ed98337SAymeric Wibo struct tbdev_rt *rt;
201*2ed98337SAymeric Wibo void *nvlpacked = NULL;
202*2ed98337SAymeric Wibo const char *cmd = NULL;
203*2ed98337SAymeric Wibo int error = 0;
204*2ed98337SAymeric Wibo
205*2ed98337SAymeric Wibo if ((ioc->data == NULL) || (ioc->size == 0)) {
206*2ed98337SAymeric Wibo printf("data or size is 0\n");
207*2ed98337SAymeric Wibo return (EINVAL);
208*2ed98337SAymeric Wibo }
209*2ed98337SAymeric Wibo
210*2ed98337SAymeric Wibo if ((ioc->len == 0) || (ioc->len > TBT_IOCMAXLEN) ||
211*2ed98337SAymeric Wibo (ioc->len > ioc->size)) {
212*2ed98337SAymeric Wibo printf("len is wrong\n");
213*2ed98337SAymeric Wibo return (EINVAL);
214*2ed98337SAymeric Wibo }
215*2ed98337SAymeric Wibo
216*2ed98337SAymeric Wibo nvlpacked = malloc(ioc->len, M_THUNDERBOLT, M_NOWAIT);
217*2ed98337SAymeric Wibo if (nvlpacked == NULL) {
218*2ed98337SAymeric Wibo printf("cannot allocate nvlpacked\n");
219*2ed98337SAymeric Wibo return (ENOMEM);
220*2ed98337SAymeric Wibo }
221*2ed98337SAymeric Wibo
222*2ed98337SAymeric Wibo error = copyin(ioc->data, nvlpacked, ioc->len);
223*2ed98337SAymeric Wibo if (error) {
224*2ed98337SAymeric Wibo free(nvlpacked, M_THUNDERBOLT);
225*2ed98337SAymeric Wibo printf("error %d from copyin\n", error);
226*2ed98337SAymeric Wibo return (error);
227*2ed98337SAymeric Wibo }
228*2ed98337SAymeric Wibo
229*2ed98337SAymeric Wibo nvl = nvlist_unpack(nvlpacked, ioc->len, NV_FLAG_NO_UNIQUE);
230*2ed98337SAymeric Wibo if (nvl == NULL) {
231*2ed98337SAymeric Wibo free(nvlpacked, M_THUNDERBOLT);
232*2ed98337SAymeric Wibo printf("cannot unpack nvlist\n");
233*2ed98337SAymeric Wibo return (EINVAL);
234*2ed98337SAymeric Wibo }
235*2ed98337SAymeric Wibo free(nvlpacked, M_THUNDERBOLT);
236*2ed98337SAymeric Wibo nvlpacked = NULL;
237*2ed98337SAymeric Wibo
238*2ed98337SAymeric Wibo if (nvlist_exists_string(nvl, TBT_DISCOVER_TYPE))
239*2ed98337SAymeric Wibo cmd = nvlist_get_string(nvl, TBT_DISCOVER_TYPE);
240*2ed98337SAymeric Wibo if (cmd == NULL) {
241*2ed98337SAymeric Wibo printf("cannot find type string\n");
242*2ed98337SAymeric Wibo error = EINVAL;
243*2ed98337SAymeric Wibo goto out;
244*2ed98337SAymeric Wibo }
245*2ed98337SAymeric Wibo
246*2ed98337SAymeric Wibo mtx_lock(&tbdev_mtx);
247*2ed98337SAymeric Wibo if (strncmp(cmd, TBT_DISCOVER_IFACE, TBT_NAMLEN) == 0) {
248*2ed98337SAymeric Wibo TAILQ_FOREACH(dev, &tbdev_head, dev_next)
249*2ed98337SAymeric Wibo nvlist_add_string(nvl, TBT_DISCOVER_IFACE, dev->name);
250*2ed98337SAymeric Wibo } else if (strncmp(cmd, TBT_DISCOVER_DOMAIN, TBT_NAMLEN) == 0) {
251*2ed98337SAymeric Wibo TAILQ_FOREACH(dm, &tbdomain_head, dev_next)
252*2ed98337SAymeric Wibo nvlist_add_string(nvl, TBT_DISCOVER_DOMAIN, dm->uid);
253*2ed98337SAymeric Wibo } else if (strncmp(cmd, TBT_DISCOVER_ROUTER, TBT_NAMLEN) == 0) {
254*2ed98337SAymeric Wibo TAILQ_FOREACH(rt, &tbrouter_head, dev_next)
255*2ed98337SAymeric Wibo nvlist_add_number(nvl, TBT_DISCOVER_ROUTER, rt->route);
256*2ed98337SAymeric Wibo } else {
257*2ed98337SAymeric Wibo printf("cannot find supported tpye\n");
258*2ed98337SAymeric Wibo error = EINVAL;
259*2ed98337SAymeric Wibo goto out;
260*2ed98337SAymeric Wibo }
261*2ed98337SAymeric Wibo mtx_unlock(&tbdev_mtx);
262*2ed98337SAymeric Wibo
263*2ed98337SAymeric Wibo error = nvlist_error(nvl);
264*2ed98337SAymeric Wibo if (error != 0) {
265*2ed98337SAymeric Wibo printf("error %d state in nvlist\n", error);
266*2ed98337SAymeric Wibo return (error);
267*2ed98337SAymeric Wibo }
268*2ed98337SAymeric Wibo
269*2ed98337SAymeric Wibo nvlpacked = nvlist_pack(nvl, &ioc->len);
270*2ed98337SAymeric Wibo if (nvlpacked == NULL) {
271*2ed98337SAymeric Wibo printf("cannot allocate new packed buffer\n");
272*2ed98337SAymeric Wibo return (ENOMEM);
273*2ed98337SAymeric Wibo }
274*2ed98337SAymeric Wibo if (ioc->size < ioc->len) {
275*2ed98337SAymeric Wibo printf("packed buffer is too big to copyout\n");
276*2ed98337SAymeric Wibo return (ENOSPC);
277*2ed98337SAymeric Wibo }
278*2ed98337SAymeric Wibo
279*2ed98337SAymeric Wibo error = copyout(nvlpacked, ioc->data, ioc->len);
280*2ed98337SAymeric Wibo if (error)
281*2ed98337SAymeric Wibo printf("error %d on copyout\n", error);
282*2ed98337SAymeric Wibo
283*2ed98337SAymeric Wibo out:
284*2ed98337SAymeric Wibo if (nvlpacked != NULL)
285*2ed98337SAymeric Wibo free(nvlpacked, M_NVLIST);
286*2ed98337SAymeric Wibo if (nvl != NULL)
287*2ed98337SAymeric Wibo nvlist_destroy(nvl);
288*2ed98337SAymeric Wibo
289*2ed98337SAymeric Wibo return (error);
290*2ed98337SAymeric Wibo }
291*2ed98337SAymeric Wibo
292*2ed98337SAymeric Wibo static int
tbdev_request(caddr_t addr)293*2ed98337SAymeric Wibo tbdev_request(caddr_t addr)
294*2ed98337SAymeric Wibo {
295*2ed98337SAymeric Wibo struct tbt_ioc *ioc = (struct tbt_ioc *)addr;
296*2ed98337SAymeric Wibo nvlist_t *nvl = NULL;
297*2ed98337SAymeric Wibo void *nvlpacked = NULL;
298*2ed98337SAymeric Wibo int error = 0;
299*2ed98337SAymeric Wibo
300*2ed98337SAymeric Wibo if ((ioc->data == NULL) || (ioc->size == 0))
301*2ed98337SAymeric Wibo return (ENOMEM);
302*2ed98337SAymeric Wibo
303*2ed98337SAymeric Wibo nvlpacked = nvlist_pack(nvl, &ioc->len);
304*2ed98337SAymeric Wibo if (nvlpacked == NULL)
305*2ed98337SAymeric Wibo return (ENOMEM);
306*2ed98337SAymeric Wibo if (ioc->size < ioc->len)
307*2ed98337SAymeric Wibo return (ENOSPC);
308*2ed98337SAymeric Wibo
309*2ed98337SAymeric Wibo error = copyout(nvlpacked, ioc->data, ioc->len);
310*2ed98337SAymeric Wibo return (error);
311*2ed98337SAymeric Wibo }
312*2ed98337SAymeric Wibo
313*2ed98337SAymeric Wibo static int
tbdev_static_ioctl(struct cdev * dev,u_long cmd,caddr_t addr,int flags,struct thread * td)314*2ed98337SAymeric Wibo tbdev_static_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
315*2ed98337SAymeric Wibo struct thread *td)
316*2ed98337SAymeric Wibo {
317*2ed98337SAymeric Wibo int error = 0;
318*2ed98337SAymeric Wibo
319*2ed98337SAymeric Wibo switch (cmd) {
320*2ed98337SAymeric Wibo case TBT_DISCOVER:
321*2ed98337SAymeric Wibo error = tbdev_discover(addr);
322*2ed98337SAymeric Wibo break;
323*2ed98337SAymeric Wibo case TBT_REQUEST:
324*2ed98337SAymeric Wibo error = tbdev_request(addr);
325*2ed98337SAymeric Wibo break;
326*2ed98337SAymeric Wibo default:
327*2ed98337SAymeric Wibo error = EINVAL;
328*2ed98337SAymeric Wibo }
329*2ed98337SAymeric Wibo
330*2ed98337SAymeric Wibo return (error);
331*2ed98337SAymeric Wibo }
332