Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 2 Oct 2025 22:17:40 +0100
From:      Nuno Teixeira <eduardo@freebsd.org>
To:        Wolfram Schneider <wosch@freebsd.org>
Cc:        Aymeric Wibo <obiwac@freebsd.org>, src-committers@freebsd.org,  dev-commits-src-all@freebsd.org, dev-commits-src-main@freebsd.org
Subject:   Re: git: 2ed9833791f2 - main - thunderbolt: Import USB4 code
Message-ID:  <CAFDf7ULhDCEf6ZZniWAtHP0Qv0zi64UgD=VBiyAaM=Uv51bRDg@mail.gmail.com>
In-Reply-To: <CAMWY7CAy4Gv-7tTHdgZMwq=kGUV2NPtC4BvBBiS=93J0OhZnCA@mail.gmail.com>
References:  <202509271713.58RHDTTL008060@gitrepo.freebsd.org> <CAMWY7CAy4Gv-7tTHdgZMwq=kGUV2NPtC4BvBBiS=93J0OhZnCA@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
--00000000000085e79c0640338477
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

yep, seing that symlink too.

Wolfram Schneider <wosch@freebsd.org> escreveu (ter=C3=A7a, 30/09/2025 =C3=
=A0(s)
07:44):

> I'm now getting a stale symlink:
>
> ./tools/build/stale-symlink-buildworld.sh
> stale symlink detected: lrwxrwxr-x  1 wosch wheel 91 Sep 29 22:14
>
> /var/tmp/freebsd-obj-wosch/home/projects/freebsd-src/amd64.amd64/sys/GENE=
RIC/modules/home/projects/freebsd-src/sys/modules/thunderbolt/opt_acpi_wmi.=
h
> ->
> /var/tmp/freebsd-obj-wosch/home/projects/freebsd-src/amd64.amd64/sys/GENE=
RIC/opt_acpi_wmi.h
>
> the only reference to the file "opt_acpi_wmi.h" is in the Makefile
>
> sys/modules/thunderbolt/Makefile:SRCS+=3D opt_acpi.h opt_acpi_wmi.h
> acpi_if.h acpi_wmi_if.h
>
> What is this file supposed to do, where does it come from?
>
> -Wolfram
>
> On Sat, 27 Sept 2025 at 19:13, Aymeric Wibo <obiwac@freebsd.org> wrote:
> >
> > The branch main has been updated by obiwac:
> >
> > URL:
> https://cgit.FreeBSD.org/src/commit/?id=3D2ed9833791f28e14843ac813f90cb03=
0e45948dc
> >
> > commit 2ed9833791f28e14843ac813f90cb030e45948dc
> > Author:     Aymeric Wibo <obiwac@FreeBSD.org>
> > AuthorDate: 2025-09-27 11:50:43 +0000
> > Commit:     Aymeric Wibo <obiwac@FreeBSD.org>
> > CommitDate: 2025-09-27 17:13:13 +0000
> >
> >     thunderbolt: Import USB4 code
> >
> >     Add initial USB4 code written by Scott Long and originally passed o=
n
> to
> >     HPS (source: https://github.com/hselasky/usb4), minus the ICM code
> and
> >     with some small fixes.
> >
> >     For context, older TB chips implemented the connection manager in
> >     firmware (ICM) instead of in the OS (HCM), but maintaining the ICM
> code
> >     would be a huge burden for not many chips.
> >
> >     Mostly completed work:
> >
> >     - Debug/trace framework.
> >     - NHI controller driver.
> >     - PCIe bridge driver.
> >     - Router and config space layer handling (just reading in this
> commit).
> >
> >     Link to the email where Scott shared details about the initial USB4
> >     work:
> >
> >
> https://lists.freebsd.org/archives/freebsd-hackers/2024-July/003411.html
> >
> >     Glanced at by:  emaste, imp
> >     Sponsored by:   The FreeBSD Foundation
> >     Differential Revision:  https://reviews.freebsd.org/D49450
> >     Event:          EuroBSDcon 2025
> > ---
> >  sys/dev/thunderbolt/hcm.c          |  223 +++++++
> >  sys/dev/thunderbolt/hcm_var.h      |   47 ++
> >  sys/dev/thunderbolt/nhi.c          | 1170
> ++++++++++++++++++++++++++++++++++++
> >  sys/dev/thunderbolt/nhi_pci.c      |  529 ++++++++++++++++
> >  sys/dev/thunderbolt/nhi_reg.h      |  332 ++++++++++
> >  sys/dev/thunderbolt/nhi_var.h      |  277 +++++++++
> >  sys/dev/thunderbolt/nhi_wmi.c      |  198 ++++++
> >  sys/dev/thunderbolt/router.c       |  939 ++++++++++++++++++++++++++++=
+
> >  sys/dev/thunderbolt/router_var.h   |  242 ++++++++
> >  sys/dev/thunderbolt/tb_acpi_pcib.c |  181 ++++++
> >  sys/dev/thunderbolt/tb_debug.c     |  334 ++++++++++
> >  sys/dev/thunderbolt/tb_debug.h     |   93 +++
> >  sys/dev/thunderbolt/tb_dev.c       |  331 ++++++++++
> >  sys/dev/thunderbolt/tb_dev.h       |   41 ++
> >  sys/dev/thunderbolt/tb_if.m        |  121 ++++
> >  sys/dev/thunderbolt/tb_ioctl.h     |   52 ++
> >  sys/dev/thunderbolt/tb_pcib.c      |  614 +++++++++++++++++++
> >  sys/dev/thunderbolt/tb_pcib.h      |   93 +++
> >  sys/dev/thunderbolt/tb_reg.h       |   52 ++
> >  sys/dev/thunderbolt/tb_var.h       |   54 ++
> >  sys/dev/thunderbolt/tbcfg_reg.h    |  363 +++++++++++
> >  sys/modules/Makefile               |    5 +
> >  sys/modules/thunderbolt/Makefile   |   13 +
> >  23 files changed, 6304 insertions(+)
> >
> > diff --git a/sys/dev/thunderbolt/hcm.c b/sys/dev/thunderbolt/hcm.c
> > new file mode 100644
> > index 000000000000..b8f703fc3b52
> > --- /dev/null
> > +++ b/sys/dev/thunderbolt/hcm.c
> > @@ -0,0 +1,223 @@
> > +/*-
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + *
> > + * Copyright (c) 2022 Scott Long
> > + * All rights reserved.
> > + *
> > + * Redistribution and use in source and binary forms, with or without
> > + * modification, are permitted provided that the following conditions
> > + * are met:
> > + * 1. Redistributions of source code must retain the above copyright
> > + *    notice, this list of conditions and the following disclaimer.
> > + * 2. Redistributions in binary form must reproduce the above copyrigh=
t
> > + *    notice, this list of conditions and the following disclaimer in
> the
> > + *    documentation and/or other materials provided with the
> distribution.
> > + *
> > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
> AND
> > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, T=
HE
> > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> PURPOSE
> > + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
> LIABLE
> > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL
> > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
> GOODS
> > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTIO=
N)
> > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> STRICT
> > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
> ANY WAY
> > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
> OF
> > + * SUCH DAMAGE.
> > + */
> > +
> > +#include "opt_thunderbolt.h"
> > +
> > +/* Host Configuration Manager (HCM) for USB4 and later TB3 */
> > +#include <sys/types.h>
> > +#include <sys/param.h>
> > +#include <sys/systm.h>
> > +#include <sys/kernel.h>
> > +#include <sys/module.h>
> > +#include <sys/bus.h>
> > +#include <sys/conf.h>
> > +#include <sys/malloc.h>
> > +#include <sys/queue.h>
> > +#include <sys/sysctl.h>
> > +#include <sys/lock.h>
> > +#include <sys/mutex.h>
> > +#include <sys/taskqueue.h>
> > +#include <sys/gsb_crc32.h>
> > +#include <sys/endian.h>
> > +#include <vm/vm.h>
> > +#include <vm/pmap.h>
> > +
> > +#include <machine/bus.h>
> > +#include <machine/stdarg.h>
> > +
> > +#include <dev/thunderbolt/nhi_reg.h>
> > +#include <dev/thunderbolt/nhi_var.h>
> > +#include <dev/thunderbolt/tb_reg.h>
> > +#include <dev/thunderbolt/tb_var.h>
> > +#include <dev/thunderbolt/tb_debug.h>
> > +#include <dev/thunderbolt/tbcfg_reg.h>
> > +#include <dev/thunderbolt/router_var.h>
> > +#include <dev/thunderbolt/hcm_var.h>
> > +
> > +static void hcm_cfg_task(void *, int);
> > +
> > +int
> > +hcm_attach(struct nhi_softc *nsc)
> > +{
> > +       struct hcm_softc *hcm;
> > +
> > +       tb_debug(nsc, DBG_HCM|DBG_EXTRA, "hcm_attach called\n");
> > +
> > +       hcm =3D malloc(sizeof(struct hcm_softc), M_THUNDERBOLT,
> M_NOWAIT|M_ZERO);
> > +       if (hcm =3D=3D NULL) {
> > +               tb_debug(nsc, DBG_HCM, "Cannot allocate hcm object\n");
> > +               return (ENOMEM);
> > +       }
> > +
> > +       hcm->dev =3D nsc->dev;
> > +       hcm->nsc =3D nsc;
> > +       nsc->hcm =3D hcm;
> > +
> > +       hcm->taskqueue =3D taskqueue_create("hcm_event", M_NOWAIT,
> > +           taskqueue_thread_enqueue, &hcm->taskqueue);
> > +       if (hcm->taskqueue =3D=3D NULL)
> > +               return (ENOMEM);
> > +       taskqueue_start_threads(&hcm->taskqueue, 1, PI_DISK,
> "tbhcm%d_tq",
> > +           device_get_unit(nsc->dev));
> > +       TASK_INIT(&hcm->cfg_task, 0, hcm_cfg_task, hcm);
> > +
> > +       return (0);
> > +}
> > +
> > +int
> > +hcm_detach(struct nhi_softc *nsc)
> > +{
> > +       struct hcm_softc *hcm;
> > +
> > +       hcm =3D nsc->hcm;
> > +       if (hcm->taskqueue)
> > +               taskqueue_free(hcm->taskqueue);
> > +
> > +       return (0);
> > +}
> > +
> > +int
> > +hcm_router_discover(struct hcm_softc *hcm)
> > +{
> > +
> > +       taskqueue_enqueue(hcm->taskqueue, &hcm->cfg_task);
> > +
> > +       return (0);
> > +}
> > +
> > +static void
> > +hcm_cfg_task(void *arg, int pending)
> > +{
> > +       struct hcm_softc *hcm;
> > +       struct router_softc *rsc;
> > +       struct router_cfg_cap cap;
> > +       struct tb_cfg_router *cfg;
> > +       struct tb_cfg_adapter *adp;
> > +       struct tb_cfg_cap_lane *lane;
> > +       uint32_t *buf;
> > +       uint8_t *u;
> > +       u_int error, i, offset;
> > +
> > +       hcm =3D (struct hcm_softc *)arg;
> > +
> > +       tb_debug(hcm, DBG_HCM|DBG_EXTRA, "hcm_cfg_task called\n");
> > +
> > +       buf =3D malloc(8 * 4, M_THUNDERBOLT, M_NOWAIT|M_ZERO);
> > +       if (buf =3D=3D NULL) {
> > +               tb_debug(hcm, DBG_HCM, "Cannot alloc memory for
> discovery\n");
> > +               return;
> > +       }
> > +
> > +       rsc =3D hcm->nsc->root_rsc;
> > +       error =3D tb_config_router_read(rsc, 0, 5, buf);
> > +       if (error !=3D 0) {
> > +               free(buf, M_NHI);
> > +               return;
> > +       }
> > +
> > +       cfg =3D (struct tb_cfg_router *)buf;
> > +
> > +       cap.space =3D TB_CFG_CS_ROUTER;
> > +       cap.adap =3D 0;
> > +       cap.next_cap =3D GET_ROUTER_CS_NEXT_CAP(cfg);
> > +       while (cap.next_cap !=3D 0) {
> > +               error =3D tb_config_next_cap(rsc, &cap);
> > +               if (error !=3D 0)
> > +                       break;
> > +
> > +               if ((cap.cap_id =3D=3D TB_CFG_CAP_VSEC) && (cap.vsc_len=
 =3D=3D
> 0)) {
> > +                       tb_debug(hcm, DBG_HCM, "Router Cap=3D %d, vsec=
=3D
> %d, "
> > +                           "len=3D %d, next_cap=3D %d\n", cap.cap_id,
> > +                           cap.vsc_id, cap.vsec_len, cap.next_cap);
> > +               } else if (cap.cap_id =3D=3D TB_CFG_CAP_VSC) {
> > +                       tb_debug(hcm, DBG_HCM, "Router cap=3D %d, vsc=
=3D %d,
> "
> > +                           "len=3D %d, next_cap=3D %d\n", cap.cap_id,
> > +                           cap.vsc_id, cap.vsc_len, cap.next_cap);
> > +               } else
> > +                       tb_debug(hcm, DBG_HCM, "Router cap=3D %d, "
> > +                           "next_cap=3D %d\n", cap.cap_id, cap.next_ca=
p);
> > +               if (cap.next_cap > TB_CFG_CAP_OFFSET_MAX)
> > +                       cap.next_cap =3D 0;
> > +       }
> > +
> > +       u =3D (uint8_t *)buf;
> > +       error =3D tb_config_get_lc_uuid(rsc, u);
> > +       if (error =3D=3D 0) {
> > +               tb_debug(hcm, DBG_HCM, "Router LC UUID:
> %02x%02x%02x%02x-"
> > +
>  "%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
> > +                   u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8=
],
> > +                   u[9], u[10], u[11], u[12], u[13], u[14], u[15]);
> > +       } else
> > +               tb_printf(hcm, "Error finding LC registers: %d\n",
> error);
> > +
> > +       for (i =3D 1; i <=3D rsc->max_adap; i++) {
> > +               error =3D tb_config_adapter_read(rsc, i, 0, 8, buf);
> > +               if (error !=3D 0) {
> > +                       tb_debug(hcm, DBG_HCM, "Adapter %d: no
> adapter\n", i);
> > +                       continue;
> > +               }
> > +               adp =3D (struct tb_cfg_adapter *)buf;
> > +               tb_debug(hcm, DBG_HCM, "Adapter %d: %s, max_counters=3D
> 0x%08x,"
> > +                   " adapter_num=3D %d\n", i,
> > +                   tb_get_string(GET_ADP_CS_TYPE(adp), tb_adapter_type=
),
> > +                   GET_ADP_CS_MAX_COUNTERS(adp),
> GET_ADP_CS_ADP_NUM(adp));
> > +
> > +               if (GET_ADP_CS_TYPE(adp) !=3D ADP_CS2_LANE)
> > +                       continue;
> > +
> > +               error =3D tb_config_find_adapter_cap(rsc, i,
> TB_CFG_CAP_LANE,
> > +                   &offset);
> > +               if (error)
> > +                       continue;
> > +
> > +               error =3D tb_config_adapter_read(rsc, i, offset, 3, buf=
);
> > +               if (error)
> > +                       continue;
> > +
> > +               lane =3D (struct tb_cfg_cap_lane *)buf;
> > +               tb_debug(hcm, DBG_HCM, "Lane Adapter State=3D %s %s\n",
> > +                   tb_get_string((lane->current_lws &
> CAP_LANE_STATE_MASK),
> > +                   tb_adapter_state), (lane->targ_lwp &
> CAP_LANE_DISABLE) ?
> > +                   "disabled" : "enabled");
> > +
> > +               if ((lane->current_lws & CAP_LANE_STATE_MASK) =3D=3D
> > +                   CAP_LANE_STATE_CL0) {
> > +                       tb_route_t newr;
> > +
> > +                       newr.hi =3D rsc->route.hi;
> > +                       newr.lo =3D rsc->route.lo | (i << rsc->depth * =
8);
> > +
> > +                       tb_printf(hcm, "want to add router at
> 0x%08x%08x\n",
> > +                           newr.hi, newr.lo);
> > +                       error =3D tb_router_attach(rsc, newr);
> > +                       tb_printf(rsc, "tb_router_attach returned %d\n"=
,
> error);
> > +               }
> > +       }
> > +
> > +       free(buf, M_THUNDERBOLT);
> > +}
> > diff --git a/sys/dev/thunderbolt/hcm_var.h
> b/sys/dev/thunderbolt/hcm_var.h
> > new file mode 100644
> > index 000000000000..a11c8e9b6a92
> > --- /dev/null
> > +++ b/sys/dev/thunderbolt/hcm_var.h
> > @@ -0,0 +1,47 @@
> > +/*-
> > + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
> > + *
> > + * Copyright (c) 2022 Scott Long
> > + * All rights reserved.
> > + *
> > + * Redistribution and use in source and binary forms, with or without
> > + * modification, are permitted provided that the following conditions
> > + * are met:
> > + * 1. Redistributions of source code must retain the above copyright
> > + *    notice, this list of conditions and the following disclaimer.
> > + * 2. Redistributions in binary form must reproduce the above copyrigh=
t
> > + *    notice, this list of conditions and the following disclaimer in
> the
> > + *    documentation and/or other materials provided with the
> distribution.
> > + *
> > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
> AND
> > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, T=
HE
> > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> PURPOSE
> > + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
> LIABLE
> > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL
> > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
> GOODS
> > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTIO=
N)
> > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> STRICT
> > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
> ANY WAY
> > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
> OF
> > + * SUCH DAMAGE.
> > + *
> > + * $FreeBSD$
> > + */
> > +
> > +#ifndef _HCM_VAR_H
> > +#define _HCM_VAR_H
> > +
> > +struct hcm_softc {
> > +       u_int                   debug;
> > +       device_t                dev;
> > +       struct nhi_softc        *nsc;
> > +
> > +       struct task             cfg_task;
> > +       struct taskqueue        *taskqueue;
> > +};
> > +
> > +int hcm_attach(struct nhi_softc *);
> > +int hcm_detach(struct nhi_softc *);
> > +int hcm_router_discover(struct hcm_softc *);
> > +
> > +#endif /* _HCM_VAR_H */
> > diff --git a/sys/dev/thunderbolt/nhi.c b/sys/dev/thunderbolt/nhi.c
> > new file mode 100644
> > index 000000000000..205e69c16253
> > --- /dev/null
> > +++ b/sys/dev/thunderbolt/nhi.c
> > @@ -0,0 +1,1170 @@
> > +/*-
> > + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
> > + *
> > + * Copyright (c) 2022 Scott Long
> > + * All rights reserved.
> > + *
> > + * Redistribution and use in source and binary forms, with or without
> > + * modification, are permitted provided that the following conditions
> > + * are met:
> > + * 1. Redistributions of source code must retain the above copyright
> > + *    notice, this list of conditions and the following disclaimer.
> > + * 2. Redistributions in binary form must reproduce the above copyrigh=
t
> > + *    notice, this list of conditions and the following disclaimer in
> the
> > + *    documentation and/or other materials provided with the
> distribution.
> > + *
> > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
> AND
> > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, T=
HE
> > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
> PURPOSE
> > + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
> LIABLE
> > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL
> > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
> GOODS
> > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTIO=
N)
> > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> STRICT
> > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
> ANY WAY
> > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
> OF
> > + * SUCH DAMAGE.
> > + */
> > +
> > +#include "opt_thunderbolt.h"
> > +
> > +/* PCIe interface for Thunderbolt Native Host Interface (nhi) */
> > +#include <sys/types.h>
> > +#include <sys/param.h>
> > +#include <sys/systm.h>
> > +#include <sys/kernel.h>
> > +#include <sys/module.h>
> > +#include <sys/bus.h>
> > +#include <sys/conf.h>
> > +#include <sys/malloc.h>
> > +#include <sys/queue.h>
> > +#include <sys/sysctl.h>
> > +#include <sys/lock.h>
> > +#include <sys/mutex.h>
> > +#include <sys/taskqueue.h>
> > +#include <sys/gsb_crc32.h>
> > +#include <sys/endian.h>
> > +#include <vm/vm.h>
> > +#include <vm/pmap.h>
> > +
> > +#include <machine/bus.h>
> > +#include <machine/stdarg.h>
> > +
> > +#include <dev/thunderbolt/nhi_reg.h>
> > +#include <dev/thunderbolt/nhi_var.h>
> > +#include <dev/thunderbolt/tb_reg.h>
> > +#include <dev/thunderbolt/tb_var.h>
> > +#include <dev/thunderbolt/tb_debug.h>
> > +#include <dev/thunderbolt/hcm_var.h>
> > +#include <dev/thunderbolt/tbcfg_reg.h>
> > +#include <dev/thunderbolt/router_var.h>
> > +#include <dev/thunderbolt/tb_dev.h>
> > +#include "tb_if.h"
> > +
> > +static int nhi_alloc_ring(struct nhi_softc *, int, int, int,
> > +    struct nhi_ring_pair **);
> > +static void nhi_free_ring(struct nhi_ring_pair *);
> > +static void nhi_free_rings(struct nhi_softc *);
> > +static int nhi_configure_ring(struct nhi_softc *, struct nhi_ring_pair
> *);
> > +static int nhi_activate_ring(struct nhi_ring_pair *);
> > +static int nhi_deactivate_ring(struct nhi_ring_pair *);
> > +static int nhi_alloc_ring0(struct nhi_softc *);
> > +static void nhi_free_ring0(struct nhi_softc *);
> > +static void nhi_fill_rx_ring(struct nhi_softc *, struct nhi_ring_pair
> *);
> > +static int nhi_init(struct nhi_softc *);
> > +static void nhi_post_init(void *);
> > +static int nhi_tx_enqueue(struct nhi_ring_pair *, struct nhi_cmd_frame
> *);
> > +static int nhi_setup_sysctl(struct nhi_softc *);
> > +
> > +SYSCTL_NODE(_hw, OID_AUTO, nhi, CTLFLAG_RD, 0, "NHI Driver Parameters"=
);
> > +
> > +MALLOC_DEFINE(M_NHI, "nhi", "nhi driver memory");
> > +
> > +#ifndef NHI_DEBUG_LEVEL
> > +#define NHI_DEBUG_LEVEL 0
> > +#endif
> > +
> > +/* 0 =3D default, 1 =3D force-on, 2 =3D force-off */
> > +#ifndef NHI_FORCE_HCM
> > +#define NHI_FORCE_HCM 0
> > +#endif
> > +
> > +void
> > +nhi_get_tunables(struct nhi_softc *sc)
> > +{
> > +       devclass_t dc;
> > +       device_t ufp;
> > +       char    tmpstr[80], oid[80];
> > +       u_int   val;
> > +
> > +       /* Set local defaults */
> > +       sc->debug =3D NHI_DEBUG_LEVEL;
> > +       sc->max_ring_count =3D NHI_DEFAULT_NUM_RINGS;
> > +       sc->force_hcm =3D NHI_FORCE_HCM;
> > +
> > +       /* Inherit setting from the upstream thunderbolt switch node */
> > +       val =3D TB_GET_DEBUG(sc->dev, &sc->debug);
> > +       if (val !=3D 0) {
> > +               dc =3D devclass_find("tbolt");
> > +               if (dc !=3D NULL) {
> > +                       ufp =3D devclass_get_device(dc,
> device_get_unit(sc->dev));
> > +                       if (ufp !=3D NULL)
> > +                               TB_GET_DEBUG(ufp, &sc->debug);
> > +               } else {
> > +                       if (TUNABLE_STR_FETCH("hw.tbolt.debug_level",
> oid,
> > +                           80) !=3D 0)
> > +                               tb_parse_debug(&sc->debug, oid);
> > +               }
> > +       }
> > +
> > +       /*
> > +        * Grab global variables.  Allow nhi debug flags to override
> > +        * thunderbolt debug flags, if present.
> > +        */
> > +       bzero(oid, 80);
> > +       if (TUNABLE_STR_FETCH("hw.nhi.debug_level", oid, 80) !=3D 0)
> > +               tb_parse_debug(&sc->debug, oid);
> > +       if (TUNABLE_INT_FETCH("hw.nhi.max_rings", &val) !=3D 0) {
> > +               val =3D min(val, NHI_MAX_NUM_RINGS);
> > +               sc->max_ring_count =3D max(val, 1);
> > +       }
> > +       if (TUNABLE_INT_FETCH("hw.nhi.force_hcm", &val) !=3D 0)
> > +               sc->force_hcm =3D val;
> > +
> > +       /* Grab instance variables */
> > +       bzero(oid, 80);
> > +       snprintf(tmpstr, sizeof(tmpstr), "dev.nhi.%d.debug_level",
> > +           device_get_unit(sc->dev));
> > +       if (TUNABLE_STR_FETCH(tmpstr, oid, 80) !=3D 0)
> > +               tb_parse_debug(&sc->debug, oid);
> > +       snprintf(tmpstr, sizeof(tmpstr), "dev.nhi.%d.max_rings",
> > +           device_get_unit(sc->dev));
> > +       if (TUNABLE_INT_FETCH(tmpstr, &val) !=3D 0) {
> > +               val =3D min(val, NHI_MAX_NUM_RINGS);
> > +               sc->max_ring_count =3D max(val, 1);
> > +       }
> > +       snprintf(tmpstr, sizeof(tmpstr), "dev, nhi.%d.force_hcm",
> > +           device_get_unit(sc->dev));
> > +       if (TUNABLE_INT_FETCH(tmpstr, &val) !=3D 0)
> > +               sc->force_hcm =3D val;
> > +
> > +       return;
> > +}
> > +
> > +static void
> > +nhi_configure_caps(struct nhi_softc *sc)
> > +{
> > +
> > +       if (NHI_IS_USB4(sc) || (sc->force_hcm =3D=3D NHI_FORCE_HCM_ON))
> > +               sc->caps |=3D NHI_CAP_HCM;
> > +       if (sc->force_hcm =3D=3D NHI_FORCE_HCM_OFF)
> > +               sc->caps &=3D ~NHI_CAP_HCM;
> > +}
> > +
> > +struct nhi_cmd_frame *
> > +nhi_alloc_tx_frame(struct nhi_ring_pair *r)
> > +{
> > +       struct nhi_cmd_frame *cmd;
> > +
> > +       mtx_lock(&r->mtx);
> > +       cmd =3D nhi_alloc_tx_frame_locked(r);
> > +       mtx_unlock(&r->mtx);
> > +
> > +       return (cmd);
> > +}
> > +
> > +void
> > +nhi_free_tx_frame(struct nhi_ring_pair *r, struct nhi_cmd_frame *cmd)
> > +{
> > +       mtx_lock(&r->mtx);
> > +       nhi_free_tx_frame_locked(r, cmd);
> > +       mtx_unlock(&r->mtx);
> > +}
> > +
> > +/*
> > + * Push a command and data dword through the mailbox to the firmware.
> > + * Response is either good, error, or timeout.  Commands that return
> data
> > + * do so by reading OUTMAILDATA.
> > + */
> > +int
> > +nhi_inmail_cmd(struct nhi_softc *sc, uint32_t cmd, uint32_t data)
> > +{
> > +       uint32_t val;
> > +       u_int error, timeout;
> > +
> > +       mtx_lock(&sc->nhi_mtx);
> > +       /*
> > +        * XXX Should a defer/reschedule happen here, or is it not wort=
h
> > +        * worrying about?
> > +        */
> > +       if (sc->hwflags & NHI_MBOX_BUSY) {
> > +               mtx_unlock(&sc->nhi_mtx);
> > +               tb_debug(sc, DBG_MBOX, "Driver busy with mailbox\n");
> > +               return (EBUSY);
> > +       }
> > +       sc->hwflags |=3D NHI_MBOX_BUSY;
> > +
> > +       val =3D nhi_read_reg(sc, TBT_INMAILCMD);
> > +       tb_debug(sc, DBG_MBOX|DBG_FULL, "Reading INMAILCMD=3D 0x%08x\n"=
,
> val);
> > +       if (val & INMAILCMD_ERROR)
> > +               tb_debug(sc, DBG_MBOX, "Error already set in
> INMAILCMD\n");
> > +       if (val & INMAILCMD_OPREQ) {
> > +               mtx_unlock(&sc->nhi_mtx);
> > +               tb_debug(sc, DBG_MBOX,
> > +                   "INMAILCMD request already in progress\n");
> > +               return (EBUSY);
> > +       }
> > +
> > +       nhi_write_reg(sc, TBT_INMAILDATA, data);
> > +       nhi_write_reg(sc, TBT_INMAILCMD, cmd | INMAILCMD_OPREQ);
> > +
> > +       /* Poll at 1s intervals */
> > +       timeout =3D NHI_MAILBOX_TIMEOUT;
> > +       while (timeout--) {
> > +               DELAY(1000000);
> > +               val =3D nhi_read_reg(sc, TBT_INMAILCMD);
> > +               tb_debug(sc, DBG_MBOX|DBG_EXTRA,
> > +                   "Polling INMAILCMD=3D 0x%08x\n", val);
> > +               if ((val & INMAILCMD_OPREQ) =3D=3D 0)
> > +                       break;
> > +       }
> > +       sc->hwflags &=3D ~NHI_MBOX_BUSY;
> > +       mtx_unlock(&sc->nhi_mtx);
> > +
> > +       error =3D 0;
> > +       if (val & INMAILCMD_OPREQ) {
> > +               tb_printf(sc, "Timeout waiting for mailbox\n");
> > +               error =3D ETIMEDOUT;
> > +       }
> > +       if (val & INMAILCMD_ERROR) {
> > +               tb_printf(sc, "Firmware reports error in mailbox\n");
> > +               error =3D EINVAL;
> > +       }
> > +
> > +       return (error);
> > +}
> > +
> > +/*
> > + * Pull command status and data from the firmware mailbox.
> > + */
> > +int
> > +nhi_outmail_cmd(struct nhi_softc *sc, uint32_t *val)
> > +{
> > +
> > +       if (val =3D=3D NULL)
> > +               return (EINVAL);
> > +       *val =3D nhi_read_reg(sc, TBT_OUTMAILCMD);
> > +       return (0);
> > +}
> > +
> > +int
> > +nhi_attach(struct nhi_softc *sc)
> > +{
> > +       uint32_t val;
> > +       int error =3D 0;
> > +
> > +       if ((error =3D nhi_setup_sysctl(sc)) !=3D 0)
> > +               return (error);
> > +
> > +       mtx_init(&sc->nhi_mtx, "nhimtx", "NHI Control Mutex", MTX_DEF);
> > +
> > +       nhi_configure_caps(sc);
> > +
> > +       /*
> > +        * Get the number of TX/RX paths.  This sizes some of the
> register
> > +        * arrays during allocation and initialization.  USB4 spec says
> that
> > +        * the max is 21.  Alpine Ridge appears to default to 12.
> > +        */
> > +       val =3D GET_HOST_CAPS_PATHS(nhi_read_reg(sc, NHI_HOST_CAPS));
> > +       tb_debug(sc, DBG_INIT|DBG_NOISY, "Total Paths=3D %d\n", val);
> > +       if ((val =3D=3D 0) || (val > 21) || ((NHI_IS_AR(sc) && val !=3D=
 12))) {
> > +               tb_printf(sc, "WARN: unexpected number of paths: %d\n",
> val);
> > +               /* return (ENXIO); */
> > +       }
> > +       sc->path_count =3D val;
> > +
> > +       SLIST_INIT(&sc->ring_list);
> > +
> > +       error =3D nhi_pci_configure_interrupts(sc);
> > +       if (error =3D=3D 0)
> > +               error =3D nhi_alloc_ring0(sc);
> > +       if (error =3D=3D 0) {
> > +               nhi_configure_ring(sc, sc->ring0);
> > +               nhi_activate_ring(sc->ring0);
> > +               nhi_fill_rx_ring(sc, sc->ring0);
> > +       }
> > +
> > +       if (error =3D=3D 0)
> > +               error =3D tbdev_add_interface(sc);
> > +
> > +       if ((error =3D=3D 0) && (NHI_USE_ICM(sc)))
> > +               tb_printf(sc, "WARN: device uses an internal connection
> manager\n");
> > +       if ((error =3D=3D 0) && (NHI_USE_HCM(sc)))
> > +               ;
> > +       error =3D hcm_attach(sc);
> > +
> > +       if (error =3D=3D 0)
> > +               error =3D nhi_init(sc);
> > +
> > +       return (error);
> > +}
> > +
> > +int
> > +nhi_detach(struct nhi_softc *sc)
> > +{
> > +
> > +       if (NHI_USE_HCM(sc))
> > +               hcm_detach(sc);
> > +
> > +       if (sc->root_rsc !=3D NULL)
> > +               tb_router_detach(sc->root_rsc);
> > +
> > +       tbdev_remove_interface(sc);
> > +
> > +       nhi_pci_disable_interrupts(sc);
> > +
> > +       nhi_free_ring0(sc);
> > +
> > +       /* XXX Should the rings be marked as !VALID in the descriptors?
> */
> > +       nhi_free_rings(sc);
> > +
> > +       mtx_destroy(&sc->nhi_mtx);
> > +
> > +       return (0);
> > +}
> > +
> > +static void
> > +nhi_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int erro=
r)
> > +{
> > +       bus_addr_t *addr;
> > +
> > +       addr =3D arg;
> > +       if (error =3D=3D 0 && nsegs =3D=3D 1) {
> > +               *addr =3D segs[0].ds_addr;
> > +       } else
> > +               *addr =3D 0;
> > +}
> > +
> > +static int
> > +nhi_alloc_ring(struct nhi_softc *sc, int ringnum, int tx_depth, int
> rx_depth,
> > +    struct nhi_ring_pair **rp)
> > +{
> > +       bus_dma_template_t t;
> > +       bus_addr_t ring_busaddr;
> > +       struct nhi_ring_pair *r;
> > +       int ring_size, error;
> > +       u_int rxring_len, txring_len;
> > +       char *ring;
> > +
> > +       if (ringnum >=3D sc->max_ring_count) {
> > +               tb_debug(sc, DBG_INIT, "Tried to allocate ring number
> %d\n",
> > +                   ringnum);
> > +               return (EINVAL);
> > +       }
> > +
> > +       /* Allocate the ring structure and the RX ring tacker together.
> */
> > +       rxring_len =3D rx_depth * sizeof(void *);
> > +       txring_len =3D tx_depth * sizeof(void *);
> > +       r =3D malloc(sizeof(struct nhi_ring_pair) + rxring_len +
> txring_len,
> > +           M_NHI, M_NOWAIT|M_ZERO);
> > +       if (r =3D=3D NULL) {
> > +               tb_printf(sc, "ERROR: Cannot allocate ring memory\n");
> > +               return (ENOMEM);
> > +       }
> > +
> > +       r->sc =3D sc;
> > +       TAILQ_INIT(&r->tx_head);
> > +       TAILQ_INIT(&r->rx_head);
> > +       r->ring_num =3D ringnum;
> > +       r->tx_ring_depth =3D tx_depth;
> > +       r->tx_ring_mask =3D tx_depth - 1;
> > +       r->rx_ring_depth =3D rx_depth;
> > +       r->rx_ring_mask =3D rx_depth - 1;
> > +       r->rx_pici_reg =3D NHI_RX_RING_PICI + ringnum * 16;
> > +       r->tx_pici_reg =3D NHI_TX_RING_PICI + ringnum * 16;
> > +       r->rx_cmd_ring =3D (struct nhi_cmd_frame **)((uint8_t *)r + siz=
eof
> (*r));
> > +       r->tx_cmd_ring =3D (struct nhi_cmd_frame **)((uint8_t
> *)r->rx_cmd_ring +
> > +           rxring_len);
> > +
> > +       snprintf(r->name, NHI_RING_NAMELEN, "nhiring%d\n", ringnum);
> > +       mtx_init(&r->mtx, r->name, "NHI Ring Lock", MTX_DEF);
> > +       tb_debug(sc, DBG_INIT | DBG_FULL, "Allocated ring context at %p=
,
> "
> > +           "mutex %p\n", r, &r->mtx);
> > +
> > +       /* Allocate the RX and TX buffer descriptor rings */
> > +       ring_size =3D sizeof(struct nhi_tx_buffer_desc) * r->tx_ring_de=
pth;
> > +       ring_size +=3D sizeof(struct nhi_rx_buffer_desc) *
> r->rx_ring_depth;
> > +       tb_debug(sc, DBG_INIT | DBG_FULL, "Ring %d ring_size=3D %d\n",
> > +           ringnum, ring_size);
> > +
> > +       bus_dma_template_init(&t, sc->parent_dmat);
> > +       t.alignment =3D 4;
> > +       t.maxsize =3D t.maxsegsize =3D ring_size;
> > +       t.nsegments =3D 1;
> > +       if ((error =3D bus_dma_template_tag(&t, &r->ring_dmat)) !=3D 0)=
 {
> > +               tb_printf(sc, "Cannot allocate ring %d DMA tag: %d\n",
> > +                   ringnum, error);
> > +               return (ENOMEM);
> > +       }
> > +       if (bus_dmamem_alloc(r->ring_dmat, (void **)&ring,
> BUS_DMA_NOWAIT,
> > +           &r->ring_map)) {
> > +               tb_printf(sc, "Cannot allocate ring memory\n");
> > +               return (ENOMEM);
> > +       }
> > +       bzero(ring, ring_size);
> > +       bus_dmamap_load(r->ring_dmat, r->ring_map, ring, ring_size,
> > +           nhi_memaddr_cb, &ring_busaddr, 0);
> > +
> > +       r->ring =3D ring;
> > +
> > +       r->tx_ring =3D (union nhi_ring_desc *)(ring);
> > +       r->tx_ring_busaddr =3D ring_busaddr;
> > +       ring +=3D sizeof(struct nhi_tx_buffer_desc) * r->tx_ring_depth;
> > +       ring_busaddr +=3D sizeof(struct nhi_tx_buffer_desc) *
> r->tx_ring_depth;
> > +
> > +       r->rx_ring =3D (union nhi_ring_desc *)(ring);
> > +       r->rx_ring_busaddr =3D ring_busaddr;
> > +
> > +       tb_debug(sc, DBG_INIT | DBG_EXTRA, "Ring %d: RX %p [0x%jx] "
> > +           "TX %p [0x%jx]\n", ringnum, r->tx_ring, r->tx_ring_busaddr,
> > +           r->rx_ring, r->rx_ring_busaddr);
> > +
> > +       *rp =3D r;
> > +       return (0);
> > +}
> > +
> > +static void
> > +nhi_free_ring(struct nhi_ring_pair *r)
> > +{
> > +
> > +       tb_debug(r->sc, DBG_INIT, "Freeing ring %d resources\n",
> r->ring_num);
> > +       nhi_deactivate_ring(r);
> > +
> > +       if (r->tx_ring_busaddr !=3D 0) {
> > +               bus_dmamap_unload(r->ring_dmat, r->ring_map);
> > +               r->tx_ring_busaddr =3D 0;
> > +       }
> > +       if (r->ring !=3D NULL) {
> > +               bus_dmamem_free(r->ring_dmat, r->ring, r->ring_map);
> > +               r->ring =3D NULL;
> > +       }
> > +       if (r->ring_dmat !=3D NULL) {
> > +               bus_dma_tag_destroy(r->ring_dmat);
> > +               r->ring_dmat =3D NULL;
> > +       }
> > +       mtx_destroy(&r->mtx);
> > +}
> > +
> > +static void
> > +nhi_free_rings(struct nhi_softc *sc)
> > +{
> > +       struct nhi_ring_pair *r;
> > +
> > +       while ((r =3D SLIST_FIRST(&sc->ring_list)) !=3D NULL) {
> > +               nhi_free_ring(r);
> > +               mtx_lock(&sc->nhi_mtx);
> > +               SLIST_REMOVE_HEAD(&sc->ring_list, ring_link);
> > +               mtx_unlock(&sc->nhi_mtx);
> > +               free(r, M_NHI);
> > +       }
> > +
> > +       return;
> > +}
> > +
> > +static int
> > +nhi_configure_ring(struct nhi_softc *sc, struct nhi_ring_pair *ring)
> > +{
> > +       bus_addr_t busaddr;
> > +       uint32_t val;
> > +       int idx;
> > +
> > +       idx =3D ring->ring_num * 16;
> > +
> > +       /* Program the TX ring address and size */
> > +       busaddr =3D ring->tx_ring_busaddr;
> > +       nhi_write_reg(sc, NHI_TX_RING_ADDR_LO + idx, busaddr &
> 0xffffffff);
> > +       nhi_write_reg(sc, NHI_TX_RING_ADDR_HI + idx, busaddr >> 32);
> > +       nhi_write_reg(sc, NHI_TX_RING_SIZE + idx, ring->tx_ring_depth);
> > +       nhi_write_reg(sc, NHI_TX_RING_TABLE_TIMESTAMP + idx, 0x0);
> > +       tb_debug(sc, DBG_INIT, "TX Ring %d TX_RING_SIZE=3D 0x%x\n",
> > +           ring->ring_num, ring->tx_ring_depth);
> > +
> > +       /* Program the RX ring address and size */
> > +       busaddr =3D ring->rx_ring_busaddr;
> > +       val =3D (ring->rx_buffer_size << 16) | ring->rx_ring_depth;
> > +       nhi_write_reg(sc, NHI_RX_RING_ADDR_LO + idx, busaddr &
> 0xffffffff);
> > +       nhi_write_reg(sc, NHI_RX_RING_ADDR_HI + idx, busaddr >> 32);
> > +       nhi_write_reg(sc, NHI_RX_RING_SIZE + idx, val);
> > +       nhi_write_reg(sc, NHI_RX_RING_TABLE_BASE1 + idx, 0xffffffff);
> > +       tb_debug(sc, DBG_INIT, "RX Ring %d RX_RING_SIZE=3D 0x%x\n",
> > +           ring->ring_num, val);
> > +
> > +       return (0);
> > +}
> > +
> > +static int
> > +nhi_activate_ring(struct nhi_ring_pair *ring)
> > +{
> > +       struct nhi_softc *sc =3D ring->sc;
> > +       int idx;
> > +
> > +       nhi_pci_enable_interrupt(ring);
> > +
> > +       idx =3D ring->ring_num * 32;
> > +       tb_debug(sc, DBG_INIT, "Activating ring %d at idx %d\n",
> > +           ring->ring_num, idx);
> > +       nhi_write_reg(sc, NHI_TX_RING_TABLE_BASE0 + idx,
> > +           TX_TABLE_RAW | TX_TABLE_VALID);
> > +       nhi_write_reg(sc, NHI_RX_RING_TABLE_BASE0 + idx,
> > +           RX_TABLE_RAW | RX_TABLE_VALID);
> > +
> > +       return (0);
> > +}
> > +
> > +static int
> > +nhi_deactivate_ring(struct nhi_ring_pair *r)
> > +{
> > +       struct nhi_softc *sc =3D r->sc;
> > +       int idx;
> > +
> > +       idx =3D r->ring_num * 32;
> > +       tb_debug(sc, DBG_INIT, "Deactiving ring %d at idx %d\n",
> > +           r->ring_num, idx);
> > +       nhi_write_reg(sc, NHI_TX_RING_TABLE_BASE0 + idx, 0);
> > +       nhi_write_reg(sc, NHI_RX_RING_TABLE_BASE0 + idx, 0);
> > +
> > +       idx =3D r->ring_num * 16;
> > +       tb_debug(sc, DBG_INIT, "Setting ring %d sizes to 0\n",
> r->ring_num);
> > +       nhi_write_reg(sc, NHI_TX_RING_SIZE + idx, 0);
> > +       nhi_write_reg(sc, NHI_RX_RING_SIZE + idx, 0);
> > +
> > +       return (0);
> > +}
> > +
> > +static int
> > +nhi_alloc_ring0(struct nhi_softc *sc)
> > +{
> > +       bus_addr_t frames_busaddr;
> > +       bus_dma_template_t t;
> > +       struct nhi_intr_tracker *trkr;
> > +       struct nhi_ring_pair *r;
> > +       struct nhi_cmd_frame *cmd;
> > +       char *frames;
> > +       int error, size, i;
> > +
> > +       if ((error =3D nhi_alloc_ring(sc, 0, NHI_RING0_TX_DEPTH,
> > +           NHI_RING0_RX_DEPTH, &r)) !=3D 0) {
> > +               tb_printf(sc, "Error allocating control ring\n");
> > +               return (error);
> > +       }
> > +
> > +       r->rx_buffer_size =3D NHI_RING0_FRAME_SIZE;/* Control packets a=
re
> small */
> > +
> > +       /* Allocate the RX and TX buffers that are used for Ring0 comms
> */
> > +       size =3D r->tx_ring_depth * NHI_RING0_FRAME_SIZE;
> > +       size +=3D r->rx_ring_depth * NHI_RING0_FRAME_SIZE;
> > +
> > +       bus_dma_template_init(&t, sc->parent_dmat);
> > +       t.maxsize =3D t.maxsegsize =3D size;
> > +       t.nsegments =3D 1;
> > +       if (bus_dma_template_tag(&t, &sc->ring0_dmat)) {
> > +               tb_printf(sc, "Error allocating control ring buffer
> tag\n");
> > +               return (ENOMEM);
> > +       }
> > +
> > +       if (bus_dmamem_alloc(sc->ring0_dmat, (void **)&frames,
> BUS_DMA_NOWAIT,
> > +           &sc->ring0_map) !=3D 0) {
> > +               tb_printf(sc, "Error allocating control ring memory\n")=
;
> > +               return (ENOMEM);
> > +       }
> > +       bzero(frames, size);
> > +       bus_dmamap_load(sc->ring0_dmat, sc->ring0_map, frames, size,
> > +           nhi_memaddr_cb, &frames_busaddr, 0);
> > +       sc->ring0_frames_busaddr =3D frames_busaddr;
> > +       sc->ring0_frames =3D frames;
> > +
> > +       /* Allocate the driver command trackers */
> > +       sc->ring0_cmds =3D malloc(sizeof(struct nhi_cmd_frame) *
> > +           (r->tx_ring_depth + r->rx_ring_depth), M_NHI, M_NOWAIT |
> M_ZERO);
> > +       if (sc->ring0_cmds =3D=3D NULL)
> > +               return (ENOMEM);
> > +
> > +       /* Initialize the RX frames so they can be used */
> > +       mtx_lock(&r->mtx);
> > +       for (i =3D 0; i < r->rx_ring_depth; i++) {
> > +               cmd =3D &sc->ring0_cmds[i];
> > +               cmd->data =3D (uint32_t *)(frames + NHI_RING0_FRAME_SIZ=
E *
> i);
> > +               cmd->data_busaddr =3D frames_busaddr +
> NHI_RING0_FRAME_SIZE * i;
> > +               cmd->flags =3D CMD_MAPPED;
> > +               cmd->idx =3D i;
> > +               TAILQ_INSERT_TAIL(&r->rx_head, cmd, cm_link);
> > +       }
> > +
> > +       /* Inititalize the TX frames */
> > +       for ( ; i < r->tx_ring_depth + r->rx_ring_depth - 1; i++) {
> > +               cmd =3D &sc->ring0_cmds[i];
> > +               cmd->data =3D (uint32_t *)(frames + NHI_RING0_FRAME_SIZ=
E *
> i);
> > +               cmd->data_busaddr =3D frames_busaddr +
> NHI_RING0_FRAME_SIZE * i;
> > +               cmd->flags =3D CMD_MAPPED;
> > +               cmd->idx =3D i;
> > +               nhi_free_tx_frame_locked(r, cmd);
> > +       }
> > +       mtx_unlock(&r->mtx);
> > +
> > +       /* Do a 1:1 mapping of rings to interrupt vectors. */
> > +       /* XXX Should be abstracted */
> > +       trkr =3D &sc->intr_trackers[0];
> > +       trkr->ring =3D r;
> > +       r->tracker =3D trkr;
> > +
> > +       /* XXX Should be an array */
> > +       sc->ring0 =3D r;
> > +       SLIST_INSERT_HEAD(&sc->ring_list, r, ring_link);
> > +
> > +       return (0);
> > +}
> > +
> > +static void
> > +nhi_free_ring0(struct nhi_softc *sc)
> > +{
> > +       if (sc->ring0_cmds !=3D NULL) {
> > +               free(sc->ring0_cmds, M_NHI);
> > +               sc->ring0_cmds =3D NULL;
> > +       }
> > +
> > +       if (sc->ring0_frames_busaddr !=3D 0) {
> > +               bus_dmamap_unload(sc->ring0_dmat, sc->ring0_map);
> > +               sc->ring0_frames_busaddr =3D 0;
> > *** 5529 LINES SKIPPED ***
>
>
>
> --
> Wolfram Schneider <wosch@FreeBSD.org> https://wolfram.schneider.org
>
>

--=20
Nuno Teixeira
FreeBSD UNIX:  <eduardo@FreeBSD.org>   Web:  https://FreeBSD.org

--00000000000085e79c0640338477
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">yep, seing that symlink too.</div><br><div class=3D"gmail_=
quote gmail_quote_container"><div dir=3D"ltr" class=3D"gmail_attr">Wolfram =
Schneider &lt;<a href=3D"mailto:wosch@freebsd.org">wosch@freebsd.org</a>&gt=
; escreveu (ter=C3=A7a, 30/09/2025 =C3=A0(s) 07:44):<br></div><blockquote c=
lass=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px soli=
d rgb(204,204,204);padding-left:1ex">I&#39;m now getting a stale symlink:<b=
r>
<br>
./tools/build/stale-symlink-buildworld.sh<br>
stale symlink detected: lrwxrwxr-x=C2=A0 1 wosch wheel 91 Sep 29 22:14<br>
/var/tmp/freebsd-obj-wosch/home/projects/freebsd-src/amd64.amd64/sys/GENERI=
C/modules/home/projects/freebsd-src/sys/modules/thunderbolt/opt_acpi_wmi.h<=
br>
-&gt; /var/tmp/freebsd-obj-wosch/home/projects/freebsd-src/amd64.amd64/sys/=
GENERIC/opt_acpi_wmi.h<br>
<br>
the only reference to the file &quot;opt_acpi_wmi.h&quot; is in the Makefil=
e<br>
<br>
sys/modules/thunderbolt/Makefile:SRCS+=3D opt_acpi.h opt_acpi_wmi.h<br>
acpi_if.h acpi_wmi_if.h<br>
<br>
What is this file supposed to do, where does it come from?<br>
<br>
-Wolfram<br>
<br>
On Sat, 27 Sept 2025 at 19:13, Aymeric Wibo &lt;<a href=3D"mailto:obiwac@fr=
eebsd.org" target=3D"_blank">obiwac@freebsd.org</a>&gt; wrote:<br>
&gt;<br>
&gt; The branch main has been updated by obiwac:<br>
&gt;<br>
&gt; URL: <a href=3D"https://cgit.FreeBSD.org/src/commit/?id=3D2ed9833791f2=
8e14843ac813f90cb030e45948dc" rel=3D"noreferrer" target=3D"_blank">https://=
cgit.FreeBSD.org/src/commit/?id=3D2ed9833791f28e14843ac813f90cb030e45948dc<=
/a><br>
&gt;<br>
&gt; commit 2ed9833791f28e14843ac813f90cb030e45948dc<br>
&gt; Author:=C2=A0 =C2=A0 =C2=A0Aymeric Wibo &lt;obiwac@FreeBSD.org&gt;<br>
&gt; AuthorDate: 2025-09-27 11:50:43 +0000<br>
&gt; Commit:=C2=A0 =C2=A0 =C2=A0Aymeric Wibo &lt;obiwac@FreeBSD.org&gt;<br>
&gt; CommitDate: 2025-09-27 17:13:13 +0000<br>
&gt;<br>
&gt;=C2=A0 =C2=A0 =C2=A0thunderbolt: Import USB4 code<br>
&gt;<br>
&gt;=C2=A0 =C2=A0 =C2=A0Add initial USB4 code written by Scott Long and ori=
ginally passed on to<br>
&gt;=C2=A0 =C2=A0 =C2=A0HPS (source: <a href=3D"https://github.com/hselasky=
/usb4" rel=3D"noreferrer" target=3D"_blank">https://github.com/hselasky/usb=
4</a>), minus the ICM code and<br>
&gt;=C2=A0 =C2=A0 =C2=A0with some small fixes.<br>
&gt;<br>
&gt;=C2=A0 =C2=A0 =C2=A0For context, older TB chips implemented the connect=
ion manager in<br>
&gt;=C2=A0 =C2=A0 =C2=A0firmware (ICM) instead of in the OS (HCM), but main=
taining the ICM code<br>
&gt;=C2=A0 =C2=A0 =C2=A0would be a huge burden for not many chips.<br>
&gt;<br>
&gt;=C2=A0 =C2=A0 =C2=A0Mostly completed work:<br>
&gt;<br>
&gt;=C2=A0 =C2=A0 =C2=A0- Debug/trace framework.<br>
&gt;=C2=A0 =C2=A0 =C2=A0- NHI controller driver.<br>
&gt;=C2=A0 =C2=A0 =C2=A0- PCIe bridge driver.<br>
&gt;=C2=A0 =C2=A0 =C2=A0- Router and config space layer handling (just read=
ing in this commit).<br>
&gt;<br>
&gt;=C2=A0 =C2=A0 =C2=A0Link to the email where Scott shared details about =
the initial USB4<br>
&gt;=C2=A0 =C2=A0 =C2=A0work:<br>
&gt;<br>
&gt;=C2=A0 =C2=A0 =C2=A0<a href=3D"https://lists.freebsd.org/archives/freeb=
sd-hackers/2024-July/003411.html" rel=3D"noreferrer" target=3D"_blank">http=
s://lists.freebsd.org/archives/freebsd-hackers/2024-July/003411.html</a><br=
>
&gt;<br>
&gt;=C2=A0 =C2=A0 =C2=A0Glanced at by:=C2=A0 emaste, imp<br>
&gt;=C2=A0 =C2=A0 =C2=A0Sponsored by:=C2=A0 =C2=A0The FreeBSD Foundation<br=
>
&gt;=C2=A0 =C2=A0 =C2=A0Differential Revision:=C2=A0 <a href=3D"https://rev=
iews.freebsd.org/D49450" rel=3D"noreferrer" target=3D"_blank">https://revie=
ws.freebsd.org/D49450</a><br>
&gt;=C2=A0 =C2=A0 =C2=A0Event:=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 EuroBSDcon=
 2025<br>
&gt; ---<br>
&gt;=C2=A0 sys/dev/thunderbolt/hcm.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 |=C2=
=A0 223 +++++++<br>
&gt;=C2=A0 sys/dev/thunderbolt/hcm_var.h=C2=A0 =C2=A0 =C2=A0 |=C2=A0 =C2=A0=
47 ++<br>
&gt;=C2=A0 sys/dev/thunderbolt/nhi.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | 11=
70 ++++++++++++++++++++++++++++++++++++<br>
&gt;=C2=A0 sys/dev/thunderbolt/nhi_pci.c=C2=A0 =C2=A0 =C2=A0 |=C2=A0 529 ++=
++++++++++++++<br>
&gt;=C2=A0 sys/dev/thunderbolt/nhi_reg.h=C2=A0 =C2=A0 =C2=A0 |=C2=A0 332 ++=
++++++++<br>
&gt;=C2=A0 sys/dev/thunderbolt/nhi_var.h=C2=A0 =C2=A0 =C2=A0 |=C2=A0 277 ++=
+++++++<br>
&gt;=C2=A0 sys/dev/thunderbolt/nhi_wmi.c=C2=A0 =C2=A0 =C2=A0 |=C2=A0 198 ++=
++++<br>
&gt;=C2=A0 sys/dev/thunderbolt/router.c=C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 9=
39 +++++++++++++++++++++++++++++<br>
&gt;=C2=A0 sys/dev/thunderbolt/router_var.h=C2=A0 =C2=A0|=C2=A0 242 +++++++=
+<br>
&gt;=C2=A0 sys/dev/thunderbolt/tb_acpi_pcib.c |=C2=A0 181 ++++++<br>
&gt;=C2=A0 sys/dev/thunderbolt/tb_debug.c=C2=A0 =C2=A0 =C2=A0|=C2=A0 334 ++=
++++++++<br>
&gt;=C2=A0 sys/dev/thunderbolt/tb_debug.h=C2=A0 =C2=A0 =C2=A0|=C2=A0 =C2=A0=
93 +++<br>
&gt;=C2=A0 sys/dev/thunderbolt/tb_dev.c=C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 3=
31 ++++++++++<br>
&gt;=C2=A0 sys/dev/thunderbolt/tb_dev.h=C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 =
=C2=A041 ++<br>
&gt;=C2=A0 sys/dev/thunderbolt/tb_if.m=C2=A0 =C2=A0 =C2=A0 =C2=A0 |=C2=A0 1=
21 ++++<br>
&gt;=C2=A0 sys/dev/thunderbolt/tb_ioctl.h=C2=A0 =C2=A0 =C2=A0|=C2=A0 =C2=A0=
52 ++<br>
&gt;=C2=A0 sys/dev/thunderbolt/tb_pcib.c=C2=A0 =C2=A0 =C2=A0 |=C2=A0 614 ++=
+++++++++++++++++<br>
&gt;=C2=A0 sys/dev/thunderbolt/tb_pcib.h=C2=A0 =C2=A0 =C2=A0 |=C2=A0 =C2=A0=
93 +++<br>
&gt;=C2=A0 sys/dev/thunderbolt/tb_reg.h=C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 =
=C2=A052 ++<br>
&gt;=C2=A0 sys/dev/thunderbolt/tb_var.h=C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 =
=C2=A054 ++<br>
&gt;=C2=A0 sys/dev/thunderbolt/tbcfg_reg.h=C2=A0 =C2=A0 |=C2=A0 363 +++++++=
++++<br>
&gt;=C2=A0 sys/modules/Makefile=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0|=C2=A0 =C2=A0 5 +<br>
&gt;=C2=A0 sys/modules/thunderbolt/Makefile=C2=A0 =C2=A0|=C2=A0 =C2=A013 +<=
br>
&gt;=C2=A0 23 files changed, 6304 insertions(+)<br>
&gt;<br>
&gt; diff --git a/sys/dev/thunderbolt/hcm.c b/sys/dev/thunderbolt/hcm.c<br>
&gt; new file mode 100644<br>
&gt; index 000000000000..b8f703fc3b52<br>
&gt; --- /dev/null<br>
&gt; +++ b/sys/dev/thunderbolt/hcm.c<br>
&gt; @@ -0,0 +1,223 @@<br>
&gt; +/*-<br>
&gt; + * SPDX-License-Identifier: BSD-2-Clause<br>
&gt; + *<br>
&gt; + * Copyright (c) 2022 Scott Long<br>
&gt; + * All rights reserved.<br>
&gt; + *<br>
&gt; + * Redistribution and use in source and binary forms, with or without=
<br>
&gt; + * modification, are permitted provided that the following conditions=
<br>
&gt; + * are met:<br>
&gt; + * 1. Redistributions of source code must retain the above copyright<=
br>
&gt; + *=C2=A0 =C2=A0 notice, this list of conditions and the following dis=
claimer.<br>
&gt; + * 2. Redistributions in binary form must reproduce the above copyrig=
ht<br>
&gt; + *=C2=A0 =C2=A0 notice, this list of conditions and the following dis=
claimer in the<br>
&gt; + *=C2=A0 =C2=A0 documentation and/or other materials provided with th=
e distribution.<br>
&gt; + *<br>
&gt; + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS&#=
39;&#39; AND<br>
&gt; + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, =
THE<br>
&gt; + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR=
 PURPOSE<br>
&gt; + * ARE DISCLAIMED.=C2=A0 IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS=
 BE LIABLE<br>
&gt; + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSE=
QUENTIAL<br>
&gt; + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE =
GOODS<br>
&gt; + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTI=
ON)<br>
&gt; + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT=
, STRICT<br>
&gt; + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN =
ANY WAY<br>
&gt; + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILIT=
Y OF<br>
&gt; + * SUCH DAMAGE.<br>
&gt; + */<br>
&gt; +<br>
&gt; +#include &quot;opt_thunderbolt.h&quot;<br>
&gt; +<br>
&gt; +/* Host Configuration Manager (HCM) for USB4 and later TB3 */<br>
&gt; +#include &lt;sys/types.h&gt;<br>
&gt; +#include &lt;sys/param.h&gt;<br>
&gt; +#include &lt;sys/systm.h&gt;<br>
&gt; +#include &lt;sys/kernel.h&gt;<br>
&gt; +#include &lt;sys/module.h&gt;<br>
&gt; +#include &lt;sys/bus.h&gt;<br>
&gt; +#include &lt;sys/conf.h&gt;<br>
&gt; +#include &lt;sys/malloc.h&gt;<br>
&gt; +#include &lt;sys/queue.h&gt;<br>
&gt; +#include &lt;sys/sysctl.h&gt;<br>
&gt; +#include &lt;sys/lock.h&gt;<br>
&gt; +#include &lt;sys/mutex.h&gt;<br>
&gt; +#include &lt;sys/taskqueue.h&gt;<br>
&gt; +#include &lt;sys/gsb_crc32.h&gt;<br>
&gt; +#include &lt;sys/endian.h&gt;<br>
&gt; +#include &lt;vm/vm.h&gt;<br>
&gt; +#include &lt;vm/pmap.h&gt;<br>
&gt; +<br>
&gt; +#include &lt;machine/bus.h&gt;<br>
&gt; +#include &lt;machine/stdarg.h&gt;<br>
&gt; +<br>
&gt; +#include &lt;dev/thunderbolt/nhi_reg.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/nhi_var.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/tb_reg.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/tb_var.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/tb_debug.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/tbcfg_reg.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/router_var.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/hcm_var.h&gt;<br>
&gt; +<br>
&gt; +static void hcm_cfg_task(void *, int);<br>
&gt; +<br>
&gt; +int<br>
&gt; +hcm_attach(struct nhi_softc *nsc)<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct hcm_softc *hcm;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(nsc, DBG_HCM|DBG_EXTRA, &quot;hcm=
_attach called\n&quot;);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0hcm =3D malloc(sizeof(struct hcm_softc), M=
_THUNDERBOLT, M_NOWAIT|M_ZERO);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (hcm =3D=3D NULL) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(nsc, =
DBG_HCM, &quot;Cannot allocate hcm object\n&quot;);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM=
);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0hcm-&gt;dev =3D nsc-&gt;dev;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0hcm-&gt;nsc =3D nsc;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nsc-&gt;hcm =3D hcm;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0hcm-&gt;taskqueue =3D taskqueue_create(&qu=
ot;hcm_event&quot;, M_NOWAIT,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0taskqueue_thread_enqueue, &a=
mp;hcm-&gt;taskqueue);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (hcm-&gt;taskqueue =3D=3D NULL)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM=
);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0taskqueue_start_threads(&amp;hcm-&gt;taskq=
ueue, 1, PI_DISK, &quot;tbhcm%d_tq&quot;,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0device_get_unit(nsc-&gt;dev)=
);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0TASK_INIT(&amp;hcm-&gt;cfg_task, 0, hcm_cf=
g_task, hcm);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);<br>
&gt; +}<br>
&gt; +<br>
&gt; +int<br>
&gt; +hcm_detach(struct nhi_softc *nsc)<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct hcm_softc *hcm;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0hcm =3D nsc-&gt;hcm;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (hcm-&gt;taskqueue)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0taskqueue_free=
(hcm-&gt;taskqueue);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);<br>
&gt; +}<br>
&gt; +<br>
&gt; +int<br>
&gt; +hcm_router_discover(struct hcm_softc *hcm)<br>
&gt; +{<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0taskqueue_enqueue(hcm-&gt;taskqueue, &amp;=
hcm-&gt;cfg_task);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);<br>
&gt; +}<br>
&gt; +<br>
&gt; +static void<br>
&gt; +hcm_cfg_task(void *arg, int pending)<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct hcm_softc *hcm;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct router_softc *rsc;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct router_cfg_cap cap;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct tb_cfg_router *cfg;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct tb_cfg_adapter *adp;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct tb_cfg_cap_lane *lane;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *buf;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t *u;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0u_int error, i, offset;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0hcm =3D (struct hcm_softc *)arg;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(hcm, DBG_HCM|DBG_EXTRA, &quot;hcm=
_cfg_task called\n&quot;);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0buf =3D malloc(8 * 4, M_THUNDERBOLT, M_NOW=
AIT|M_ZERO);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (buf =3D=3D NULL) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(hcm, =
DBG_HCM, &quot;Cannot alloc memory for discovery\n&quot;);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0rsc =3D hcm-&gt;nsc-&gt;root_rsc;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D tb_config_router_read(rsc, 0, 5,=
 buf);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error !=3D 0) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0free(buf, M_NH=
I);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0cfg =3D (struct tb_cfg_router *)buf;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0<a href=3D"http://cap.space" rel=3D"norefe=
rrer" target=3D"_blank">cap.space</a> =3D TB_CFG_CS_ROUTER;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0cap.adap =3D 0;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0cap.next_cap =3D GET_ROUTER_CS_NEXT_CAP(cf=
g);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0while (cap.next_cap !=3D 0) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D tb_c=
onfig_next_cap(rsc, &amp;cap);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (error !=3D=
 0)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0break;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if ((cap.cap_i=
d =3D=3D TB_CFG_CAP_VSEC) &amp;&amp; (cap.vsc_len =3D=3D 0)) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0tb_debug(hcm, DBG_HCM, &quot;Router Cap=3D %d, vsec=3D %d, &q=
uot;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0&quot;len=3D %d, next_cap=3D %d\n&quot;, cap.ca=
p_id,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0cap.vsc_id, cap.vsec_len, cap.next_cap);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else if (cap=
.cap_id =3D=3D TB_CFG_CAP_VSC) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0tb_debug(hcm, DBG_HCM, &quot;Router cap=3D %d, vsc=3D %d, &qu=
ot;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0&quot;len=3D %d, next_cap=3D %d\n&quot;, cap.ca=
p_id,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0cap.vsc_id, cap.vsc_len, cap.next_cap);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0tb_debug(hcm, DBG_HCM, &quot;Router cap=3D %d, &quot;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0&quot;next_cap=3D %d\n&quot;, cap.cap_id, cap.n=
ext_cap);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (cap.next_c=
ap &gt; TB_CFG_CAP_OFFSET_MAX)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0cap.next_cap =3D 0;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0u =3D (uint8_t *)buf;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D tb_config_get_lc_uuid(rsc, u);<b=
r>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error =3D=3D 0) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(hcm, =
DBG_HCM, &quot;Router LC UUID: %02x%02x%02x%02x-&quot;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
&quot;%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n&quot;,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
u[0], u[1], u[2], u[3], u[4], u[5], u[6], u[7], u[8],<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
u[9], u[10], u[11], u[12], u[13], u[14], u[15]);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0} else<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(hcm,=
 &quot;Error finding LC registers: %d\n&quot;, error);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 1; i &lt;=3D rsc-&gt;max_adap; =
i++) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D tb_c=
onfig_adapter_read(rsc, i, 0, 8, buf);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (error !=3D=
 0) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0tb_debug(hcm, DBG_HCM, &quot;Adapter %d: no adapter\n&quot;, =
i);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0continue;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0adp =3D (struc=
t tb_cfg_adapter *)buf;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(hcm, =
DBG_HCM, &quot;Adapter %d: %s, max_counters=3D 0x%08x,&quot;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
&quot; adapter_num=3D %d\n&quot;, i,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
tb_get_string(GET_ADP_CS_TYPE(adp), tb_adapter_type),<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
GET_ADP_CS_MAX_COUNTERS(adp), GET_ADP_CS_ADP_NUM(adp));<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (GET_ADP_CS=
_TYPE(adp) !=3D ADP_CS2_LANE)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0continue;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D tb_c=
onfig_find_adapter_cap(rsc, i, TB_CFG_CAP_LANE,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
&amp;offset);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (error)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0continue;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D tb_c=
onfig_adapter_read(rsc, i, offset, 3, buf);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (error)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0continue;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0lane =3D (stru=
ct tb_cfg_cap_lane *)buf;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(hcm, =
DBG_HCM, &quot;Lane Adapter State=3D %s %s\n&quot;,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
tb_get_string((lane-&gt;current_lws &amp; CAP_LANE_STATE_MASK),<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
tb_adapter_state), (lane-&gt;targ_lwp &amp; CAP_LANE_DISABLE) ?<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
&quot;disabled&quot; : &quot;enabled&quot;);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if ((lane-&gt;=
current_lws &amp; CAP_LANE_STATE_MASK) =3D=3D<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
CAP_LANE_STATE_CL0) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0tb_route_t newr;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0newr.hi =3D rsc-&gt;route.hi;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0newr.lo =3D rsc-&gt;route.lo | (i &lt;&lt; rsc-&gt;depth * 8)=
;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0tb_printf(hcm, &quot;want to add router at 0x%08x%08x\n&quot;=
,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0newr.hi, newr.lo);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0error =3D tb_router_attach(rsc, newr);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0tb_printf(rsc, &quot;tb_router_attach returned %d\n&quot;, er=
ror);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0free(buf, M_THUNDERBOLT);<br>
&gt; +}<br>
&gt; diff --git a/sys/dev/thunderbolt/hcm_var.h b/sys/dev/thunderbolt/hcm_v=
ar.h<br>
&gt; new file mode 100644<br>
&gt; index 000000000000..a11c8e9b6a92<br>
&gt; --- /dev/null<br>
&gt; +++ b/sys/dev/thunderbolt/hcm_var.h<br>
&gt; @@ -0,0 +1,47 @@<br>
&gt; +/*-<br>
&gt; + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD<br>
&gt; + *<br>
&gt; + * Copyright (c) 2022 Scott Long<br>
&gt; + * All rights reserved.<br>
&gt; + *<br>
&gt; + * Redistribution and use in source and binary forms, with or without=
<br>
&gt; + * modification, are permitted provided that the following conditions=
<br>
&gt; + * are met:<br>
&gt; + * 1. Redistributions of source code must retain the above copyright<=
br>
&gt; + *=C2=A0 =C2=A0 notice, this list of conditions and the following dis=
claimer.<br>
&gt; + * 2. Redistributions in binary form must reproduce the above copyrig=
ht<br>
&gt; + *=C2=A0 =C2=A0 notice, this list of conditions and the following dis=
claimer in the<br>
&gt; + *=C2=A0 =C2=A0 documentation and/or other materials provided with th=
e distribution.<br>
&gt; + *<br>
&gt; + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS&#=
39;&#39; AND<br>
&gt; + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, =
THE<br>
&gt; + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR=
 PURPOSE<br>
&gt; + * ARE DISCLAIMED.=C2=A0 IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS=
 BE LIABLE<br>
&gt; + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSE=
QUENTIAL<br>
&gt; + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE =
GOODS<br>
&gt; + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTI=
ON)<br>
&gt; + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT=
, STRICT<br>
&gt; + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN =
ANY WAY<br>
&gt; + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILIT=
Y OF<br>
&gt; + * SUCH DAMAGE.<br>
&gt; + *<br>
&gt; + * $FreeBSD$<br>
&gt; + */<br>
&gt; +<br>
&gt; +#ifndef _HCM_VAR_H<br>
&gt; +#define _HCM_VAR_H<br>
&gt; +<br>
&gt; +struct hcm_softc {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0u_int=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0debug;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0device_t=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 dev;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_softc=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 *nsc;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct task=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0cfg_task;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct taskqueue=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 *taskqueue;<br>
&gt; +};<br>
&gt; +<br>
&gt; +int hcm_attach(struct nhi_softc *);<br>
&gt; +int hcm_detach(struct nhi_softc *);<br>
&gt; +int hcm_router_discover(struct hcm_softc *);<br>
&gt; +<br>
&gt; +#endif /* _HCM_VAR_H */<br>
&gt; diff --git a/sys/dev/thunderbolt/nhi.c b/sys/dev/thunderbolt/nhi.c<br>
&gt; new file mode 100644<br>
&gt; index 000000000000..205e69c16253<br>
&gt; --- /dev/null<br>
&gt; +++ b/sys/dev/thunderbolt/nhi.c<br>
&gt; @@ -0,0 +1,1170 @@<br>
&gt; +/*-<br>
&gt; + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD<br>
&gt; + *<br>
&gt; + * Copyright (c) 2022 Scott Long<br>
&gt; + * All rights reserved.<br>
&gt; + *<br>
&gt; + * Redistribution and use in source and binary forms, with or without=
<br>
&gt; + * modification, are permitted provided that the following conditions=
<br>
&gt; + * are met:<br>
&gt; + * 1. Redistributions of source code must retain the above copyright<=
br>
&gt; + *=C2=A0 =C2=A0 notice, this list of conditions and the following dis=
claimer.<br>
&gt; + * 2. Redistributions in binary form must reproduce the above copyrig=
ht<br>
&gt; + *=C2=A0 =C2=A0 notice, this list of conditions and the following dis=
claimer in the<br>
&gt; + *=C2=A0 =C2=A0 documentation and/or other materials provided with th=
e distribution.<br>
&gt; + *<br>
&gt; + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS&#=
39;&#39; AND<br>
&gt; + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, =
THE<br>
&gt; + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR=
 PURPOSE<br>
&gt; + * ARE DISCLAIMED.=C2=A0 IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS=
 BE LIABLE<br>
&gt; + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSE=
QUENTIAL<br>
&gt; + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE =
GOODS<br>
&gt; + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTI=
ON)<br>
&gt; + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT=
, STRICT<br>
&gt; + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN =
ANY WAY<br>
&gt; + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILIT=
Y OF<br>
&gt; + * SUCH DAMAGE.<br>
&gt; + */<br>
&gt; +<br>
&gt; +#include &quot;opt_thunderbolt.h&quot;<br>
&gt; +<br>
&gt; +/* PCIe interface for Thunderbolt Native Host Interface (nhi) */<br>
&gt; +#include &lt;sys/types.h&gt;<br>
&gt; +#include &lt;sys/param.h&gt;<br>
&gt; +#include &lt;sys/systm.h&gt;<br>
&gt; +#include &lt;sys/kernel.h&gt;<br>
&gt; +#include &lt;sys/module.h&gt;<br>
&gt; +#include &lt;sys/bus.h&gt;<br>
&gt; +#include &lt;sys/conf.h&gt;<br>
&gt; +#include &lt;sys/malloc.h&gt;<br>
&gt; +#include &lt;sys/queue.h&gt;<br>
&gt; +#include &lt;sys/sysctl.h&gt;<br>
&gt; +#include &lt;sys/lock.h&gt;<br>
&gt; +#include &lt;sys/mutex.h&gt;<br>
&gt; +#include &lt;sys/taskqueue.h&gt;<br>
&gt; +#include &lt;sys/gsb_crc32.h&gt;<br>
&gt; +#include &lt;sys/endian.h&gt;<br>
&gt; +#include &lt;vm/vm.h&gt;<br>
&gt; +#include &lt;vm/pmap.h&gt;<br>
&gt; +<br>
&gt; +#include &lt;machine/bus.h&gt;<br>
&gt; +#include &lt;machine/stdarg.h&gt;<br>
&gt; +<br>
&gt; +#include &lt;dev/thunderbolt/nhi_reg.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/nhi_var.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/tb_reg.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/tb_var.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/tb_debug.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/hcm_var.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/tbcfg_reg.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/router_var.h&gt;<br>
&gt; +#include &lt;dev/thunderbolt/tb_dev.h&gt;<br>
&gt; +#include &quot;tb_if.h&quot;<br>
&gt; +<br>
&gt; +static int nhi_alloc_ring(struct nhi_softc *, int, int, int,<br>
&gt; +=C2=A0 =C2=A0 struct nhi_ring_pair **);<br>
&gt; +static void nhi_free_ring(struct nhi_ring_pair *);<br>
&gt; +static void nhi_free_rings(struct nhi_softc *);<br>
&gt; +static int nhi_configure_ring(struct nhi_softc *, struct nhi_ring_pai=
r *);<br>
&gt; +static int nhi_activate_ring(struct nhi_ring_pair *);<br>
&gt; +static int nhi_deactivate_ring(struct nhi_ring_pair *);<br>
&gt; +static int nhi_alloc_ring0(struct nhi_softc *);<br>
&gt; +static void nhi_free_ring0(struct nhi_softc *);<br>
&gt; +static void nhi_fill_rx_ring(struct nhi_softc *, struct nhi_ring_pair=
 *);<br>
&gt; +static int nhi_init(struct nhi_softc *);<br>
&gt; +static void nhi_post_init(void *);<br>
&gt; +static int nhi_tx_enqueue(struct nhi_ring_pair *, struct nhi_cmd_fram=
e *);<br>
&gt; +static int nhi_setup_sysctl(struct nhi_softc *);<br>
&gt; +<br>
&gt; +SYSCTL_NODE(_hw, OID_AUTO, nhi, CTLFLAG_RD, 0, &quot;NHI Driver Param=
eters&quot;);<br>
&gt; +<br>
&gt; +MALLOC_DEFINE(M_NHI, &quot;nhi&quot;, &quot;nhi driver memory&quot;);=
<br>
&gt; +<br>
&gt; +#ifndef NHI_DEBUG_LEVEL<br>
&gt; +#define NHI_DEBUG_LEVEL 0<br>
&gt; +#endif<br>
&gt; +<br>
&gt; +/* 0 =3D default, 1 =3D force-on, 2 =3D force-off */<br>
&gt; +#ifndef NHI_FORCE_HCM<br>
&gt; +#define NHI_FORCE_HCM 0<br>
&gt; +#endif<br>
&gt; +<br>
&gt; +void<br>
&gt; +nhi_get_tunables(struct nhi_softc *sc)<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0devclass_t dc;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0device_t ufp;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0char=C2=A0 =C2=A0 tmpstr[80], oid[80];<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0u_int=C2=A0 =C2=A0val;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Set local defaults */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;debug =3D NHI_DEBUG_LEVEL;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;max_ring_count =3D NHI_DEFAULT_NUM_=
RINGS;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;force_hcm =3D NHI_FORCE_HCM;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Inherit setting from the upstream thund=
erbolt switch node */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D TB_GET_DEBUG(sc-&gt;dev, &amp;sc-&=
gt;debug);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (val !=3D 0) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0dc =3D devclas=
s_find(&quot;tbolt&quot;);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (dc !=3D NU=
LL) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0ufp =3D devclass_get_device(dc, device_get_unit(sc-&gt;dev));=
<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0if (ufp !=3D NULL)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0TB_GET_DEBUG(ufp, &amp;sc-&gt;deb=
ug);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0if (TUNABLE_STR_FETCH(&quot;hw.tbolt.debug_level&quot;, oid,<=
br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A080) !=3D 0)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_parse_debug(&amp;sc-&gt;debug,=
 oid);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/*<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 * Grab global variables.=C2=A0 Allow nhi =
debug flags to override<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 * thunderbolt debug flags, if present.<br=
>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0bzero(oid, 80);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (TUNABLE_STR_FETCH(&quot;hw.nhi.debug_l=
evel&quot;, oid, 80) !=3D 0)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_parse_debug=
(&amp;sc-&gt;debug, oid);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (TUNABLE_INT_FETCH(&quot;hw.nhi.max_rin=
gs&quot;, &amp;val) !=3D 0) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D min(va=
l, NHI_MAX_NUM_RINGS);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;max_rin=
g_count =3D max(val, 1);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (TUNABLE_INT_FETCH(&quot;hw.nhi.force_h=
cm&quot;, &amp;val) !=3D 0)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;force_h=
cm =3D val;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Grab instance variables */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0bzero(oid, 80);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0snprintf(tmpstr, sizeof(tmpstr), &quot;dev=
.nhi.%d.debug_level&quot;,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0device_get_unit(sc-&gt;dev))=
;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (TUNABLE_STR_FETCH(tmpstr, oid, 80) !=
=3D 0)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_parse_debug=
(&amp;sc-&gt;debug, oid);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0snprintf(tmpstr, sizeof(tmpstr), &quot;dev=
.nhi.%d.max_rings&quot;,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0device_get_unit(sc-&gt;dev))=
;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (TUNABLE_INT_FETCH(tmpstr, &amp;val) !=
=3D 0) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D min(va=
l, NHI_MAX_NUM_RINGS);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;max_rin=
g_count =3D max(val, 1);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0snprintf(tmpstr, sizeof(tmpstr), &quot;dev=
, nhi.%d.force_hcm&quot;,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0device_get_unit(sc-&gt;dev))=
;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (TUNABLE_INT_FETCH(tmpstr, &amp;val) !=
=3D 0)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;force_h=
cm =3D val;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return;<br>
&gt; +}<br>
&gt; +<br>
&gt; +static void<br>
&gt; +nhi_configure_caps(struct nhi_softc *sc)<br>
&gt; +{<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (NHI_IS_USB4(sc) || (sc-&gt;force_hcm =
=3D=3D NHI_FORCE_HCM_ON))<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;caps |=
=3D NHI_CAP_HCM;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (sc-&gt;force_hcm =3D=3D NHI_FORCE_HCM_=
OFF)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;caps &a=
mp;=3D ~NHI_CAP_HCM;<br>
&gt; +}<br>
&gt; +<br>
&gt; +struct nhi_cmd_frame *<br>
&gt; +nhi_alloc_tx_frame(struct nhi_ring_pair *r)<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_cmd_frame *cmd;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_lock(&amp;r-&gt;mtx);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0cmd =3D nhi_alloc_tx_frame_locked(r);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&amp;r-&gt;mtx);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (cmd);<br>
&gt; +}<br>
&gt; +<br>
&gt; +void<br>
&gt; +nhi_free_tx_frame(struct nhi_ring_pair *r, struct nhi_cmd_frame *cmd)=
<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_lock(&amp;r-&gt;mtx);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_free_tx_frame_locked(r, cmd);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&amp;r-&gt;mtx);<br>
&gt; +}<br>
&gt; +<br>
&gt; +/*<br>
&gt; + * Push a command and data dword through the mailbox to the firmware.=
<br>
&gt; + * Response is either good, error, or timeout.=C2=A0 Commands that re=
turn data<br>
&gt; + * do so by reading OUTMAILDATA.<br>
&gt; + */<br>
&gt; +int<br>
&gt; +nhi_inmail_cmd(struct nhi_softc *sc, uint32_t cmd, uint32_t data)<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t val;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0u_int error, timeout;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_lock(&amp;sc-&gt;nhi_mtx);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/*<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 * XXX Should a defer/reschedule happen he=
re, or is it not worth<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 * worrying about?<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (sc-&gt;hwflags &amp; NHI_MBOX_BUSY) {<=
br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&am=
p;sc-&gt;nhi_mtx);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, D=
BG_MBOX, &quot;Driver busy with mailbox\n&quot;);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (EBUSY)=
;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;hwflags |=3D NHI_MBOX_BUSY;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D nhi_read_reg(sc, TBT_INMAILCMD);<b=
r>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_MBOX|DBG_FULL, &quot;Read=
ing INMAILCMD=3D 0x%08x\n&quot;, val);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (val &amp; INMAILCMD_ERROR)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, D=
BG_MBOX, &quot;Error already set in INMAILCMD\n&quot;);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (val &amp; INMAILCMD_OPREQ) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&am=
p;sc-&gt;nhi_mtx);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, D=
BG_MBOX,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
&quot;INMAILCMD request already in progress\n&quot;);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (EBUSY)=
;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, TBT_INMAILDATA, data);<b=
r>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, TBT_INMAILCMD, cmd | INM=
AILCMD_OPREQ);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Poll at 1s intervals */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0timeout =3D NHI_MAILBOX_TIMEOUT;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0while (timeout--) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DELAY(1000000)=
;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D nhi_re=
ad_reg(sc, TBT_INMAILCMD);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, D=
BG_MBOX|DBG_EXTRA,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
&quot;Polling INMAILCMD=3D 0x%08x\n&quot;, val);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if ((val &amp;=
 INMAILCMD_OPREQ) =3D=3D 0)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0break;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;hwflags &amp;=3D ~NHI_MBOX_BUSY;<br=
>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&amp;sc-&gt;nhi_mtx);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D 0;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (val &amp; INMAILCMD_OPREQ) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, =
&quot;Timeout waiting for mailbox\n&quot;);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D ETIM=
EDOUT;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (val &amp; INMAILCMD_ERROR) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, =
&quot;Firmware reports error in mailbox\n&quot;);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D EINV=
AL;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (error);<br>
&gt; +}<br>
&gt; +<br>
&gt; +/*<br>
&gt; + * Pull command status and data from the firmware mailbox.<br>
&gt; + */<br>
&gt; +int<br>
&gt; +nhi_outmail_cmd(struct nhi_softc *sc, uint32_t *val)<br>
&gt; +{<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (val =3D=3D NULL)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (EINVAL=
);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0*val =3D nhi_read_reg(sc, TBT_OUTMAILCMD);=
<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);<br>
&gt; +}<br>
&gt; +<br>
&gt; +int<br>
&gt; +nhi_attach(struct nhi_softc *sc)<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t val;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0int error =3D 0;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if ((error =3D nhi_setup_sysctl(sc)) !=3D =
0)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (error)=
;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_init(&amp;sc-&gt;nhi_mtx, &quot;nhimtx=
&quot;, &quot;NHI Control Mutex&quot;, MTX_DEF);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_configure_caps(sc);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/*<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 * Get the number of TX/RX paths.=C2=A0 Th=
is sizes some of the register<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 * arrays during allocation and initializa=
tion.=C2=A0 USB4 spec says that<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 * the max is 21.=C2=A0 Alpine Ridge appea=
rs to default to 12.<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D GET_HOST_CAPS_PATHS(nhi_read_reg(s=
c, NHI_HOST_CAPS));<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT|DBG_NOISY, &quot;Tot=
al Paths=3D %d\n&quot;, val);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if ((val =3D=3D 0) || (val &gt; 21) || ((N=
HI_IS_AR(sc) &amp;&amp; val !=3D 12))) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, =
&quot;WARN: unexpected number of paths: %d\n&quot;, val);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* return (ENX=
IO); */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;path_count =3D val;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0SLIST_INIT(&amp;sc-&gt;ring_list);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D nhi_pci_configure_interrupts(sc)=
;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error =3D=3D 0)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D nhi_=
alloc_ring0(sc);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error =3D=3D 0) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_configure_=
ring(sc, sc-&gt;ring0);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_activate_r=
ing(sc-&gt;ring0);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_fill_rx_ri=
ng(sc, sc-&gt;ring0);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error =3D=3D 0)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D tbde=
v_add_interface(sc);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if ((error =3D=3D 0) &amp;&amp; (NHI_USE_I=
CM(sc)))<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, =
&quot;WARN: device uses an internal connection manager\n&quot;);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if ((error =3D=3D 0) &amp;&amp; (NHI_USE_H=
CM(sc)))<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D hcm_attach(sc);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error =3D=3D 0)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D nhi_=
init(sc);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (error);<br>
&gt; +}<br>
&gt; +<br>
&gt; +int<br>
&gt; +nhi_detach(struct nhi_softc *sc)<br>
&gt; +{<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (NHI_USE_HCM(sc))<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0hcm_detach(sc)=
;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (sc-&gt;root_rsc !=3D NULL)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_router_deta=
ch(sc-&gt;root_rsc);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0tbdev_remove_interface(sc);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_pci_disable_interrupts(sc);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_free_ring0(sc);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* XXX Should the rings be marked as !VALI=
D in the descriptors? */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_free_rings(sc);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_destroy(&amp;sc-&gt;nhi_mtx);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);<br>
&gt; +}<br>
&gt; +<br>
&gt; +static void<br>
&gt; +nhi_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int err=
or)<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_addr_t *addr;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0addr =3D arg;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error =3D=3D 0 &amp;&amp; nsegs =3D=3D=
 1) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*addr =3D segs=
[0].ds_addr;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0} else<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*addr =3D 0;<b=
r>
&gt; +}<br>
&gt; +<br>
&gt; +static int<br>
&gt; +nhi_alloc_ring(struct nhi_softc *sc, int ringnum, int tx_depth, int r=
x_depth,<br>
&gt; +=C2=A0 =C2=A0 struct nhi_ring_pair **rp)<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dma_template_t t;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_addr_t ring_busaddr;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_ring_pair *r;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0int ring_size, error;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0u_int rxring_len, txring_len;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0char *ring;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (ringnum &gt;=3D sc-&gt;max_ring_count)=
 {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, D=
BG_INIT, &quot;Tried to allocate ring number %d\n&quot;,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
ringnum);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (EINVAL=
);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Allocate the ring structure and the RX =
ring tacker together. */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0rxring_len =3D rx_depth * sizeof(void *);<=
br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0txring_len =3D tx_depth * sizeof(void *);<=
br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r =3D malloc(sizeof(struct nhi_ring_pair) =
+ rxring_len + txring_len,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0M_NHI, M_NOWAIT|M_ZERO);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (r =3D=3D NULL) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, =
&quot;ERROR: Cannot allocate ring memory\n&quot;);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM=
);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;sc =3D sc;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0TAILQ_INIT(&amp;r-&gt;tx_head);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0TAILQ_INIT(&amp;r-&gt;rx_head);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;ring_num =3D ringnum;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;tx_ring_depth =3D tx_depth;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;tx_ring_mask =3D tx_depth - 1;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;rx_ring_depth =3D rx_depth;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;rx_ring_mask =3D rx_depth - 1;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;rx_pici_reg =3D NHI_RX_RING_PICI + r=
ingnum * 16;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;tx_pici_reg =3D NHI_TX_RING_PICI + r=
ingnum * 16;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;rx_cmd_ring =3D (struct nhi_cmd_fram=
e **)((uint8_t *)r + sizeof (*r));<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;tx_cmd_ring =3D (struct nhi_cmd_fram=
e **)((uint8_t *)r-&gt;rx_cmd_ring +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0rxring_len);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0snprintf(r-&gt;name, NHI_RING_NAMELEN, &qu=
ot;nhiring%d\n&quot;, ringnum);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_init(&amp;r-&gt;mtx, r-&gt;name, &quot=
;NHI Ring Lock&quot;, MTX_DEF);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT | DBG_FULL, &quot;Al=
located ring context at %p, &quot;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&quot;mutex %p\n&quot;, r, &=
amp;r-&gt;mtx);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Allocate the RX and TX buffer descripto=
r rings */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0ring_size =3D sizeof(struct nhi_tx_buffer_=
desc) * r-&gt;tx_ring_depth;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0ring_size +=3D sizeof(struct nhi_rx_buffer=
_desc) * r-&gt;rx_ring_depth;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT | DBG_FULL, &quot;Ri=
ng %d ring_size=3D %d\n&quot;,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ringnum, ring_size);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dma_template_init(&amp;t, sc-&gt;paren=
t_dmat);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0t.alignment =3D 4;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0t.maxsize =3D t.maxsegsize =3D ring_size;<=
br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0t.nsegments =3D 1;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if ((error =3D bus_dma_template_tag(&amp;t=
, &amp;r-&gt;ring_dmat)) !=3D 0) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, =
&quot;Cannot allocate ring %d DMA tag: %d\n&quot;,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
ringnum, error);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM=
);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (bus_dmamem_alloc(r-&gt;ring_dmat, (voi=
d **)&amp;ring, BUS_DMA_NOWAIT,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&amp;r-&gt;ring_map)) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, =
&quot;Cannot allocate ring memory\n&quot;);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM=
);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0bzero(ring, ring_size);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dmamap_load(r-&gt;ring_dmat, r-&gt;rin=
g_map, ring, ring_size,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_memaddr_cb, &amp;ring_bu=
saddr, 0);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;ring =3D ring;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;tx_ring =3D (union nhi_ring_desc *)(=
ring);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;tx_ring_busaddr =3D ring_busaddr;<br=
>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0ring +=3D sizeof(struct nhi_tx_buffer_desc=
) * r-&gt;tx_ring_depth;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0ring_busaddr +=3D sizeof(struct nhi_tx_buf=
fer_desc) * r-&gt;tx_ring_depth;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;rx_ring =3D (union nhi_ring_desc *)(=
ring);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;rx_ring_busaddr =3D ring_busaddr;<br=
>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT | DBG_EXTRA, &quot;R=
ing %d: RX %p [0x%jx] &quot;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&quot;TX %p [0x%jx]\n&quot;,=
 ringnum, r-&gt;tx_ring, r-&gt;tx_ring_busaddr,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;rx_ring, r-&gt;rx_ring=
_busaddr);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0*rp =3D r;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);<br>
&gt; +}<br>
&gt; +<br>
&gt; +static void<br>
&gt; +nhi_free_ring(struct nhi_ring_pair *r)<br>
&gt; +{<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(r-&gt;sc, DBG_INIT, &quot;Freeing=
 ring %d resources\n&quot;, r-&gt;ring_num);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_deactivate_ring(r);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (r-&gt;tx_ring_busaddr !=3D 0) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dmamap_unl=
oad(r-&gt;ring_dmat, r-&gt;ring_map);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;tx_ring_=
busaddr =3D 0;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (r-&gt;ring !=3D NULL) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dmamem_fre=
e(r-&gt;ring_dmat, r-&gt;ring, r-&gt;ring_map);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;ring =3D=
 NULL;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (r-&gt;ring_dmat !=3D NULL) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dma_tag_de=
stroy(r-&gt;ring_dmat);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;ring_dma=
t =3D NULL;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_destroy(&amp;r-&gt;mtx);<br>
&gt; +}<br>
&gt; +<br>
&gt; +static void<br>
&gt; +nhi_free_rings(struct nhi_softc *sc)<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_ring_pair *r;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0while ((r =3D SLIST_FIRST(&amp;sc-&gt;ring=
_list)) !=3D NULL) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_free_ring(=
r);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_lock(&amp;=
sc-&gt;nhi_mtx);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0SLIST_REMOVE_H=
EAD(&amp;sc-&gt;ring_list, ring_link);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&am=
p;sc-&gt;nhi_mtx);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0free(r, M_NHI)=
;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return;<br>
&gt; +}<br>
&gt; +<br>
&gt; +static int<br>
&gt; +nhi_configure_ring(struct nhi_softc *sc, struct nhi_ring_pair *ring)<=
br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_addr_t busaddr;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t val;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0int idx;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0idx =3D ring-&gt;ring_num * 16;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Program the TX ring address and size */=
<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0busaddr =3D ring-&gt;tx_ring_busaddr;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_TX_RING_ADDR_LO + id=
x, busaddr &amp; 0xffffffff);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_TX_RING_ADDR_HI + id=
x, busaddr &gt;&gt; 32);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_TX_RING_SIZE + idx, =
ring-&gt;tx_ring_depth);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_TX_RING_TABLE_TIMEST=
AMP + idx, 0x0);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT, &quot;TX Ring %d TX=
_RING_SIZE=3D 0x%x\n&quot;,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ring-&gt;ring_num, ring-&gt;=
tx_ring_depth);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Program the RX ring address and size */=
<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0busaddr =3D ring-&gt;rx_ring_busaddr;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D (ring-&gt;rx_buffer_size &lt;&lt; =
16) | ring-&gt;rx_ring_depth;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_RX_RING_ADDR_LO + id=
x, busaddr &amp; 0xffffffff);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_RX_RING_ADDR_HI + id=
x, busaddr &gt;&gt; 32);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_RX_RING_SIZE + idx, =
val);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_RX_RING_TABLE_BASE1 =
+ idx, 0xffffffff);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT, &quot;RX Ring %d RX=
_RING_SIZE=3D 0x%x\n&quot;,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ring-&gt;ring_num, val);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);<br>
&gt; +}<br>
&gt; +<br>
&gt; +static int<br>
&gt; +nhi_activate_ring(struct nhi_ring_pair *ring)<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_softc *sc =3D ring-&gt;sc;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0int idx;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_pci_enable_interrupt(ring);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0idx =3D ring-&gt;ring_num * 32;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT, &quot;Activating ri=
ng %d at idx %d\n&quot;,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ring-&gt;ring_num, idx);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_TX_RING_TABLE_BASE0 =
+ idx,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0TX_TABLE_RAW | TX_TABLE_VALI=
D);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_RX_RING_TABLE_BASE0 =
+ idx,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0RX_TABLE_RAW | RX_TABLE_VALI=
D);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);<br>
&gt; +}<br>
&gt; +<br>
&gt; +static int<br>
&gt; +nhi_deactivate_ring(struct nhi_ring_pair *r)<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_softc *sc =3D r-&gt;sc;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0int idx;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0idx =3D r-&gt;ring_num * 32;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT, &quot;Deactiving ri=
ng %d at idx %d\n&quot;,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;ring_num, idx);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_TX_RING_TABLE_BASE0 =
+ idx, 0);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_RX_RING_TABLE_BASE0 =
+ idx, 0);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0idx =3D r-&gt;ring_num * 16;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT, &quot;Setting ring =
%d sizes to 0\n&quot;, r-&gt;ring_num);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_TX_RING_SIZE + idx, =
0);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_RX_RING_SIZE + idx, =
0);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);<br>
&gt; +}<br>
&gt; +<br>
&gt; +static int<br>
&gt; +nhi_alloc_ring0(struct nhi_softc *sc)<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_addr_t frames_busaddr;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dma_template_t t;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_intr_tracker *trkr;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_ring_pair *r;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_cmd_frame *cmd;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0char *frames;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0int error, size, i;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if ((error =3D nhi_alloc_ring(sc, 0, NHI_R=
ING0_TX_DEPTH,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0NHI_RING0_RX_DEPTH, &amp;r))=
 !=3D 0) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, =
&quot;Error allocating control ring\n&quot;);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (error)=
;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;rx_buffer_size =3D NHI_RING0_FRAME_S=
IZE;/* Control packets are small */<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Allocate the RX and TX buffers that are=
 used for Ring0 comms */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0size =3D r-&gt;tx_ring_depth * NHI_RING0_F=
RAME_SIZE;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0size +=3D r-&gt;rx_ring_depth * NHI_RING0_=
FRAME_SIZE;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dma_template_init(&amp;t, sc-&gt;paren=
t_dmat);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0t.maxsize =3D t.maxsegsize =3D size;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0t.nsegments =3D 1;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (bus_dma_template_tag(&amp;t, &amp;sc-&=
gt;ring0_dmat)) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, =
&quot;Error allocating control ring buffer tag\n&quot;);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM=
);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (bus_dmamem_alloc(sc-&gt;ring0_dmat, (v=
oid **)&amp;frames, BUS_DMA_NOWAIT,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&amp;sc-&gt;ring0_map) !=3D =
0) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, =
&quot;Error allocating control ring memory\n&quot;);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM=
);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0bzero(frames, size);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dmamap_load(sc-&gt;ring0_dmat, sc-&gt;=
ring0_map, frames, size,<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_memaddr_cb, &amp;frames_=
busaddr, 0);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;ring0_frames_busaddr =3D frames_bus=
addr;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;ring0_frames =3D frames;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Allocate the driver command trackers */=
<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;ring0_cmds =3D malloc(sizeof(struct=
 nhi_cmd_frame) *<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(r-&gt;tx_ring_depth + r-&gt=
;rx_ring_depth), M_NHI, M_NOWAIT | M_ZERO);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (sc-&gt;ring0_cmds =3D=3D NULL)<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM=
);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Initialize the RX frames so they can be=
 used */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_lock(&amp;r-&gt;mtx);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 0; i &lt; r-&gt;rx_ring_depth; =
i++) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd =3D &amp;s=
c-&gt;ring0_cmds[i];<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd-&gt;data =
=3D (uint32_t *)(frames + NHI_RING0_FRAME_SIZE * i);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd-&gt;data_b=
usaddr =3D frames_busaddr + NHI_RING0_FRAME_SIZE * i;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd-&gt;flags =
=3D CMD_MAPPED;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd-&gt;idx =
=3D i;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0TAILQ_INSERT_T=
AIL(&amp;r-&gt;rx_head, cmd, cm_link);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Inititalize the TX frames */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0for ( ; i &lt; r-&gt;tx_ring_depth + r-&gt=
;rx_ring_depth - 1; i++) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd =3D &amp;s=
c-&gt;ring0_cmds[i];<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd-&gt;data =
=3D (uint32_t *)(frames + NHI_RING0_FRAME_SIZE * i);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd-&gt;data_b=
usaddr =3D frames_busaddr + NHI_RING0_FRAME_SIZE * i;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd-&gt;flags =
=3D CMD_MAPPED;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd-&gt;idx =
=3D i;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_free_tx_fr=
ame_locked(r, cmd);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&amp;r-&gt;mtx);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Do a 1:1 mapping of rings to interrupt =
vectors. */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* XXX Should be abstracted */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0trkr =3D &amp;sc-&gt;intr_trackers[0];<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0trkr-&gt;ring =3D r;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0r-&gt;tracker =3D trkr;<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* XXX Should be an array */<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;ring0 =3D r;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0SLIST_INSERT_HEAD(&amp;sc-&gt;ring_list, r=
, ring_link);<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);<br>
&gt; +}<br>
&gt; +<br>
&gt; +static void<br>
&gt; +nhi_free_ring0(struct nhi_softc *sc)<br>
&gt; +{<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (sc-&gt;ring0_cmds !=3D NULL) {<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0free(sc-&gt;ri=
ng0_cmds, M_NHI);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;ring0_c=
mds =3D NULL;<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
&gt; +<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (sc-&gt;ring0_frames_busaddr !=3D 0) {<=
br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dmamap_unl=
oad(sc-&gt;ring0_dmat, sc-&gt;ring0_map);<br>
&gt; +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc-&gt;ring0_f=
rames_busaddr =3D 0;<br>
&gt; *** 5529 LINES SKIPPED ***<br>
<br>
<br>
<br>
-- <br>
Wolfram Schneider &lt;wosch@FreeBSD.org&gt; <a href=3D"https://wolfram.schn=
eider.org" rel=3D"noreferrer" target=3D"_blank">https://wolfram.schneider.o=
rg</a><br>
<br>
</blockquote></div><div><br clear=3D"all"></div><br><span class=3D"gmail_si=
gnature_prefix">-- </span><br><div dir=3D"ltr" class=3D"gmail_signature"><d=
iv dir=3D"ltr"><div><font color=3D"#888888">Nuno Teixeira</font></div><div>=
<div><font color=3D"#888888">
FreeBSD UNIX:=C2=A0 &lt;eduardo@FreeBSD.org&gt;=C2=A0 =C2=A0Web:=C2=A0 <a h=
ref=3D"https://FreeBSD.org" rel=3D"noreferrer" target=3D"_blank">https://Fr=
eeBSD.org</a><br></font></div></div></div></div>

--00000000000085e79c0640338477--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAFDf7ULhDCEf6ZZniWAtHP0Qv0zi64UgD=VBiyAaM=Uv51bRDg>