From nobody Thu Oct 2 21:17:40 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4cd4Q82jfwz6B4lr for ; Thu, 02 Oct 2025 21:17:52 +0000 (UTC) (envelope-from eduardo@freebsd.org) Received: from smtp.freebsd.org (smtp.freebsd.org [IPv6:2610:1c1:1:606c::24b:4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "smtp.freebsd.org", Issuer "R13" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4cd4Q80rHdz3Ym2 for ; Thu, 02 Oct 2025 21:17:52 +0000 (UTC) (envelope-from eduardo@freebsd.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1759439872; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=Qwbt+pDBDwRA8lnpPaDcDiB1/grMxsN8qy4FI99ML5A=; b=JRJp7nGW/X2MOLsx+rnIinpO7R1eStkU3yKnAzNhZ8lY5FhEYYQt1wfsGz7P6PQpk1KLLa YwLaHXei4WUpo8ggm3tx48HkZyuwF6z3FJY1QEXa9pZBi3JPJ+QcVl1RVOyuDBlsyXrZTO hj1+h5fT7tn15dDz9DuaEvelXu3j0aH6yVxgiqNgd8RC7OZCpUl7Lf982BdLd/SOK8CaWz 5M9Gg5Zz5pIxhc4Mi+qbxhb1OvNAvqo0PK2CjSmMxedIg4+BY0wU0DoeXNTRtXwZ0HncIN Vf6yELJOKf6oPopdQizAUj7sstAgUqDC1jp29ElznSw2MVB4OXMuzk/7cyY25w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1759439872; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=Qwbt+pDBDwRA8lnpPaDcDiB1/grMxsN8qy4FI99ML5A=; b=Tc7xkTfCMGkSEUAwNHhmiZgvTw3xKcgZWKnsF7cq0F/llAklmH2gNiiaQmwU27vamyhqie 1g6RDe6ROmGxrtM+BUeMns3XGGDPnVIXSz9Yt7a2o2rj20PigYFY+jYqEhii/wYYZt1grU fr2qSQazSk3prdJemuJQSQKDVjNoMudfHw5/XNWd2jUuwoUyPHNF+tfzzopIvMRf+5WTe7 WuMjryjqFG2WN4jQb+MzkcB9DuHDfCbc3dicVk4/e0Ap5Q0p7dMBVZQci2jTATdMay3eaW 9YCYWwE3vSre46sTgGpvoyJxrFHr0m6qRWA/VRP94FXVUl6bU0JK2aNexPwwZg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1759439872; a=rsa-sha256; cv=none; b=kncsjRYgaU9y4aEstZHLC46KEJPQCdXpBdxTMJuZxcmct4gLDQYIaDt4eQGeHOLp9lxQt1 mu8U87N5AWyapSFPXi4uQJTmt6GDOiEeEeq5oid+XMi1kftMF7J+1AQmt1lAsADFDwNDOD TtI+mxHIr+lKJCLINc6eIyvyBgRHBh/Iw/aBMhUcj1Z26TSQzsw9yNm87+mRnJszCMAzZs iNVId0KfxUgliZ2SatCI+sSddg6i6yBG/fe2bossVysGEQXaPuf4HUUJTddF/9lDfsC9Pk jSnpYo0b9WuOnqpWhhLtc+DDLaVz1Vf2aYho15SVsPem5sXEIqfDFDNfJowYHA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from mail-qt1-f170.google.com (mail-qt1-f170.google.com [209.85.160.170]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (2048 bits) client-digest SHA256) (Client CN "smtp.gmail.com", Issuer "WR4" (verified OK)) (Authenticated sender: eduardo) by smtp.freebsd.org (Postfix) with ESMTPSA id 4cd4Q7677hz17jJ for ; Thu, 02 Oct 2025 21:17:51 +0000 (UTC) (envelope-from eduardo@freebsd.org) Received: by mail-qt1-f170.google.com with SMTP id d75a77b69052e-4dffec0f14eso1872321cf.0 for ; Thu, 02 Oct 2025 14:17:51 -0700 (PDT) X-Forwarded-Encrypted: i=1; AJvYcCWgHh46S66aWQdcPPWZB1UPvlva0GzB76kjs7XVuAxKJUrcB8kQVfTwO8A+UDuHyZ0IQw8buelubneyYzZigkAQn0xTpQ==@freebsd.org X-Gm-Message-State: AOJu0YwjFQAifglEwEOzzbNyrdpOeW/tqZjeeVG7bvnkd3FXWijmaqGg 84u2WaVpqlYpAlDuEwG8Z+jHu7NynNOA4qSJyBb9B0VsgU+a71zqVc8nr08QaEtNmwKCUduUuNn JuW2OF48kYYCApRAPzoElw9AhInHGsnY= X-Google-Smtp-Source: AGHT+IF6EhDf/XOCe8lmPLv/PqaSkaQ9MnDB+hvGF18Ng7cPiGCK0QeTaefioiC+tMxZxVVr1O5M9EqIUDYLt2CM1H4= X-Received: by 2002:a05:622a:7391:b0:4b5:f521:30f7 with SMTP id d75a77b69052e-4e576b13f65mr6884331cf.4.1759439871139; Thu, 02 Oct 2025 14:17:51 -0700 (PDT) List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 References: <202509271713.58RHDTTL008060@gitrepo.freebsd.org> In-Reply-To: From: Nuno Teixeira Date: Thu, 2 Oct 2025 22:17:40 +0100 X-Gmail-Original-Message-ID: X-Gm-Features: AS18NWDu3FdJ61eDau00qp4NE-zGhKcVeUFYvqSwWPUmz227_dVgFGg_DRrygAs Message-ID: Subject: Re: git: 2ed9833791f2 - main - thunderbolt: Import USB4 code To: Wolfram Schneider Cc: Aymeric Wibo , src-committers@freebsd.org, dev-commits-src-all@freebsd.org, dev-commits-src-main@freebsd.org Content-Type: multipart/alternative; boundary="00000000000085e79c0640338477" --00000000000085e79c0640338477 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable yep, seing that symlink too. Wolfram Schneider 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 wrote: > > > > The branch main has been updated by obiwac: > > > > URL: > https://cgit.FreeBSD.org/src/commit/?id=3D2ed9833791f28e14843ac813f90cb03= 0e45948dc > > > > commit 2ed9833791f28e14843ac813f90cb030e45948dc > > Author: Aymeric Wibo > > AuthorDate: 2025-09-27 11:50:43 +0000 > > Commit: Aymeric Wibo > > 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 > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include > > +#include > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +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 > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include > > +#include > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#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 https://wolfram.schneider.org > > --=20 Nuno Teixeira FreeBSD UNIX: Web: https://FreeBSD.org --00000000000085e79c0640338477 Content-Type: text/html; 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=C2=A0 1 wosch wheel 91 Sep 29 22:14
/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> -> /var/tmp/freebsd-obj-wosch/home/projects/freebsd-src/amd64.amd64/sys/= GENERIC/opt_acpi_wmi.h

the only reference to the file "opt_acpi_wmi.h" is in the Makefil= e

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=3D2ed9833791f28e14843ac813f90cb030e45948dc<= /a>
>
> commit 2ed9833791f28e14843ac813f90cb030e45948dc
> Author:=C2=A0 =C2=A0 =C2=A0Aymeric Wibo <obiwac@FreeBSD.org>
> AuthorDate: 2025-09-27 11:50:43 +0000
> Commit:=C2=A0 =C2=A0 =C2=A0Aymeric Wibo <obiwac@FreeBSD.org>
> CommitDate: 2025-09-27 17:13:13 +0000
>
>=C2=A0 =C2=A0 =C2=A0thunderbolt: Import USB4 code
>
>=C2=A0 =C2=A0 =C2=A0Add initial USB4 code written by Scott Long and ori= ginally passed on to
>=C2=A0 =C2=A0 =C2=A0HPS (source:
https://github.com/hselasky/usb= 4), minus the ICM code and
>=C2=A0 =C2=A0 =C2=A0with some small fixes.
>
>=C2=A0 =C2=A0 =C2=A0For context, older TB chips implemented the connect= ion manager in
>=C2=A0 =C2=A0 =C2=A0firmware (ICM) instead of in the OS (HCM), but main= taining the ICM code
>=C2=A0 =C2=A0 =C2=A0would be a huge burden for not many chips.
>
>=C2=A0 =C2=A0 =C2=A0Mostly completed work:
>
>=C2=A0 =C2=A0 =C2=A0- Debug/trace framework.
>=C2=A0 =C2=A0 =C2=A0- NHI controller driver.
>=C2=A0 =C2=A0 =C2=A0- PCIe bridge driver.
>=C2=A0 =C2=A0 =C2=A0- Router and config space layer handling (just read= ing in this commit).
>
>=C2=A0 =C2=A0 =C2=A0Link to the email where Scott shared details about = the initial USB4
>=C2=A0 =C2=A0 =C2=A0work:
>
>=C2=A0 =C2=A0 =C2=A0http= s://lists.freebsd.org/archives/freebsd-hackers/2024-July/003411.html >
>=C2=A0 =C2=A0 =C2=A0Glanced at by:=C2=A0 emaste, imp
>=C2=A0 =C2=A0 =C2=A0Sponsored by:=C2=A0 =C2=A0The FreeBSD Foundation >=C2=A0 =C2=A0 =C2=A0Differential Revision:=C2=A0 https://revie= ws.freebsd.org/D49450
>=C2=A0 =C2=A0 =C2=A0Event:=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 EuroBSDcon= 2025
> ---
>=C2=A0 sys/dev/thunderbolt/hcm.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 |=C2= =A0 223 +++++++
>=C2=A0 sys/dev/thunderbolt/hcm_var.h=C2=A0 =C2=A0 =C2=A0 |=C2=A0 =C2=A0= 47 ++
>=C2=A0 sys/dev/thunderbolt/nhi.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | 11= 70 ++++++++++++++++++++++++++++++++++++
>=C2=A0 sys/dev/thunderbolt/nhi_pci.c=C2=A0 =C2=A0 =C2=A0 |=C2=A0 529 ++= ++++++++++++++
>=C2=A0 sys/dev/thunderbolt/nhi_reg.h=C2=A0 =C2=A0 =C2=A0 |=C2=A0 332 ++= ++++++++
>=C2=A0 sys/dev/thunderbolt/nhi_var.h=C2=A0 =C2=A0 =C2=A0 |=C2=A0 277 ++= +++++++
>=C2=A0 sys/dev/thunderbolt/nhi_wmi.c=C2=A0 =C2=A0 =C2=A0 |=C2=A0 198 ++= ++++
>=C2=A0 sys/dev/thunderbolt/router.c=C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 9= 39 +++++++++++++++++++++++++++++
>=C2=A0 sys/dev/thunderbolt/router_var.h=C2=A0 =C2=A0|=C2=A0 242 +++++++= +
>=C2=A0 sys/dev/thunderbolt/tb_acpi_pcib.c |=C2=A0 181 ++++++
>=C2=A0 sys/dev/thunderbolt/tb_debug.c=C2=A0 =C2=A0 =C2=A0|=C2=A0 334 ++= ++++++++
>=C2=A0 sys/dev/thunderbolt/tb_debug.h=C2=A0 =C2=A0 =C2=A0|=C2=A0 =C2=A0= 93 +++
>=C2=A0 sys/dev/thunderbolt/tb_dev.c=C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 3= 31 ++++++++++
>=C2=A0 sys/dev/thunderbolt/tb_dev.h=C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 = =C2=A041 ++
>=C2=A0 sys/dev/thunderbolt/tb_if.m=C2=A0 =C2=A0 =C2=A0 =C2=A0 |=C2=A0 1= 21 ++++
>=C2=A0 sys/dev/thunderbolt/tb_ioctl.h=C2=A0 =C2=A0 =C2=A0|=C2=A0 =C2=A0= 52 ++
>=C2=A0 sys/dev/thunderbolt/tb_pcib.c=C2=A0 =C2=A0 =C2=A0 |=C2=A0 614 ++= +++++++++++++++++
>=C2=A0 sys/dev/thunderbolt/tb_pcib.h=C2=A0 =C2=A0 =C2=A0 |=C2=A0 =C2=A0= 93 +++
>=C2=A0 sys/dev/thunderbolt/tb_reg.h=C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 = =C2=A052 ++
>=C2=A0 sys/dev/thunderbolt/tb_var.h=C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 = =C2=A054 ++
>=C2=A0 sys/dev/thunderbolt/tbcfg_reg.h=C2=A0 =C2=A0 |=C2=A0 363 +++++++= ++++
>=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 +
>=C2=A0 sys/modules/thunderbolt/Makefile=C2=A0 =C2=A0|=C2=A0 =C2=A013 +<= br> >=C2=A0 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<= br> > + *=C2=A0 =C2=A0 notice, this list of conditions and the following dis= claimer.
> + * 2. Redistributions in binary form must reproduce the above copyrig= ht
> + *=C2=A0 =C2=A0 notice, this list of conditions and the following dis= claimer in the
> + *=C2=A0 =C2=A0 documentation and/or other materials provided with th= e distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS&#= 39;' AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, = THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR= PURPOSE
> + * ARE DISCLAIMED.=C2=A0 IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS= BE LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSE= QUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE = GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTI= ON)
> + * 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 POSSIBILIT= Y 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)
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct hcm_softc *hcm;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(nsc, DBG_HCM|DBG_EXTRA, "hcm= _attach called\n");
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0hcm =3D malloc(sizeof(struct hcm_softc), M= _THUNDERBOLT, M_NOWAIT|M_ZERO);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (hcm =3D=3D NULL) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(nsc, = DBG_HCM, "Cannot allocate hcm object\n");
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM= );
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0hcm->dev =3D nsc->dev;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0hcm->nsc =3D nsc;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nsc->hcm =3D hcm;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0hcm->taskqueue =3D taskqueue_create(&qu= ot;hcm_event", M_NOWAIT,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0taskqueue_thread_enqueue, &a= mp;hcm->taskqueue);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (hcm->taskqueue =3D=3D NULL)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM= );
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0taskqueue_start_threads(&hcm->taskq= ueue, 1, PI_DISK, "tbhcm%d_tq",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0device_get_unit(nsc->dev)= );
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0TASK_INIT(&hcm->cfg_task, 0, hcm_cf= g_task, hcm);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);
> +}
> +
> +int
> +hcm_detach(struct nhi_softc *nsc)
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct hcm_softc *hcm;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0hcm =3D nsc->hcm;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (hcm->taskqueue)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0taskqueue_free= (hcm->taskqueue);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);
> +}
> +
> +int
> +hcm_router_discover(struct hcm_softc *hcm)
> +{
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0taskqueue_enqueue(hcm->taskqueue, &= hcm->cfg_task);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);
> +}
> +
> +static void
> +hcm_cfg_task(void *arg, int pending)
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct hcm_softc *hcm;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct router_softc *rsc;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct router_cfg_cap cap;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct tb_cfg_router *cfg;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct tb_cfg_adapter *adp;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct tb_cfg_cap_lane *lane;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t *buf;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t *u;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0u_int error, i, offset;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0hcm =3D (struct hcm_softc *)arg;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(hcm, DBG_HCM|DBG_EXTRA, "hcm= _cfg_task called\n");
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0buf =3D malloc(8 * 4, M_THUNDERBOLT, M_NOW= AIT|M_ZERO);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (buf =3D=3D NULL) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(hcm, = DBG_HCM, "Cannot alloc memory for discovery\n");
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0rsc =3D hcm->nsc->root_rsc;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D tb_config_router_read(rsc, 0, 5,= buf);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error !=3D 0) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0free(buf, M_NH= I);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0cfg =3D (struct tb_cfg_router *)buf;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0cap.space =3D TB_CFG_CS_ROUTER;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0cap.adap =3D 0;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0cap.next_cap =3D GET_ROUTER_CS_NEXT_CAP(cf= g);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0while (cap.next_cap !=3D 0) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D tb_c= onfig_next_cap(rsc, &cap);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (error !=3D= 0)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0break;
> +
> +=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) && (cap.vsc_len =3D=3D 0)) {
> +=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, "Router Cap=3D %d, vsec=3D %d, &q= uot;
> +=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"len=3D %d, next_cap=3D %d\n", cap.ca= p_id,
> +=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);
> +=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) {
> +=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, "Router cap=3D %d, vsc=3D %d, &qu= ot;
> +=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"len=3D %d, next_cap=3D %d\n", cap.ca= p_id,
> +=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);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else
> +=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, "Router cap=3D %d, "
> +=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"next_cap=3D %d\n", cap.cap_id, cap.n= ext_cap);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (cap.next_c= ap > TB_CFG_CAP_OFFSET_MAX)
> +=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;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0u =3D (uint8_t *)buf;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D tb_config_get_lc_uuid(rsc, u); > +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error =3D=3D 0) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(hcm, = DBG_HCM, "Router LC UUID: %02x%02x%02x%02x-"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= "%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
> +=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],
> +=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]);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0} else
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(hcm,= "Error finding LC registers: %d\n", error);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 1; i <=3D rsc->max_adap; = i++) {
> +=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);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (error !=3D= 0) {
> +=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, "Adapter %d: no adapter\n", = i);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0continue;
> +=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=A0adp =3D (struc= t tb_cfg_adapter *)buf;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(hcm, = DBG_HCM, "Adapter %d: %s, max_counters=3D 0x%08x,"
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= " adapter_num=3D %d\n", i,
> +=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),
> +=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));
> +
> +=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)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0continue;
> +
> +=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,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= &offset);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (error)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0continue;
> +
> +=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);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (error)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0continue;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0lane =3D (stru= ct tb_cfg_cap_lane *)buf;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(hcm, = DBG_HCM, "Lane Adapter State=3D %s %s\n",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= tb_get_string((lane->current_lws & CAP_LANE_STATE_MASK),
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= tb_adapter_state), (lane->targ_lwp & CAP_LANE_DISABLE) ?
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= "disabled" : "enabled");
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if ((lane->= current_lws & CAP_LANE_STATE_MASK) =3D=3D
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= CAP_LANE_STATE_CL0) {
> +=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;
> +
> +=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->route.hi;
> +=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->route.lo | (i << rsc->depth * 8)= ;
> +
> +=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, "want to add router at 0x%08x%08x\n"= ,
> +=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);
> +=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);
> +=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, "tb_router_attach returned %d\n", er= ror);
> +=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=A0free(buf, M_THUNDERBOLT);
> +}
> diff --git a/sys/dev/thunderbolt/hcm_var.h b/sys/dev/thunderbolt/hcm_v= ar.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<= br> > + *=C2=A0 =C2=A0 notice, this list of conditions and the following dis= claimer.
> + * 2. Redistributions in binary form must reproduce the above copyrig= ht
> + *=C2=A0 =C2=A0 notice, this list of conditions and the following dis= claimer in the
> + *=C2=A0 =C2=A0 documentation and/or other materials provided with th= e distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS&#= 39;' AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, = THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR= PURPOSE
> + * ARE DISCLAIMED.=C2=A0 IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS= BE LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSE= QUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE = GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTI= ON)
> + * 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 POSSIBILIT= Y OF
> + * SUCH DAMAGE.
> + *
> + * $FreeBSD$
> + */
> +
> +#ifndef _HCM_VAR_H
> +#define _HCM_VAR_H
> +
> +struct hcm_softc {
> +=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;
> +=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;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_softc=C2=A0 =C2=A0 =C2=A0 =C2= =A0 *nsc;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct task=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0cfg_task;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct taskqueue=C2=A0 =C2=A0 =C2=A0 =C2= =A0 *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<= br> > + *=C2=A0 =C2=A0 notice, this list of conditions and the following dis= claimer.
> + * 2. Redistributions in binary form must reproduce the above copyrig= ht
> + *=C2=A0 =C2=A0 notice, this list of conditions and the following dis= claimer in the
> + *=C2=A0 =C2=A0 documentation and/or other materials provided with th= e distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS&#= 39;' AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, = THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR= PURPOSE
> + * ARE DISCLAIMED.=C2=A0 IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS= BE LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSE= QUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE = GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTI= ON)
> + * 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 POSSIBILIT= Y 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,
> +=C2=A0 =C2=A0 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_pai= r *);
> +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_fram= e *);
> +static int nhi_setup_sysctl(struct nhi_softc *);
> +
> +SYSCTL_NODE(_hw, OID_AUTO, nhi, CTLFLAG_RD, 0, "NHI Driver Param= eters");
> +
> +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)
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0devclass_t dc;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0device_t ufp;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0char=C2=A0 =C2=A0 tmpstr[80], oid[80];
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0u_int=C2=A0 =C2=A0val;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Set local defaults */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc->debug =3D NHI_DEBUG_LEVEL;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc->max_ring_count =3D NHI_DEFAULT_NUM_= RINGS;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc->force_hcm =3D NHI_FORCE_HCM;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Inherit setting from the upstream thund= erbolt switch node */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D TB_GET_DEBUG(sc->dev, &sc-&= gt;debug);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (val !=3D 0) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0dc =3D devclas= s_find("tbolt");
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (dc !=3D NU= LL) {
> +=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->dev));=
> +=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)
> +=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, &sc->deb= ug);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else {
> +=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("hw.tbolt.debug_level", oid,<= br> > +=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)
> +=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(&sc->debug,= oid);
> +=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=A0/*
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 * Grab global variables.=C2=A0 Allow nhi = debug flags to override
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 * thunderbolt debug flags, if present. > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0bzero(oid, 80);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (TUNABLE_STR_FETCH("hw.nhi.debug_l= evel", oid, 80) !=3D 0)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_parse_debug= (&sc->debug, oid);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (TUNABLE_INT_FETCH("hw.nhi.max_rin= gs", &val) !=3D 0) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D min(va= l, NHI_MAX_NUM_RINGS);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc->max_rin= g_count =3D max(val, 1);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (TUNABLE_INT_FETCH("hw.nhi.force_h= cm", &val) !=3D 0)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc->force_h= cm =3D val;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Grab instance variables */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0bzero(oid, 80);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0snprintf(tmpstr, sizeof(tmpstr), "dev= .nhi.%d.debug_level",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0device_get_unit(sc->dev))= ;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (TUNABLE_STR_FETCH(tmpstr, oid, 80) != =3D 0)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_parse_debug= (&sc->debug, oid);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0snprintf(tmpstr, sizeof(tmpstr), "dev= .nhi.%d.max_rings",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0device_get_unit(sc->dev))= ;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (TUNABLE_INT_FETCH(tmpstr, &val) != =3D 0) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D min(va= l, NHI_MAX_NUM_RINGS);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc->max_rin= g_count =3D max(val, 1);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0snprintf(tmpstr, sizeof(tmpstr), "dev= , nhi.%d.force_hcm",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0device_get_unit(sc->dev))= ;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (TUNABLE_INT_FETCH(tmpstr, &val) != =3D 0)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc->force_h= cm =3D val;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return;
> +}
> +
> +static void
> +nhi_configure_caps(struct nhi_softc *sc)
> +{
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (NHI_IS_USB4(sc) || (sc->force_hcm = =3D=3D NHI_FORCE_HCM_ON))
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc->caps |= =3D NHI_CAP_HCM;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (sc->force_hcm =3D=3D NHI_FORCE_HCM_= OFF)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc->caps &a= mp;=3D ~NHI_CAP_HCM;
> +}
> +
> +struct nhi_cmd_frame *
> +nhi_alloc_tx_frame(struct nhi_ring_pair *r)
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_cmd_frame *cmd;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_lock(&r->mtx);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0cmd =3D nhi_alloc_tx_frame_locked(r);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&r->mtx);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (cmd);
> +}
> +
> +void
> +nhi_free_tx_frame(struct nhi_ring_pair *r, struct nhi_cmd_frame *cmd)=
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_lock(&r->mtx);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_free_tx_frame_locked(r, cmd);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&r->mtx);
> +}
> +
> +/*
> + * Push a command and data dword through the mailbox to the firmware.=
> + * Response is either good, error, or timeout.=C2=A0 Commands that re= turn data
> + * do so by reading OUTMAILDATA.
> + */
> +int
> +nhi_inmail_cmd(struct nhi_softc *sc, uint32_t cmd, uint32_t data)
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t val;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0u_int error, timeout;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_lock(&sc->nhi_mtx);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/*
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 * XXX Should a defer/reschedule happen he= re, or is it not worth
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 * worrying about?
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (sc->hwflags & NHI_MBOX_BUSY) {<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&am= p;sc->nhi_mtx);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, D= BG_MBOX, "Driver busy with mailbox\n");
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (EBUSY)= ;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc->hwflags |=3D NHI_MBOX_BUSY;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D nhi_read_reg(sc, TBT_INMAILCMD); > +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_MBOX|DBG_FULL, "Read= ing INMAILCMD=3D 0x%08x\n", val);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (val & INMAILCMD_ERROR)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, D= BG_MBOX, "Error already set in INMAILCMD\n");
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (val & INMAILCMD_OPREQ) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&am= p;sc->nhi_mtx);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, D= BG_MBOX,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= "INMAILCMD request already in progress\n");
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (EBUSY)= ;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, TBT_INMAILDATA, data); > +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, TBT_INMAILCMD, cmd | INM= AILCMD_OPREQ);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Poll at 1s intervals */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0timeout =3D NHI_MAILBOX_TIMEOUT;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0while (timeout--) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0DELAY(1000000)= ;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D nhi_re= ad_reg(sc, TBT_INMAILCMD);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, D= BG_MBOX|DBG_EXTRA,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= "Polling INMAILCMD=3D 0x%08x\n", val);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if ((val &= INMAILCMD_OPREQ) =3D=3D 0)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0break;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc->hwflags &=3D ~NHI_MBOX_BUSY; > +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&sc->nhi_mtx);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D 0;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (val & INMAILCMD_OPREQ) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, = "Timeout waiting for mailbox\n");
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D ETIM= EDOUT;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (val & INMAILCMD_ERROR) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, = "Firmware reports error in mailbox\n");
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D EINV= AL;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (error);
> +}
> +
> +/*
> + * Pull command status and data from the firmware mailbox.
> + */
> +int
> +nhi_outmail_cmd(struct nhi_softc *sc, uint32_t *val)
> +{
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (val =3D=3D NULL)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (EINVAL= );
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0*val =3D nhi_read_reg(sc, TBT_OUTMAILCMD);=
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);
> +}
> +
> +int
> +nhi_attach(struct nhi_softc *sc)
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t val;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0int error =3D 0;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if ((error =3D nhi_setup_sysctl(sc)) !=3D = 0)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (error)= ;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_init(&sc->nhi_mtx, "nhimtx= ", "NHI Control Mutex", MTX_DEF);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_configure_caps(sc);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/*
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 * Get the number of TX/RX paths.=C2=A0 Th= is sizes some of the register
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 * arrays during allocation and initializa= tion.=C2=A0 USB4 spec says that
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 * the max is 21.=C2=A0 Alpine Ridge appea= rs to default to 12.
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D GET_HOST_CAPS_PATHS(nhi_read_reg(s= c, NHI_HOST_CAPS));
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT|DBG_NOISY, "Tot= al Paths=3D %d\n", val);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if ((val =3D=3D 0) || (val > 21) || ((N= HI_IS_AR(sc) && val !=3D 12))) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, = "WARN: unexpected number of paths: %d\n", val);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* return (ENX= IO); */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc->path_count =3D val;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0SLIST_INIT(&sc->ring_list);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D nhi_pci_configure_interrupts(sc)= ;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error =3D=3D 0)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D nhi_= alloc_ring0(sc);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error =3D=3D 0) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_configure_= ring(sc, sc->ring0);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_activate_r= ing(sc->ring0);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_fill_rx_ri= ng(sc, sc->ring0);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error =3D=3D 0)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D tbde= v_add_interface(sc);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if ((error =3D=3D 0) && (NHI_USE_I= CM(sc)))
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, = "WARN: device uses an internal connection manager\n");
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if ((error =3D=3D 0) && (NHI_USE_H= CM(sc)))
> +=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 hcm_attach(sc);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error =3D=3D 0)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0error =3D nhi_= init(sc);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (error);
> +}
> +
> +int
> +nhi_detach(struct nhi_softc *sc)
> +{
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (NHI_USE_HCM(sc))
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0hcm_detach(sc)= ;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (sc->root_rsc !=3D NULL)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_router_deta= ch(sc->root_rsc);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0tbdev_remove_interface(sc);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_pci_disable_interrupts(sc);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_free_ring0(sc);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* XXX Should the rings be marked as !VALI= D in the descriptors? */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_free_rings(sc);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_destroy(&sc->nhi_mtx);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);
> +}
> +
> +static void
> +nhi_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int err= or)
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_addr_t *addr;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0addr =3D arg;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (error =3D=3D 0 && nsegs =3D=3D= 1) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*addr =3D segs= [0].ds_addr;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0} else
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*addr =3D 0; > +}
> +
> +static int
> +nhi_alloc_ring(struct nhi_softc *sc, int ringnum, int tx_depth, int r= x_depth,
> +=C2=A0 =C2=A0 struct nhi_ring_pair **rp)
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dma_template_t t;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_addr_t ring_busaddr;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_ring_pair *r;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0int ring_size, error;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0u_int rxring_len, txring_len;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0char *ring;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (ringnum >=3D sc->max_ring_count)= {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, D= BG_INIT, "Tried to allocate ring number %d\n",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= ringnum);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (EINVAL= );
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Allocate the ring structure and the RX = ring tacker together. */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0rxring_len =3D rx_depth * sizeof(void *);<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0txring_len =3D tx_depth * sizeof(void *);<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0r =3D malloc(sizeof(struct nhi_ring_pair) = + rxring_len + txring_len,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0M_NHI, M_NOWAIT|M_ZERO);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (r =3D=3D NULL) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, = "ERROR: Cannot allocate ring memory\n");
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM= );
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->sc =3D sc;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0TAILQ_INIT(&r->tx_head);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0TAILQ_INIT(&r->rx_head);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->ring_num =3D ringnum;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->tx_ring_depth =3D tx_depth;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->tx_ring_mask =3D tx_depth - 1;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->rx_ring_depth =3D rx_depth;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->rx_ring_mask =3D rx_depth - 1;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->rx_pici_reg =3D NHI_RX_RING_PICI + r= ingnum * 16;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->tx_pici_reg =3D NHI_TX_RING_PICI + r= ingnum * 16;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->rx_cmd_ring =3D (struct nhi_cmd_fram= e **)((uint8_t *)r + sizeof (*r));
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->tx_cmd_ring =3D (struct nhi_cmd_fram= e **)((uint8_t *)r->rx_cmd_ring +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0rxring_len);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0snprintf(r->name, NHI_RING_NAMELEN, &qu= ot;nhiring%d\n", ringnum);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_init(&r->mtx, r->name, "= ;NHI Ring Lock", MTX_DEF);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT | DBG_FULL, "Al= located ring context at %p, "
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"mutex %p\n", r, &= amp;r->mtx);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Allocate the RX and TX buffer descripto= r rings */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0ring_size =3D sizeof(struct nhi_tx_buffer_= desc) * r->tx_ring_depth;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0ring_size +=3D sizeof(struct nhi_rx_buffer= _desc) * r->rx_ring_depth;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT | DBG_FULL, "Ri= ng %d ring_size=3D %d\n",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ringnum, ring_size);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dma_template_init(&t, sc->paren= t_dmat);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0t.alignment =3D 4;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0t.maxsize =3D t.maxsegsize =3D ring_size;<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0t.nsegments =3D 1;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if ((error =3D bus_dma_template_tag(&t= , &r->ring_dmat)) !=3D 0) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, = "Cannot allocate ring %d DMA tag: %d\n",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= ringnum, error);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM= );
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (bus_dmamem_alloc(r->ring_dmat, (voi= d **)&ring, BUS_DMA_NOWAIT,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&r->ring_map)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, = "Cannot allocate ring memory\n");
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM= );
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0bzero(ring, ring_size);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dmamap_load(r->ring_dmat, r->rin= g_map, ring, ring_size,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_memaddr_cb, &ring_bu= saddr, 0);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->ring =3D ring;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->tx_ring =3D (union nhi_ring_desc *)(= ring);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->tx_ring_busaddr =3D ring_busaddr; > +=C2=A0 =C2=A0 =C2=A0 =C2=A0ring +=3D sizeof(struct nhi_tx_buffer_desc= ) * r->tx_ring_depth;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0ring_busaddr +=3D sizeof(struct nhi_tx_buf= fer_desc) * r->tx_ring_depth;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->rx_ring =3D (union nhi_ring_desc *)(= ring);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->rx_ring_busaddr =3D ring_busaddr; > +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT | DBG_EXTRA, "R= ing %d: RX %p [0x%jx] "
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"TX %p [0x%jx]\n",= ringnum, r->tx_ring, r->tx_ring_busaddr,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0r->rx_ring, r->rx_ring= _busaddr);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0*rp =3D r;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);
> +}
> +
> +static void
> +nhi_free_ring(struct nhi_ring_pair *r)
> +{
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(r->sc, DBG_INIT, "Freeing= ring %d resources\n", r->ring_num);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_deactivate_ring(r);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (r->tx_ring_busaddr !=3D 0) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dmamap_unl= oad(r->ring_dmat, r->ring_map);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0r->tx_ring_= busaddr =3D 0;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (r->ring !=3D NULL) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dmamem_fre= e(r->ring_dmat, r->ring, r->ring_map);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0r->ring =3D= NULL;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (r->ring_dmat !=3D NULL) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dma_tag_de= stroy(r->ring_dmat);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0r->ring_dma= t =3D NULL;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_destroy(&r->mtx);
> +}
> +
> +static void
> +nhi_free_rings(struct nhi_softc *sc)
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_ring_pair *r;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0while ((r =3D SLIST_FIRST(&sc->ring= _list)) !=3D NULL) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_free_ring(= r);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_lock(&= sc->nhi_mtx);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0SLIST_REMOVE_H= EAD(&sc->ring_list, ring_link);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&am= p;sc->nhi_mtx);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0free(r, M_NHI)= ;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return;
> +}
> +
> +static int
> +nhi_configure_ring(struct nhi_softc *sc, struct nhi_ring_pair *ring)<= br> > +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_addr_t busaddr;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t val;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0int idx;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0idx =3D ring->ring_num * 16;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Program the TX ring address and size */=
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0busaddr =3D ring->tx_ring_busaddr;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_TX_RING_ADDR_LO + id= x, busaddr & 0xffffffff);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_TX_RING_ADDR_HI + id= x, busaddr >> 32);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_TX_RING_SIZE + idx, = ring->tx_ring_depth);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_TX_RING_TABLE_TIMEST= AMP + idx, 0x0);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT, "TX Ring %d TX= _RING_SIZE=3D 0x%x\n",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ring->ring_num, ring->= tx_ring_depth);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Program the RX ring address and size */=
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0busaddr =3D ring->rx_ring_busaddr;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0val =3D (ring->rx_buffer_size << = 16) | ring->rx_ring_depth;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_RX_RING_ADDR_LO + id= x, busaddr & 0xffffffff);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_RX_RING_ADDR_HI + id= x, busaddr >> 32);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_RX_RING_SIZE + idx, = val);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_RX_RING_TABLE_BASE1 = + idx, 0xffffffff);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT, "RX Ring %d RX= _RING_SIZE=3D 0x%x\n",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ring->ring_num, val);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);
> +}
> +
> +static int
> +nhi_activate_ring(struct nhi_ring_pair *ring)
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_softc *sc =3D ring->sc;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0int idx;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_pci_enable_interrupt(ring);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0idx =3D ring->ring_num * 32;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT, "Activating ri= ng %d at idx %d\n",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ring->ring_num, idx);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_TX_RING_TABLE_BASE0 = + idx,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0TX_TABLE_RAW | TX_TABLE_VALI= D);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_RX_RING_TABLE_BASE0 = + idx,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0RX_TABLE_RAW | RX_TABLE_VALI= D);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);
> +}
> +
> +static int
> +nhi_deactivate_ring(struct nhi_ring_pair *r)
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_softc *sc =3D r->sc;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0int idx;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0idx =3D r->ring_num * 32;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT, "Deactiving ri= ng %d at idx %d\n",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0r->ring_num, idx);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_TX_RING_TABLE_BASE0 = + idx, 0);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_RX_RING_TABLE_BASE0 = + idx, 0);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0idx =3D r->ring_num * 16;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0tb_debug(sc, DBG_INIT, "Setting ring = %d sizes to 0\n", r->ring_num);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_TX_RING_SIZE + idx, = 0);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_write_reg(sc, NHI_RX_RING_SIZE + idx, = 0);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);
> +}
> +
> +static int
> +nhi_alloc_ring0(struct nhi_softc *sc)
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_addr_t frames_busaddr;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dma_template_t t;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_intr_tracker *trkr;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_ring_pair *r;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0struct nhi_cmd_frame *cmd;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0char *frames;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0int error, size, i;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if ((error =3D nhi_alloc_ring(sc, 0, NHI_R= ING0_TX_DEPTH,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0NHI_RING0_RX_DEPTH, &r))= !=3D 0) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, = "Error allocating control ring\n");
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (error)= ;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->rx_buffer_size =3D NHI_RING0_FRAME_S= IZE;/* Control packets are small */
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Allocate the RX and TX buffers that are= used for Ring0 comms */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0size =3D r->tx_ring_depth * NHI_RING0_F= RAME_SIZE;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0size +=3D r->rx_ring_depth * NHI_RING0_= FRAME_SIZE;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dma_template_init(&t, sc->paren= t_dmat);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0t.maxsize =3D t.maxsegsize =3D size;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0t.nsegments =3D 1;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (bus_dma_template_tag(&t, &sc-&= gt;ring0_dmat)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, = "Error allocating control ring buffer tag\n");
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM= );
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (bus_dmamem_alloc(sc->ring0_dmat, (v= oid **)&frames, BUS_DMA_NOWAIT,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&sc->ring0_map) !=3D = 0) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tb_printf(sc, = "Error allocating control ring memory\n");
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM= );
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0bzero(frames, size);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dmamap_load(sc->ring0_dmat, sc->= ring0_map, frames, size,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_memaddr_cb, &frames_= busaddr, 0);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc->ring0_frames_busaddr =3D frames_bus= addr;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc->ring0_frames =3D frames;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Allocate the driver command trackers */=
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc->ring0_cmds =3D malloc(sizeof(struct= nhi_cmd_frame) *
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(r->tx_ring_depth + r->= ;rx_ring_depth), M_NHI, M_NOWAIT | M_ZERO);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (sc->ring0_cmds =3D=3D NULL)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return (ENOMEM= );
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Initialize the RX frames so they can be= used */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_lock(&r->mtx);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 0; i < r->rx_ring_depth; = i++) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd =3D &s= c->ring0_cmds[i];
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd->data = =3D (uint32_t *)(frames + NHI_RING0_FRAME_SIZE * i);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd->data_b= usaddr =3D frames_busaddr + NHI_RING0_FRAME_SIZE * i;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd->flags = =3D CMD_MAPPED;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd->idx = =3D i;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0TAILQ_INSERT_T= AIL(&r->rx_head, cmd, cm_link);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Inititalize the TX frames */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0for ( ; i < r->tx_ring_depth + r->= ;rx_ring_depth - 1; i++) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd =3D &s= c->ring0_cmds[i];
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd->data = =3D (uint32_t *)(frames + NHI_RING0_FRAME_SIZE * i);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd->data_b= usaddr =3D frames_busaddr + NHI_RING0_FRAME_SIZE * i;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd->flags = =3D CMD_MAPPED;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmd->idx = =3D i;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nhi_free_tx_fr= ame_locked(r, cmd);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0mtx_unlock(&r->mtx);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Do a 1:1 mapping of rings to interrupt = vectors. */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* XXX Should be abstracted */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0trkr =3D &sc->intr_trackers[0];
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0trkr->ring =3D r;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0r->tracker =3D trkr;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0/* XXX Should be an array */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0sc->ring0 =3D r;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0SLIST_INSERT_HEAD(&sc->ring_list, r= , ring_link);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0return (0);
> +}
> +
> +static void
> +nhi_free_ring0(struct nhi_softc *sc)
> +{
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (sc->ring0_cmds !=3D NULL) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0free(sc->ri= ng0_cmds, M_NHI);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc->ring0_c= mds =3D NULL;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0}
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0if (sc->ring0_frames_busaddr !=3D 0) {<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0bus_dmamap_unl= oad(sc->ring0_dmat, sc->ring0_map);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sc->ring0_f= rames_busaddr =3D 0;
> *** 5529 LINES SKIPPED ***



--
Wolfram Schneider <wosch@FreeBSD.org> https://wolfram.schneider.o= rg



--
Nuno Teixeira
=
FreeBSD UNIX:=C2=A0 <eduardo@FreeBSD.org>=C2=A0 =C2=A0Web:=C2=A0 https://Fr= eeBSD.org
--00000000000085e79c0640338477--