From patchwork Mon Aug 15 19:22:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 12944084 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 58FA9C3F6B0 for ; Mon, 15 Aug 2022 21:28:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345230AbiHOV2W (ORCPT ); Mon, 15 Aug 2022 17:28:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45338 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347323AbiHOVZh (ORCPT ); Mon, 15 Aug 2022 17:25:37 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 546992F018 for ; Mon, 15 Aug 2022 12:22:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1660591364; x=1692127364; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=8MiiEmJrUVg6tXUUT3jHHbUKQ3S9VPBvZYaANeWql+s=; b=bKCVozSv3zrzsUt6LnM6CAhbv4j1e/slSRBiaxzgt+sCmwjGjaNmYURF 3b2gKuk/t33zQY+ApeLSYZQfiEND3pk934wQk5ii+Bg9YoXECEzThFh57 oihFZoE2qSW97DLe/8KcT9XSSpkAo7MiHSycLPP9BYrqv8ohNtXe2cpe4 BQk4pwXP3lejHb6ncmkDxyGTcAdmaDkzctEx8OxsmoVtOeslS1D22kxZL YLihJq9SxDWcQ5RxK/nbkf6giP/ye4DmLlURCNoLD6eRKUlDCF782Uln1 wIuydxA3lf+IJHOq4zto8c4QsIXC8DjdRbQUJKhi1Dqsmxev7JELT5BfO w==; X-IronPort-AV: E=McAfee;i="6400,9594,10440"; a="293313121" X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="293313121" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:18 -0700 X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="606758239" Received: from smadiset-mobl1.amr.corp.intel.com (HELO vverma7-desk1.intel.com) ([10.209.5.99]) by orsmga002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:18 -0700 From: Vishal Verma To: Cc: , Dan Williams , Alison Schofield , Ira Weiny , Dave Jiang , Vishal Verma Subject: [ndctl PATCH v3 01/11] libcxl: add a depth attribute to cxl_port Date: Mon, 15 Aug 2022 13:22:04 -0600 Message-Id: <20220815192214.545800-2-vishal.l.verma@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220815192214.545800-1-vishal.l.verma@intel.com> References: <20220815192214.545800-1-vishal.l.verma@intel.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=1236; h=from:subject; bh=8MiiEmJrUVg6tXUUT3jHHbUKQ3S9VPBvZYaANeWql+s=; b=owGbwMvMwCXGf25diOft7jLG02pJDEm/5jzdnFGQtnwnh+BFjX+8zMfjL6TctTFQYveX0dki9Lji 3Kc7HaUsDGJcDLJiiix/93xkPCa3PZ8nMMERZg4rE8gQBi5OAZiIox0jwwwDhYW7uzTk5viJ6fYaXN tw+s09s49cN7NYbz1Pye/8soHhf/qht/cdmy1uRbI7PbbIv3v70tK9hnvEvm6eIx9a8j9jMRcA X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Add a depth attribute to the cxl_port structure, that can be used for calculating its distance from the root port, and will be needed for interleave granularity calculations during region creation. Suggested-by: Dan Williams Reviewed-by: Dan Williams Signed-off-by: Vishal Verma --- cxl/lib/private.h | 1 + cxl/lib/libcxl.c | 1 + 2 files changed, 2 insertions(+) diff --git a/cxl/lib/private.h b/cxl/lib/private.h index f6d4573..832a815 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -66,6 +66,7 @@ struct cxl_port { int decoders_init; int dports_init; int nr_dports; + int depth; struct cxl_ctx *ctx; struct cxl_bus *bus; enum cxl_port_type type; diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index be6bc2c..946cd4b 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -744,6 +744,7 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_port *parent_port, port->type = type; port->parent = parent_port; port->type = type; + port->depth = parent_port ? parent_port->depth + 1 : 0; list_head_init(&port->child_ports); list_head_init(&port->endpoints); From patchwork Mon Aug 15 19:22:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 12944076 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 47BEBC3F6B0 for ; Mon, 15 Aug 2022 21:28:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232677AbiHOV17 (ORCPT ); Mon, 15 Aug 2022 17:27:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48028 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347834AbiHOV0U (ORCPT ); Mon, 15 Aug 2022 17:26:20 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B9E26E8334 for ; Mon, 15 Aug 2022 12:22:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1660591364; x=1692127364; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=hWdnQGSa5Du+Yzjo1XKDR7Gzv21wnxh5foUJXYJfm4I=; b=S4yzr+5ELN2Es/t1TWQlYk1w4yeoBqwuJC/NfQv5JC7Xw0EjU9/NO449 Ts/CuWiDA5t+8DGJG3dJgq7qPXmufLkOhcOjwLQqkkB7BvtTt3RInYyPX y7omoIUmf3mrJev0ke9TAQBL/GivsIZrKILOwWbo0+BCupPAAOz8Ks7OY 6PC5vp8wzNWe/Ko6ssp868aIfvkfE3qFOKg2N0IPMWIH9gHk1aGPwCqan NiV4S2WrsQJH2vNn4sXPnXM0fhjUNdWAeueuxxjIR2cPbrK+U1kPj7BOs DHtfT96vwsPMEfwH4YCZq3mYTg0OSA2nwM4yWWXJ13HVpEImL71pANv33 A==; X-IronPort-AV: E=McAfee;i="6400,9594,10440"; a="293313123" X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="293313123" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:18 -0700 X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="606758243" Received: from smadiset-mobl1.amr.corp.intel.com (HELO vverma7-desk1.intel.com) ([10.209.5.99]) by orsmga002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:18 -0700 From: Vishal Verma To: Cc: , Dan Williams , Alison Schofield , Ira Weiny , Dave Jiang , Vishal Verma Subject: [ndctl PATCH v3 02/11] cxl/port: Consolidate the debug option in cxl-port man pages Date: Mon, 15 Aug 2022 13:22:05 -0600 Message-Id: <20220815192214.545800-3-vishal.l.verma@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220815192214.545800-1-vishal.l.verma@intel.com> References: <20220815192214.545800-1-vishal.l.verma@intel.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=2436; h=from:subject; bh=hWdnQGSa5Du+Yzjo1XKDR7Gzv21wnxh5foUJXYJfm4I=; b=owGbwMvMwCXGf25diOft7jLG02pJDEm/5jy1T4txFP074dWHG/zNkyPcl98UsY4oOVsXqv59wvM1 YcoPOkpZGMS4GGTFFFn+7vnIeExuez5PYIIjzBxWJpAhDFycAjCR2ZMY/ofwVSRcrLCZ0bn+yvWWi/ euXZn6JiLbNubFxdqTvB2VvPMZGZZvenv6nCf35j+nd/Xm1BiWHe0+LlHXtn//9sLJ+qte2vECAA== X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org In preparation for additional commands that implement the --debug option, consolidate the option description from the cxl-port man pages into an include. The port man pages also mentioned the debug option requiring a build with debug enabled, which wasn't true - so remove that part. Cc: Dan Williams Reviewed-by: Dan Williams Signed-off-by: Vishal Verma --- Documentation/cxl/cxl-disable-port.txt | 5 +---- Documentation/cxl/cxl-enable-port.txt | 5 +---- Documentation/cxl/debug-option.txt | 4 ++++ Documentation/cxl/meson.build | 1 + 4 files changed, 7 insertions(+), 8 deletions(-) create mode 100644 Documentation/cxl/debug-option.txt diff --git a/Documentation/cxl/cxl-disable-port.txt b/Documentation/cxl/cxl-disable-port.txt index ac56f20..7a22efc 100644 --- a/Documentation/cxl/cxl-disable-port.txt +++ b/Documentation/cxl/cxl-disable-port.txt @@ -30,10 +30,7 @@ OPTIONS firmware and disabling an active device is akin to force removing memory from a running system. ---debug:: - If the cxl tool was built with debug disabled, turn on debug - messages. - +include::debug-option.txt[] include::../copyright.txt[] diff --git a/Documentation/cxl/cxl-enable-port.txt b/Documentation/cxl/cxl-enable-port.txt index 9a37cef..50b53d1 100644 --- a/Documentation/cxl/cxl-enable-port.txt +++ b/Documentation/cxl/cxl-enable-port.txt @@ -31,10 +31,7 @@ OPTIONS memdev is only enabled after all CXL ports in its device topology ancestry are enabled. ---debug:: - If the cxl tool was built with debug enabled, turn on debug - messages. - +include::debug-option.txt[] include::../copyright.txt[] diff --git a/Documentation/cxl/debug-option.txt b/Documentation/cxl/debug-option.txt new file mode 100644 index 0000000..70b922f --- /dev/null +++ b/Documentation/cxl/debug-option.txt @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 + +--debug:: + Turn on additional debug messages including library debug. diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build index d019dfc..423be90 100644 --- a/Documentation/cxl/meson.build +++ b/Documentation/cxl/meson.build @@ -22,6 +22,7 @@ filedeps = [ '../copyright.txt', 'memdev-option.txt', 'labels-options.txt', + 'debug-option.txt', ] cxl_manpages = [ From patchwork Mon Aug 15 19:22:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 12944077 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C4771C00140 for ; Mon, 15 Aug 2022 21:28:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244039AbiHOV2L (ORCPT ); Mon, 15 Aug 2022 17:28:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47078 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347812AbiHOV0T (ORCPT ); Mon, 15 Aug 2022 17:26:19 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CBEA5E8335 for ; Mon, 15 Aug 2022 12:22:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1660591364; x=1692127364; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=7BFJRklHB9Q8+ZO+vRUd1gtiGtVTpF4CnQfiprfpVzs=; b=OIGq20txxBMH2dMSjdtJ5jHbbYY5ydNwkWzJDQSoxZFUsKXDi9Jh+eQO 1+qxkfbbPFXxQ/+lCSFh8iMITth5pBf0dVAVIGle7KxHCjNhZoOk9Avg2 lTd+9VsHwyw5QUlc6WeDuW2Xln+gxCEoqFZXjVMY5swh2FdyjWHn2pJMU 1RvwsC2BMGNp0pFu9nHAaMxCenbwpucZKQ+D8SBUcRDExZGwpkKAS6Z9s 1dm7E+b2c5DYqMhXpV/cbzPXX4nHLCwAV9bKbp9K0vBxa8Hnyofvx6wCU A0VY0GP1GEwDxgpR+P0NmY0LbSb2UXa0GuEgULNn/vlmUC+ApuGCmaHGl Q==; X-IronPort-AV: E=McAfee;i="6400,9594,10440"; a="293313125" X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="293313125" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:19 -0700 X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="606758246" Received: from smadiset-mobl1.amr.corp.intel.com (HELO vverma7-desk1.intel.com) ([10.209.5.99]) by orsmga002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:18 -0700 From: Vishal Verma To: Cc: , Dan Williams , Alison Schofield , Ira Weiny , Dave Jiang , Vishal Verma Subject: [ndctl PATCH v3 03/11] cxl/memdev: refactor decoder mode string parsing Date: Mon, 15 Aug 2022 13:22:06 -0600 Message-Id: <20220815192214.545800-4-vishal.l.verma@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220815192214.545800-1-vishal.l.verma@intel.com> References: <20220815192214.545800-1-vishal.l.verma@intel.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=2080; h=from:subject; bh=7BFJRklHB9Q8+ZO+vRUd1gtiGtVTpF4CnQfiprfpVzs=; b=owGbwMvMwCXGf25diOft7jLG02pJDEm/5jztzCo/tKB8F+Oe5+LaT50fTJ5nyLgn7C/PpapJscbe woUCHaUsDGJcDLJiiix/93xkPCa3PZ8nMMERZg4rE8gQBi5OAZhIzSNGhvnHjP/td3yurSb19gZfwF zv53sPB9Xser2vwbrguZlAhCUjw4HGoFvpqmFTak///y/Iu6HmKHvfuv28/JEfiwUavs2ZzQMA X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org In preparation for create-region to use a similar decoder mode string to enum operation, break out the mode string parsing into its own inline helper in libcxl.h, and call it from memdev.c:__reserve_dpa(). Cc: Dan Williams Signed-off-by: Vishal Verma Reviewed-by: Dan Williams --- cxl/libcxl.h | 13 +++++++++++++ cxl/memdev.c | 11 ++--------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 33a216e..c1f8d14 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -4,6 +4,7 @@ #define _LIBCXL_H_ #include +#include #include #include @@ -154,6 +155,18 @@ static inline const char *cxl_decoder_mode_name(enum cxl_decoder_mode mode) return names[mode]; } +static inline enum cxl_decoder_mode +cxl_decoder_mode_from_ident(const char *ident) +{ + if (strcmp(ident, "ram") == 0) + return CXL_DECODER_MODE_RAM; + else if (strcmp(ident, "volatile") == 0) + return CXL_DECODER_MODE_RAM; + else if (strcmp(ident, "pmem") == 0) + return CXL_DECODER_MODE_PMEM; + return CXL_DECODER_MODE_NONE; +} + enum cxl_decoder_mode cxl_decoder_get_mode(struct cxl_decoder *decoder); int cxl_decoder_set_mode(struct cxl_decoder *decoder, enum cxl_decoder_mode mode); diff --git a/cxl/memdev.c b/cxl/memdev.c index e42f554..0b3ad02 100644 --- a/cxl/memdev.c +++ b/cxl/memdev.c @@ -154,15 +154,8 @@ static int __reserve_dpa(struct cxl_memdev *memdev, int rc; if (param.type) { - if (strcmp(param.type, "ram") == 0) - mode = CXL_DECODER_MODE_RAM; - else if (strcmp(param.type, "volatile") == 0) - mode = CXL_DECODER_MODE_RAM; - else if (strcmp(param.type, "ram") == 0) - mode = CXL_DECODER_MODE_RAM; - else if (strcmp(param.type, "pmem") == 0) - mode = CXL_DECODER_MODE_PMEM; - else { + mode = cxl_decoder_mode_from_ident(param.type); + if (mode == CXL_DECODER_MODE_NONE) { log_err(&ml, "%s: unsupported type: %s\n", devname, param.type); return -EINVAL; From patchwork Mon Aug 15 19:22:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 12944078 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5681CC00140 for ; Mon, 15 Aug 2022 21:28:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243533AbiHOV2M (ORCPT ); Mon, 15 Aug 2022 17:28:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48980 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348051AbiHOV0x (ORCPT ); Mon, 15 Aug 2022 17:26:53 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 25075E725A for ; Mon, 15 Aug 2022 12:22:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1660591370; x=1692127370; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Z7Quewel5vRsNwZc9Ca7qLU/GwpYh9lKdBU8hslGcJ8=; b=S72O7CRLjEAT1uuQCUxjzhgm4U2dFGeGeTkugLx4WcKzo1FkMpGwv3LT udhLSvYGx/VMNp1kHFiweDYTNmrXLbaWNUpZ/+WQkWxtpwkUCCafW4/Yv Xihx/Xo73RuzxNeuuNPp5voq9UAlyMICEgkri2s2GPxKzYijwMXMM6ZkD kukRmjENpaRiPHl0GgATgMy+KnsEhO0dF7BywIvx3J2RsBuk4PlWNGAUu XTLuIhOOGCnj1i1uIe85iqZBXbJT7NODH56hOwS/UUXuHKw/lF1F1QTAO LW7SAbDFN/lCWSZDOGY/OGx66Ukl0a06aJ5K6ZTCwsxSGMv4hjQw4uHUT Q==; X-IronPort-AV: E=McAfee;i="6400,9594,10440"; a="293313126" X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="293313126" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:19 -0700 X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="606758249" Received: from smadiset-mobl1.amr.corp.intel.com (HELO vverma7-desk1.intel.com) ([10.209.5.99]) by orsmga002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:19 -0700 From: Vishal Verma To: Cc: , Dan Williams , Alison Schofield , Ira Weiny , Dave Jiang , Vishal Verma Subject: [ndctl PATCH v3 04/11] libcxl: Introduce libcxl region and mapping objects Date: Mon, 15 Aug 2022 13:22:07 -0600 Message-Id: <20220815192214.545800-5-vishal.l.verma@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220815192214.545800-1-vishal.l.verma@intel.com> References: <20220815192214.545800-1-vishal.l.verma@intel.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=18887; h=from:subject; bh=Z7Quewel5vRsNwZc9Ca7qLU/GwpYh9lKdBU8hslGcJ8=; b=owGbwMvMwCXGf25diOft7jLG02pJDEm/5jwNU+xP8n2+/tN2I5bZT1aySu0vuiSpWN188VL/lTaH TPPXHaUsDGJcDLJiiix/93xkPCa3PZ8nMMERZg4rE8gQBi5OAZjILENGhveSii+evBIJnq1/uXnCrA 8pF5m9Lnpr32bSX2fHVVmzypbhD1/r7Gdth+IkxNYsUGU+6Lxsj+nzqBYJm2Vay+9YTIubxgQA X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Add a cxl_region object to libcxl that represents a CXL region. CXL regions are made up of one or more cxl_memdev 'targets'. The relationship between a target and a region is conveyed with a cxl_memdev_mapping object. CXL regions are childeren of root decoders, and are organized as such. Mapping objects are childeren of a CXL region. Introduce the two classes of objects themselves, and common accessors related to them. Cc: Dan Williams Reviewed-by: Dan Williams Signed-off-by: Vishal Verma --- cxl/lib/private.h | 35 ++++ cxl/lib/libcxl.c | 442 ++++++++++++++++++++++++++++++++++++++++++++- cxl/libcxl.h | 41 +++++ .clang-format | 2 + cxl/lib/libcxl.sym | 20 ++ 5 files changed, 530 insertions(+), 10 deletions(-) diff --git a/cxl/lib/private.h b/cxl/lib/private.h index 832a815..5e2fdd5 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -116,7 +116,42 @@ struct cxl_decoder { bool accelmem_capable; bool locked; enum cxl_decoder_target_type target_type; + int regions_init; struct list_head targets; + struct list_head regions; + struct list_head stale_regions; +}; + +enum cxl_decode_state { + CXL_DECODE_UNKNOWN = -1, + CXL_DECODE_RESET = 0, + CXL_DECODE_COMMIT, +}; + +struct cxl_region { + struct cxl_decoder *decoder; + struct list_node list; + int mappings_init; + struct cxl_ctx *ctx; + void *dev_buf; + size_t buf_len; + char *dev_path; + int id; + uuid_t uuid; + u64 start; + u64 size; + unsigned int interleave_ways; + unsigned int interleave_granularity; + enum cxl_decode_state decode_state; + struct kmod_module *module; + struct list_head mappings; +}; + +struct cxl_memdev_mapping { + struct cxl_region *region; + struct cxl_decoder *decoder; + unsigned int position; + struct list_node list; }; enum cxl_cmd_query_status { diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 946cd4b..1879c15 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -79,6 +79,38 @@ static void free_target(struct cxl_target *target, struct list_head *head) free(target); } +static void free_region(struct cxl_region *region, struct list_head *head) +{ + struct cxl_memdev_mapping *mapping, *_m; + + list_for_each_safe(®ion->mappings, mapping, _m, list) { + list_del_from(®ion->mappings, &mapping->list); + free(mapping); + } + if (head) + list_del_from(head, ®ion->list); + kmod_module_unref(region->module); + free(region->dev_buf); + free(region->dev_path); + free(region); +} + +static void free_stale_regions(struct cxl_decoder *decoder) +{ + struct cxl_region *region, *_r; + + list_for_each_safe(&decoder->stale_regions, region, _r, list) + free_region(region, &decoder->stale_regions); +} + +static void free_regions(struct cxl_decoder *decoder) +{ + struct cxl_region *region, *_r; + + list_for_each_safe(&decoder->regions, region, _r, list) + free_region(region, &decoder->regions); +} + static void free_decoder(struct cxl_decoder *decoder, struct list_head *head) { struct cxl_target *target, *_t; @@ -87,6 +119,8 @@ static void free_decoder(struct cxl_decoder *decoder, struct list_head *head) list_del_from(head, &decoder->list); list_for_each_safe(&decoder->targets, target, _t, list) free_target(target, &decoder->targets); + free_regions(decoder); + free_stale_regions(decoder); free(decoder->dev_buf); free(decoder->dev_path); free(decoder); @@ -304,6 +338,402 @@ CXL_EXPORT void cxl_set_log_priority(struct cxl_ctx *ctx, int priority) ctx->ctx.log_priority = priority; } +static int is_enabled(const char *drvpath) +{ + struct stat st; + + if (lstat(drvpath, &st) < 0 || !S_ISLNK(st.st_mode)) + return 0; + else + return 1; +} + +CXL_EXPORT int cxl_region_is_enabled(struct cxl_region *region) +{ + struct cxl_ctx *ctx = cxl_region_get_ctx(region); + char *path = region->dev_buf; + int len = region->buf_len; + + if (snprintf(path, len, "%s/driver", region->dev_path) >= len) { + err(ctx, "%s: buffer too small!\n", cxl_region_get_devname(region)); + return 0; + } + + return is_enabled(path); +} + +CXL_EXPORT int cxl_region_disable(struct cxl_region *region) +{ + const char *devname = cxl_region_get_devname(region); + struct cxl_ctx *ctx = cxl_region_get_ctx(region); + + util_unbind(region->dev_path, ctx); + + if (cxl_region_is_enabled(region)) { + err(ctx, "%s: failed to disable\n", devname); + return -EBUSY; + } + + dbg(ctx, "%s: disabled\n", devname); + + return 0; +} + +CXL_EXPORT int cxl_region_enable(struct cxl_region *region) +{ + const char *devname = cxl_region_get_devname(region); + struct cxl_ctx *ctx = cxl_region_get_ctx(region); + char *path = region->dev_buf; + int len = region->buf_len; + char buf[SYSFS_ATTR_SIZE]; + u64 resource = ULLONG_MAX; + + if (cxl_region_is_enabled(region)) + return 0; + + util_bind(devname, region->module, "cxl", ctx); + + if (!cxl_region_is_enabled(region)) { + err(ctx, "%s: failed to enable\n", devname); + return -ENXIO; + } + + /* + * Currently 'resource' is the only attr that may change after enabling. + * Just refresh it here. If there are additional resources that need + * to be refreshed here later, split these out into a common helper + * for this and add_cxl_region() + */ + if (snprintf(path, len, "%s/resource", region->dev_path) >= len) { + err(ctx, "%s: buffer too small!\n", devname); + return 0; + } + + if (sysfs_read_attr(ctx, path, buf) == 0) + resource = strtoull(buf, NULL, 0); + + if (resource < ULLONG_MAX) + region->start = resource; + + dbg(ctx, "%s: enabled\n", devname); + + return 0; +} + +static void *add_cxl_region(void *parent, int id, const char *cxlregion_base) +{ + const char *devname = devpath_to_devname(cxlregion_base); + char *path = calloc(1, strlen(cxlregion_base) + 100); + struct cxl_region *region, *region_dup, *_r; + struct cxl_decoder *decoder = parent; + struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder); + char buf[SYSFS_ATTR_SIZE]; + u64 resource = ULLONG_MAX; + + dbg(ctx, "%s: base: \'%s\'\n", devname, cxlregion_base); + + if (!path) + return NULL; + + region = calloc(1, sizeof(*region)); + if (!region) + goto err; + + region->id = id; + region->ctx = ctx; + region->decoder = decoder; + list_head_init(®ion->mappings); + + region->dev_path = strdup(cxlregion_base); + if (!region->dev_path) + goto err; + + region->dev_buf = calloc(1, strlen(cxlregion_base) + 50); + if (!region->dev_buf) + goto err; + region->buf_len = strlen(cxlregion_base) + 50; + + sprintf(path, "%s/size", cxlregion_base); + if (sysfs_read_attr(ctx, path, buf) < 0) + region->size = ULLONG_MAX; + else + region->size = strtoull(buf, NULL, 0); + + sprintf(path, "%s/resource", cxlregion_base); + if (sysfs_read_attr(ctx, path, buf) == 0) + resource = strtoull(buf, NULL, 0); + + if (resource < ULLONG_MAX) + region->start = resource; + + sprintf(path, "%s/uuid", cxlregion_base); + if (sysfs_read_attr(ctx, path, buf) < 0) + goto err; + if (strlen(buf) && uuid_parse(buf, region->uuid) < 0) { + dbg(ctx, "%s:%s\n", path, buf); + goto err; + } + + sprintf(path, "%s/interleave_granularity", cxlregion_base); + if (sysfs_read_attr(ctx, path, buf) < 0) + region->interleave_granularity = UINT_MAX; + else + region->interleave_granularity = strtoul(buf, NULL, 0); + + sprintf(path, "%s/interleave_ways", cxlregion_base); + if (sysfs_read_attr(ctx, path, buf) < 0) + region->interleave_ways = UINT_MAX; + else + region->interleave_ways = strtoul(buf, NULL, 0); + + sprintf(path, "%s/commit", cxlregion_base); + if (sysfs_read_attr(ctx, path, buf) < 0) + region->decode_state = CXL_DECODE_UNKNOWN; + else + region->decode_state = strtoul(buf, NULL, 0); + + sprintf(path, "%s/modalias", cxlregion_base); + if (sysfs_read_attr(ctx, path, buf) == 0) + region->module = util_modalias_to_module(ctx, buf); + + cxl_region_foreach_safe(decoder, region_dup, _r) + if (region_dup->id == region->id) { + list_del_from(&decoder->regions, ®ion_dup->list); + list_add_tail(&decoder->stale_regions, + ®ion_dup->list); + break; + } + + list_add(&decoder->regions, ®ion->list); + + return region; +err: + free(region->dev_path); + free(region->dev_buf); + free(region); + free(path); + return NULL; +} + +static void cxl_regions_init(struct cxl_decoder *decoder) +{ + struct cxl_port *port = cxl_decoder_get_port(decoder); + struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder); + + if (decoder->regions_init) + return; + + /* Only root port decoders may have child regions */ + if (!cxl_port_is_root(port)) + return; + + decoder->regions_init = 1; + + sysfs_device_parse(ctx, decoder->dev_path, "region", decoder, + add_cxl_region); +} + +CXL_EXPORT struct cxl_region *cxl_region_get_first(struct cxl_decoder *decoder) +{ + cxl_regions_init(decoder); + + return list_top(&decoder->regions, struct cxl_region, list); +} + +CXL_EXPORT struct cxl_region *cxl_region_get_next(struct cxl_region *region) +{ + struct cxl_decoder *decoder = region->decoder; + + return list_next(&decoder->regions, region, list); +} + +CXL_EXPORT struct cxl_ctx *cxl_region_get_ctx(struct cxl_region *region) +{ + return region->ctx; +} + +CXL_EXPORT struct cxl_decoder *cxl_region_get_decoder(struct cxl_region *region) +{ + return region->decoder; +} + +CXL_EXPORT int cxl_region_get_id(struct cxl_region *region) +{ + return region->id; +} + +CXL_EXPORT const char *cxl_region_get_devname(struct cxl_region *region) +{ + return devpath_to_devname(region->dev_path); +} + +CXL_EXPORT void cxl_region_get_uuid(struct cxl_region *region, uuid_t uu) +{ + memcpy(uu, region->uuid, sizeof(uuid_t)); +} + +CXL_EXPORT unsigned long long cxl_region_get_size(struct cxl_region *region) +{ + return region->size; +} + +CXL_EXPORT unsigned long long cxl_region_get_resource(struct cxl_region *region) +{ + return region->start; +} + +CXL_EXPORT unsigned int +cxl_region_get_interleave_ways(struct cxl_region *region) +{ + return region->interleave_ways; +} + +CXL_EXPORT int cxl_region_decode_is_committed(struct cxl_region *region) +{ + return (region->decode_state == CXL_DECODE_COMMIT) ? 1 : 0; +} + +CXL_EXPORT unsigned int +cxl_region_get_interleave_granularity(struct cxl_region *region) +{ + return region->interleave_granularity; +} + +static struct cxl_decoder *__cxl_port_match_decoder(struct cxl_port *port, + const char *ident) +{ + struct cxl_decoder *decoder; + + cxl_decoder_foreach(port, decoder) + if (strcmp(cxl_decoder_get_devname(decoder), ident) == 0) + return decoder; + + return NULL; +} + +static struct cxl_decoder *cxl_port_find_decoder(struct cxl_port *port, + const char *ident) +{ + struct cxl_decoder *decoder; + struct cxl_endpoint *ep; + + /* First, check decoders directly under @port */ + decoder = __cxl_port_match_decoder(port, ident); + if (decoder) + return decoder; + + /* Next, iterate over the endpoints under @port */ + cxl_endpoint_foreach(port, ep) { + decoder = __cxl_port_match_decoder(cxl_endpoint_get_port(ep), + ident); + if (decoder) + return decoder; + } + + return NULL; +} + +static struct cxl_decoder *cxl_decoder_get_by_name(struct cxl_ctx *ctx, + const char *ident) +{ + struct cxl_bus *bus; + + cxl_bus_foreach(ctx, bus) { + struct cxl_decoder *decoder; + struct cxl_port *port, *top; + + port = cxl_bus_get_port(bus); + decoder = cxl_port_find_decoder(port, ident); + if (decoder) + return decoder; + + top = port; + cxl_port_foreach_all (top, port) { + decoder = cxl_port_find_decoder(port, ident); + if (decoder) + return decoder; + } + } + + return NULL; +} + +static void cxl_mappings_init(struct cxl_region *region) +{ + const char *devname = cxl_region_get_devname(region); + struct cxl_ctx *ctx = cxl_region_get_ctx(region); + char *mapping_path, buf[SYSFS_ATTR_SIZE]; + unsigned int i; + + if (region->mappings_init) + return; + region->mappings_init = 1; + + mapping_path = calloc(1, strlen(region->dev_path) + 100); + if (!mapping_path) { + err(ctx, "%s: allocation failure\n", devname); + return; + } + + for (i = 0; i < region->interleave_ways; i++) { + struct cxl_memdev_mapping *mapping; + struct cxl_decoder *decoder; + + sprintf(mapping_path, "%s/target%d", region->dev_path, i); + if (sysfs_read_attr(ctx, mapping_path, buf) < 0) { + err(ctx, "%s: failed to read target%d\n", devname, i); + continue; + } + + decoder = cxl_decoder_get_by_name(ctx, buf); + if (!decoder) { + err(ctx, "%s target%d: %s lookup failure\n", + devname, i, buf); + continue; + } + + mapping = calloc(1, sizeof(*mapping)); + if (!mapping) { + err(ctx, "%s target%d: allocation failure\n", devname, i); + continue; + } + + mapping->region = region; + mapping->decoder = decoder; + mapping->position = i; + list_add(®ion->mappings, &mapping->list); + } + free(mapping_path); +} + +CXL_EXPORT struct cxl_memdev_mapping * +cxl_mapping_get_first(struct cxl_region *region) +{ + cxl_mappings_init(region); + + return list_top(®ion->mappings, struct cxl_memdev_mapping, list); +} + +CXL_EXPORT struct cxl_memdev_mapping * +cxl_mapping_get_next(struct cxl_memdev_mapping *mapping) +{ + struct cxl_region *region = mapping->region; + + return list_next(®ion->mappings, mapping, list); +} + +CXL_EXPORT struct cxl_decoder * +cxl_mapping_get_decoder(struct cxl_memdev_mapping *mapping) +{ + return mapping->decoder; +} + +CXL_EXPORT unsigned int +cxl_mapping_get_position(struct cxl_memdev_mapping *mapping) +{ + return mapping->position; +} + static void *add_cxl_pmem(void *parent, int id, const char *br_base) { const char *devname = devpath_to_devname(br_base); @@ -681,16 +1111,6 @@ CXL_EXPORT size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev) return memdev->lsa_size; } -static int is_enabled(const char *drvpath) -{ - struct stat st; - - if (lstat(drvpath, &st) < 0 || !S_ISLNK(st.st_mode)) - return 0; - else - return 1; -} - CXL_EXPORT int cxl_memdev_is_enabled(struct cxl_memdev *memdev) { struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); @@ -939,6 +1359,8 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base) decoder->ctx = ctx; decoder->port = port; list_head_init(&decoder->targets); + list_head_init(&decoder->regions); + list_head_init(&decoder->stale_regions); decoder->dev_path = strdup(cxldecoder_base); if (!decoder->dev_path) diff --git a/cxl/libcxl.h b/cxl/libcxl.h index c1f8d14..19d94e4 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -237,6 +237,47 @@ int cxl_memdev_is_enabled(struct cxl_memdev *memdev); for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \ endpoint = cxl_endpoint_get_next(endpoint)) +struct cxl_region; +struct cxl_region *cxl_region_get_first(struct cxl_decoder *decoder); +struct cxl_region *cxl_region_get_next(struct cxl_region *region); +int cxl_region_decode_is_committed(struct cxl_region *region); +int cxl_region_is_enabled(struct cxl_region *region); +int cxl_region_disable(struct cxl_region *region); +int cxl_region_enable(struct cxl_region *region); +struct cxl_ctx *cxl_region_get_ctx(struct cxl_region *region); +struct cxl_decoder *cxl_region_get_decoder(struct cxl_region *region); +int cxl_region_get_id(struct cxl_region *region); +const char *cxl_region_get_devname(struct cxl_region *region); +void cxl_region_get_uuid(struct cxl_region *region, uuid_t uu); +unsigned long long cxl_region_get_size(struct cxl_region *region); +unsigned long long cxl_region_get_resource(struct cxl_region *region); +unsigned int cxl_region_get_interleave_ways(struct cxl_region *region); +unsigned int cxl_region_get_interleave_granularity(struct cxl_region *region); + +#define cxl_region_foreach(decoder, region) \ + for (region = cxl_region_get_first(decoder); region != NULL; \ + region = cxl_region_get_next(region)) + +#define cxl_region_foreach_safe(decoder, region, _region) \ + for (region = cxl_region_get_first(decoder), \ + _region = region ? cxl_region_get_next(region) : NULL; \ + region != NULL; \ + region = _region, \ + _region = _region ? cxl_region_get_next(_region) : NULL) + +struct cxl_memdev_mapping; +struct cxl_memdev_mapping *cxl_mapping_get_first(struct cxl_region *region); +struct cxl_memdev_mapping * +cxl_mapping_get_next(struct cxl_memdev_mapping *mapping); +struct cxl_decoder *cxl_mapping_get_decoder(struct cxl_memdev_mapping *mapping); +struct cxl_region *cxl_mapping_get_region(struct cxl_memdev_mapping *mapping); +unsigned int cxl_mapping_get_position(struct cxl_memdev_mapping *mapping); + +#define cxl_mapping_foreach(region, mapping) \ + for (mapping = cxl_mapping_get_first(region); \ + mapping != NULL; \ + mapping = cxl_mapping_get_next(mapping)) + struct cxl_cmd; const char *cxl_cmd_get_devname(struct cxl_cmd *cmd); struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode); diff --git a/.clang-format b/.clang-format index 7254a1b..b6169e1 100644 --- a/.clang-format +++ b/.clang-format @@ -86,6 +86,8 @@ ForEachMacros: - 'cxl_dport_foreach' - 'cxl_endpoint_foreach' - 'cxl_port_foreach_all' + - 'cxl_region_foreach' + - 'cxl_region_foreach_safe' - 'daxctl_dev_foreach' - 'daxctl_mapping_foreach' - 'daxctl_region_foreach' diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 7712de0..e410298 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -177,4 +177,24 @@ global: cxl_decoder_get_prev; cxl_decoder_set_dpa_size; cxl_decoder_set_mode; + cxl_region_get_first; + cxl_region_get_next; + cxl_region_decode_is_committed; + cxl_region_is_enabled; + cxl_region_disable; + cxl_region_enable; + cxl_region_get_ctx; + cxl_region_get_decoder; + cxl_region_get_id; + cxl_region_get_devname; + cxl_region_get_uuid; + cxl_region_get_size; + cxl_region_get_resource; + cxl_region_get_interleave_ways; + cxl_region_get_interleave_granularity; + cxl_mapping_get_first; + cxl_mapping_get_next; + cxl_mapping_get_decoder; + cxl_mapping_get_region; + cxl_mapping_get_position; } LIBCXL_2; From patchwork Mon Aug 15 19:22:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 12944085 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EE84FC28B2B for ; Mon, 15 Aug 2022 21:28:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345293AbiHOV2Y (ORCPT ); Mon, 15 Aug 2022 17:28:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48940 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348063AbiHOV0x (ORCPT ); Mon, 15 Aug 2022 17:26:53 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 20BBFE97CE for ; Mon, 15 Aug 2022 12:22:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1660591371; x=1692127371; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=LRIDiwWAjYsy+li9ACjyVd56pQaTOROh0GT8Bp+3jig=; b=OkpkAVkq195Rvxg4lILZ/Uc2sJfcigWnX3SedeBQptfnpX3eLqee/aGr t4hsBM+k6sQr+Hs++ZgaFw4hZqWeXIXIlb045HpMNVPyOOfM9jPgy57Jk 2awn9wPFoxsHq8uMMWxjEI70wvAkgkc4NZyQpx86k4Bgp0rnzU9Z5vidI alivVxjcNi5P0Abd58GzBzrmvl6bezQv6t4cxxtv+UEaCIiJ1ygcDY8lp +CmCkx3XUHDiPXZgTKYN9TqrkBxNnj5Bjut1BWHhOd85gPvDEtVMXNmqZ ZwbvX6p30sQbIT1xQ50qMl97cOiGpVUcgAc/Ob6GnYt4/viqFVD53EROw w==; X-IronPort-AV: E=McAfee;i="6400,9594,10440"; a="293313128" X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="293313128" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:20 -0700 X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="606758252" Received: from smadiset-mobl1.amr.corp.intel.com (HELO vverma7-desk1.intel.com) ([10.209.5.99]) by orsmga002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:19 -0700 From: Vishal Verma To: Cc: , Dan Williams , Alison Schofield , Ira Weiny , Dave Jiang , Vishal Verma Subject: [ndctl PATCH v3 05/11] cxl-cli: add region listing support Date: Mon, 15 Aug 2022 13:22:08 -0600 Message-Id: <20220815192214.545800-6-vishal.l.verma@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220815192214.545800-1-vishal.l.verma@intel.com> References: <20220815192214.545800-1-vishal.l.verma@intel.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=17004; h=from:subject; bh=LRIDiwWAjYsy+li9ACjyVd56pQaTOROh0GT8Bp+3jig=; b=owGbwMvMwCXGf25diOft7jLG02pJDEm/5jzNU/sQr5nTE67O4DZ/U5Zvv79rq1Llm2lq27r+hhpr fTfsKGVhEONikBVTZPm75yPjMbnt+TyBCY4wc1iZQIYwcHEKwETuTWJkmNWr++SQxCLOWQdKhdZ/UX hf4lblnqzt1WtzasYVNfUYXkaG9ZuUKuSO3WoJf529OK6/X6vhpJizm/rFLJvQiwnHozpYAA== X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Add cxl_region -> json and cxl_mapping -> json emitter helpers, and teach cxl_filter_walk about cxl_regions. With these in place, 'cxl-list' can now emit json objects for CXL regions. They can be top-level objects if requested by themselves, or nested under root-decoders, if listed along with decoders. Allow a plain 'cxl list' command to imply '--regions'. Cc: Dan Williams Reviewed-by: Dan Williams Signed-off-by: Vishal Verma --- Documentation/cxl/cxl-list.txt | 13 ++- cxl/filter.h | 4 + cxl/json.h | 5 ++ cxl/filter.c | 158 +++++++++++++++++++++++++++++++-- cxl/json.c | 114 ++++++++++++++++++++++++ cxl/list.c | 25 +++--- 6 files changed, 295 insertions(+), 24 deletions(-) diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index f6aba0c..f952e4d 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -309,8 +309,9 @@ OPTIONS -T:: --targets:: - Extend decoder listings with downstream port target information, and / - or port and bus listings with the downstream port information. + Extend decoder listings with downstream port target information, port + and bus listings with the downstream port information, and / or regions + with mapping information. ---- # cxl list -BTu -b ACPI.CXL { @@ -327,6 +328,14 @@ OPTIONS } ---- +-R:: +--regions:: + Include region objects in the listing. + +-r:: +--region:: + Specify CXL region device name(s), or device id(s), to filter the listing. + --debug:: If the cxl tool was built with debug enabled, turn on debug messages. diff --git a/cxl/filter.h b/cxl/filter.h index c913daf..609433c 100644 --- a/cxl/filter.h +++ b/cxl/filter.h @@ -13,9 +13,11 @@ struct cxl_filter_params { const char *port_filter; const char *endpoint_filter; const char *decoder_filter; + const char *region_filter; bool single; bool endpoints; bool decoders; + bool regions; bool targets; bool memdevs; bool ports; @@ -33,6 +35,8 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port, const char *ident, const char *serial); +struct cxl_region *util_cxl_region_filter(struct cxl_region *region, + const char *__ident); enum cxl_port_filter_mode { CXL_PF_SINGLE, diff --git a/cxl/json.h b/cxl/json.h index 9a5a845..eb7572b 100644 --- a/cxl/json.h +++ b/cxl/json.h @@ -15,6 +15,11 @@ struct json_object *util_cxl_endpoint_to_json(struct cxl_endpoint *endpoint, unsigned long flags); struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder, unsigned long flags); +struct json_object *util_cxl_region_to_json(struct cxl_region *region, + unsigned long flags); +void util_cxl_mappings_append_json(struct json_object *jregion, + struct cxl_region *region, + unsigned long flags); void util_cxl_targets_append_json(struct json_object *jdecoder, struct cxl_decoder *decoder, const char *ident, const char *serial, diff --git a/cxl/filter.c b/cxl/filter.c index e5fab19..38ece55 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -585,6 +585,73 @@ util_cxl_memdev_filter_by_port(struct cxl_memdev *memdev, const char *bus_ident, return NULL; } +static struct cxl_region * +util_cxl_region_filter_by_bus(struct cxl_region *region, const char *__ident) +{ + struct cxl_decoder *decoder = cxl_region_get_decoder(region); + + if (!util_cxl_decoder_filter_by_bus(decoder, __ident)) + return NULL; + return region; +} + +static struct cxl_region * +util_cxl_region_filter_by_port(struct cxl_region *region, const char *__ident) +{ + struct cxl_decoder *decoder = cxl_region_get_decoder(region); + struct cxl_port *port = cxl_decoder_get_port(decoder); + + if (!util_cxl_port_filter(port, __ident ,CXL_PF_ANCESTRY)) + return NULL; + return region; +} + +static struct cxl_region * +util_cxl_region_filter_by_decoder(struct cxl_region *region, + const char *__ident) +{ + struct cxl_decoder *decoder = cxl_region_get_decoder(region); + + if (!util_cxl_decoder_filter(decoder, __ident)) + return NULL; + return region; +} + +struct cxl_region *util_cxl_region_filter(struct cxl_region *region, + const char *__ident) +{ + char *ident, *save; + const char *name; + int id; + + if (!__ident) + return region; + + ident = strdup(__ident); + if (!ident) + return NULL; + + for (name = strtok_r(ident, which_sep(__ident), &save); name; + name = strtok_r(NULL, which_sep(__ident), &save)) { + if (strcmp(name, "all") == 0) + break; + + if ((sscanf(name, "%d", &id) == 1 || + sscanf(name, "region%d", &id) == 1) && + cxl_region_get_id(region) == id) + break; + + if (strcmp(name, cxl_region_get_devname(region)) == 0) + break; + } + + free(ident); + if (name) + return region; + return NULL; + +} + static unsigned long params_to_flags(struct cxl_filter_params *param) { unsigned long flags = 0; @@ -672,26 +739,57 @@ static struct json_object *pick_array(struct json_object *child, return NULL; } +static void walk_regions(struct cxl_decoder *decoder, + struct json_object *jregions, + struct cxl_filter_params *p, + unsigned long flags) +{ + struct json_object *jregion; + struct cxl_region *region; + + cxl_region_foreach(decoder, region) { + if (!util_cxl_region_filter(region, p->region_filter)) + continue; + if (!util_cxl_region_filter_by_bus(region, p->bus_filter)) + continue; + if (!util_cxl_region_filter_by_port(region, p->port_filter)) + continue; + if (!util_cxl_region_filter_by_decoder(region, p->decoder_filter)) + continue; + if (!p->idle && !cxl_region_is_enabled(region)) + continue; + jregion = util_cxl_region_to_json(region, flags); + if (!jregion) + continue; + json_object_array_add(jregions, jregion); + } + + return; +} + static void walk_decoders(struct cxl_port *port, struct cxl_filter_params *p, - struct json_object *jdecoders, unsigned long flags) + struct json_object *jdecoders, + struct json_object *jregions, unsigned long flags) { struct cxl_decoder *decoder; cxl_decoder_foreach(port, decoder) { + const char *devname = cxl_decoder_get_devname(decoder); + struct json_object *jchildregions = NULL; struct json_object *jdecoder; if (!p->decoders) - continue; + goto walk_children; if (!util_cxl_decoder_filter(decoder, p->decoder_filter)) - continue; + goto walk_children; if (!util_cxl_decoder_filter_by_bus(decoder, p->bus_filter)) - continue; + goto walk_children; if (!util_cxl_decoder_filter_by_port(decoder, p->port_filter, pf_mode(p))) - continue; + goto walk_children; if (!util_cxl_decoder_filter_by_memdev( decoder, p->memdev_filter, p->serial_filter)) - continue; + goto walk_children; if (!p->idle && cxl_decoder_get_size(decoder) == 0) continue; jdecoder = util_cxl_decoder_to_json(decoder, flags); @@ -702,7 +800,27 @@ static void walk_decoders(struct cxl_port *port, struct cxl_filter_params *p, util_cxl_targets_append_json(jdecoder, decoder, p->memdev_filter, p->serial_filter, flags); + + if (p->regions) { + jchildregions = json_object_new_array(); + if (!jchildregions) { + err(p, "failed to allocate region object\n"); + return; + } + } + json_object_array_add(jdecoders, jdecoder); + +walk_children: + if (!p->regions) + continue; + if (!cxl_port_is_root(port)) + continue; + walk_regions(decoder, + pick_array(jchildregions, jregions), + p, flags); + cond_add_put_array_suffix(jdecoder, "regions", devname, + jchildregions); } } @@ -782,7 +900,7 @@ static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p, if (!p->decoders) continue; walk_decoders(cxl_endpoint_get_port(endpoint), p, - pick_array(jchilddecoders, jdecoders), flags); + pick_array(jchilddecoders, jdecoders), NULL, flags); cond_add_put_array_suffix(jendpoint, "decoders", devname, jchilddecoders); } @@ -869,7 +987,8 @@ walk_children: flags); walk_decoders(port, p, - pick_array(jchilddecoders, jportdecoders), flags); + pick_array(jchilddecoders, jportdecoders), NULL, + flags); walk_child_ports(port, p, pick_array(jchildports, jports), pick_array(jchilddecoders, jportdecoders), pick_array(jchildeps, jeps), @@ -894,6 +1013,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) struct json_object *jbusdecoders = NULL; struct json_object *jepdecoders = NULL; struct json_object *janondevs = NULL; + struct json_object *jregions = NULL; struct json_object *jeps = NULL; struct cxl_memdev *memdev; int top_level_objs = 0; @@ -936,6 +1056,10 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) if (!jepdecoders) goto err; + jregions = json_object_new_array(); + if (!jregions) + goto err; + dbg(p, "walk memdevs\n"); cxl_memdev_foreach(ctx, memdev) { struct json_object *janondev; @@ -964,6 +1088,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) struct json_object *jchildports = NULL; struct json_object *jchilddevs = NULL; struct json_object *jchildeps = NULL; + struct json_object *jchildregions = NULL; struct cxl_port *port = cxl_bus_get_port(bus); const char *devname = cxl_bus_get_devname(bus); @@ -1021,11 +1146,20 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) continue; } } + if (p->regions && !p->decoders) { + jchildregions = json_object_new_array(); + if (!jchildregions) { + err(p, + "%s: failed to enumerate child regions\n", + devname); + continue; + } + } } walk_children: dbg(p, "walk decoders\n"); walk_decoders(port, p, pick_array(jchilddecoders, jbusdecoders), - flags); + pick_array(jchildregions, jregions), flags); dbg(p, "walk ports\n"); walk_child_ports(port, p, pick_array(jchildports, jports), @@ -1038,6 +1172,8 @@ walk_children: jchildeps); cond_add_put_array_suffix(jbus, "decoders", devname, jchilddecoders); + cond_add_put_array_suffix(jbus, "regions", devname, + jchildregions); cond_add_put_array_suffix(jbus, "memdevs", devname, jchilddevs); } @@ -1057,6 +1193,8 @@ walk_children: top_level_objs++; if (json_object_array_length(jepdecoders)) top_level_objs++; + if (json_object_array_length(jregions)) + top_level_objs++; splice_array(p, janondevs, jplatform, "anon memdevs", top_level_objs > 1); splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1); @@ -1069,6 +1207,7 @@ walk_children: top_level_objs > 1); splice_array(p, jepdecoders, jplatform, "endpoint decoders", top_level_objs > 1); + splice_array(p, jregions, jplatform, "regions", top_level_objs > 1); util_display_json_array(stdout, jplatform, flags); @@ -1082,6 +1221,7 @@ err: json_object_put(jbusdecoders); json_object_put(jportdecoders); json_object_put(jepdecoders); + json_object_put(jregions); json_object_put(jplatform); return -ENOMEM; } diff --git a/cxl/json.c b/cxl/json.c index ae9c812..70cf286 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -524,6 +524,120 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder, return jdecoder; } +void util_cxl_mappings_append_json(struct json_object *jregion, + struct cxl_region *region, + unsigned long flags) +{ + struct json_object *jobj, *jmappings; + struct cxl_memdev_mapping *mapping; + unsigned int val, nr_mappings; + const char *devname; + + nr_mappings = cxl_region_get_interleave_ways(region); + if (!nr_mappings || (nr_mappings == UINT_MAX)) + return; + + if (!(flags & UTIL_JSON_TARGETS)) + return; + + jmappings = json_object_new_array(); + if (!jmappings) + return; + + cxl_mapping_foreach(region, mapping) { + struct json_object *jmapping; + struct cxl_decoder *decoder; + + jmapping = json_object_new_object(); + if (!jmapping) + continue; + + val = cxl_mapping_get_position(mapping); + if (val < UINT_MAX) { + jobj = json_object_new_int(val); + if (jobj) + json_object_object_add(jmapping, "position", + jobj); + } + + decoder = cxl_mapping_get_decoder(mapping); + if (!decoder) + continue; + + devname = cxl_decoder_get_devname(decoder); + jobj = json_object_new_string(devname); + if (jobj) + json_object_object_add(jmapping, "decoder", jobj); + + json_object_array_add(jmappings, jmapping); + } + + json_object_object_add(jregion, "mappings", jmappings); +} + +struct json_object *util_cxl_region_to_json(struct cxl_region *region, + unsigned long flags) +{ + const char *devname = cxl_region_get_devname(region); + struct json_object *jregion, *jobj; + u64 val; + + jregion = json_object_new_object(); + if (!jregion) + return NULL; + + jobj = json_object_new_string(devname); + if (jobj) + json_object_object_add(jregion, "region", jobj); + + val = cxl_region_get_resource(region); + if (val < ULLONG_MAX) { + jobj = util_json_object_hex(val, flags); + if (jobj) + json_object_object_add(jregion, "resource", jobj); + } + + val = cxl_region_get_size(region); + if (val < ULLONG_MAX) { + jobj = util_json_object_size(val, flags); + if (jobj) + json_object_object_add(jregion, "size", jobj); + } + + val = cxl_region_get_interleave_ways(region); + if (val < INT_MAX) { + jobj = json_object_new_int(val); + if (jobj) + json_object_object_add(jregion, + "interleave_ways", jobj); + } + + val = cxl_region_get_interleave_granularity(region); + if (val < INT_MAX) { + jobj = json_object_new_int(val); + if (jobj) + json_object_object_add(jregion, + "interleave_granularity", jobj); + } + + if (cxl_region_decode_is_committed(region)) + jobj = json_object_new_string("commit"); + else + jobj = json_object_new_string("reset"); + if (jobj) + json_object_object_add(jregion, "decode_state", jobj); + + if (!cxl_region_is_enabled(region)) { + jobj = json_object_new_string("disabled"); + if (jobj) + json_object_object_add(jregion, "state", jobj); + } + + util_cxl_mappings_append_json(jregion, region, flags); + + return jregion; +} + void util_cxl_targets_append_json(struct json_object *jdecoder, struct cxl_decoder *decoder, const char *ident, const char *serial, diff --git a/cxl/list.c b/cxl/list.c index 1b5f583..88ca9d9 100644 --- a/cxl/list.c +++ b/cxl/list.c @@ -41,7 +41,10 @@ static const struct option options[] = { OPT_BOOLEAN('D', "decoders", ¶m.decoders, "include CXL decoder info"), OPT_BOOLEAN('T', "targets", ¶m.targets, - "include CXL target data with decoders or ports"), + "include CXL target data with decoders, ports, or regions"), + OPT_STRING('r', "region", ¶m.region_filter, "region name", + "filter by CXL region name(s)"), + OPT_BOOLEAN('R', "regions", ¶m.regions, "include CXL regions"), OPT_BOOLEAN('i', "idle", ¶m.idle, "include disabled devices"), OPT_BOOLEAN('u', "human", ¶m.human, "use human friendly number formats"), @@ -58,7 +61,7 @@ static const struct option options[] = { static int num_list_flags(void) { return !!param.memdevs + !!param.buses + !!param.ports + - !!param.endpoints + !!param.decoders; + !!param.endpoints + !!param.decoders + !!param.regions; } int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) @@ -92,18 +95,14 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) param.endpoints = true; if (param.decoder_filter) param.decoders = true; - if (num_list_flags() == 0) { - /* - * TODO: We likely want to list regions by default if - * nothing was explicitly asked for. But until we have - * region support, print this error asking for devices - * explicitly. Once region support is added, this TODO - * can be removed. - */ - error("please specify entities to list, e.g. using -m/-M\n"); - usage_with_options(u, options); - } param.single = true; + if (param.region_filter) + param.regions = true; + } + + /* List regions by default */ + if (num_list_flags() == 0) { + param.regions = true; } log_init(¶m.ctx, "cxl list", "CXL_LIST_LOG"); From patchwork Mon Aug 15 19:22:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 12944083 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 913B0C25B0E for ; Mon, 15 Aug 2022 21:28:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345048AbiHOV2U (ORCPT ); Mon, 15 Aug 2022 17:28:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45096 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348110AbiHOV04 (ORCPT ); Mon, 15 Aug 2022 17:26:56 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1077FE97DD for ; Mon, 15 Aug 2022 12:22:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1660591374; x=1692127374; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=TvHwJQ4a87ZyGSVWuTfeOBASb+iEQnzjx00h/SftybQ=; b=M5iwUtDFsQfLy3WcPv/BV5S/TMU7ZOSESmOf7TW3mjtFhxkt0OI13t3y pUGdjebf3T8CTF2MYAwSOeMc6EuvJc6i06hZ5W2cFr6KC/AMLnv/GgCqW IbHaIOJskiqs/VyMYKCWNIcBF+y6PgSjSAc+QVqxIzqTPqq5N7KSV+m83 GCv9dGQLd3+ANzD1v+DnRebg5cVFmMZYDJCAH/rBWnx1c2xJY5MDYdSUW gcR3YuHGlO0lj9WvUImBkVg+wvA8vzJf3yc9RlUvhyP0mdr9WMWjoijw2 fdsnBJNYVjVolBNO07G+JqyQilx4Vcum6Bgv/NMXiLci9r3JY7oiFjmqi g==; X-IronPort-AV: E=McAfee;i="6400,9594,10440"; a="293313130" X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="293313130" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:20 -0700 X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="606758255" Received: from smadiset-mobl1.amr.corp.intel.com (HELO vverma7-desk1.intel.com) ([10.209.5.99]) by orsmga002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:20 -0700 From: Vishal Verma To: Cc: , Dan Williams , Alison Schofield , Ira Weiny , Dave Jiang , Vishal Verma Subject: [ndctl PATCH v3 06/11] libcxl: add low level APIs for region creation Date: Mon, 15 Aug 2022 13:22:09 -0600 Message-Id: <20220815192214.545800-7-vishal.l.verma@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220815192214.545800-1-vishal.l.verma@intel.com> References: <20220815192214.545800-1-vishal.l.verma@intel.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=21097; h=from:subject; bh=TvHwJQ4a87ZyGSVWuTfeOBASb+iEQnzjx00h/SftybQ=; b=owGbwMvMwCXGf25diOft7jLG02pJDEm/5jx9ZiuldvBduOzLe6Vq+3hkLWL7heaJL6q5/06iqmm9 i8L2jlIWBjEuBlkxRZa/ez4yHpPbns8TmOAIM4eVCWQIAxenAEzky3GGvxI9odLxkcsKTp5YlCWYkh i9p3gei/+vz61GLju0n+QVHmJkWLrR6sYNXq3KSXsE17/947OX44Fx0rHZh7Ku+pZ1tsS/ZAEA X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Add libcxl APIs to create a region under a given root decoder, and to set different attributes for the new region. These allow setting the size, interleave_ways, interleave_granularity, uuid, and the target devices for the newly minted cxl_region object. Cc: Dan Williams Reviewed-by: Dan Williams Signed-off-by: Vishal Verma --- Documentation/cxl/lib/libcxl.txt | 69 ++++++ cxl/lib/private.h | 2 + cxl/lib/libcxl.c | 381 ++++++++++++++++++++++++++++++- cxl/libcxl.h | 23 +- cxl/lib/libcxl.sym | 16 ++ 5 files changed, 488 insertions(+), 3 deletions(-) diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index 7a38ce4..50b0c9c 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -508,6 +508,75 @@ device to represent the root of a PCI device hierarchy. The cxl_target_get_physical_node() helper returns the device name of that companion object in the PCI hierarchy. +==== REGIONS +A CXL region is composed of one or more slices of CXL memdevs, with configurable +interleave settings - both the number of interleave ways, and the interleave +granularity. In terms of hierarchy, it is the child of a CXL root decoder. A root +decoder (recall that this corresponds to an ACPI CEDT.CFMWS 'window'), may have +multiple child regions, but a region is strictly tied to one root decoder. + +The slices that compose a region are called mappings. A mapping is a +tuple of 'memdev', 'endpoint decoder', and the 'position'. + +===== REGION: Enumeration +---- +struct cxl_region *cxl_region_get_first(struct cxl_decoder *decoder); +struct cxl_region *cxl_region_get_next(struct cxl_region *region); + +#define cxl_region_foreach(decoder, region) \ + for (region = cxl_region_get_first(decoder); region != NULL; \ + region = cxl_region_get_next(region)) + +#define cxl_region_foreach_safe(decoder, region, _region) \ + for (region = cxl_region_get_first(decoder), \ + _region = region ? cxl_region_get_next(region) : NULL; \ + region != NULL; \ + region = _region, \ + _region = _region ? cxl_region_get_next(_region) : NULL) +---- + +===== REGION: Attributes +---- +int cxl_region_get_id(struct cxl_region *region); +const char *cxl_region_get_devname(struct cxl_region *region); +void cxl_region_get_uuid(struct cxl_region *region, uuid_t uu); +unsigned long long cxl_region_get_size(struct cxl_region *region); +unsigned long long cxl_region_get_resource(struct cxl_region *region); +unsigned int cxl_region_get_interleave_ways(struct cxl_region *region); +unsigned int cxl_region_get_interleave_granularity(struct cxl_region *region); +struct cxl_decoder *cxl_region_get_target_decoder(struct cxl_region *region, + int position); +int cxl_region_set_size(struct cxl_region *region, unsigned long long size); +int cxl_region_set_uuid(struct cxl_region *region, uuid_t uu); +int cxl_region_set_interleave_ways(struct cxl_region *region, + unsigned int ways); +int cxl_region_set_interleave_granularity(struct cxl_region *region, + unsigned int granularity); +int cxl_region_set_target(struct cxl_region *region, int position, + struct cxl_decoder *decoder); +int cxl_region_clear_target(struct cxl_region *region, int position); +int cxl_region_clear_all_targets(struct cxl_region *region); +int cxl_region_decode_commit(struct cxl_region *region); +int cxl_region_decode_reset(struct cxl_region *region); +---- + +A region's resource attribute is the Host Physical Address at which the region's +address space starts. The region's address space is a subset of the parent root +decoder's address space. + +The interleave ways is the number of component memdevs participating in the +region. + +The interleave granularity depends on the root decoder's granularity, and must +follow the interleave math rules defined in the CXL spec. + +Regions have a list of targets 0..N, which are programmed with the name of an +endpoint decoder under each participating memdev. + +The 'decode_commit' and 'decode_reset' attributes reserve and free DPA space +on a given memdev by allocating an endpoint decoder, and programming it based +on the region's interleave geometry. + include::../../copyright.txt[] SEE ALSO diff --git a/cxl/lib/private.h b/cxl/lib/private.h index 5e2fdd5..8bc9620 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -110,6 +110,8 @@ struct cxl_decoder { int nr_targets; int id; enum cxl_decoder_mode mode; + unsigned int interleave_ways; + unsigned int interleave_granularity; bool pmem_capable; bool volatile_capable; bool mem_capable; diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 1879c15..2b1cf7e 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -420,6 +421,40 @@ CXL_EXPORT int cxl_region_enable(struct cxl_region *region) return 0; } +static int cxl_region_delete_name(struct cxl_decoder *decoder, + const char *devname) +{ + struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder); + char *path = decoder->dev_buf; + int rc; + + sprintf(path, "%s/delete_region", decoder->dev_path); + rc = sysfs_write_attr(ctx, path, devname); + if (rc != 0) { + err(ctx, "error deleting region: %s\n", strerror(-rc)); + return rc; + } + return 0; +} + +CXL_EXPORT int cxl_region_delete(struct cxl_region *region) +{ + struct cxl_decoder *decoder = cxl_region_get_decoder(region); + const char *devname = cxl_region_get_devname(region); + int rc; + + if (cxl_region_is_enabled(region)) + return -EBUSY; + + rc = cxl_region_delete_name(decoder, devname); + if (rc != 0) + return rc; + + decoder->regions_init = 0; + free_region(region, &decoder->regions); + return 0; +} + static void *add_cxl_region(void *parent, int id, const char *cxlregion_base) { const char *devname = devpath_to_devname(cxlregion_base); @@ -599,6 +634,258 @@ cxl_region_get_interleave_granularity(struct cxl_region *region) return region->interleave_granularity; } +CXL_EXPORT struct cxl_decoder * +cxl_region_get_target_decoder(struct cxl_region *region, int position) +{ + const char *devname = cxl_region_get_devname(region); + struct cxl_ctx *ctx = cxl_region_get_ctx(region); + int len = region->buf_len, rc; + char *path = region->dev_buf; + struct cxl_decoder *decoder; + char buf[SYSFS_ATTR_SIZE]; + + if (snprintf(path, len, "%s/target%d", region->dev_path, position) >= + len) { + err(ctx, "%s: buffer too small!\n", devname); + return NULL; + } + + rc = sysfs_read_attr(ctx, path, buf); + if (rc < 0) { + err(ctx, "%s: error reading target%d: %s\n", devname, + position, strerror(-rc)); + return NULL; + } + + decoder = cxl_decoder_get_by_name(ctx, buf); + if (!decoder) { + err(ctx, "%s: error locating decoder for target%d\n", devname, + position); + return NULL; + } + return decoder; +} + +CXL_EXPORT int cxl_region_set_size(struct cxl_region *region, + unsigned long long size) +{ + const char *devname = cxl_region_get_devname(region); + struct cxl_ctx *ctx = cxl_region_get_ctx(region); + int len = region->buf_len, rc; + char *path = region->dev_buf; + char buf[SYSFS_ATTR_SIZE]; + + if (size == 0) { + dbg(ctx, "%s: cannot use %s to delete a region\n", __func__, + devname); + return -EINVAL; + } + + if (snprintf(path, len, "%s/size", region->dev_path) >= len) { + err(ctx, "%s: buffer too small!\n", devname); + return -ENXIO; + } + + sprintf(buf, "%#llx\n", size); + rc = sysfs_write_attr(ctx, path, buf); + if (rc < 0) + return rc; + + region->size = size; + + return 0; +} + +CXL_EXPORT int cxl_region_set_uuid(struct cxl_region *region, uuid_t uu) +{ + const char *devname = cxl_region_get_devname(region); + struct cxl_ctx *ctx = cxl_region_get_ctx(region); + int len = region->buf_len, rc; + char *path = region->dev_buf; + char uuid[SYSFS_ATTR_SIZE]; + + if (snprintf(path, len, "%s/uuid", region->dev_path) >= len) { + err(ctx, "%s: buffer too small!\n", devname); + return -ENXIO; + } + + uuid_unparse(uu, uuid); + rc = sysfs_write_attr(ctx, path, uuid); + if (rc != 0) + return rc; + memcpy(region->uuid, uu, sizeof(uuid_t)); + return 0; +} + +CXL_EXPORT int cxl_region_set_interleave_ways(struct cxl_region *region, + unsigned int ways) +{ + const char *devname = cxl_region_get_devname(region); + struct cxl_ctx *ctx = cxl_region_get_ctx(region); + int len = region->buf_len, rc; + char *path = region->dev_buf; + char buf[SYSFS_ATTR_SIZE]; + + if (snprintf(path, len, "%s/interleave_ways", + region->dev_path) >= len) { + err(ctx, "%s: buffer too small!\n", devname); + return -ENXIO; + } + + sprintf(buf, "%u\n", ways); + rc = sysfs_write_attr(ctx, path, buf); + if (rc < 0) + return rc; + + region->interleave_ways = ways; + + return 0; +} + +CXL_EXPORT int cxl_region_set_interleave_granularity(struct cxl_region *region, + unsigned int granularity) +{ + const char *devname = cxl_region_get_devname(region); + struct cxl_ctx *ctx = cxl_region_get_ctx(region); + int len = region->buf_len, rc; + char *path = region->dev_buf; + char buf[SYSFS_ATTR_SIZE]; + + if (snprintf(path, len, "%s/interleave_granularity", + region->dev_path) >= len) { + err(ctx, "%s: buffer too small!\n", devname); + return -ENXIO; + } + + sprintf(buf, "%u\n", granularity); + rc = sysfs_write_attr(ctx, path, buf); + if (rc < 0) + return rc; + + region->interleave_granularity = granularity; + + return 0; +} + +static int region_write_target(struct cxl_region *region, int position, + struct cxl_decoder *decoder) +{ + const char *devname = cxl_region_get_devname(region); + struct cxl_ctx *ctx = cxl_region_get_ctx(region); + int len = region->buf_len, rc; + char *path = region->dev_buf; + const char *dec_name = ""; + + if (decoder) + dec_name = cxl_decoder_get_devname(decoder); + + if (snprintf(path, len, "%s/target%d", region->dev_path, position) >= + len) { + err(ctx, "%s: buffer too small!\n", devname); + return -ENXIO; + } + + rc = sysfs_write_attr(ctx, path, dec_name); + if (rc < 0) + return rc; + + return 0; +} + +CXL_EXPORT int cxl_region_set_target(struct cxl_region *region, int position, + struct cxl_decoder *decoder) +{ + if (!decoder) + return -ENXIO; + + return region_write_target(region, position, decoder); +} + +CXL_EXPORT int cxl_region_clear_target(struct cxl_region *region, int position) +{ + const char *devname = cxl_region_get_devname(region); + struct cxl_ctx *ctx = cxl_region_get_ctx(region); + int rc; + + if (cxl_region_is_enabled(region)) { + err(ctx, "%s: can't clear targets on an active region\n", + devname); + return -EBUSY; + } + + rc = region_write_target(region, position, NULL); + if (rc) { + err(ctx, "%s: error clearing target%d: %s\n", + devname, position, strerror(-rc)); + return rc; + } + + return 0; +} + +CXL_EXPORT int cxl_region_clear_all_targets(struct cxl_region *region) +{ + const char *devname = cxl_region_get_devname(region); + struct cxl_ctx *ctx = cxl_region_get_ctx(region); + unsigned int ways, i; + int rc; + + if (cxl_region_is_enabled(region)) { + err(ctx, "%s: can't clear targets on an active region\n", + devname); + return -EBUSY; + } + + ways = cxl_region_get_interleave_ways(region); + if (ways == 0 || ways == UINT_MAX) + return -ENXIO; + + for (i = 0; i < ways; i++) { + rc = region_write_target(region, i, NULL); + if (rc) { + err(ctx, "%s: error clearing target%d: %s\n", + devname, i, strerror(-rc)); + return rc; + } + } + + return 0; +} + +static int set_region_decode(struct cxl_region *region, + enum cxl_decode_state decode_state) +{ + const char *devname = cxl_region_get_devname(region); + struct cxl_ctx *ctx = cxl_region_get_ctx(region); + int len = region->buf_len, rc; + char *path = region->dev_buf; + char buf[SYSFS_ATTR_SIZE]; + + if (snprintf(path, len, "%s/commit", region->dev_path) >= len) { + err(ctx, "%s: buffer too small!\n", devname); + return -ENXIO; + } + + sprintf(buf, "%d\n", decode_state); + rc = sysfs_write_attr(ctx, path, buf); + if (rc < 0) + return rc; + + region->decode_state = decode_state; + + return 0; +} + +CXL_EXPORT int cxl_region_decode_commit(struct cxl_region *region) +{ + return set_region_decode(region, CXL_DECODE_COMMIT); +} + +CXL_EXPORT int cxl_region_decode_reset(struct cxl_region *region) +{ + return set_region_decode(region, CXL_DECODE_RESET); +} + static struct cxl_decoder *__cxl_port_match_decoder(struct cxl_port *port, const char *ident) { @@ -633,8 +920,8 @@ static struct cxl_decoder *cxl_port_find_decoder(struct cxl_port *port, return NULL; } -static struct cxl_decoder *cxl_decoder_get_by_name(struct cxl_ctx *ctx, - const char *ident) +CXL_EXPORT struct cxl_decoder *cxl_decoder_get_by_name(struct cxl_ctx *ctx, + const char *ident) { struct cxl_bus *bus; @@ -1398,6 +1685,18 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base) } else decoder->mode = CXL_DECODER_MODE_NONE; + sprintf(path, "%s/interleave_granularity", cxldecoder_base); + if (sysfs_read_attr(ctx, path, buf) < 0) + decoder->interleave_granularity = UINT_MAX; + else + decoder->interleave_granularity = strtoul(buf, NULL, 0); + + sprintf(path, "%s/interleave_ways", cxldecoder_base); + if (sysfs_read_attr(ctx, path, buf) < 0) + decoder->interleave_ways = UINT_MAX; + else + decoder->interleave_ways = strtoul(buf, NULL, 0); + switch (port->type) { case CXL_PORT_ENDPOINT: sprintf(path, "%s/dpa_resource", cxldecoder_base); @@ -1730,6 +2029,66 @@ CXL_EXPORT bool cxl_decoder_is_locked(struct cxl_decoder *decoder) return decoder->locked; } +CXL_EXPORT unsigned int +cxl_decoder_get_interleave_granularity(struct cxl_decoder *decoder) +{ + return decoder->interleave_granularity; +} + +CXL_EXPORT unsigned int +cxl_decoder_get_interleave_ways(struct cxl_decoder *decoder) +{ + return decoder->interleave_ways; +} + +CXL_EXPORT struct cxl_region * +cxl_decoder_create_pmem_region(struct cxl_decoder *decoder) +{ + struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder); + char *path = decoder->dev_buf; + char buf[SYSFS_ATTR_SIZE]; + struct cxl_region *region; + int rc; + + sprintf(path, "%s/create_pmem_region", decoder->dev_path); + rc = sysfs_read_attr(ctx, path, buf); + if (rc < 0) { + err(ctx, "failed to read new region name: %s\n", + strerror(-rc)); + return NULL; + } + + rc = sysfs_write_attr(ctx, path, buf); + if (rc < 0) { + err(ctx, "failed to write new region name: %s\n", + strerror(-rc)); + return NULL; + } + + /* Force a re-init of regions so that the new one can be discovered */ + decoder->regions_init = 0; + + /* create_region was successful, walk to the new region */ + cxl_region_foreach(decoder, region) { + const char *devname = cxl_region_get_devname(region); + + if (strcmp(devname, buf) == 0) + goto found; + } + + /* + * If walking to the region we just created failed, something has gone + * very wrong. Attempt to delete it to avoid leaving a dangling region + * id behind. + */ + err(ctx, "failed to add new region to libcxl\n"); + cxl_region_delete_name(decoder, buf); + return NULL; + + found: + return region; +} + CXL_EXPORT int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder) { return decoder->nr_targets; @@ -1740,6 +2099,24 @@ CXL_EXPORT const char *cxl_decoder_get_devname(struct cxl_decoder *decoder) return devpath_to_devname(decoder->dev_path); } +CXL_EXPORT struct cxl_memdev * +cxl_decoder_get_memdev(struct cxl_decoder *decoder) +{ + struct cxl_port *port = cxl_decoder_get_port(decoder); + struct cxl_endpoint *ep; + + if (!port) + return NULL; + if (!cxl_port_is_endpoint(port)) + return NULL; + + ep = container_of(port, struct cxl_endpoint, port); + if (!ep) + return NULL; + + return cxl_endpoint_get_memdev(ep); +} + CXL_EXPORT struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder) { return list_top(&decoder->targets, struct cxl_target, list); diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 19d94e4..69d9c09 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -195,7 +195,13 @@ bool cxl_decoder_is_volatile_capable(struct cxl_decoder *decoder); bool cxl_decoder_is_mem_capable(struct cxl_decoder *decoder); bool cxl_decoder_is_accelmem_capable(struct cxl_decoder *decoder); bool cxl_decoder_is_locked(struct cxl_decoder *decoder); - +unsigned int +cxl_decoder_get_interleave_granularity(struct cxl_decoder *decoder); +unsigned int cxl_decoder_get_interleave_ways(struct cxl_decoder *decoder); +struct cxl_region *cxl_decoder_create_pmem_region(struct cxl_decoder *decoder); +struct cxl_decoder *cxl_decoder_get_by_name(struct cxl_ctx *ctx, + const char *ident); +struct cxl_memdev *cxl_decoder_get_memdev(struct cxl_decoder *decoder); #define cxl_decoder_foreach(port, decoder) \ for (decoder = cxl_decoder_get_first(port); decoder != NULL; \ decoder = cxl_decoder_get_next(decoder)) @@ -244,6 +250,7 @@ int cxl_region_decode_is_committed(struct cxl_region *region); int cxl_region_is_enabled(struct cxl_region *region); int cxl_region_disable(struct cxl_region *region); int cxl_region_enable(struct cxl_region *region); +int cxl_region_delete(struct cxl_region *region); struct cxl_ctx *cxl_region_get_ctx(struct cxl_region *region); struct cxl_decoder *cxl_region_get_decoder(struct cxl_region *region); int cxl_region_get_id(struct cxl_region *region); @@ -253,6 +260,20 @@ unsigned long long cxl_region_get_size(struct cxl_region *region); unsigned long long cxl_region_get_resource(struct cxl_region *region); unsigned int cxl_region_get_interleave_ways(struct cxl_region *region); unsigned int cxl_region_get_interleave_granularity(struct cxl_region *region); +struct cxl_decoder *cxl_region_get_target_decoder(struct cxl_region *region, + int position); +int cxl_region_set_size(struct cxl_region *region, unsigned long long size); +int cxl_region_set_uuid(struct cxl_region *region, uuid_t uu); +int cxl_region_set_interleave_ways(struct cxl_region *region, + unsigned int ways); +int cxl_region_set_interleave_granularity(struct cxl_region *region, + unsigned int granularity); +int cxl_region_set_target(struct cxl_region *region, int position, + struct cxl_decoder *decoder); +int cxl_region_clear_target(struct cxl_region *region, int position); +int cxl_region_clear_all_targets(struct cxl_region *region); +int cxl_region_decode_commit(struct cxl_region *region); +int cxl_region_decode_reset(struct cxl_region *region); #define cxl_region_foreach(decoder, region) \ for (region = cxl_region_get_first(decoder); region != NULL; \ diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index e410298..cb23a0b 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -140,6 +140,7 @@ global: cxl_decoder_is_mem_capable; cxl_decoder_is_accelmem_capable; cxl_decoder_is_locked; + cxl_decoder_create_pmem_region; cxl_target_get_first; cxl_target_get_next; cxl_target_get_decoder; @@ -183,6 +184,7 @@ global: cxl_region_is_enabled; cxl_region_disable; cxl_region_enable; + cxl_region_delete; cxl_region_get_ctx; cxl_region_get_decoder; cxl_region_get_id; @@ -192,9 +194,23 @@ global: cxl_region_get_resource; cxl_region_get_interleave_ways; cxl_region_get_interleave_granularity; + cxl_region_get_target_decoder; + cxl_region_set_size; + cxl_region_set_uuid; + cxl_region_set_interleave_ways; + cxl_region_set_interleave_granularity; + cxl_region_set_target; + cxl_region_clear_target; + cxl_region_clear_all_targets; + cxl_region_decode_commit; + cxl_region_decode_reset; cxl_mapping_get_first; cxl_mapping_get_next; cxl_mapping_get_decoder; cxl_mapping_get_region; cxl_mapping_get_position; + cxl_decoder_get_by_name; + cxl_decoder_get_memdev; + cxl_decoder_get_interleave_granularity; + cxl_decoder_get_interleave_ways; } LIBCXL_2; From patchwork Mon Aug 15 19:22:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 12944082 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4F8D7C25B08 for ; Mon, 15 Aug 2022 21:28:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344874AbiHOV2T (ORCPT ); Mon, 15 Aug 2022 17:28:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53758 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348127AbiHOV05 (ORCPT ); Mon, 15 Aug 2022 17:26:57 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 539B7E97E1 for ; Mon, 15 Aug 2022 12:22:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1660591374; x=1692127374; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=QCN9NP5pTAHuTKN2JVgW3vlfKGrx2QsnmrCfpoAXji8=; b=Nro1O4KgqMhix4HtfdoqSUB1MrjiWnf0LWhISa78zVcxC9sVXYgkWweo 323UCnQoS4sjLkUdrPFLjf0NTyhPDDgzKIqsdVglmQZuo06PYyZ7YQU1M jFm9gTMY6HFBsSOB6JfQzJg+UhrH1y1R8tb0UKoulB4rCgnuRVPci/4rM lUHfCFbMa28ymoy5b5g1/CuYPwEtITPtcArAAsC4LhvpUi5DRP9FIxHIM KfCLMNTOK3NjTHSbcIRt/JblNL62Mt7Aq06tBtZtklJEqyVNkBF/6HDId MZkrLOzCaGVvVtP4rV/tJbE3g/YU1y68bcXZelpR6a2DCe+UviJqju+YW Q==; X-IronPort-AV: E=McAfee;i="6400,9594,10440"; a="293313133" X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="293313133" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:20 -0700 X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="606758258" Received: from smadiset-mobl1.amr.corp.intel.com (HELO vverma7-desk1.intel.com) ([10.209.5.99]) by orsmga002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:20 -0700 From: Vishal Verma To: Cc: , Dan Williams , Alison Schofield , Ira Weiny , Dave Jiang , Vishal Verma Subject: [ndctl PATCH v3 07/11] cxl: add a 'create-region' command Date: Mon, 15 Aug 2022 13:22:10 -0600 Message-Id: <20220815192214.545800-8-vishal.l.verma@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220815192214.545800-1-vishal.l.verma@intel.com> References: <20220815192214.545800-1-vishal.l.verma@intel.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=23444; h=from:subject; bh=QCN9NP5pTAHuTKN2JVgW3vlfKGrx2QsnmrCfpoAXji8=; b=owGbwMvMwCXGf25diOft7jLG02pJDEm/5jzdaTjR1KP7gfWKg4JLt4a/NmFR2uqyUybCyVGbK/X0 +nS/jlIWBjEuBlkxRZa/ez4yHpPbns8TmOAIM4eVCWQIAxenAEzkaz8jQ0dI/Vth82s3J9fO7DuZsy joyaZF2gc5Xk3OmZ/LquRcYMnwT1tsl9Fh5+VnZlu76cvcKntetWebRpv27BWuD/c8etn9kBcA X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Add a 'create-region' command to cxl-cli that walks the platform's CXL hierarchy to find an appropriate root decoder based on any options provided, and uses libcxl APIs to create a 'region' that is comprehended by libnvdimm and ndctl. Cc: Dan Williams Reviewed-by: Dan Williams Signed-off-by: Vishal Verma --- Documentation/cxl/bus-option.txt | 5 + Documentation/cxl/cxl-create-region.txt | 112 +++++ Documentation/cxl/region-description.txt | 7 + cxl/builtin.h | 1 + cxl/filter.h | 4 +- cxl/cxl.c | 1 + cxl/json.c | 9 + cxl/region.c | 550 +++++++++++++++++++++++ Documentation/cxl/meson.build | 2 + cxl/meson.build | 1 + 10 files changed, 691 insertions(+), 1 deletion(-) create mode 100644 Documentation/cxl/bus-option.txt create mode 100644 Documentation/cxl/cxl-create-region.txt create mode 100644 Documentation/cxl/region-description.txt create mode 100644 cxl/region.c diff --git a/Documentation/cxl/bus-option.txt b/Documentation/cxl/bus-option.txt new file mode 100644 index 0000000..02e2f08 --- /dev/null +++ b/Documentation/cxl/bus-option.txt @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0 + +-b:: +--bus=:: + Restrict the operation to the specified bus. diff --git a/Documentation/cxl/cxl-create-region.txt b/Documentation/cxl/cxl-create-region.txt new file mode 100644 index 0000000..6b740d5 --- /dev/null +++ b/Documentation/cxl/cxl-create-region.txt @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0 + +cxl-create-region(1) +==================== + +NAME +---- +cxl-create-region - Assemble a CXL region by setting up attributes of its +constituent CXL memdevs. + +SYNOPSIS +-------- +[verse] +'cxl create-region []' + +include::region-description.txt[] + +For create-region, a size can optionally be specified, but if not, the maximum +possible size for each memdev will be used up to the available decode capacity +in the system for the given memory type. For persistent regions a UUID can +optionally be specified, but if not, one will be generated. + +If the region-creation operation is successful, a region object will be +emitted on stdout in JSON format (see examples). If the specified arguments +cannot be satisfied with a legal configuration, then an appropriate error will +be emitted on stderr. + +EXAMPLE +------- +---- +#cxl create - region - m - d decoder0 .1 - w 2 - g 1024 mem0 mem1 +{ + "region":"region0", + "resource":"0xc90000000", + "size":"512.00 MiB (536.87 MB)", + "interleave_ways":2, + "interleave_granularity":1024, + "mappings":[ + { + "position":1, + "decoder":"decoder4.0" + }, + { + "position":0, + "decoder":"decoder3.0" + } + ] +} +created 1 region +---- + +OPTIONS +------- +:: +The CXL targets that should be used to form the region. The number of +'target' arguments must match the '--ways' option (if provided). The +targets are memdev names such as 'mem0', 'mem1' etc. + +include::bus-option.txt[] + +-m:: +--memdevs:: + Indicate that the non-option arguments for 'target(s)' refer to memdev + names. Currently this is the only option supported, and must be + specified. + +-s:: +--size=:: + Specify the total size for the new region. This is optional, and by + default, the maximum possible size will be used. The maximum possible + size is gated by both the contiguous free HPA space remaining in the + root decoder, and the available DPA space in the component memdevs. + +-t:: +--type=:: + Specify the region type - 'pmem' or 'ram'. Defaults to 'pmem'. + +-U:: +--uuid=:: + Specify a UUID for the new region. This shouldn't usually need to be + specified, as one will be generated by default. + +-w:: +--ways=:: + The number of interleave ways for the new region's interleave. This + should be equal to the number of memdevs specified in --memdevs, if + --memdevs is being supplied. If --ways is not specified, it will be + determined based on the number of memdev targets provided. + +-g:: +--granularity=:: + The interleave granularity for the new region. Must match the selected + root decoder's (if provided) granularity. If the root decoder is + interleaved across more than one host-bridge then this value must match + that granularity. Otherwise, for non-interleaved decode windows, any + granularity can be specified as long as all devices support that setting. + +-d:: +--decoder=:: + The root decoder that the region should be created under. If not + supplied, the first cross-host bridge (if available), decoder that + supports the largest interleave will be chosen. + +include::human-option.txt[] + +include::debug-option.txt[] + +include::../copyright.txt[] + +SEE ALSO +-------- +linkcxl:cxl-list[1], diff --git a/Documentation/cxl/region-description.txt b/Documentation/cxl/region-description.txt new file mode 100644 index 0000000..d7e3077 --- /dev/null +++ b/Documentation/cxl/region-description.txt @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 + +DESCRIPTION +----------- +A CXL region is composed of one or more slices of CXL memdevs, with configurable +interleave settings - both the number of interleave ways, and the interleave +granularity. diff --git a/cxl/builtin.h b/cxl/builtin.h index 9e6fc62..843bada 100644 --- a/cxl/builtin.h +++ b/cxl/builtin.h @@ -18,4 +18,5 @@ int cmd_disable_port(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_set_partition(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_disable_bus(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_create_region(int argc, const char **argv, struct cxl_ctx *ctx); #endif /* _CXL_BUILTIN_H_ */ diff --git a/cxl/filter.h b/cxl/filter.h index 609433c..d22d8b1 100644 --- a/cxl/filter.h +++ b/cxl/filter.h @@ -35,8 +35,10 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port, const char *ident, const char *serial); -struct cxl_region *util_cxl_region_filter(struct cxl_region *region, +struct cxl_decoder *util_cxl_decoder_filter(struct cxl_decoder *decoder, const char *__ident); +struct cxl_region *util_cxl_region_filter(struct cxl_region *region, + const char *__ident); enum cxl_port_filter_mode { CXL_PF_SINGLE, diff --git a/cxl/cxl.c b/cxl/cxl.c index ef4cda9..f0afcfe 100644 --- a/cxl/cxl.c +++ b/cxl/cxl.c @@ -72,6 +72,7 @@ static struct cmd_struct commands[] = { { "enable-port", .c_fn = cmd_enable_port }, { "set-partition", .c_fn = cmd_set_partition }, { "disable-bus", .c_fn = cmd_disable_bus }, + { "create-region", .c_fn = cmd_create_region }, }; int main(int argc, const char **argv) diff --git a/cxl/json.c b/cxl/json.c index 70cf286..9dc99df 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -547,6 +547,7 @@ void util_cxl_mappings_append_json(struct json_object *jregion, cxl_mapping_foreach(region, mapping) { struct json_object *jmapping; struct cxl_decoder *decoder; + struct cxl_memdev *memdev; jmapping = json_object_new_object(); if (!jmapping) @@ -564,6 +565,14 @@ void util_cxl_mappings_append_json(struct json_object *jregion, if (!decoder) continue; + memdev = cxl_decoder_get_memdev(decoder); + if (memdev) { + devname = cxl_memdev_get_devname(memdev); + jobj = json_object_new_string(devname); + if (jobj) + json_object_object_add(jmapping, "memdev", jobj); + } + devname = cxl_decoder_get_devname(decoder); jobj = json_object_new_string(devname); if (jobj) diff --git a/cxl/region.c b/cxl/region.c new file mode 100644 index 0000000..2791ac9 --- /dev/null +++ b/cxl/region.c @@ -0,0 +1,550 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2020-2022 Intel Corporation. All rights reserved. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "filter.h" +#include "json.h" + +static struct region_params { + const char *bus; + const char *size; + const char *ways; + const char *granularity; + const char *type; + const char *root_decoder; + const char *region; + bool memdevs; + bool force; + bool human; + bool debug; +} param; + +struct parsed_params { + u64 size; + u64 ep_min_size; + unsigned int ways; + unsigned int granularity; + const char **targets; + int num_targets; + struct cxl_decoder *root_decoder; + enum cxl_decoder_mode mode; +}; + +enum region_actions { + ACTION_CREATE, +}; + +static struct log_ctx rl; + +#define BASE_OPTIONS() \ +OPT_STRING('b', "bus", ¶m.bus, "bus name", \ + "Limit operation to the specified bus"), \ +OPT_STRING('d', "decoder", ¶m.root_decoder, "root decoder name", \ + "Limit to / use the specified root decoder"), \ +OPT_BOOLEAN(0, "debug", ¶m.debug, "turn on debug") + +#define CREATE_OPTIONS() \ +OPT_STRING('s', "size", ¶m.size, \ + "size in bytes or with a K/M/G etc. suffix", \ + "total size desired for the resulting region."), \ +OPT_STRING('w', "ways", ¶m.ways, \ + "number of interleave ways", \ + "number of memdevs participating in the regions interleave set"), \ +OPT_STRING('g', "granularity", \ + ¶m.granularity, "interleave granularity", \ + "granularity of the interleave set"), \ +OPT_STRING('t', "type", ¶m.type, \ + "region type", "region type - 'pmem' or 'ram'"), \ +OPT_BOOLEAN('m', "memdevs", ¶m.memdevs, \ + "non-option arguments are memdevs"), \ +OPT_BOOLEAN('u', "human", ¶m.human, "use human friendly number formats") + +static const struct option create_options[] = { + BASE_OPTIONS(), + CREATE_OPTIONS(), + OPT_END(), +}; + + + +static int parse_create_options(int argc, const char **argv, + struct parsed_params *p) +{ + int i; + + if (!param.root_decoder) { + log_err(&rl, "no root decoder specified\n"); + return -EINVAL; + } + + if (param.type) { + p->mode = cxl_decoder_mode_from_ident(param.type); + if (p->mode == CXL_DECODER_MODE_NONE) { + log_err(&rl, "unsupported type: %s\n", param.type); + return -EINVAL; + } + } else { + p->mode = CXL_DECODER_MODE_PMEM; + } + + if (param.size) { + p->size = parse_size64(param.size); + if (p->size == ULLONG_MAX) { + log_err(&rl, "Invalid size: %s\n", param.size); + return -EINVAL; + } + } + + if (param.ways) { + unsigned long ways = strtoul(param.ways, NULL, 0); + + if (ways == ULONG_MAX || (int)ways <= 0) { + log_err(&rl, "Invalid interleave ways: %s\n", + param.ways); + return -EINVAL; + } + p->ways = ways; + } else if (argc) { + p->ways = argc; + } else { + log_err(&rl, + "couldn't determine interleave ways from options or arguments\n"); + return -EINVAL; + } + + if (param.granularity) { + unsigned long granularity = strtoul(param.granularity, NULL, 0); + + if (granularity == ULONG_MAX || (int)granularity <= 0) { + log_err(&rl, "Invalid interleave granularity: %s\n", + param.granularity); + return -EINVAL; + } + p->granularity = granularity; + } + + + if (argc > (int)p->ways) { + for (i = p->ways; i < argc; i++) + log_err(&rl, "extra argument: %s\n", p->targets[i]); + return -EINVAL; + } + + if (argc < (int)p->ways) { + log_err(&rl, + "too few target arguments (%d) for interleave ways (%u)\n", + argc, p->ways); + return -EINVAL; + } + + if (p->size && p->ways) { + if (p->size % p->ways) { + log_err(&rl, + "size (%lu) is not an integral multiple of interleave-ways (%u)\n", + p->size, p->ways); + return -EINVAL; + } + } + + /* + * For all practical purposes, -m is the default target type, but + * hold off on actively making that decision until a second target + * option is available. + */ + if (!param.memdevs) { + log_err(&rl, + "must specify option for target object types (-m)\n"); + return -EINVAL; + } + + return 0; +} + +static int parse_region_options(int argc, const char **argv, + struct cxl_ctx *ctx, enum region_actions action, + const struct option *options, + struct parsed_params *p, const char *usage) +{ + const char * const u[] = { + usage, + NULL + }; + + argc = parse_options(argc, argv, options, u, 0); + p->targets = argv; + p->num_targets = argc; + + if (param.debug) { + cxl_set_log_priority(ctx, LOG_DEBUG); + rl.log_priority = LOG_DEBUG; + } else + rl.log_priority = LOG_INFO; + + switch(action) { + case ACTION_CREATE: + return parse_create_options(argc, argv, p); + default: + return 0; + } +} + +/** + * validate_memdev() - match memdev with the target provided, + * and determine its size contribution + * @memdev: cxl_memdev being tested for a match against the named target + * @target: target memdev + * @p: params structure + * + * This is called for each memdev in the system, and only returns 'true' if + * the memdev name matches the target argument being tested. Additionally, + * it sets an ep_min_size attribute that always contains the size of the + * smallest target in the provided list. This is used during the automatic + * size determination later, to ensure that all targets contribute equally + * to the region in case of unevenly sized memdevs. + */ +static bool validate_memdev(struct cxl_memdev *memdev, const char *target, + struct parsed_params *p) +{ + const char *devname = cxl_memdev_get_devname(memdev); + u64 size; + + if (strcmp(devname, target) != 0) + return false; + + size = cxl_memdev_get_pmem_size(memdev); + if (!p->ep_min_size) + p->ep_min_size = size; + else + p->ep_min_size = min(p->ep_min_size, size); + + return true; +} + +static int validate_config_memdevs(struct cxl_ctx *ctx, struct parsed_params *p) +{ + unsigned int i, matched = 0; + + for (i = 0; i < p->ways; i++) { + struct cxl_memdev *memdev; + + cxl_memdev_foreach(ctx, memdev) + if (validate_memdev(memdev, p->targets[i], p)) + matched++; + } + if (matched != p->ways) { + log_err(&rl, + "one or more memdevs not found in CXL topology\n"); + return -ENXIO; + } + + return 0; +} + +static int validate_decoder(struct cxl_decoder *decoder, + struct parsed_params *p) +{ + const char *devname = cxl_decoder_get_devname(decoder); + + switch(p->mode) { + case CXL_DECODER_MODE_RAM: + if (!cxl_decoder_is_volatile_capable(decoder)) { + log_err(&rl, "%s is not volatile capable\n", devname); + return -EINVAL; + } + break; + case CXL_DECODER_MODE_PMEM: + if (!cxl_decoder_is_pmem_capable(decoder)) { + log_err(&rl, "%s is not pmem capable\n", devname); + return -EINVAL; + } + break; + default: + log_err(&rl, "unknown type: %s\n", param.type); + return -EINVAL; + } + + /* TODO check if the interleave config is possible under this decoder */ + + return 0; +} + +static int create_region_validate_config(struct cxl_ctx *ctx, + struct parsed_params *p) +{ + struct cxl_bus *bus; + int rc; + + cxl_bus_foreach(ctx, bus) { + struct cxl_decoder *decoder; + struct cxl_port *port; + + if (!util_cxl_bus_filter(bus, param.bus)) + continue; + + port = cxl_bus_get_port(bus); + if (!cxl_port_is_root(port)) + continue; + + cxl_decoder_foreach (port, decoder) { + if (util_cxl_decoder_filter(decoder, + param.root_decoder)) { + p->root_decoder = decoder; + goto found; + } + } + } + +found: + if (p->root_decoder == NULL) { + log_err(&rl, "%s not found in CXL topology\n", + param.root_decoder); + return -ENXIO; + } + + rc = validate_decoder(p->root_decoder, p); + if (rc) + return rc; + + return validate_config_memdevs(ctx, p); +} + +static struct cxl_decoder * +cxl_memdev_target_find_decoder(struct cxl_ctx *ctx, const char *memdev_name) +{ + struct cxl_endpoint *ep = NULL; + struct cxl_decoder *decoder; + struct cxl_memdev *memdev; + struct cxl_port *port; + + cxl_memdev_foreach(ctx, memdev) { + const char *devname = cxl_memdev_get_devname(memdev); + + if (strcmp(devname, memdev_name) != 0) + continue; + + ep = cxl_memdev_get_endpoint(memdev); + } + + if (!ep) { + log_err(&rl, "could not get an endpoint for %s\n", + memdev_name); + return NULL; + } + + port = cxl_endpoint_get_port(ep); + if (!port) { + log_err(&rl, "could not get a port for %s\n", + memdev_name); + return NULL; + } + + cxl_decoder_foreach(port, decoder) + if (cxl_decoder_get_size(decoder) == 0) + return decoder; + + log_err(&rl, "could not get a free decoder for %s\n", memdev_name); + return NULL; +} + +#define try(prefix, op, dev, p) \ +do { \ + int __rc = prefix##_##op(dev, p); \ + if (__rc) { \ + log_err(&rl, "%s: " #op " failed: %s\n", \ + prefix##_get_devname(dev), \ + strerror(abs(__rc))); \ + rc = __rc; \ + goto err_delete; \ + } \ +} while (0) + +static int cxl_region_determine_granularity(struct cxl_region *region, + struct parsed_params *p) +{ + const char *devname = cxl_region_get_devname(region); + unsigned int granularity, ways; + + /* Default granularity will be the root decoder's granularity */ + granularity = cxl_decoder_get_interleave_granularity(p->root_decoder); + if (granularity == 0 || granularity == UINT_MAX) { + log_err(&rl, "%s: unable to determine root decoder granularity\n", + devname); + return -ENXIO; + } + + /* If no user-supplied granularity, just use the default */ + if (!p->granularity) + return granularity; + + ways = cxl_decoder_get_interleave_ways(p->root_decoder); + if (ways == 0 || ways == UINT_MAX) { + log_err(&rl, "%s: unable to determine root decoder ways\n", + devname); + return -ENXIO; + } + + /* For ways == 1, any user-supplied granularity is fine */ + if (ways == 1) + return p->granularity; + + /* + * For ways > 1, only allow the same granularity as the selected + * root decoder + */ + if (p->granularity == granularity) + return granularity; + + log_err(&rl, + "%s: For an x%d root, only root decoder granularity (%d) permitted\n", + devname, ways, granularity); + return -EINVAL; +} + +static int create_region(struct cxl_ctx *ctx, int *count, + struct parsed_params *p) +{ + unsigned long flags = UTIL_JSON_TARGETS; + struct json_object *jregion; + unsigned int i, granularity; + struct cxl_region *region; + const char *devname; + uuid_t uuid; + u64 size; + int rc; + + rc = create_region_validate_config(ctx, p); + if (rc) + return rc; + + if (p->size) { + size = p->size; + } else if (p->ep_min_size) { + size = p->ep_min_size * p->ways; + } else { + log_err(&rl, "%s: unable to determine region size\n", __func__); + return -ENXIO; + } + + if (p->mode == CXL_DECODER_MODE_PMEM) { + region = cxl_decoder_create_pmem_region(p->root_decoder); + if (!region) { + log_err(&rl, "failed to create region under %s\n", + param.root_decoder); + return -ENXIO; + } + } else { + log_err(&rl, "region type '%s' not supported yet\n", + param.type); + return -EOPNOTSUPP; + } + + devname = cxl_region_get_devname(region); + + rc = cxl_region_determine_granularity(region, p); + if (rc < 0) + goto err_delete; + granularity = rc; + + uuid_generate(uuid); + try(cxl_region, set_interleave_granularity, region, granularity); + try(cxl_region, set_interleave_ways, region, p->ways); + try(cxl_region, set_uuid, region, uuid); + try(cxl_region, set_size, region, size); + + for (i = 0; i < p->ways; i++) { + struct cxl_decoder *ep_decoder = NULL; + + ep_decoder = cxl_memdev_target_find_decoder(ctx, p->targets[i]); + if (!ep_decoder) { + rc = -ENXIO; + goto err_delete; + } + if (cxl_decoder_get_mode(ep_decoder) != p->mode) { + /* + * The memdev_target_find_decoder() helper returns a free + * decoder whose size has been checked for 0. + * Thus it is safe to change the mode here if needed. + */ + try(cxl_decoder, set_dpa_size, ep_decoder, 0); + try(cxl_decoder, set_mode, ep_decoder, p->mode); + } + try(cxl_decoder, set_dpa_size, ep_decoder, size/p->ways); + rc = cxl_region_set_target(region, i, ep_decoder); + if (rc) { + log_err(&rl, "%s: failed to set target%d to %s\n", + devname, i, p->targets[i]); + goto err_delete; + } + } + + rc = cxl_region_decode_commit(region); + if (rc) { + log_err(&rl, "%s: failed to commit decode: %s\n", devname, + strerror(-rc)); + goto err_delete; + } + + rc = cxl_region_enable(region); + if (rc) { + log_err(&rl, "%s: failed to enable: %s\n", devname, + strerror(-rc)); + goto err_delete; + } + *count = 1; + + if (isatty(1)) + flags |= UTIL_JSON_HUMAN; + jregion = util_cxl_region_to_json(region, flags); + if (jregion) + printf("%s\n", json_object_to_json_string_ext(jregion, + JSON_C_TO_STRING_PRETTY)); + + return 0; + +err_delete: + cxl_region_delete(region); + return rc; +} + +static int region_action(int argc, const char **argv, struct cxl_ctx *ctx, + enum region_actions action, + const struct option *options, struct parsed_params *p, + int *count, const char *u) +{ + int rc = -ENXIO; + + log_init(&rl, "cxl region", "CXL_REGION_LOG"); + rc = parse_region_options(argc, argv, ctx, action, options, p, u); + if (rc) + return rc; + + if (action == ACTION_CREATE) + return create_region(ctx, count, p); + + return rc; +} + +int cmd_create_region(int argc, const char **argv, struct cxl_ctx *ctx) +{ + const char *u = "cxl create-region ... []"; + struct parsed_params p = { 0 }; + int rc, count = 0; + + rc = region_action(argc, argv, ctx, ACTION_CREATE, create_options, &p, + &count, u); + log_info(&rl, "created %d region%s\n", count, count == 1 ? "" : "s"); + return rc == 0 ? 0 : EXIT_FAILURE; +} diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build index 423be90..340cdee 100644 --- a/Documentation/cxl/meson.build +++ b/Documentation/cxl/meson.build @@ -23,6 +23,7 @@ filedeps = [ 'memdev-option.txt', 'labels-options.txt', 'debug-option.txt', + 'region-description.txt', ] cxl_manpages = [ @@ -39,6 +40,7 @@ cxl_manpages = [ 'cxl-set-partition.txt', 'cxl-reserve-dpa.txt', 'cxl-free-dpa.txt', + 'cxl-create-region.txt', ] foreach man : cxl_manpages diff --git a/cxl/meson.build b/cxl/meson.build index d63dcb1..f2474aa 100644 --- a/cxl/meson.build +++ b/cxl/meson.build @@ -3,6 +3,7 @@ cxl_src = [ 'list.c', 'port.c', 'bus.c', + 'region.c', 'memdev.c', 'json.c', 'filter.c', From patchwork Mon Aug 15 19:22:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 12944086 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8ABF9C25B0E for ; Mon, 15 Aug 2022 21:28:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243679AbiHOV20 (ORCPT ); Mon, 15 Aug 2022 17:28:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45180 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348114AbiHOV05 (ORCPT ); Mon, 15 Aug 2022 17:26:57 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E5A3FE97E6 for ; Mon, 15 Aug 2022 12:22:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1660591374; x=1692127374; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=kWdpWopw0zYMnyW3Hpoy0cThHlwGFMQI8KBEr1SCr0g=; b=EDijpVjvcKFvw8zdSqyauIHNxEaCai8Nj0r2VQQMr4aYgCadLbiVM9ew 4Ysw8uvSkOcUn792LGYeB3YIIQ98gaubT25LJD7oymyTED7hKtqmjX4Rt XOf1le4JJ8v3J1VffHAOLfLhjgcI7MUPc8LLP7TAoRl6t/47XOmaYNvaN 9PYpuNLha66a8/al49k3WKBN1JidhzLlqD78PkPFRfZqmNM1l5VK+pII/ 6U6uSZvwPJiSZLLmEOIYpp4lSsLbxHYFLvSbcwenkAjToGbvrTklrEcXN o2RsYMzwd3DRGOK/kql6C+K2OZztcAKm0Ca+caiicPv7HNMJjuuOFu1Zv A==; X-IronPort-AV: E=McAfee;i="6400,9594,10440"; a="293313134" X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="293313134" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:21 -0700 X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="606758261" Received: from smadiset-mobl1.amr.corp.intel.com (HELO vverma7-desk1.intel.com) ([10.209.5.99]) by orsmga002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:20 -0700 From: Vishal Verma To: Cc: , Dan Williams , Alison Schofield , Ira Weiny , Dave Jiang , Vishal Verma Subject: [ndctl PATCH v3 08/11] cxl: add commands to {enable,disable,destroy}-region Date: Mon, 15 Aug 2022 13:22:11 -0600 Message-Id: <20220815192214.545800-9-vishal.l.verma@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220815192214.545800-1-vishal.l.verma@intel.com> References: <20220815192214.545800-1-vishal.l.verma@intel.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=12123; h=from:subject; bh=kWdpWopw0zYMnyW3Hpoy0cThHlwGFMQI8KBEr1SCr0g=; b=owGbwMvMwCXGf25diOft7jLG02pJDEm/5jyz+mJe3DE147J0nF2YjefLDcGzz5rKyDcb17B15Z3l Xv64o5SFQYyLQVZMkeXvno+Mx+S25/MEJjjCzGFlAhnCwMUpABOpC2P4w3EgmnXJzf1HFnLVqSd8uG RyT/HXmQeVV3Ya+GpfXCnDcZmR4f2W8gRO//nze/zWJHnM3G/k8OziZhMF4UXKBxRnG7h95QIA X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org With a template from cxl-create-region in place, add its friends: cxl enable-region cxl disable-region cxl destroy-region Cc: Dan Williams Reviewed-by: Dan Williams Signed-off-by: Vishal Verma --- Documentation/cxl/cxl-destroy-region.txt | 41 +++++ Documentation/cxl/cxl-disable-region.txt | 36 +++++ Documentation/cxl/cxl-enable-region.txt | 36 +++++ Documentation/cxl/decoder-option.txt | 6 + cxl/builtin.h | 3 + cxl/cxl.c | 3 + cxl/region.c | 193 ++++++++++++++++++++++- Documentation/cxl/meson.build | 4 + 8 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 Documentation/cxl/cxl-destroy-region.txt create mode 100644 Documentation/cxl/cxl-disable-region.txt create mode 100644 Documentation/cxl/cxl-enable-region.txt create mode 100644 Documentation/cxl/decoder-option.txt diff --git a/Documentation/cxl/cxl-destroy-region.txt b/Documentation/cxl/cxl-destroy-region.txt new file mode 100644 index 0000000..74f4093 --- /dev/null +++ b/Documentation/cxl/cxl-destroy-region.txt @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0 + +cxl-destroy-region(1) +===================== + +NAME +---- +cxl-destroy-region - destroy specified region(s). + +SYNOPSIS +-------- +[verse] +'cxl destroy-region []' + +include::region-description.txt[] + +EXAMPLE +------- +---- +# cxl destroy-region all +destroyed 2 regions +---- + +OPTIONS +------- +include::bus-option.txt[] + +-f:: +--force:: + Force a destroy operation even if the region is active. + This will attempt to disable the region first. + +include::decoder-option.txt[] + +include::debug-option.txt[] + +include::../copyright.txt[] + +SEE ALSO +-------- +linkcxl:cxl-list[1], linkcxl:cxl-create-region[1] diff --git a/Documentation/cxl/cxl-disable-region.txt b/Documentation/cxl/cxl-disable-region.txt new file mode 100644 index 0000000..6a39aee --- /dev/null +++ b/Documentation/cxl/cxl-disable-region.txt @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 + +cxl-disable-region(1) +===================== + +NAME +---- +cxl-disable-region - disable specified region(s). + +SYNOPSIS +-------- +[verse] +'cxl disable-region []' + +include::region-description.txt[] + +EXAMPLE +------- +---- +# cxl disable-region all +disabled 2 regions +---- + +OPTIONS +------- +include::bus-option.txt[] + +include::decoder-option.txt[] + +include::debug-option.txt[] + +include::../copyright.txt[] + +SEE ALSO +-------- +linkcxl:cxl-list[1], linkcxl:cxl-enable-region[1] diff --git a/Documentation/cxl/cxl-enable-region.txt b/Documentation/cxl/cxl-enable-region.txt new file mode 100644 index 0000000..f6ef00f --- /dev/null +++ b/Documentation/cxl/cxl-enable-region.txt @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 + +cxl-enable-region(1) +===================== + +NAME +---- +cxl-enable-region - enable specified region(s). + +SYNOPSIS +-------- +[verse] +'cxl enable-region []' + +include::region-description.txt[] + +EXAMPLE +------- +---- +# cxl enable-region all +enabled 2 regions +---- + +OPTIONS +------- +include::bus-option.txt[] + +include::decoder-option.txt[] + +include::debug-option.txt[] + +include::../copyright.txt[] + +SEE ALSO +-------- +linkcxl:cxl-list[1], linkcxl:cxl-disable-region[1] diff --git a/Documentation/cxl/decoder-option.txt b/Documentation/cxl/decoder-option.txt new file mode 100644 index 0000000..e638d6e --- /dev/null +++ b/Documentation/cxl/decoder-option.txt @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 + +-d:: +--decoder=:: + The root decoder to limit the operation to. Only regions that are + children of the specified decoder will be acted upon. diff --git a/cxl/builtin.h b/cxl/builtin.h index 843bada..b28c221 100644 --- a/cxl/builtin.h +++ b/cxl/builtin.h @@ -19,4 +19,7 @@ int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_set_partition(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_disable_bus(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_create_region(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_enable_region(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_disable_region(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_destroy_region(int argc, const char **argv, struct cxl_ctx *ctx); #endif /* _CXL_BUILTIN_H_ */ diff --git a/cxl/cxl.c b/cxl/cxl.c index f0afcfe..dd1be7a 100644 --- a/cxl/cxl.c +++ b/cxl/cxl.c @@ -73,6 +73,9 @@ static struct cmd_struct commands[] = { { "set-partition", .c_fn = cmd_set_partition }, { "disable-bus", .c_fn = cmd_disable_bus }, { "create-region", .c_fn = cmd_create_region }, + { "enable-region", .c_fn = cmd_enable_region }, + { "disable-region", .c_fn = cmd_disable_region }, + { "destroy-region", .c_fn = cmd_destroy_region }, }; int main(int argc, const char **argv) diff --git a/cxl/region.c b/cxl/region.c index 2791ac9..b22d3c8 100644 --- a/cxl/region.c +++ b/cxl/region.c @@ -45,6 +45,9 @@ struct parsed_params { enum region_actions { ACTION_CREATE, + ACTION_ENABLE, + ACTION_DISABLE, + ACTION_DESTROY, }; static struct log_ctx rl; @@ -78,7 +81,22 @@ static const struct option create_options[] = { OPT_END(), }; +static const struct option enable_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; +static const struct option disable_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static const struct option destroy_options[] = { + BASE_OPTIONS(), + OPT_BOOLEAN('f', "force", ¶m.force, + "destroy region even if currently active"), + OPT_END(), +}; static int parse_create_options(int argc, const char **argv, struct parsed_params *p) @@ -519,12 +537,122 @@ err_delete: return rc; } +static int destroy_region(struct cxl_region *region) +{ + const char *devname = cxl_region_get_devname(region); + unsigned int ways, i; + int rc; + + /* First, unbind/disable the region if needed */ + if (cxl_region_is_enabled(region)) { + if (param.force) { + rc = cxl_region_disable(region); + if (rc) { + log_err(&rl, "%s: error disabling region: %s\n", + devname, strerror(-rc)); + return rc; + } + } else { + log_err(&rl, "%s active. Disable it or use --force\n", + devname); + return -EBUSY; + } + } + + /* Reset the region decode in preparation for removal */ + rc = cxl_region_decode_reset(region); + if (rc) { + log_err(&rl, "%s: failed to reset decode: %s\n", devname, + strerror(-rc)); + return rc; + } + + /* Reset all endpoint decoders and region targets */ + ways = cxl_region_get_interleave_ways(region); + if (ways == 0 || ways == UINT_MAX) { + log_err(&rl, "%s: error getting interleave ways\n", devname); + return -ENXIO; + } + + for (i = 0; i < ways; i++) { + struct cxl_decoder *ep_decoder; + + ep_decoder = cxl_region_get_target_decoder(region, i); + if (!ep_decoder) + return -ENXIO; + + rc = cxl_region_clear_target(region, i); + if (rc) { + log_err(&rl, "%s: clearing target%d failed: %s\n", + devname, i, strerror(abs(rc))); + return rc; + } + + rc = cxl_decoder_set_dpa_size(ep_decoder, 0); + if (rc) { + log_err(&rl, "%s: set_dpa_size failed: %s\n", + cxl_decoder_get_devname(ep_decoder), + strerror(abs(rc))); + return rc; + } + } + + /* Finally, delete the region */ + return cxl_region_delete(region); +} + +static int do_region_xable(struct cxl_region *region, enum region_actions action) +{ + switch (action) { + case ACTION_ENABLE: + return cxl_region_enable(region); + case ACTION_DISABLE: + return cxl_region_disable(region); + case ACTION_DESTROY: + return destroy_region(region); + default: + return -EINVAL; + } +} + +static int decoder_region_action(struct parsed_params *p, + struct cxl_decoder *decoder, + enum region_actions action, int *count) +{ + struct cxl_region *region, *_r; + int rc = 0, err_rc = 0; + + cxl_region_foreach_safe (decoder, region, _r) { + int i, match = 0; + + for (i = 0; i < p->num_targets; i++) { + if (util_cxl_region_filter(region, p->targets[i])) { + match = 1; + break; + } + } + if (!match) + continue; + + rc = do_region_xable(region, action); + if (rc == 0) { + *count += 1; + } else { + log_err(&rl, "%s: failed: %s\n", + cxl_region_get_devname(region), strerror(-rc)); + err_rc = rc; + } + } + return err_rc ? err_rc : rc; +} + static int region_action(int argc, const char **argv, struct cxl_ctx *ctx, enum region_actions action, const struct option *options, struct parsed_params *p, int *count, const char *u) { - int rc = -ENXIO; + int rc = 0, err_rc = 0; + struct cxl_bus *bus; log_init(&rl, "cxl region", "CXL_REGION_LOG"); rc = parse_region_options(argc, argv, ctx, action, options, p, u); @@ -534,6 +662,33 @@ static int region_action(int argc, const char **argv, struct cxl_ctx *ctx, if (action == ACTION_CREATE) return create_region(ctx, count, p); + cxl_bus_foreach(ctx, bus) { + struct cxl_decoder *decoder; + struct cxl_port *port; + + if (!util_cxl_bus_filter(bus, param.bus)) + continue; + + port = cxl_bus_get_port(bus); + if (!cxl_port_is_root(port)) + continue; + + cxl_decoder_foreach (port, decoder) { + decoder = util_cxl_decoder_filter(decoder, + param.root_decoder); + if (!decoder) + continue; + rc = decoder_region_action(p, decoder, action, count); + if (rc) + err_rc = rc; + } + } + + if (err_rc) { + log_err(&rl, "one or more failures, last failure: %s\n", + strerror(-err_rc)); + return err_rc; + } return rc; } @@ -548,3 +703,39 @@ int cmd_create_region(int argc, const char **argv, struct cxl_ctx *ctx) log_info(&rl, "created %d region%s\n", count, count == 1 ? "" : "s"); return rc == 0 ? 0 : EXIT_FAILURE; } + +int cmd_enable_region(int argc, const char **argv, struct cxl_ctx *ctx) +{ + const char *u = "cxl enable-region ... []"; + struct parsed_params p = { 0 }; + int rc, count = 0; + + rc = region_action(argc, argv, ctx, ACTION_ENABLE, enable_options, &p, + &count, u); + log_info(&rl, "enabled %d region%s\n", count, count == 1 ? "" : "s"); + return rc == 0 ? 0 : EXIT_FAILURE; +} + +int cmd_disable_region(int argc, const char **argv, struct cxl_ctx *ctx) +{ + const char *u = "cxl disable-region ... []"; + struct parsed_params p = { 0 }; + int rc, count = 0; + + rc = region_action(argc, argv, ctx, ACTION_DISABLE, disable_options, &p, + &count, u); + log_info(&rl, "disabled %d region%s\n", count, count == 1 ? "" : "s"); + return rc == 0 ? 0 : EXIT_FAILURE; +} + +int cmd_destroy_region(int argc, const char **argv, struct cxl_ctx *ctx) +{ + const char *u = "cxl destroy-region ... []"; + struct parsed_params p = { 0 }; + int rc, count = 0; + + rc = region_action(argc, argv, ctx, ACTION_DESTROY, destroy_options, &p, + &count, u); + log_info(&rl, "destroyed %d region%s\n", count, count == 1 ? "" : "s"); + return rc == 0 ? 0 : EXIT_FAILURE; +} diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build index 340cdee..147ea71 100644 --- a/Documentation/cxl/meson.build +++ b/Documentation/cxl/meson.build @@ -24,6 +24,7 @@ filedeps = [ 'labels-options.txt', 'debug-option.txt', 'region-description.txt', + 'decoder-option.txt', ] cxl_manpages = [ @@ -41,6 +42,9 @@ cxl_manpages = [ 'cxl-reserve-dpa.txt', 'cxl-free-dpa.txt', 'cxl-create-region.txt', + 'cxl-disable-region.txt', + 'cxl-enable-region.txt', + 'cxl-destroy-region.txt', ] foreach man : cxl_manpages From patchwork Mon Aug 15 19:22:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 12944079 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6A99BC3F6B0 for ; Mon, 15 Aug 2022 21:28:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344239AbiHOV2P (ORCPT ); Mon, 15 Aug 2022 17:28:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53816 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348145AbiHOV06 (ORCPT ); Mon, 15 Aug 2022 17:26:58 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B296AE97F9 for ; Mon, 15 Aug 2022 12:22:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1660591377; x=1692127377; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=yYRPJ8O/nI5XLYfuqFzW+C2ugl+ImE/phG1tck5CQp0=; b=Reja2tqELy7L4BIf/Iz9ThoNPbZsmLKnDIRIQfM9bKP867PoBGuYqJ/Y dvWaaUghyXUwgU3mxKEs7HsBkXDJplHdcaSATMErjeDgtEbzTbWoygSIr alGXZ3P3mOjOLpNxnXUbrdXQLGF2Xu9vb0PaI8pptiRoTvuc+z18beajc p6vX4jEhfFvcLFXocWDpiP2WkFkMYHr0Cj4mTYfH/muV3l8alWkofQlxV wX3vizZuYrUodftbgoiuVy7Hcl7jvi09jDOklK+WFrkHMPD6+zHuLQ7Tx 97D80KhCX7AyF8oo1sFFSltbotnJe7HmNssMqsIhxUtmaluqjgrUMxyLk g==; X-IronPort-AV: E=McAfee;i="6400,9594,10440"; a="293313136" X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="293313136" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:22 -0700 X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="606758264" Received: from smadiset-mobl1.amr.corp.intel.com (HELO vverma7-desk1.intel.com) ([10.209.5.99]) by orsmga002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:21 -0700 From: Vishal Verma To: Cc: , Dan Williams , Alison Schofield , Ira Weiny , Dave Jiang , Vishal Verma Subject: [ndctl PATCH v3 09/11] cxl/list: make memdevs and regions the default listing Date: Mon, 15 Aug 2022 13:22:12 -0600 Message-Id: <20220815192214.545800-10-vishal.l.verma@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220815192214.545800-1-vishal.l.verma@intel.com> References: <20220815192214.545800-1-vishal.l.verma@intel.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=1039; h=from:subject; bh=yYRPJ8O/nI5XLYfuqFzW+C2ugl+ImE/phG1tck5CQp0=; b=owGbwMvMwCXGf25diOft7jLG02pJDEm/5jx7cK5bfeUdwWf5jRGysYe1xS/ueyJ2kKOMbZnLdb2k Gfb8HaUsDGJcDLJiiix/93xkPCa3PZ8nMMERZg4rE8gQBi5OAZiI4lVGhiVnG3f1aaS1RWyfsvTgTy 6Lz4wSvJ0NL2c+SAw85aplbcvI8Pev9/aOWdM6Ww/MipPW/uB2zvRbYPJcg/J0qQKuPTP/MAAA X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Instead of only listing regions by default (which can often be empty if no regions have been configured), change the default listing mode to both memdevs and regions. This will allow a plain 'cxl-list' to be a quick health check of whether all the expected memdevs have enumerated correctly, and see any regions that have been configured. Cc: Dan Williams Reviewed-by: Dan Williams Signed-off-by: Vishal Verma --- cxl/list.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cxl/list.c b/cxl/list.c index 88ca9d9..5f604ec 100644 --- a/cxl/list.c +++ b/cxl/list.c @@ -100,9 +100,10 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) param.regions = true; } - /* List regions by default */ + /* List regions and memdevs by default */ if (num_list_flags() == 0) { param.regions = true; + param.memdevs = true; } log_init(¶m.ctx, "cxl list", "CXL_LIST_LOG"); From patchwork Mon Aug 15 19:22:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 12944087 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C89BCC00140 for ; Mon, 15 Aug 2022 21:28:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345968AbiHOV23 (ORCPT ); Mon, 15 Aug 2022 17:28:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46412 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348181AbiHOV1B (ORCPT ); Mon, 15 Aug 2022 17:27:01 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 54BBCE9A81 for ; Mon, 15 Aug 2022 12:22:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1660591379; x=1692127379; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=PBfYQPgZSq7q+c20aALR0P51XJsCwD7YzY7SKX4OEDM=; b=CPDxzWS/3uQTfFF1DGgZT/6FjneruLJiRlDxa2g7atmvK4RyBbVS4Wus TYnUz+0e2sLPvml4U2nrVAnbRr9I9ZRQcxK1/5ftkMyS3OMaoqk6Fv4dX QaQtabHMB3elMiZeDt66e0r+fDoxb1KnSZ4Ru05BEoTPJNWAb8RAVhv4T //+As4kztKBB8+siTTpa1VSnoa0fmYlsosf6rdmGz+HQ9LR3hkfryzjV5 0YHjcqxJ9vz8YDAg7npc4qp2Ek3pvq9XORtuqb/H7w3edOWgITRu8jKph 8dxJBTKaN0/BWE4JGZBRW3hYSE/wWP1go/lBOxBjbLUEIAcw/gnQ5yr/F Q==; X-IronPort-AV: E=McAfee;i="6400,9594,10440"; a="293313137" X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="293313137" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:22 -0700 X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="606758268" Received: from smadiset-mobl1.amr.corp.intel.com (HELO vverma7-desk1.intel.com) ([10.209.5.99]) by orsmga002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:21 -0700 From: Vishal Verma To: Cc: , Dan Williams , Alison Schofield , Ira Weiny , Dave Jiang , Vishal Verma Subject: [ndctl PATCH v3 10/11] test: add a cxl-create-region test Date: Mon, 15 Aug 2022 13:22:13 -0600 Message-Id: <20220815192214.545800-11-vishal.l.verma@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220815192214.545800-1-vishal.l.verma@intel.com> References: <20220815192214.545800-1-vishal.l.verma@intel.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=4439; h=from:subject; bh=PBfYQPgZSq7q+c20aALR0P51XJsCwD7YzY7SKX4OEDM=; b=owGbwMvMwCXGf25diOft7jLG02pJDEm/5jy7IvjewHTetdgFKT8Y571nd7hy9GPL9bw0kQoxucDN khZrO0pZGMS4GGTFFFn+7vnIeExuez5PYIIjzBxWJpAhDFycAjAR/xxGhq6ltRI3c2PYTh4r7Nk7vU aOp3s+85cVBiviH27SdFtbv5bhn3K021sf8+bGPYfuyIXsYy7sVjilq1ew6nPKXPkTTPl3mAE= X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Add a unit test to exercise the cxl-create-region command with different combinations of memdevs and decoders, using cxl_test based mocked devices. Cc: Dan Williams Reviewed-by: Dan Williams Signed-off-by: Vishal Verma --- test/cxl-create-region.sh | 125 ++++++++++++++++++++++++++++++++++++++ test/meson.build | 2 + 2 files changed, 127 insertions(+) create mode 100644 test/cxl-create-region.sh diff --git a/test/cxl-create-region.sh b/test/cxl-create-region.sh new file mode 100644 index 0000000..66df38f --- /dev/null +++ b/test/cxl-create-region.sh @@ -0,0 +1,125 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2022 Intel Corporation. All rights reserved. + +. $(dirname $0)/common + +rc=1 + +set -ex + +trap 'err $LINENO' ERR + +check_prereq "jq" + +modprobe -r cxl_test +modprobe cxl_test +udevadm settle + +destroy_regions() +{ + if [[ "$*" ]]; then + $CXL destroy-region -f -b cxl_test "$@" + else + $CXL destroy-region -f -b cxl_test all + fi +} + +create_x1_region() +{ + mem="$1" + + # find a pmem capable root decoder for this mem + decoder=$($CXL list -b cxl_test -D -d root -m "$mem" | + jq -r ".[] | + select(.pmem_capable == true) | + select(.nr_targets == 1) | + .decoder") + + if [[ ! $decoder ]]; then + echo "no suitable decoder found for $mem, skipping" + return + fi + + # create region + region=$($CXL create-region -d "$decoder" -m "$mem" | jq -r ".region") + + if [[ ! $region ]]; then + echo "create-region failed for $decoder / $mem" + err "$LINENO" + fi + + # cycle disable/enable + $CXL disable-region --bus=cxl_test "$region" + $CXL enable-region --bus=cxl_test "$region" + + # cycle destroying and creating the same region + destroy_regions "$region" + region=$($CXL create-region -d "$decoder" -m "$mem" | jq -r ".region") + + if [[ ! $region ]]; then + echo "create-region failed for $decoder / $mem" + err "$LINENO" + fi + destroy_regions "$region" +} + +create_subregions() +{ + slice=$((256 << 20)) + mem="$1" + + # find a pmem capable root decoder for this mem + decoder=$($CXL list -b cxl_test -D -d root -m "$mem" | + jq -r ".[] | + select(.pmem_capable == true) | + select(.nr_targets == 1) | + .decoder") + + if [[ ! $decoder ]]; then + echo "no suitable decoder found for $mem, skipping" + return + fi + + size="$($CXL list -m "$mem" | jq -r '.[].pmem_size')" + if [[ ! $size ]]; then + echo "$mem: unable to determine size" + err "$LINENO" + fi + + num_regions=$((size / slice)) + + declare -a regions + for (( i = 0; i < num_regions; i++ )); do + regions[$i]=$($CXL create-region -d "$decoder" -m "$mem" -s "$slice" | jq -r ".region") + if [[ ! ${regions[$i]} ]]; then + echo "create sub-region failed for $decoder / $mem" + err "$LINENO" + fi + udevadm settle + done + + echo "created $num_regions subregions:" + for (( i = 0; i < num_regions; i++ )); do + echo "${regions[$i]}" + done + + for (( i = (num_regions - 1); i >= 0; i-- )); do + destroy_regions "${regions[$i]}" + done +} + +# test reading labels directly through cxl-cli +readarray -t mems < <("$CXL" list -b cxl_test -M | jq -r '.[].memdev') + +for mem in ${mems[@]}; do + create_x1_region "$mem" +done + +# test multiple subregions under the same decoder, using slices of the same memdev +# to test out back-to-back pmem DPA allocations on memdevs +for mem in ${mems[@]}; do + create_subregions "$mem" +done + +modprobe -r cxl_test diff --git a/test/meson.build b/test/meson.build index b382f46..5953c28 100644 --- a/test/meson.build +++ b/test/meson.build @@ -153,6 +153,7 @@ track_uuid = find_program('track-uuid.sh') cxl_topo = find_program('cxl-topology.sh') cxl_sysfs = find_program('cxl-region-sysfs.sh') cxl_labels = find_program('cxl-labels.sh') +cxl_create_region = find_program('cxl-create-region.sh') tests = [ [ 'libndctl', libndctl, 'ndctl' ], @@ -180,6 +181,7 @@ tests = [ [ 'cxl-topology.sh', cxl_topo, 'cxl' ], [ 'cxl-region-sysfs.sh', cxl_sysfs, 'cxl' ], [ 'cxl-labels.sh', cxl_labels, 'cxl' ], + [ 'cxl-create-region.sh', cxl_create_region, 'cxl' ], ] if get_option('destructive').enabled() From patchwork Mon Aug 15 19:22:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 12944081 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 83DCAC28B2C for ; Mon, 15 Aug 2022 21:28:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344484AbiHOV2R (ORCPT ); Mon, 15 Aug 2022 17:28:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47078 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348192AbiHOV1C (ORCPT ); Mon, 15 Aug 2022 17:27:02 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D0D72E97D9 for ; Mon, 15 Aug 2022 12:23:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1660591380; x=1692127380; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=WDNXlB354Po247leSI7+Prye1anfCbOBQGC3r3VATvY=; b=VoRvZGTKr0NDKax1pX1gC6SwytBOqhWuru/9+Udo5KSvhn6LjgGIkqS4 +3bqcjJH9gCBkZ8v+j/3Vpxbh9kpo/hq9f2xFhnaNio6+KS/cLuRqcxaI sVflrWc8ZF4VFtEbPiYJgWN0mHv6qB839xlkqLYkkwGmXyXSxG9i9Jn2Y wxmp0BuvS+0DaBnjEnyKe0b+byam/QAK+ufifBLhPC1QksUm2J6ee+BUh 1wTZwKS249Wcr4zLEpeRzVDXwZY3aeTNZezPnRNbEF3PNEQl6G3SDWCte Z15yuFcRE/IYs5kkTdZE3cdAsU3OKogQPAbvpeEzkNvddHPoGOWekMZwD Q==; X-IronPort-AV: E=McAfee;i="6400,9594,10440"; a="293313139" X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="293313139" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:22 -0700 X-IronPort-AV: E=Sophos;i="5.93,239,1654585200"; d="scan'208";a="606758272" Received: from smadiset-mobl1.amr.corp.intel.com (HELO vverma7-desk1.intel.com) ([10.209.5.99]) by orsmga002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Aug 2022 12:22:22 -0700 From: Vishal Verma To: Cc: , Dan Williams , Alison Schofield , Ira Weiny , Dave Jiang , Vishal Verma Subject: [ndctl PATCH v3 11/11] cxl/decoder: add a max_available_extent attribute Date: Mon, 15 Aug 2022 13:22:14 -0600 Message-Id: <20220815192214.545800-12-vishal.l.verma@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220815192214.545800-1-vishal.l.verma@intel.com> References: <20220815192214.545800-1-vishal.l.verma@intel.com> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=7823; h=from:subject; bh=WDNXlB354Po247leSI7+Prye1anfCbOBQGC3r3VATvY=; b=owGbwMvMwCXGf25diOft7jLG02pJDEm/5jzb+sp1C/vBJVtiFa3rHVWTfxYeEhWNUPvxdsPi3CoB 3RqpjlIWBjEuBlkxRZa/ez4yHpPbns8TmOAIM4eVCWQIAxenAEzkFy/DX9HTc690bT3w/9bGmHcNrw XXSeYLnFnzQKnBfyuzVZRew1NGhrXLnxobKCfWbS1i/t/he4gn+efx3qWhCf7Ttwcs1Tl0mQcA X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Add a max_available_extent attribute to cxl_decoder. In order to aid in its calculation, change the order of regions in the root decoder's list to be sorted by start HPA of the region. Additionally, emit this attribute in decoder listings, and consult it for available space before creating a new region. Cc: Dan Williams Reviewed-by: Dan Williams Signed-off-by: Vishal Verma --- cxl/lib/private.h | 1 + cxl/lib/libcxl.c | 84 +++++++++++++++++++++++++++++++++++++++++++++- cxl/libcxl.h | 3 ++ cxl/json.c | 8 +++++ cxl/region.c | 14 +++++++- cxl/lib/libcxl.sym | 1 + 6 files changed, 109 insertions(+), 2 deletions(-) diff --git a/cxl/lib/private.h b/cxl/lib/private.h index 8bc9620..437eade 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -104,6 +104,7 @@ struct cxl_decoder { u64 size; u64 dpa_resource; u64 dpa_size; + u64 max_available_extent; void *dev_buf; size_t buf_len; char *dev_path; diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 2b1cf7e..a40b0e6 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -455,6 +455,16 @@ CXL_EXPORT int cxl_region_delete(struct cxl_region *region) return 0; } +static int region_start_cmp(struct cxl_region *r1, struct cxl_region *r2) +{ + if (r1->start == r2->start) + return 0; + else if (r1->start < r2->start) + return -1; + else + return 1; +} + static void *add_cxl_region(void *parent, int id, const char *cxlregion_base) { const char *devname = devpath_to_devname(cxlregion_base); @@ -539,7 +549,7 @@ static void *add_cxl_region(void *parent, int id, const char *cxlregion_base) break; } - list_add(&decoder->regions, ®ion->list); + list_add_sorted(&decoder->regions, region, list, region_start_cmp); return region; err: @@ -1617,6 +1627,70 @@ cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint) return NULL; } +static bool cxl_region_is_configured(struct cxl_region *region) +{ + return region->size && (region->decode_state != CXL_DECODE_RESET); +} + +/** + * cxl_decoder_calc_max_available_extent() - calculate max available free space + * @decoder - the root decoder to calculate the free extents for + * + * The add_cxl_region() function adds regions to the parent decoder's list + * sorted by the region's start HPAs. It can also be assumed that regions have + * no overlapped / aliased HPA space. Therefore, calculating each extent is as + * simple as walking the region list in order, and subtracting the previous + * region's end HPA from the next region's start HPA (and taking into account + * the decoder's start and end HPAs as well). + */ +static unsigned long long +cxl_decoder_calc_max_available_extent(struct cxl_decoder *decoder) +{ + u64 prev_end, decoder_end, cur_extent, max_extent = 0; + struct cxl_port *port = cxl_decoder_get_port(decoder); + struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder); + struct cxl_region *region; + + if (!cxl_port_is_root(port)) { + err(ctx, "%s: not a root decoder\n", + cxl_decoder_get_devname(decoder)); + return ULLONG_MAX; + } + + /* + * Preload prev_end with an imaginary region that ends just before + * the decoder's start, so that the extent calculation for the + * first region Just Works + */ + prev_end = decoder->start - 1; + + cxl_region_foreach(decoder, region) { + if (!cxl_region_is_configured(region)) + continue; + + /* + * region->start - prev_end would get the difference in + * addresses, but a difference of 1 in addresses implies + * an extent of 0. Hence the '-1'. + */ + cur_extent = region->start - prev_end - 1; + max_extent = max(max_extent, cur_extent); + prev_end = region->start + region->size - 1; + } + + /* + * Finally, consider the extent after the last region, up to the end + * of the decoder's address space, if any. If there were no regions, + * this simply reduces to decoder->size. + * Subtracting two addrs gets us a 'size' directly, no need for +/- 1. + */ + decoder_end = decoder->start + decoder->size - 1; + cur_extent = decoder_end - prev_end; + max_extent = max(max_extent, cur_extent); + + return max_extent; +} + static int decoder_id_cmp(struct cxl_decoder *d1, struct cxl_decoder *d2) { return d1->id - d2->id; @@ -1747,6 +1821,8 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base) if (sysfs_read_attr(ctx, path, buf) == 0) *(flag->flag) = !!strtoul(buf, NULL, 0); } + decoder->max_available_extent = + cxl_decoder_calc_max_available_extent(decoder); break; } } @@ -1911,6 +1987,12 @@ cxl_decoder_get_dpa_size(struct cxl_decoder *decoder) return decoder->dpa_size; } +CXL_EXPORT unsigned long long +cxl_decoder_get_max_available_extent(struct cxl_decoder *decoder) +{ + return decoder->max_available_extent; +} + CXL_EXPORT int cxl_decoder_set_dpa_size(struct cxl_decoder *decoder, unsigned long long size) { diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 69d9c09..61c7fc4 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -134,6 +134,9 @@ unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder); unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder); unsigned long long cxl_decoder_get_dpa_resource(struct cxl_decoder *decoder); unsigned long long cxl_decoder_get_dpa_size(struct cxl_decoder *decoder); +unsigned long long +cxl_decoder_get_max_available_extent(struct cxl_decoder *decoder); + enum cxl_decoder_mode { CXL_DECODER_MODE_NONE, CXL_DECODER_MODE_MIXED, diff --git a/cxl/json.c b/cxl/json.c index 9dc99df..9cec58b 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -499,6 +499,14 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder, } if (cxl_port_is_root(port) && cxl_decoder_is_mem_capable(decoder)) { + size = cxl_decoder_get_max_available_extent(decoder); + if (size < ULLONG_MAX) { + jobj = util_json_object_size(size, flags); + if (jobj) + json_object_object_add(jdecoder, + "max_available_extent", + jobj); + } if (cxl_decoder_is_pmem_capable(decoder)) { jobj = json_object_new_boolean(true); if (jobj) diff --git a/cxl/region.c b/cxl/region.c index b22d3c8..a30313c 100644 --- a/cxl/region.c +++ b/cxl/region.c @@ -438,9 +438,9 @@ static int create_region(struct cxl_ctx *ctx, int *count, struct json_object *jregion; unsigned int i, granularity; struct cxl_region *region; + u64 size, max_extent; const char *devname; uuid_t uuid; - u64 size; int rc; rc = create_region_validate_config(ctx, p); @@ -455,6 +455,18 @@ static int create_region(struct cxl_ctx *ctx, int *count, log_err(&rl, "%s: unable to determine region size\n", __func__); return -ENXIO; } + max_extent = cxl_decoder_get_max_available_extent(p->root_decoder); + if (max_extent == ULLONG_MAX) { + log_err(&rl, "%s: unable to determine max extent\n", + cxl_decoder_get_devname(p->root_decoder)); + return -EINVAL; + } + if (size > max_extent) { + log_err(&rl, + "%s: region size %#lx exceeds max available space\n", + cxl_decoder_get_devname(p->root_decoder), size); + return -ENOSPC; + } if (p->mode == CXL_DECODER_MODE_PMEM) { region = cxl_decoder_create_pmem_region(p->root_decoder); diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index cb23a0b..549f88d 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -213,4 +213,5 @@ global: cxl_decoder_get_memdev; cxl_decoder_get_interleave_granularity; cxl_decoder_get_interleave_ways; + cxl_decoder_get_max_available_extent; } LIBCXL_2;