From nobody Tue Sep 30 15:17:20 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 4cbhWv5TzWz69DSg; Tue, 30 Sep 2025 15:18:03 +0000 (UTC) (envelope-from zlei@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 4cbhWv532Zz3Kf6; Tue, 30 Sep 2025 15:18:03 +0000 (UTC) (envelope-from zlei@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1759245483; 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: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=yN9RHlNA5wPgJnT/Nu5mgkqKJPN8xT6Ql/iVOYZZ04E=; b=gn9hh8vPMYdml/ecz6R72v246z/wW3NB7kH6jaaAfrzey24iLfG0CTxtCbdUT7j4RVj+Tp 8LgJOKbzHMzHPh5Ja3yBuCl9SBjuOzQ+f5LEbm69WQjVmxTHuAX21MZTdeoJTA/FMLsPb/ 4JHlnVsXhsOUrshoQ/SIPlQNMuHkQxPw/35PQ7nUJ/MVZjqpg/pTUGtgmqbZEEnCSylpwU c//Vx3oXU4ikg2ZPEzWUQnLnJ0986TxgBX2LWujAdvc/u3xl8WzzQKzxERO9tTaq7rncKq PXixQeBsbKMbIg7wmAUJUj4LsJfe59/mDXvF5X2x6Yz/UCcMluIEvfXC6yCZbg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1759245483; 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: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=yN9RHlNA5wPgJnT/Nu5mgkqKJPN8xT6Ql/iVOYZZ04E=; b=Exv5MkcX4Vqrj69tAECUNsELlhCCOTZ8/myuFs7J0G9uIKX1SMPlt87z7y54zZREafkkDc VXc/YrS03i/p6gKxkUxfr/oNoG6kNM9+ZtDdzQsTLXCGIiAOHEtrkRPbGbydIWyScJACmL E73BHl/b5wce7UV8MxTlQIO73HKjK5M4Fvs/XmTxxS/FK5apDka0ip9sf+JFxE52R+Vdbd DbSQFRW9MzQ5QXc4rQPUXSzrZSytd9dF5KmGtMPj7huUWS2bSFoAYj7dHq8RxgfMhguHhJ BZOIrCoDMKQENxB0HpyhJElyzMYNcpcA73LB8s6L4PztOHbvMTLJ+GyJ5RCM6g== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1759245483; a=rsa-sha256; cv=none; b=puQz+gRNdp3lCgWNUidrnmNTerp9zNo+vEKWvd1rxik5hglE2kuk8IGFmgR/S04NbKOzWe tA+9JwqxcLb6b0qwKdSKEOMk7x1yJ9qiXnExc/n0UTXR2gZ7OnE5fhaiDMlgIruWxtdQf5 QovRC2IajNGwGi9ZmNqjaeYNZ+UGh8DcbZsKDZQTAk+esz02t9Mpb6xLGFAksiVGg9mVwS OWoJhAYjYjgoesSt/9tt2CwvqT+wlNc36mQHz4RaZXSKUgj6avovAZ9UHF+UibjDYIs2Hy GDooIy193nZGkiMhJjpakJAW80+sjK3fK4UvDw6hJcDfpEfFL+D5cxbjNwTKCQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from smtpclient.apple (ns1.oxydns.net [45.32.91.63]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) (Authenticated sender: zlei/mail) by smtp.freebsd.org (Postfix) with ESMTPSA id 4cbhWg5PyFzwMd; Tue, 30 Sep 2025 15:17:51 +0000 (UTC) (envelope-from zlei@FreeBSD.org) Content-Type: text/plain; charset=us-ascii 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 (Mac OS X Mail 16.0 \(3696.120.41.1.10\)) Subject: Re: git: 2ed9833791f2 - main - thunderbolt: Import USB4 code From: Zhenlei Huang In-Reply-To: <202509271713.58RHDTTL008060@gitrepo.freebsd.org> Date: Tue, 30 Sep 2025 23:17:20 +0800 Cc: "src-committers@freebsd.org" , "dev-commits-src-all@freebsd.org" , "dev-commits-src-main@freebsd.org" Content-Transfer-Encoding: quoted-printable Message-Id: <76A05154-90E6-4237-851F-EFA35D29D3CC@FreeBSD.org> References: <202509271713.58RHDTTL008060@gitrepo.freebsd.org> To: Aymeric Wibo X-Mailer: Apple Mail (2.3696.120.41.1.10) Nice work ! Now my thunderbolt ethernet is correctly recognized and works great on = my old MBP. Cheers ! Best regards, Zhenlei > On Sep 28, 2025, at 1:13 AM, Aymeric Wibo wrote: >=20 > The branch main has been updated by obiwac: >=20 > URL: = https://cgit.FreeBSD.org/src/commit/?id=3D2ed9833791f28e14843ac813f90cb030= e45948dc >=20 > commit 2ed9833791f28e14843ac813f90cb030e45948dc > Author: Aymeric Wibo > AuthorDate: 2025-09-27 11:50:43 +0000 > Commit: Aymeric Wibo > CommitDate: 2025-09-27 17:13:13 +0000 >=20 > thunderbolt: Import USB4 code >=20 > Add initial USB4 code written by Scott Long and originally passed = on to > HPS (source: https://github.com/hselasky/usb4), minus the ICM code = and > with some small fixes. >=20 > 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. >=20 > Mostly completed work: >=20 > - Debug/trace framework. > - NHI controller driver. > - PCIe bridge driver. > - Router and config space layer handling (just reading in this = commit). >=20 > Link to the email where Scott shared details about the initial USB4 > work: >=20 > = https://lists.freebsd.org/archives/freebsd-hackers/2024-July/003411.html >=20 > 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(+) >=20 > 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 = copyright > + * 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, = THE > + * 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 = INTERRUPTION) > + * 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_cap); > + 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 = copyright > + * 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, = THE > + * 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 = INTERRUPTION) > + * 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 = copyright > + * 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, = THE > + * 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 = INTERRUPTION) > + * 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 worth > + * 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 = error) > +{ > + 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 + = sizeof (*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_depth; > + 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 = are 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_SIZE = * 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_SIZE = * 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 ***