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 /* Config space access for switches, ports, and devices in TB3 and USB4 */
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/taskqueue.h>
45*2ed98337SAymeric Wibo #include <sys/gsb_crc32.h>
46*2ed98337SAymeric Wibo #include <sys/endian.h>
47*2ed98337SAymeric Wibo #include <vm/vm.h>
48*2ed98337SAymeric Wibo #include <vm/pmap.h>
49*2ed98337SAymeric Wibo
50*2ed98337SAymeric Wibo #include <machine/bus.h>
51*2ed98337SAymeric Wibo #include <machine/stdarg.h>
52*2ed98337SAymeric Wibo
53*2ed98337SAymeric Wibo #include <dev/thunderbolt/nhi_reg.h>
54*2ed98337SAymeric Wibo #include <dev/thunderbolt/nhi_var.h>
55*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_reg.h>
56*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_var.h>
57*2ed98337SAymeric Wibo #include <dev/thunderbolt/tbcfg_reg.h>
58*2ed98337SAymeric Wibo #include <dev/thunderbolt/router_var.h>
59*2ed98337SAymeric Wibo #include <dev/thunderbolt/tb_debug.h>
60*2ed98337SAymeric Wibo
61*2ed98337SAymeric Wibo static int router_alloc_cmd(struct router_softc *, struct router_command **);
62*2ed98337SAymeric Wibo static void router_free_cmd(struct router_softc *, struct router_command *);
63*2ed98337SAymeric Wibo static int _tb_router_attach(struct router_softc *);
64*2ed98337SAymeric Wibo static void router_prepare_read(struct router_softc *, struct router_command *,
65*2ed98337SAymeric Wibo int);
66*2ed98337SAymeric Wibo static int _tb_config_read(struct router_softc *, u_int, u_int, u_int, u_int,
67*2ed98337SAymeric Wibo uint32_t *, void *, struct router_command **);
68*2ed98337SAymeric Wibo static int router_schedule(struct router_softc *, struct router_command *);
69*2ed98337SAymeric Wibo static int router_schedule_locked(struct router_softc *,
70*2ed98337SAymeric Wibo struct router_command *);
71*2ed98337SAymeric Wibo static nhi_ring_cb_t router_complete_intr;
72*2ed98337SAymeric Wibo static nhi_ring_cb_t router_response_intr;
73*2ed98337SAymeric Wibo static nhi_ring_cb_t router_notify_intr;
74*2ed98337SAymeric Wibo
75*2ed98337SAymeric Wibo #define CFG_DEFAULT_RETRIES 3
76*2ed98337SAymeric Wibo #define CFG_DEFAULT_TIMEOUT 2
77*2ed98337SAymeric Wibo
78*2ed98337SAymeric Wibo static int
router_lookup_device(struct router_softc * sc,tb_route_t route,struct router_softc ** dev)79*2ed98337SAymeric Wibo router_lookup_device(struct router_softc *sc, tb_route_t route,
80*2ed98337SAymeric Wibo struct router_softc **dev)
81*2ed98337SAymeric Wibo {
82*2ed98337SAymeric Wibo struct router_softc *cursor;
83*2ed98337SAymeric Wibo uint64_t search_rt, remainder_rt, this_rt;
84*2ed98337SAymeric Wibo uint8_t hop;
85*2ed98337SAymeric Wibo
86*2ed98337SAymeric Wibo KASSERT(dev != NULL, ("dev cannot be NULL\n"));
87*2ed98337SAymeric Wibo
88*2ed98337SAymeric Wibo cursor = tb_config_get_root(sc);
89*2ed98337SAymeric Wibo remainder_rt = search_rt = route.lo | ((uint64_t)route.hi << 32);
90*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
91*2ed98337SAymeric Wibo "%s: Searching for router 0x%016jx\n", __func__, search_rt);
92*2ed98337SAymeric Wibo
93*2ed98337SAymeric Wibo while (cursor != NULL) {
94*2ed98337SAymeric Wibo this_rt = TB_ROUTE(cursor);
95*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
96*2ed98337SAymeric Wibo "Comparing cursor route 0x%016jx\n", this_rt);
97*2ed98337SAymeric Wibo if (this_rt == search_rt)
98*2ed98337SAymeric Wibo break;
99*2ed98337SAymeric Wibo
100*2ed98337SAymeric Wibo /* Prepare to go to the next hop node in the route */
101*2ed98337SAymeric Wibo hop = remainder_rt & 0xff;
102*2ed98337SAymeric Wibo remainder_rt >>= 8;
103*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
104*2ed98337SAymeric Wibo "hop= 0x%02x, remainder= 0x%016jx\n", hop, remainder_rt);
105*2ed98337SAymeric Wibo
106*2ed98337SAymeric Wibo /*
107*2ed98337SAymeric Wibo * An adapter index of 0x0 is only for the host interface
108*2ed98337SAymeric Wibo * adapter on the root route. The only time that
109*2ed98337SAymeric Wibo * it's valid for searches is when you're looking for the
110*2ed98337SAymeric Wibo * root route, and that case has already been handled.
111*2ed98337SAymeric Wibo */
112*2ed98337SAymeric Wibo if (hop == 0) {
113*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER,
114*2ed98337SAymeric Wibo "End of route chain, route not found\n");
115*2ed98337SAymeric Wibo return (ENOENT);
116*2ed98337SAymeric Wibo }
117*2ed98337SAymeric Wibo
118*2ed98337SAymeric Wibo if (hop > cursor->max_adap) {
119*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER,
120*2ed98337SAymeric Wibo "Route hop out of range for parent\n");
121*2ed98337SAymeric Wibo return (EINVAL);
122*2ed98337SAymeric Wibo }
123*2ed98337SAymeric Wibo
124*2ed98337SAymeric Wibo if (cursor->adapters == NULL) {
125*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER,
126*2ed98337SAymeric Wibo "Error, router not fully initialized\n");
127*2ed98337SAymeric Wibo return (EINVAL);
128*2ed98337SAymeric Wibo }
129*2ed98337SAymeric Wibo
130*2ed98337SAymeric Wibo cursor = cursor->adapters[hop];
131*2ed98337SAymeric Wibo }
132*2ed98337SAymeric Wibo
133*2ed98337SAymeric Wibo if (cursor == NULL)
134*2ed98337SAymeric Wibo return (ENOENT);
135*2ed98337SAymeric Wibo
136*2ed98337SAymeric Wibo *dev = cursor;
137*2ed98337SAymeric Wibo return (0);
138*2ed98337SAymeric Wibo }
139*2ed98337SAymeric Wibo
140*2ed98337SAymeric Wibo static int
router_insert(struct router_softc * sc,struct router_softc * parent)141*2ed98337SAymeric Wibo router_insert(struct router_softc *sc, struct router_softc *parent)
142*2ed98337SAymeric Wibo {
143*2ed98337SAymeric Wibo uint64_t this_rt;
144*2ed98337SAymeric Wibo uint8_t this_hop;
145*2ed98337SAymeric Wibo
146*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_insert called\n");
147*2ed98337SAymeric Wibo
148*2ed98337SAymeric Wibo if (parent == NULL) {
149*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER, "Parent cannot be NULL in insert\n");
150*2ed98337SAymeric Wibo return (EINVAL);
151*2ed98337SAymeric Wibo }
152*2ed98337SAymeric Wibo
153*2ed98337SAymeric Wibo this_rt = TB_ROUTE(sc);
154*2ed98337SAymeric Wibo if (((this_rt >> (sc->depth * 8)) > 0xffULL) ||
155*2ed98337SAymeric Wibo (parent->depth + 1 != sc->depth)) {
156*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER, "Added route 0x%08x%08x is not a "
157*2ed98337SAymeric Wibo "direct child of the parent route 0x%08x%08x\n",
158*2ed98337SAymeric Wibo sc->route.hi, sc->route.lo, parent->route.hi,
159*2ed98337SAymeric Wibo parent->route.lo);
160*2ed98337SAymeric Wibo return (EINVAL);
161*2ed98337SAymeric Wibo }
162*2ed98337SAymeric Wibo
163*2ed98337SAymeric Wibo this_hop = (uint8_t)(this_rt >> (sc->depth * 8));
164*2ed98337SAymeric Wibo
165*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER, "Inserting route 0x%08x%08x with last hop "
166*2ed98337SAymeric Wibo "of 0x%02x and depth of %d\n", sc->route.hi, sc->route.lo,
167*2ed98337SAymeric Wibo this_hop, sc->depth);
168*2ed98337SAymeric Wibo
169*2ed98337SAymeric Wibo if (this_hop > parent->max_adap) {
170*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
171*2ed98337SAymeric Wibo "Inserted route is out of range of the parent\n");
172*2ed98337SAymeric Wibo return (EINVAL);
173*2ed98337SAymeric Wibo }
174*2ed98337SAymeric Wibo
175*2ed98337SAymeric Wibo if (parent->adapters[this_hop] != NULL) {
176*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
177*2ed98337SAymeric Wibo "Inserted route already exists\n");
178*2ed98337SAymeric Wibo return (EEXIST);
179*2ed98337SAymeric Wibo }
180*2ed98337SAymeric Wibo
181*2ed98337SAymeric Wibo parent->adapters[this_hop] = sc;
182*2ed98337SAymeric Wibo
183*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER, "Added router 0x%08x%08x to parent "
184*2ed98337SAymeric Wibo "0x%08x%08x\n", sc->route.hi, sc->route.lo, parent->route.hi,
185*2ed98337SAymeric Wibo parent->route.lo);
186*2ed98337SAymeric Wibo return (0);
187*2ed98337SAymeric Wibo }
188*2ed98337SAymeric Wibo
189*2ed98337SAymeric Wibo static int
router_register_interrupts(struct router_softc * sc)190*2ed98337SAymeric Wibo router_register_interrupts(struct router_softc *sc)
191*2ed98337SAymeric Wibo {
192*2ed98337SAymeric Wibo struct nhi_dispatch tx[] = { { PDF_READ, router_complete_intr, sc },
193*2ed98337SAymeric Wibo { PDF_WRITE, router_complete_intr, sc },
194*2ed98337SAymeric Wibo { 0, NULL, NULL } };
195*2ed98337SAymeric Wibo struct nhi_dispatch rx[] = { { PDF_READ, router_response_intr, sc },
196*2ed98337SAymeric Wibo { PDF_WRITE, router_response_intr, sc },
197*2ed98337SAymeric Wibo { PDF_NOTIFY, router_notify_intr, sc },
198*2ed98337SAymeric Wibo { 0, NULL, NULL } };
199*2ed98337SAymeric Wibo
200*2ed98337SAymeric Wibo return (nhi_register_pdf(sc->ring0, tx, rx));
201*2ed98337SAymeric Wibo }
202*2ed98337SAymeric Wibo
203*2ed98337SAymeric Wibo int
tb_router_attach(struct router_softc * parent,tb_route_t route)204*2ed98337SAymeric Wibo tb_router_attach(struct router_softc *parent, tb_route_t route)
205*2ed98337SAymeric Wibo {
206*2ed98337SAymeric Wibo struct router_softc *sc;
207*2ed98337SAymeric Wibo
208*2ed98337SAymeric Wibo tb_debug(parent, DBG_ROUTER|DBG_EXTRA, "tb_router_attach called\n");
209*2ed98337SAymeric Wibo
210*2ed98337SAymeric Wibo sc = malloc(sizeof(*sc), M_THUNDERBOLT, M_ZERO|M_NOWAIT);
211*2ed98337SAymeric Wibo if (sc == NULL) {
212*2ed98337SAymeric Wibo tb_debug(parent, DBG_ROUTER, "Cannot allocate root router\n");
213*2ed98337SAymeric Wibo return (ENOMEM);
214*2ed98337SAymeric Wibo }
215*2ed98337SAymeric Wibo
216*2ed98337SAymeric Wibo sc->dev = parent->dev;
217*2ed98337SAymeric Wibo sc->debug = parent->debug;
218*2ed98337SAymeric Wibo sc->ring0 = parent->ring0;
219*2ed98337SAymeric Wibo sc->route = route;
220*2ed98337SAymeric Wibo sc->nsc = parent->nsc;
221*2ed98337SAymeric Wibo
222*2ed98337SAymeric Wibo mtx_init(&sc->mtx, "tbcfg", "Thunderbolt Router Config", MTX_DEF);
223*2ed98337SAymeric Wibo TAILQ_INIT(&sc->cmd_queue);
224*2ed98337SAymeric Wibo
225*2ed98337SAymeric Wibo router_insert(sc, parent);
226*2ed98337SAymeric Wibo
227*2ed98337SAymeric Wibo return (_tb_router_attach(sc));
228*2ed98337SAymeric Wibo }
229*2ed98337SAymeric Wibo
230*2ed98337SAymeric Wibo int
tb_router_attach_root(struct nhi_softc * nsc,tb_route_t route)231*2ed98337SAymeric Wibo tb_router_attach_root(struct nhi_softc *nsc, tb_route_t route)
232*2ed98337SAymeric Wibo {
233*2ed98337SAymeric Wibo struct router_softc *sc;
234*2ed98337SAymeric Wibo int error;
235*2ed98337SAymeric Wibo
236*2ed98337SAymeric Wibo tb_debug(nsc, DBG_ROUTER|DBG_EXTRA, "tb_router_attach_root called\n");
237*2ed98337SAymeric Wibo
238*2ed98337SAymeric Wibo sc = malloc(sizeof(*sc), M_THUNDERBOLT, M_ZERO|M_NOWAIT);
239*2ed98337SAymeric Wibo if (sc == NULL) {
240*2ed98337SAymeric Wibo tb_debug(nsc, DBG_ROUTER, "Cannot allocate root router\n");
241*2ed98337SAymeric Wibo return (ENOMEM);
242*2ed98337SAymeric Wibo }
243*2ed98337SAymeric Wibo
244*2ed98337SAymeric Wibo sc->dev = nsc->dev;
245*2ed98337SAymeric Wibo sc->debug = nsc->debug;
246*2ed98337SAymeric Wibo sc->ring0 = nsc->ring0;
247*2ed98337SAymeric Wibo sc->route = route;
248*2ed98337SAymeric Wibo sc->nsc = nsc;
249*2ed98337SAymeric Wibo
250*2ed98337SAymeric Wibo mtx_init(&sc->mtx, "tbcfg", "Thunderbolt Router Config", MTX_DEF);
251*2ed98337SAymeric Wibo TAILQ_INIT(&sc->cmd_queue);
252*2ed98337SAymeric Wibo
253*2ed98337SAymeric Wibo /*
254*2ed98337SAymeric Wibo * This router is semi-virtual and represents the router that's part
255*2ed98337SAymeric Wibo * of the NHI DMA engine. Commands can't be issued to the topology
256*2ed98337SAymeric Wibo * until the NHI is initialized and this router is initialized, so
257*2ed98337SAymeric Wibo * there's no point in registering router interrupts earlier than this,
258*2ed98337SAymeric Wibo * even if other routers are found first.
259*2ed98337SAymeric Wibo */
260*2ed98337SAymeric Wibo tb_config_set_root(sc);
261*2ed98337SAymeric Wibo error = router_register_interrupts(sc);
262*2ed98337SAymeric Wibo if (error) {
263*2ed98337SAymeric Wibo tb_router_detach(sc);
264*2ed98337SAymeric Wibo return (error);
265*2ed98337SAymeric Wibo }
266*2ed98337SAymeric Wibo
267*2ed98337SAymeric Wibo error = _tb_router_attach(sc);
268*2ed98337SAymeric Wibo if (error)
269*2ed98337SAymeric Wibo return (error);
270*2ed98337SAymeric Wibo
271*2ed98337SAymeric Wibo bcopy((uint8_t *)sc->uuid, nsc->uuid, 16);
272*2ed98337SAymeric Wibo return (0);
273*2ed98337SAymeric Wibo }
274*2ed98337SAymeric Wibo
275*2ed98337SAymeric Wibo static int
_tb_router_attach(struct router_softc * sc)276*2ed98337SAymeric Wibo _tb_router_attach(struct router_softc *sc)
277*2ed98337SAymeric Wibo {
278*2ed98337SAymeric Wibo struct tb_cfg_router *cfg;
279*2ed98337SAymeric Wibo uint32_t *buf;
280*2ed98337SAymeric Wibo int error, up;
281*2ed98337SAymeric Wibo
282*2ed98337SAymeric Wibo buf = malloc(9 * 4, M_THUNDERBOLT, M_NOWAIT|M_ZERO);
283*2ed98337SAymeric Wibo if (buf == NULL)
284*2ed98337SAymeric Wibo return (ENOMEM);
285*2ed98337SAymeric Wibo
286*2ed98337SAymeric Wibo error = tb_config_router_read_polled(sc, 0, 9, buf);
287*2ed98337SAymeric Wibo if (error != 0) {
288*2ed98337SAymeric Wibo free(buf, M_THUNDERBOLT);
289*2ed98337SAymeric Wibo return (error);
290*2ed98337SAymeric Wibo }
291*2ed98337SAymeric Wibo
292*2ed98337SAymeric Wibo cfg = (struct tb_cfg_router *)buf;
293*2ed98337SAymeric Wibo up = GET_ROUTER_CS_UPSTREAM_ADAP(cfg);
294*2ed98337SAymeric Wibo sc->max_adap = GET_ROUTER_CS_MAX_ADAP(cfg);
295*2ed98337SAymeric Wibo sc->depth = GET_ROUTER_CS_DEPTH(cfg);
296*2ed98337SAymeric Wibo sc->uuid[0] = cfg->uuid_lo;
297*2ed98337SAymeric Wibo sc->uuid[1] = cfg->uuid_hi;
298*2ed98337SAymeric Wibo sc->uuid[2] = 0xffffffff;
299*2ed98337SAymeric Wibo sc->uuid[3] = 0xffffffff;
300*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER, "Router upstream_port= %d, max_port= %d, "
301*2ed98337SAymeric Wibo "depth= %d\n", up, sc->max_adap, sc->depth);
302*2ed98337SAymeric Wibo free(buf, M_THUNDERBOLT);
303*2ed98337SAymeric Wibo
304*2ed98337SAymeric Wibo /* Downstream adapters are indexed in the array allocated here. */
305*2ed98337SAymeric Wibo sc->max_adap = MIN(sc->max_adap, ROUTER_CS1_MAX_ADAPTERS);
306*2ed98337SAymeric Wibo sc->adapters = malloc((1 + sc->max_adap) * sizeof(void *),
307*2ed98337SAymeric Wibo M_THUNDERBOLT, M_NOWAIT|M_ZERO);
308*2ed98337SAymeric Wibo if (sc->adapters == NULL) {
309*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER,
310*2ed98337SAymeric Wibo "Cannot allocate downstream adapter memory\n");
311*2ed98337SAymeric Wibo return (ENOMEM);
312*2ed98337SAymeric Wibo }
313*2ed98337SAymeric Wibo
314*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER, "Router created, route 0x%08x%08x\n",
315*2ed98337SAymeric Wibo sc->route.hi, sc->route.lo);
316*2ed98337SAymeric Wibo
317*2ed98337SAymeric Wibo return (0);
318*2ed98337SAymeric Wibo }
319*2ed98337SAymeric Wibo
320*2ed98337SAymeric Wibo int
tb_router_detach(struct router_softc * sc)321*2ed98337SAymeric Wibo tb_router_detach(struct router_softc *sc)
322*2ed98337SAymeric Wibo {
323*2ed98337SAymeric Wibo
324*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "tb_router_deattach called\n");
325*2ed98337SAymeric Wibo
326*2ed98337SAymeric Wibo if (TAILQ_FIRST(&sc->cmd_queue) != NULL)
327*2ed98337SAymeric Wibo return (EBUSY);
328*2ed98337SAymeric Wibo
329*2ed98337SAymeric Wibo mtx_destroy(&sc->mtx);
330*2ed98337SAymeric Wibo
331*2ed98337SAymeric Wibo if (sc->adapters != NULL)
332*2ed98337SAymeric Wibo free(sc->adapters, M_THUNDERBOLT);
333*2ed98337SAymeric Wibo
334*2ed98337SAymeric Wibo if (sc != NULL)
335*2ed98337SAymeric Wibo free(sc, M_THUNDERBOLT);
336*2ed98337SAymeric Wibo
337*2ed98337SAymeric Wibo return (0);
338*2ed98337SAymeric Wibo }
339*2ed98337SAymeric Wibo
340*2ed98337SAymeric Wibo static void
router_get_config_cb(struct router_softc * sc,struct router_command * cmd,void * arg)341*2ed98337SAymeric Wibo router_get_config_cb(struct router_softc *sc, struct router_command *cmd,
342*2ed98337SAymeric Wibo void *arg)
343*2ed98337SAymeric Wibo {
344*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_get_config_cb called\n");
345*2ed98337SAymeric Wibo
346*2ed98337SAymeric Wibo /*
347*2ed98337SAymeric Wibo * Only do the copy if the command didn't have a notify event thrown.
348*2ed98337SAymeric Wibo * These events serve as asynchronous exception signals, which is
349*2ed98337SAymeric Wibo * cumbersome.
350*2ed98337SAymeric Wibo */
351*2ed98337SAymeric Wibo if (cmd->ev == 0)
352*2ed98337SAymeric Wibo bcopy((uint8_t *)cmd->resp_buffer,
353*2ed98337SAymeric Wibo (uint8_t *)cmd->callback_arg, cmd->dwlen * 4);
354*2ed98337SAymeric Wibo
355*2ed98337SAymeric Wibo mtx_lock(&sc->mtx);
356*2ed98337SAymeric Wibo sc->inflight_cmd = NULL;
357*2ed98337SAymeric Wibo
358*2ed98337SAymeric Wibo if ((cmd->flags & RCMD_POLLED) == 0)
359*2ed98337SAymeric Wibo wakeup(cmd);
360*2ed98337SAymeric Wibo else
361*2ed98337SAymeric Wibo cmd->flags |= RCMD_POLL_COMPLETE;
362*2ed98337SAymeric Wibo
363*2ed98337SAymeric Wibo router_schedule_locked(sc, NULL);
364*2ed98337SAymeric Wibo mtx_unlock(&sc->mtx);
365*2ed98337SAymeric Wibo }
366*2ed98337SAymeric Wibo
367*2ed98337SAymeric Wibo int
tb_config_read(struct router_softc * sc,u_int space,u_int adapter,u_int offset,u_int dwlen,uint32_t * buf)368*2ed98337SAymeric Wibo tb_config_read(struct router_softc *sc, u_int space, u_int adapter,
369*2ed98337SAymeric Wibo u_int offset, u_int dwlen, uint32_t *buf)
370*2ed98337SAymeric Wibo {
371*2ed98337SAymeric Wibo struct router_command *cmd;
372*2ed98337SAymeric Wibo int error, retries;
373*2ed98337SAymeric Wibo
374*2ed98337SAymeric Wibo if ((error = _tb_config_read(sc, space, adapter, offset, dwlen, buf,
375*2ed98337SAymeric Wibo router_get_config_cb, &cmd)) != 0)
376*2ed98337SAymeric Wibo return (error);
377*2ed98337SAymeric Wibo
378*2ed98337SAymeric Wibo retries = cmd->retries;
379*2ed98337SAymeric Wibo mtx_lock(&sc->mtx);
380*2ed98337SAymeric Wibo while (retries-- >= 0) {
381*2ed98337SAymeric Wibo error = router_schedule_locked(sc, cmd);
382*2ed98337SAymeric Wibo if (error)
383*2ed98337SAymeric Wibo break;
384*2ed98337SAymeric Wibo
385*2ed98337SAymeric Wibo error = msleep(cmd, &sc->mtx, 0, "tbtcfg", cmd->timeout * hz);
386*2ed98337SAymeric Wibo if (error != EWOULDBLOCK)
387*2ed98337SAymeric Wibo break;
388*2ed98337SAymeric Wibo sc->inflight_cmd = NULL;
389*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER, "Config command timed out, retries=%d\n", retries);
390*2ed98337SAymeric Wibo }
391*2ed98337SAymeric Wibo
392*2ed98337SAymeric Wibo if (cmd->ev != 0)
393*2ed98337SAymeric Wibo error = EINVAL;
394*2ed98337SAymeric Wibo router_free_cmd(sc, cmd);
395*2ed98337SAymeric Wibo mtx_unlock(&sc->mtx);
396*2ed98337SAymeric Wibo return (error);
397*2ed98337SAymeric Wibo }
398*2ed98337SAymeric Wibo
399*2ed98337SAymeric Wibo int
tb_config_read_polled(struct router_softc * sc,u_int space,u_int adapter,u_int offset,u_int dwlen,uint32_t * buf)400*2ed98337SAymeric Wibo tb_config_read_polled(struct router_softc *sc, u_int space, u_int adapter,
401*2ed98337SAymeric Wibo u_int offset, u_int dwlen, uint32_t *buf)
402*2ed98337SAymeric Wibo {
403*2ed98337SAymeric Wibo struct router_command *cmd;
404*2ed98337SAymeric Wibo int error, retries, timeout;
405*2ed98337SAymeric Wibo
406*2ed98337SAymeric Wibo if ((error = _tb_config_read(sc, space, adapter, offset, dwlen, buf,
407*2ed98337SAymeric Wibo router_get_config_cb, &cmd)) != 0)
408*2ed98337SAymeric Wibo return (error);
409*2ed98337SAymeric Wibo
410*2ed98337SAymeric Wibo retries = cmd->retries;
411*2ed98337SAymeric Wibo cmd->flags |= RCMD_POLLED;
412*2ed98337SAymeric Wibo timeout = cmd->timeout * 1000000;
413*2ed98337SAymeric Wibo
414*2ed98337SAymeric Wibo mtx_lock(&sc->mtx);
415*2ed98337SAymeric Wibo while (retries-- >= 0) {
416*2ed98337SAymeric Wibo error = router_schedule_locked(sc, cmd);
417*2ed98337SAymeric Wibo if (error)
418*2ed98337SAymeric Wibo break;
419*2ed98337SAymeric Wibo mtx_unlock(&sc->mtx);
420*2ed98337SAymeric Wibo
421*2ed98337SAymeric Wibo while (timeout > 0) {
422*2ed98337SAymeric Wibo DELAY(100 * 1000);
423*2ed98337SAymeric Wibo if ((cmd->flags & RCMD_POLL_COMPLETE) != 0)
424*2ed98337SAymeric Wibo break;
425*2ed98337SAymeric Wibo timeout -= 100000;
426*2ed98337SAymeric Wibo }
427*2ed98337SAymeric Wibo
428*2ed98337SAymeric Wibo mtx_lock(&sc->mtx);
429*2ed98337SAymeric Wibo if ((cmd->flags & RCMD_POLL_COMPLETE) == 0) {
430*2ed98337SAymeric Wibo error = ETIMEDOUT;
431*2ed98337SAymeric Wibo sc->inflight_cmd = NULL;
432*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER, "Config command timed out, retries=%d\n", retries);
433*2ed98337SAymeric Wibo continue;
434*2ed98337SAymeric Wibo } else
435*2ed98337SAymeric Wibo break;
436*2ed98337SAymeric Wibo }
437*2ed98337SAymeric Wibo
438*2ed98337SAymeric Wibo if (cmd->ev != 0)
439*2ed98337SAymeric Wibo error = EINVAL;
440*2ed98337SAymeric Wibo router_free_cmd(sc, cmd);
441*2ed98337SAymeric Wibo mtx_unlock(&sc->mtx);
442*2ed98337SAymeric Wibo return (error);
443*2ed98337SAymeric Wibo }
444*2ed98337SAymeric Wibo
445*2ed98337SAymeric Wibo int
tb_config_read_async(struct router_softc * sc,u_int space,u_int adapter,u_int offset,u_int dwlen,uint32_t * buf,void * cb)446*2ed98337SAymeric Wibo tb_config_read_async(struct router_softc *sc, u_int space, u_int adapter,
447*2ed98337SAymeric Wibo u_int offset, u_int dwlen, uint32_t *buf, void *cb)
448*2ed98337SAymeric Wibo {
449*2ed98337SAymeric Wibo struct router_command *cmd;
450*2ed98337SAymeric Wibo int error;
451*2ed98337SAymeric Wibo
452*2ed98337SAymeric Wibo if ((error = _tb_config_read(sc, space, adapter, offset, dwlen, buf,
453*2ed98337SAymeric Wibo cb, &cmd)) != 0)
454*2ed98337SAymeric Wibo return (error);
455*2ed98337SAymeric Wibo
456*2ed98337SAymeric Wibo error = router_schedule(sc, cmd);
457*2ed98337SAymeric Wibo
458*2ed98337SAymeric Wibo return (error);
459*2ed98337SAymeric Wibo }
460*2ed98337SAymeric Wibo
461*2ed98337SAymeric Wibo static int
_tb_config_read(struct router_softc * sc,u_int space,u_int adapter,u_int offset,u_int dwlen,uint32_t * buf,void * cb,struct router_command ** rcmd)462*2ed98337SAymeric Wibo _tb_config_read(struct router_softc *sc, u_int space, u_int adapter,
463*2ed98337SAymeric Wibo u_int offset, u_int dwlen, uint32_t *buf, void *cb,
464*2ed98337SAymeric Wibo struct router_command **rcmd)
465*2ed98337SAymeric Wibo {
466*2ed98337SAymeric Wibo struct router_command *cmd;
467*2ed98337SAymeric Wibo struct tb_cfg_read *msg;
468*2ed98337SAymeric Wibo int error;
469*2ed98337SAymeric Wibo
470*2ed98337SAymeric Wibo if ((error = router_alloc_cmd(sc, &cmd)) != 0)
471*2ed98337SAymeric Wibo return (error);
472*2ed98337SAymeric Wibo
473*2ed98337SAymeric Wibo msg = router_get_frame_data(cmd);
474*2ed98337SAymeric Wibo bzero(msg, sizeof(*msg));
475*2ed98337SAymeric Wibo msg->route.hi = sc->route.hi;
476*2ed98337SAymeric Wibo msg->route.lo = sc->route.lo;
477*2ed98337SAymeric Wibo msg->addr_attrs = TB_CONFIG_ADDR(0, space, adapter, dwlen, offset);
478*2ed98337SAymeric Wibo cmd->callback = cb;
479*2ed98337SAymeric Wibo cmd->callback_arg = buf;
480*2ed98337SAymeric Wibo cmd->dwlen = dwlen;
481*2ed98337SAymeric Wibo router_prepare_read(sc, cmd, sizeof(*msg));
482*2ed98337SAymeric Wibo
483*2ed98337SAymeric Wibo if (rcmd != NULL)
484*2ed98337SAymeric Wibo *rcmd = cmd;
485*2ed98337SAymeric Wibo
486*2ed98337SAymeric Wibo return (0);
487*2ed98337SAymeric Wibo }
488*2ed98337SAymeric Wibo
489*2ed98337SAymeric Wibo int
tb_config_write(struct router_softc * sc,u_int space,u_int adapter,u_int offset,u_int dwlen,uint32_t * buf)490*2ed98337SAymeric Wibo tb_config_write(struct router_softc *sc, u_int space, u_int adapter,
491*2ed98337SAymeric Wibo u_int offset, u_int dwlen, uint32_t *buf)
492*2ed98337SAymeric Wibo {
493*2ed98337SAymeric Wibo
494*2ed98337SAymeric Wibo return(0);
495*2ed98337SAymeric Wibo }
496*2ed98337SAymeric Wibo
497*2ed98337SAymeric Wibo static int
router_alloc_cmd(struct router_softc * sc,struct router_command ** rcmd)498*2ed98337SAymeric Wibo router_alloc_cmd(struct router_softc *sc, struct router_command **rcmd)
499*2ed98337SAymeric Wibo {
500*2ed98337SAymeric Wibo struct router_command *cmd;
501*2ed98337SAymeric Wibo
502*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_alloc_cmd\n");
503*2ed98337SAymeric Wibo
504*2ed98337SAymeric Wibo cmd = malloc(sizeof(*cmd), M_THUNDERBOLT, M_ZERO|M_NOWAIT);
505*2ed98337SAymeric Wibo if (cmd == NULL) {
506*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER, "Cannot allocate cmd/response\n");
507*2ed98337SAymeric Wibo return (ENOMEM);
508*2ed98337SAymeric Wibo }
509*2ed98337SAymeric Wibo
510*2ed98337SAymeric Wibo cmd->nhicmd = nhi_alloc_tx_frame(sc->ring0);
511*2ed98337SAymeric Wibo if (cmd->nhicmd == NULL) {
512*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER, "Cannot allocate command frame\n");
513*2ed98337SAymeric Wibo free(cmd, M_THUNDERBOLT);
514*2ed98337SAymeric Wibo return (EBUSY);
515*2ed98337SAymeric Wibo }
516*2ed98337SAymeric Wibo
517*2ed98337SAymeric Wibo cmd->sc = sc;
518*2ed98337SAymeric Wibo *rcmd = cmd;
519*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "Allocated command with index %d\n",
520*2ed98337SAymeric Wibo cmd->nhicmd->idx);
521*2ed98337SAymeric Wibo
522*2ed98337SAymeric Wibo return (0);
523*2ed98337SAymeric Wibo }
524*2ed98337SAymeric Wibo
525*2ed98337SAymeric Wibo static void
router_free_cmd(struct router_softc * sc,struct router_command * cmd)526*2ed98337SAymeric Wibo router_free_cmd(struct router_softc *sc, struct router_command *cmd)
527*2ed98337SAymeric Wibo {
528*2ed98337SAymeric Wibo
529*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_free_cmd\n");
530*2ed98337SAymeric Wibo
531*2ed98337SAymeric Wibo if (cmd == NULL)
532*2ed98337SAymeric Wibo return;
533*2ed98337SAymeric Wibo
534*2ed98337SAymeric Wibo if (cmd->nhicmd != NULL) {
535*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "Freeing nhi command %d\n",
536*2ed98337SAymeric Wibo cmd->nhicmd->idx);
537*2ed98337SAymeric Wibo nhi_free_tx_frame(sc->ring0, cmd->nhicmd);
538*2ed98337SAymeric Wibo }
539*2ed98337SAymeric Wibo free(cmd, M_THUNDERBOLT);
540*2ed98337SAymeric Wibo
541*2ed98337SAymeric Wibo return;
542*2ed98337SAymeric Wibo }
543*2ed98337SAymeric Wibo
544*2ed98337SAymeric Wibo static void
router_prepare_read(struct router_softc * sc,struct router_command * cmd,int len)545*2ed98337SAymeric Wibo router_prepare_read(struct router_softc *sc, struct router_command *cmd,
546*2ed98337SAymeric Wibo int len)
547*2ed98337SAymeric Wibo {
548*2ed98337SAymeric Wibo struct nhi_cmd_frame *nhicmd;
549*2ed98337SAymeric Wibo uint32_t *msg;
550*2ed98337SAymeric Wibo int msglen, i;
551*2ed98337SAymeric Wibo
552*2ed98337SAymeric Wibo KASSERT(cmd != NULL, ("cmd cannot be NULL\n"));
553*2ed98337SAymeric Wibo KASSERT(len != 0, ("Invalid zero-length command\n"));
554*2ed98337SAymeric Wibo KASSERT(len % 4 == 0, ("Message must be 32bit padded\n"));
555*2ed98337SAymeric Wibo
556*2ed98337SAymeric Wibo nhicmd = cmd->nhicmd;
557*2ed98337SAymeric Wibo msglen = (len - 4) / 4;
558*2ed98337SAymeric Wibo for (i = 0; i < msglen; i++)
559*2ed98337SAymeric Wibo nhicmd->data[i] = htobe32(nhicmd->data[i]);
560*2ed98337SAymeric Wibo
561*2ed98337SAymeric Wibo msg = (uint32_t *)nhicmd->data;
562*2ed98337SAymeric Wibo msg[msglen] = htobe32(tb_calc_crc(nhicmd->data, len-4));
563*2ed98337SAymeric Wibo
564*2ed98337SAymeric Wibo nhicmd->pdf = PDF_READ;
565*2ed98337SAymeric Wibo nhicmd->req_len = len;
566*2ed98337SAymeric Wibo
567*2ed98337SAymeric Wibo nhicmd->timeout = NHI_CMD_TIMEOUT;
568*2ed98337SAymeric Wibo nhicmd->retries = 0;
569*2ed98337SAymeric Wibo nhicmd->resp_buffer = (uint32_t *)cmd->resp_buffer;
570*2ed98337SAymeric Wibo nhicmd->resp_len = (cmd->dwlen + 3) * 4;
571*2ed98337SAymeric Wibo nhicmd->context = cmd;
572*2ed98337SAymeric Wibo
573*2ed98337SAymeric Wibo cmd->retries = CFG_DEFAULT_RETRIES;
574*2ed98337SAymeric Wibo cmd->timeout = CFG_DEFAULT_TIMEOUT;
575*2ed98337SAymeric Wibo
576*2ed98337SAymeric Wibo return;
577*2ed98337SAymeric Wibo }
578*2ed98337SAymeric Wibo
579*2ed98337SAymeric Wibo static int
router_schedule(struct router_softc * sc,struct router_command * cmd)580*2ed98337SAymeric Wibo router_schedule(struct router_softc *sc, struct router_command *cmd)
581*2ed98337SAymeric Wibo {
582*2ed98337SAymeric Wibo int error;
583*2ed98337SAymeric Wibo
584*2ed98337SAymeric Wibo mtx_lock(&sc->mtx);
585*2ed98337SAymeric Wibo error = router_schedule_locked(sc, cmd);
586*2ed98337SAymeric Wibo mtx_unlock(&sc->mtx);
587*2ed98337SAymeric Wibo
588*2ed98337SAymeric Wibo return(error);
589*2ed98337SAymeric Wibo }
590*2ed98337SAymeric Wibo
591*2ed98337SAymeric Wibo static int
router_schedule_locked(struct router_softc * sc,struct router_command * cmd)592*2ed98337SAymeric Wibo router_schedule_locked(struct router_softc *sc, struct router_command *cmd)
593*2ed98337SAymeric Wibo {
594*2ed98337SAymeric Wibo struct nhi_cmd_frame *nhicmd;
595*2ed98337SAymeric Wibo int error;
596*2ed98337SAymeric Wibo
597*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_schedule\n");
598*2ed98337SAymeric Wibo
599*2ed98337SAymeric Wibo if (cmd != NULL)
600*2ed98337SAymeric Wibo TAILQ_INSERT_TAIL(&sc->cmd_queue, cmd, link);
601*2ed98337SAymeric Wibo
602*2ed98337SAymeric Wibo while ((sc->inflight_cmd == NULL) &&
603*2ed98337SAymeric Wibo ((cmd = TAILQ_FIRST(&sc->cmd_queue)) != NULL)) {
604*2ed98337SAymeric Wibo
605*2ed98337SAymeric Wibo TAILQ_REMOVE(&sc->cmd_queue, cmd, link);
606*2ed98337SAymeric Wibo nhicmd = cmd->nhicmd;
607*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
608*2ed98337SAymeric Wibo "Scheduling command with index %d\n", nhicmd->idx);
609*2ed98337SAymeric Wibo sc->inflight_cmd = cmd;
610*2ed98337SAymeric Wibo if ((error = nhi_tx_schedule(sc->ring0, nhicmd)) != 0) {
611*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER, "nhi ring error "
612*2ed98337SAymeric Wibo "%d\n", error);
613*2ed98337SAymeric Wibo sc->inflight_cmd = NULL;
614*2ed98337SAymeric Wibo if (error == EBUSY) {
615*2ed98337SAymeric Wibo TAILQ_INSERT_HEAD(&sc->cmd_queue, cmd, link);
616*2ed98337SAymeric Wibo error = 0;
617*2ed98337SAymeric Wibo }
618*2ed98337SAymeric Wibo break;
619*2ed98337SAymeric Wibo }
620*2ed98337SAymeric Wibo }
621*2ed98337SAymeric Wibo
622*2ed98337SAymeric Wibo return (error);
623*2ed98337SAymeric Wibo }
624*2ed98337SAymeric Wibo
625*2ed98337SAymeric Wibo static void
router_complete_intr(void * context,union nhi_ring_desc * ring,struct nhi_cmd_frame * nhicmd)626*2ed98337SAymeric Wibo router_complete_intr(void *context, union nhi_ring_desc *ring,
627*2ed98337SAymeric Wibo struct nhi_cmd_frame *nhicmd)
628*2ed98337SAymeric Wibo {
629*2ed98337SAymeric Wibo struct router_softc *sc;
630*2ed98337SAymeric Wibo struct router_command *cmd;
631*2ed98337SAymeric Wibo
632*2ed98337SAymeric Wibo KASSERT(context != NULL, ("context cannot be NULL\n"));
633*2ed98337SAymeric Wibo KASSERT(nhicmd != NULL, ("nhicmd cannot be NULL\n"));
634*2ed98337SAymeric Wibo
635*2ed98337SAymeric Wibo cmd = (struct router_command *)(nhicmd->context);
636*2ed98337SAymeric Wibo sc = cmd->sc;
637*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_complete_intr called\n");
638*2ed98337SAymeric Wibo
639*2ed98337SAymeric Wibo if (nhicmd->flags & CMD_RESP_COMPLETE) {
640*2ed98337SAymeric Wibo cmd->callback(sc, cmd, cmd->callback_arg);
641*2ed98337SAymeric Wibo }
642*2ed98337SAymeric Wibo
643*2ed98337SAymeric Wibo return;
644*2ed98337SAymeric Wibo }
645*2ed98337SAymeric Wibo
646*2ed98337SAymeric Wibo static void
router_response_intr(void * context,union nhi_ring_desc * ring,struct nhi_cmd_frame * nhicmd)647*2ed98337SAymeric Wibo router_response_intr(void *context, union nhi_ring_desc *ring, struct nhi_cmd_frame *nhicmd)
648*2ed98337SAymeric Wibo {
649*2ed98337SAymeric Wibo struct router_softc *sc, *dev;
650*2ed98337SAymeric Wibo struct tb_cfg_read_resp *read;
651*2ed98337SAymeric Wibo struct tb_cfg_write_resp *write;
652*2ed98337SAymeric Wibo struct router_command *cmd;
653*2ed98337SAymeric Wibo tb_route_t route;
654*2ed98337SAymeric Wibo u_int error, i, eof, len;
655*2ed98337SAymeric Wibo uint32_t attrs;
656*2ed98337SAymeric Wibo
657*2ed98337SAymeric Wibo KASSERT(context != NULL, ("context cannot be NULL\n"));
658*2ed98337SAymeric Wibo
659*2ed98337SAymeric Wibo sc = (struct router_softc *)context;
660*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_response_intr called\n");
661*2ed98337SAymeric Wibo
662*2ed98337SAymeric Wibo eof = ring->rxpost.eof_len >> RX_BUFFER_DESC_EOF_SHIFT;
663*2ed98337SAymeric Wibo
664*2ed98337SAymeric Wibo if (eof == PDF_WRITE) {
665*2ed98337SAymeric Wibo write = (struct tb_cfg_write_resp *)nhicmd->data;
666*2ed98337SAymeric Wibo route.hi = be32toh(write->route.hi);
667*2ed98337SAymeric Wibo route.lo = be32toh(write->route.lo);
668*2ed98337SAymeric Wibo } else {
669*2ed98337SAymeric Wibo read = (struct tb_cfg_read_resp *)nhicmd->data;
670*2ed98337SAymeric Wibo route.hi = be32toh(read->route.hi);
671*2ed98337SAymeric Wibo route.lo = be32toh(read->route.lo);
672*2ed98337SAymeric Wibo attrs = be32toh(read->addr_attrs);
673*2ed98337SAymeric Wibo len = (attrs & TB_CFG_SIZE_MASK) >> TB_CFG_SIZE_SHIFT;
674*2ed98337SAymeric Wibo }
675*2ed98337SAymeric Wibo
676*2ed98337SAymeric Wibo /* XXX Is this a problem? */
677*2ed98337SAymeric Wibo if ((route.hi & 0x80000000) == 0)
678*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER, "Invalid route\n");
679*2ed98337SAymeric Wibo route.hi &= ~0x80000000;
680*2ed98337SAymeric Wibo
681*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "Looking up route 0x%08x%08x\n",
682*2ed98337SAymeric Wibo route.hi, route.lo);
683*2ed98337SAymeric Wibo
684*2ed98337SAymeric Wibo error = router_lookup_device(sc, route, &dev);
685*2ed98337SAymeric Wibo if (error != 0 || dev == NULL) {
686*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER, "Cannot find device, error= %d\n",
687*2ed98337SAymeric Wibo error);
688*2ed98337SAymeric Wibo return;
689*2ed98337SAymeric Wibo }
690*2ed98337SAymeric Wibo
691*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "Found device %s route 0x%08x%08x, "
692*2ed98337SAymeric Wibo "inflight_cmd= %p\n", device_get_nameunit(dev->dev), dev->route.hi,
693*2ed98337SAymeric Wibo dev->route.lo, dev->inflight_cmd);
694*2ed98337SAymeric Wibo
695*2ed98337SAymeric Wibo cmd = dev->inflight_cmd;
696*2ed98337SAymeric Wibo if (cmd == NULL) {
697*2ed98337SAymeric Wibo tb_debug(dev, DBG_ROUTER, "Null inflight cmd\n");
698*2ed98337SAymeric Wibo return;
699*2ed98337SAymeric Wibo }
700*2ed98337SAymeric Wibo
701*2ed98337SAymeric Wibo if (eof == PDF_READ) {
702*2ed98337SAymeric Wibo for (i = 0; i < len; i++)
703*2ed98337SAymeric Wibo cmd->nhicmd->resp_buffer[i] = be32toh(read->data[i]);
704*2ed98337SAymeric Wibo }
705*2ed98337SAymeric Wibo
706*2ed98337SAymeric Wibo cmd->nhicmd->flags |= CMD_RESP_COMPLETE;
707*2ed98337SAymeric Wibo if (cmd->nhicmd->flags & CMD_REQ_COMPLETE) {
708*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "TX_COMPLETE set\n");
709*2ed98337SAymeric Wibo cmd->callback(dev, cmd, cmd->callback_arg);
710*2ed98337SAymeric Wibo }
711*2ed98337SAymeric Wibo
712*2ed98337SAymeric Wibo return;
713*2ed98337SAymeric Wibo }
714*2ed98337SAymeric Wibo
715*2ed98337SAymeric Wibo static void
router_notify_intr(void * context,union nhi_ring_desc * ring,struct nhi_cmd_frame * nhicmd)716*2ed98337SAymeric Wibo router_notify_intr(void *context, union nhi_ring_desc *ring, struct nhi_cmd_frame *nhicmd)
717*2ed98337SAymeric Wibo {
718*2ed98337SAymeric Wibo struct router_softc *sc;
719*2ed98337SAymeric Wibo struct router_command *cmd;
720*2ed98337SAymeric Wibo struct tb_cfg_notify event;
721*2ed98337SAymeric Wibo u_int ev, adap;
722*2ed98337SAymeric Wibo
723*2ed98337SAymeric Wibo KASSERT(context != NULL, ("context cannot be NULL\n"));
724*2ed98337SAymeric Wibo
725*2ed98337SAymeric Wibo sc = (struct router_softc *)context;
726*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "router_notify_intr called\n");
727*2ed98337SAymeric Wibo
728*2ed98337SAymeric Wibo event.route.hi = be32toh(nhicmd->data[0]);
729*2ed98337SAymeric Wibo event.route.lo = be32toh(nhicmd->data[1]);
730*2ed98337SAymeric Wibo event.event_adap = be32toh(nhicmd->data[2]);
731*2ed98337SAymeric Wibo
732*2ed98337SAymeric Wibo ev = GET_NOTIFY_EVENT(&event);
733*2ed98337SAymeric Wibo adap = GET_NOTIFY_ADAPTER(&event);
734*2ed98337SAymeric Wibo
735*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER, "Event route 0x%08x%08x adap %d code %s\n",
736*2ed98337SAymeric Wibo event.route.hi, event.route.lo, adap,
737*2ed98337SAymeric Wibo tb_get_string(ev, tb_notify_event));
738*2ed98337SAymeric Wibo
739*2ed98337SAymeric Wibo switch (ev) {
740*2ed98337SAymeric Wibo case TB_CFG_ERR_CONN:
741*2ed98337SAymeric Wibo case TB_CFG_ERR_LINK:
742*2ed98337SAymeric Wibo case TB_CFG_ERR_ADDR:
743*2ed98337SAymeric Wibo case TB_CFG_ERR_ADP:
744*2ed98337SAymeric Wibo case TB_CFG_ERR_ENUM:
745*2ed98337SAymeric Wibo case TB_CFG_ERR_NUA:
746*2ed98337SAymeric Wibo case TB_CFG_ERR_LEN:
747*2ed98337SAymeric Wibo case TB_CFG_ERR_HEC:
748*2ed98337SAymeric Wibo case TB_CFG_ERR_FC:
749*2ed98337SAymeric Wibo case TB_CFG_ERR_PLUG:
750*2ed98337SAymeric Wibo case TB_CFG_ERR_LOCK:
751*2ed98337SAymeric Wibo case TB_CFG_HP_ACK:
752*2ed98337SAymeric Wibo case TB_CFG_DP_BW:
753*2ed98337SAymeric Wibo if (sc->inflight_cmd != NULL) {
754*2ed98337SAymeric Wibo cmd = sc->inflight_cmd;
755*2ed98337SAymeric Wibo cmd->ev = ev;
756*2ed98337SAymeric Wibo cmd->callback(sc, cmd, cmd->callback_arg);
757*2ed98337SAymeric Wibo }
758*2ed98337SAymeric Wibo break;
759*2ed98337SAymeric Wibo default:
760*2ed98337SAymeric Wibo break;
761*2ed98337SAymeric Wibo }
762*2ed98337SAymeric Wibo return;
763*2ed98337SAymeric Wibo }
764*2ed98337SAymeric Wibo
765*2ed98337SAymeric Wibo int
tb_config_next_cap(struct router_softc * sc,struct router_cfg_cap * cap)766*2ed98337SAymeric Wibo tb_config_next_cap(struct router_softc *sc, struct router_cfg_cap *cap)
767*2ed98337SAymeric Wibo {
768*2ed98337SAymeric Wibo union tb_cfg_cap *tbcap;
769*2ed98337SAymeric Wibo uint32_t *buf;
770*2ed98337SAymeric Wibo uint16_t current;
771*2ed98337SAymeric Wibo int error;
772*2ed98337SAymeric Wibo
773*2ed98337SAymeric Wibo KASSERT(cap != NULL, ("cap cannot be NULL\n"));
774*2ed98337SAymeric Wibo KASSERT(cap->next_cap != 0, ("next_cap cannot be 0\n"));
775*2ed98337SAymeric Wibo
776*2ed98337SAymeric Wibo buf = malloc(sizeof(*tbcap), M_THUNDERBOLT, M_NOWAIT|M_ZERO);
777*2ed98337SAymeric Wibo
778*2ed98337SAymeric Wibo current = cap->next_cap;
779*2ed98337SAymeric Wibo error = tb_config_read(sc, cap->space, cap->adap, current, 1, buf);
780*2ed98337SAymeric Wibo if (error)
781*2ed98337SAymeric Wibo return (error);
782*2ed98337SAymeric Wibo
783*2ed98337SAymeric Wibo tbcap = (union tb_cfg_cap *)buf;
784*2ed98337SAymeric Wibo cap->cap_id = tbcap->hdr.cap_id;
785*2ed98337SAymeric Wibo cap->next_cap = tbcap->hdr.next_cap;
786*2ed98337SAymeric Wibo cap->current_cap = current;
787*2ed98337SAymeric Wibo
788*2ed98337SAymeric Wibo if ((cap->space != TB_CFG_CS_ROUTER) &&
789*2ed98337SAymeric Wibo (tbcap->hdr.cap_id != TB_CFG_CAP_VSC)) {
790*2ed98337SAymeric Wibo free(buf, M_THUNDERBOLT);
791*2ed98337SAymeric Wibo return (0);
792*2ed98337SAymeric Wibo }
793*2ed98337SAymeric Wibo
794*2ed98337SAymeric Wibo tb_config_read(sc, cap->space, cap->adap, current, 2, buf);
795*2ed98337SAymeric Wibo if (error) {
796*2ed98337SAymeric Wibo free(buf, M_THUNDERBOLT);
797*2ed98337SAymeric Wibo return (error);
798*2ed98337SAymeric Wibo }
799*2ed98337SAymeric Wibo
800*2ed98337SAymeric Wibo cap->vsc_id = tbcap->vsc.vsc_id;
801*2ed98337SAymeric Wibo cap->vsc_len = tbcap->vsc.len;
802*2ed98337SAymeric Wibo if (tbcap->vsc.len == 0) {
803*2ed98337SAymeric Wibo cap->next_cap = tbcap->vsec.vsec_next_cap;
804*2ed98337SAymeric Wibo cap->vsec_len = tbcap->vsec.vsec_len;
805*2ed98337SAymeric Wibo }
806*2ed98337SAymeric Wibo
807*2ed98337SAymeric Wibo free(buf, M_THUNDERBOLT);
808*2ed98337SAymeric Wibo return (0);
809*2ed98337SAymeric Wibo }
810*2ed98337SAymeric Wibo
811*2ed98337SAymeric Wibo int
tb_config_find_cap(struct router_softc * sc,struct router_cfg_cap * cap)812*2ed98337SAymeric Wibo tb_config_find_cap(struct router_softc *sc, struct router_cfg_cap *cap)
813*2ed98337SAymeric Wibo {
814*2ed98337SAymeric Wibo u_int cap_id, vsc_id;
815*2ed98337SAymeric Wibo int error;
816*2ed98337SAymeric Wibo
817*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA, "tb_config_find_cap called\n");
818*2ed98337SAymeric Wibo
819*2ed98337SAymeric Wibo cap_id = cap->cap_id;
820*2ed98337SAymeric Wibo vsc_id = cap->vsc_id;
821*2ed98337SAymeric Wibo
822*2ed98337SAymeric Wibo cap->cap_id = cap->vsc_id = 0;
823*2ed98337SAymeric Wibo while ((cap->cap_id != cap_id) || (cap->vsc_id != vsc_id)) {
824*2ed98337SAymeric Wibo tb_debug(sc, DBG_ROUTER|DBG_EXTRA,
825*2ed98337SAymeric Wibo "Looking for cap %d at offset %d\n", cap->cap_id,
826*2ed98337SAymeric Wibo cap->next_cap);
827*2ed98337SAymeric Wibo if ((cap->next_cap == 0) ||
828*2ed98337SAymeric Wibo (cap->next_cap > TB_CFG_CAP_OFFSET_MAX))
829*2ed98337SAymeric Wibo return (EINVAL);
830*2ed98337SAymeric Wibo error = tb_config_next_cap(sc, cap);
831*2ed98337SAymeric Wibo if (error)
832*2ed98337SAymeric Wibo break;
833*2ed98337SAymeric Wibo }
834*2ed98337SAymeric Wibo
835*2ed98337SAymeric Wibo return (0);
836*2ed98337SAymeric Wibo }
837*2ed98337SAymeric Wibo
838*2ed98337SAymeric Wibo int
tb_config_find_router_cap(struct router_softc * sc,u_int cap,u_int vsc,u_int * offset)839*2ed98337SAymeric Wibo tb_config_find_router_cap(struct router_softc *sc, u_int cap, u_int vsc, u_int *offset)
840*2ed98337SAymeric Wibo {
841*2ed98337SAymeric Wibo struct router_cfg_cap rcap;
842*2ed98337SAymeric Wibo struct tb_cfg_router *cfg;
843*2ed98337SAymeric Wibo uint32_t *buf;
844*2ed98337SAymeric Wibo int error;
845*2ed98337SAymeric Wibo
846*2ed98337SAymeric Wibo buf = malloc(8 * 4, M_THUNDERBOLT, M_NOWAIT|M_ZERO);
847*2ed98337SAymeric Wibo if (buf == NULL)
848*2ed98337SAymeric Wibo return (ENOMEM);
849*2ed98337SAymeric Wibo
850*2ed98337SAymeric Wibo error = tb_config_router_read(sc, 0, 5, buf);
851*2ed98337SAymeric Wibo if (error != 0) {
852*2ed98337SAymeric Wibo free(buf, M_THUNDERBOLT);
853*2ed98337SAymeric Wibo return (error);
854*2ed98337SAymeric Wibo }
855*2ed98337SAymeric Wibo
856*2ed98337SAymeric Wibo cfg = (struct tb_cfg_router *)buf;
857*2ed98337SAymeric Wibo rcap.space = TB_CFG_CS_ROUTER;
858*2ed98337SAymeric Wibo rcap.adap = 0;
859*2ed98337SAymeric Wibo rcap.next_cap = GET_ROUTER_CS_NEXT_CAP(cfg);
860*2ed98337SAymeric Wibo rcap.cap_id = cap;
861*2ed98337SAymeric Wibo rcap.vsc_id = vsc;
862*2ed98337SAymeric Wibo error = tb_config_find_cap(sc, &rcap);
863*2ed98337SAymeric Wibo if (error == 0)
864*2ed98337SAymeric Wibo *offset = rcap.current_cap;
865*2ed98337SAymeric Wibo
866*2ed98337SAymeric Wibo free(buf, M_THUNDERBOLT);
867*2ed98337SAymeric Wibo return (error);
868*2ed98337SAymeric Wibo }
869*2ed98337SAymeric Wibo
870*2ed98337SAymeric Wibo int
tb_config_find_router_vsc(struct router_softc * sc,u_int cap,u_int * offset)871*2ed98337SAymeric Wibo tb_config_find_router_vsc(struct router_softc *sc, u_int cap, u_int *offset)
872*2ed98337SAymeric Wibo {
873*2ed98337SAymeric Wibo
874*2ed98337SAymeric Wibo return (tb_config_find_router_cap(sc, TB_CFG_CAP_VSC, cap, offset));
875*2ed98337SAymeric Wibo }
876*2ed98337SAymeric Wibo
877*2ed98337SAymeric Wibo int
tb_config_find_router_vsec(struct router_softc * sc,u_int cap,u_int * offset)878*2ed98337SAymeric Wibo tb_config_find_router_vsec(struct router_softc *sc, u_int cap, u_int *offset)
879*2ed98337SAymeric Wibo {
880*2ed98337SAymeric Wibo
881*2ed98337SAymeric Wibo return (tb_config_find_router_cap(sc, TB_CFG_CAP_VSEC, cap, offset));
882*2ed98337SAymeric Wibo }
883*2ed98337SAymeric Wibo
884*2ed98337SAymeric Wibo int
tb_config_find_adapter_cap(struct router_softc * sc,u_int adap,u_int cap,u_int * offset)885*2ed98337SAymeric Wibo tb_config_find_adapter_cap(struct router_softc *sc, u_int adap, u_int cap, u_int *offset)
886*2ed98337SAymeric Wibo {
887*2ed98337SAymeric Wibo struct router_cfg_cap rcap;
888*2ed98337SAymeric Wibo struct tb_cfg_adapter *cfg;
889*2ed98337SAymeric Wibo uint32_t *buf;
890*2ed98337SAymeric Wibo int error;
891*2ed98337SAymeric Wibo
892*2ed98337SAymeric Wibo buf = malloc(8 * 4, M_THUNDERBOLT, M_NOWAIT|M_ZERO);
893*2ed98337SAymeric Wibo if (buf == NULL)
894*2ed98337SAymeric Wibo return (ENOMEM);
895*2ed98337SAymeric Wibo
896*2ed98337SAymeric Wibo error = tb_config_adapter_read(sc, adap, 0, 8, buf);
897*2ed98337SAymeric Wibo if (error != 0) {
898*2ed98337SAymeric Wibo free(buf, M_THUNDERBOLT);
899*2ed98337SAymeric Wibo return (error);
900*2ed98337SAymeric Wibo }
901*2ed98337SAymeric Wibo
902*2ed98337SAymeric Wibo cfg = (struct tb_cfg_adapter *)buf;
903*2ed98337SAymeric Wibo rcap.space = TB_CFG_CS_ADAPTER;
904*2ed98337SAymeric Wibo rcap.adap = adap;
905*2ed98337SAymeric Wibo rcap.next_cap = GET_ADP_CS_NEXT_CAP(cfg);
906*2ed98337SAymeric Wibo rcap.cap_id = cap;
907*2ed98337SAymeric Wibo rcap.vsc_id = 0;
908*2ed98337SAymeric Wibo error = tb_config_find_cap(sc, &rcap);
909*2ed98337SAymeric Wibo if (error == 0)
910*2ed98337SAymeric Wibo *offset = rcap.current_cap;
911*2ed98337SAymeric Wibo
912*2ed98337SAymeric Wibo free(buf, M_THUNDERBOLT);
913*2ed98337SAymeric Wibo return (error);
914*2ed98337SAymeric Wibo }
915*2ed98337SAymeric Wibo
916*2ed98337SAymeric Wibo int
tb_config_get_lc_uuid(struct router_softc * rsc,uint8_t * uuid)917*2ed98337SAymeric Wibo tb_config_get_lc_uuid(struct router_softc *rsc, uint8_t *uuid)
918*2ed98337SAymeric Wibo {
919*2ed98337SAymeric Wibo u_int error, offset;
920*2ed98337SAymeric Wibo uint32_t buf[8];
921*2ed98337SAymeric Wibo
922*2ed98337SAymeric Wibo bzero(buf, sizeof(buf));
923*2ed98337SAymeric Wibo
924*2ed98337SAymeric Wibo error = tb_config_find_router_vsec(rsc, TB_CFG_VSEC_LC, &offset);
925*2ed98337SAymeric Wibo if (error != 0) {
926*2ed98337SAymeric Wibo tb_debug(rsc, DBG_ROUTER, "Error finding LC registers: %d\n",
927*2ed98337SAymeric Wibo error);
928*2ed98337SAymeric Wibo return (error);
929*2ed98337SAymeric Wibo }
930*2ed98337SAymeric Wibo
931*2ed98337SAymeric Wibo error = tb_config_router_read(rsc, offset + TB_LC_UUID, 4, buf);
932*2ed98337SAymeric Wibo if (error != 0) {
933*2ed98337SAymeric Wibo tb_debug(rsc, DBG_ROUTER, "Error fetching UUID: %d\n", error);
934*2ed98337SAymeric Wibo return (error);
935*2ed98337SAymeric Wibo }
936*2ed98337SAymeric Wibo
937*2ed98337SAymeric Wibo bcopy(buf, uuid, 16);
938*2ed98337SAymeric Wibo return (0);
939*2ed98337SAymeric Wibo }
940