From patchwork Fri Oct 13 12:06:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mika Westerberg X-Patchwork-Id: 733849 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AF1D814297 for ; Fri, 13 Oct 2023 12:06:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="awqRzu9F" Received: from mgamail.intel.com (mgamail.intel.com [134.134.136.20]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EEF3DDC for ; Fri, 13 Oct 2023 05:06:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1697198808; x=1728734808; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=LVB9d1j4l8rWI7muJmnyjcFcDQCiuND/wpiFnw7J+Ec=; b=awqRzu9FYmU0lbXVII3D2L42uIqwW23ROvToYJVFFdHvvte4m7wHPJra 0TxTeSE1PLjvhVosGRz1aXkhydHkxjihkhEUVk2r9yQEiPAXPWDK84kC2 0wqRCHm/oqE+h3AnHPLknMl4fTBG8CLWaYb+z95aOr/DuiUvqcfn0Abd8 pCoJNlnnVGF8qoQEvJjLplT6mY/HDKLhJSgdyWiPFy0Um913CFyktxohT JS8U3o8dVptqzX6X0Bi0yxqWzeLkbfbxX/eFbVqm32yTiGGuwPXRWYPP7 rHsgEHzg6+V/CdAjGj80IGGKfH78AiP9JVlqFayYp2mWeOpoVHQcayyGS Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10861"; a="375515470" X-IronPort-AV: E=Sophos;i="6.03,222,1694761200"; d="scan'208";a="375515470" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Oct 2023 05:06:47 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10861"; a="754683576" X-IronPort-AV: E=Sophos;i="6.03,222,1694761200"; d="scan'208";a="754683576" Received: from black.fi.intel.com ([10.237.72.28]) by orsmga002.jf.intel.com with ESMTP; 13 Oct 2023 05:06:45 -0700 Received: by black.fi.intel.com (Postfix, from userid 1001) id 05C9B6DA; Fri, 13 Oct 2023 15:06:41 +0300 (EEST) From: Mika Westerberg To: linux-usb@vger.kernel.org Cc: Yehezkel Bernat , Michael Jamet , Lukas Wunner , Andreas Noever , Gil Fine , Mika Westerberg Subject: [PATCH v2 05/10] thunderbolt: Set path power management packet support bit for USB4 v2 routers Date: Fri, 13 Oct 2023 15:06:35 +0300 Message-Id: <20231013120640.709255-6-mika.westerberg@linux.intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20231013120640.709255-1-mika.westerberg@linux.intel.com> References: <20231013120640.709255-1-mika.westerberg@linux.intel.com> Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,SPF_NONE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net USB4 v2 spec allows USB4 links that are part of a pass through tunnel (such as DisplayPort and USB 3.x Gen T) to enter lower CL states, which provide better power management. For this USB4 v2 routers in their path config space of lane 0 adapter include a new bit PMPS (PM packet support) that needs to be set. Signed-off-by: Mika Westerberg --- drivers/thunderbolt/path.c | 7 ++++--- drivers/thunderbolt/tb.h | 2 ++ drivers/thunderbolt/tb_regs.h | 3 ++- drivers/thunderbolt/tunnel.c | 35 ++++++++++++++++++++++++++--------- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/drivers/thunderbolt/path.c b/drivers/thunderbolt/path.c index ee03fd75a472..091a81bbdbdc 100644 --- a/drivers/thunderbolt/path.c +++ b/drivers/thunderbolt/path.c @@ -19,9 +19,9 @@ static void tb_dump_hop(const struct tb_path_hop *hop, const struct tb_regs_hop tb_port_dbg(port, " In HopID: %d => Out port: %d Out HopID: %d\n", hop->in_hop_index, regs->out_port, regs->next_hop); - tb_port_dbg(port, " Weight: %d Priority: %d Credits: %d Drop: %d\n", - regs->weight, regs->priority, - regs->initial_credits, regs->drop_packages); + tb_port_dbg(port, " Weight: %d Priority: %d Credits: %d Drop: %d PM: %d\n", + regs->weight, regs->priority, regs->initial_credits, + regs->drop_packages, regs->pmps); tb_port_dbg(port, " Counter enabled: %d Counter index: %d\n", regs->counter_enable, regs->counter); tb_port_dbg(port, " Flow Control (In/Eg): %d/%d Shared Buffer (In/Eg): %d/%d\n", @@ -535,6 +535,7 @@ int tb_path_activate(struct tb_path *path) hop.next_hop = path->hops[i].next_hop_index; hop.out_port = path->hops[i].out_port->port; hop.initial_credits = path->hops[i].initial_credits; + hop.pmps = path->hops[i].pm_support; hop.unknown1 = 0; hop.enable = 1; diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index f29bbafb977f..3c9ae5584569 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -348,6 +348,7 @@ struct tb_retimer { * the path * @nfc_credits: Number of non-flow controlled buffers allocated for the * @in_port. + * @pm_support: Set path PM packet support bit to 1 (for USB4 v2 routers) * * Hop configuration is always done on the IN port of a switch. * in_port and out_port have to be on the same switch. Packets arriving on @@ -368,6 +369,7 @@ struct tb_path_hop { int next_hop_index; unsigned int initial_credits; unsigned int nfc_credits; + bool pm_support; }; /** diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h index 32839315948b..c14a1c3bc992 100644 --- a/drivers/thunderbolt/tb_regs.h +++ b/drivers/thunderbolt/tb_regs.h @@ -496,7 +496,8 @@ struct tb_regs_hop { * out_port (on the incoming port of the next switch) */ u32 out_port:6; /* next port of the path (on the same switch) */ - u32 initial_credits:8; + u32 initial_credits:7; + u32 pmps:1; u32 unknown1:6; /* set to zero */ bool enable:1; diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c index 876b8f07f716..db0546c62cb3 100644 --- a/drivers/thunderbolt/tunnel.c +++ b/drivers/thunderbolt/tunnel.c @@ -134,6 +134,16 @@ static unsigned int tb_available_credits(const struct tb_port *port, return credits > 0 ? credits : 0; } +static void tb_init_pm_support(struct tb_path_hop *hop) +{ + struct tb_port *out_port = hop->out_port; + struct tb_port *in_port = hop->in_port; + + if (tb_port_is_null(in_port) && tb_port_is_null(out_port) && + usb4_switch_version(in_port->sw) >= 2) + hop->pm_support = true; +} + static struct tb_tunnel *tb_tunnel_alloc(struct tb *tb, size_t npaths, enum tb_tunnel_type type) { @@ -1213,7 +1223,7 @@ static void tb_dp_init_aux_credits(struct tb_path_hop *hop) hop->initial_credits = 1; } -static void tb_dp_init_aux_path(struct tb_path *path) +static void tb_dp_init_aux_path(struct tb_path *path, bool pm_support) { struct tb_path_hop *hop; @@ -1224,8 +1234,11 @@ static void tb_dp_init_aux_path(struct tb_path *path) path->priority = TB_DP_AUX_PRIORITY; path->weight = TB_DP_AUX_WEIGHT; - tb_path_for_each_hop(path, hop) + tb_path_for_each_hop(path, hop) { tb_dp_init_aux_credits(hop); + if (pm_support) + tb_init_pm_support(hop); + } } static int tb_dp_init_video_credits(struct tb_path_hop *hop) @@ -1257,7 +1270,7 @@ static int tb_dp_init_video_credits(struct tb_path_hop *hop) return 0; } -static int tb_dp_init_video_path(struct tb_path *path) +static int tb_dp_init_video_path(struct tb_path *path, bool pm_support) { struct tb_path_hop *hop; @@ -1274,6 +1287,8 @@ static int tb_dp_init_video_path(struct tb_path *path) ret = tb_dp_init_video_credits(hop); if (ret) return ret; + if (pm_support) + tb_init_pm_support(hop); } return 0; @@ -1365,7 +1380,7 @@ struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in, goto err_free; } tunnel->paths[TB_DP_VIDEO_PATH_OUT] = path; - if (tb_dp_init_video_path(tunnel->paths[TB_DP_VIDEO_PATH_OUT])) + if (tb_dp_init_video_path(tunnel->paths[TB_DP_VIDEO_PATH_OUT], false)) goto err_free; path = tb_path_discover(in, TB_DP_AUX_TX_HOPID, NULL, -1, NULL, "AUX TX", @@ -1373,14 +1388,14 @@ struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in, if (!path) goto err_deactivate; tunnel->paths[TB_DP_AUX_PATH_OUT] = path; - tb_dp_init_aux_path(tunnel->paths[TB_DP_AUX_PATH_OUT]); + tb_dp_init_aux_path(tunnel->paths[TB_DP_AUX_PATH_OUT], false); path = tb_path_discover(tunnel->dst_port, -1, in, TB_DP_AUX_RX_HOPID, &port, "AUX RX", alloc_hopid); if (!path) goto err_deactivate; tunnel->paths[TB_DP_AUX_PATH_IN] = path; - tb_dp_init_aux_path(tunnel->paths[TB_DP_AUX_PATH_IN]); + tb_dp_init_aux_path(tunnel->paths[TB_DP_AUX_PATH_IN], false); /* Validate that the tunnel is complete */ if (!tb_port_is_dpout(tunnel->dst_port)) { @@ -1435,6 +1450,7 @@ struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in, struct tb_tunnel *tunnel; struct tb_path **paths; struct tb_path *path; + bool pm_support; if (WARN_ON(!in->cap_adap || !out->cap_adap)) return NULL; @@ -1456,26 +1472,27 @@ struct tb_tunnel *tb_tunnel_alloc_dp(struct tb *tb, struct tb_port *in, tunnel->max_down = max_down; paths = tunnel->paths; + pm_support = usb4_switch_version(in->sw) >= 2; path = tb_path_alloc(tb, in, TB_DP_VIDEO_HOPID, out, TB_DP_VIDEO_HOPID, link_nr, "Video"); if (!path) goto err_free; - tb_dp_init_video_path(path); + tb_dp_init_video_path(path, pm_support); paths[TB_DP_VIDEO_PATH_OUT] = path; path = tb_path_alloc(tb, in, TB_DP_AUX_TX_HOPID, out, TB_DP_AUX_TX_HOPID, link_nr, "AUX TX"); if (!path) goto err_free; - tb_dp_init_aux_path(path); + tb_dp_init_aux_path(path, pm_support); paths[TB_DP_AUX_PATH_OUT] = path; path = tb_path_alloc(tb, out, TB_DP_AUX_RX_HOPID, in, TB_DP_AUX_RX_HOPID, link_nr, "AUX RX"); if (!path) goto err_free; - tb_dp_init_aux_path(path); + tb_dp_init_aux_path(path, pm_support); paths[TB_DP_AUX_PATH_IN] = path; return tunnel;