From patchwork Mon Jan 24 00:51:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721338 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 6DB87C433F5 for ; Mon, 24 Jan 2022 00:51:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240638AbiAXAv4 (ORCPT ); Sun, 23 Jan 2022 19:51:56 -0500 Received: from mga02.intel.com ([134.134.136.20]:37216 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240634AbiAXAvz (ORCPT ); Sun, 23 Jan 2022 19:51:55 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985515; x=1674521515; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=DYCU5+G667mp+YOiS7/QvNSu+aBhOgO2WwQwWkPTsMY=; b=Ndf9KRhiDk3e1fNzJbyT00hbkshxVkOG90peEY6WrWmObAZNn1TE+3Iy wXAN8w6FrQYxF6F4woy+F8dj/cA+LV09niZY9LmF2k9YzDUBt7UKwxIlX C7xfyLIFEmr8L4R3gbt3OPJ4EmHybvSo33vagB4ojLFs+0ABDxUOowbxk w2jtxnOK5iFA55WFuxSoz7om6e/ZEM9VwO/EZVJbTirBZ0gpFB/G8FyV1 dLhGnQ6wxKGmu8OJEkjMdIy0RBYuwegNKa2Z3nDWxYHqSkcaxFJANhDAq 3ypiLrM+znPIzWGeZcqcaJNS0HNbO7fVMqiQkcXzQ536S7EIvwJiXXH1p g==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="233293902" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="233293902" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:51:55 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="623905841" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga002-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:51:54 -0800 Subject: [ndctl PATCH 01/37] test: Add 'suite' identifiers to tests From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:51:54 -0800 Message-ID: <164298551461.3021641.4591877842309963514.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org In preparation for adding CXL tests, and in anticipation of wanting to only run the CXL tests, label each test with a suite id. Signed-off-by: Dan Williams --- test/meson.build | 73 +++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/test/meson.build b/test/meson.build index 94287aaef85b..07a5bb6e7f62 100644 --- a/test/meson.build +++ b/test/meson.build @@ -152,28 +152,28 @@ pfn_meta_errors = find_program('pfn-meta-errors.sh') track_uuid = find_program('track-uuid.sh') tests = [ - [ 'libndctl', libndctl ], - [ 'dsm-fail', dsm_fail ], - [ 'create.sh', create ], - [ 'clear.sh', clear ], - [ 'pmem-errors.sh', pmem_errors ], - [ 'daxdev-errors.sh', daxdev_errors_sh ], - [ 'multi-dax.sh', multi_dax ], - [ 'btt-check.sh', btt_check ], - [ 'label-compat.sh', label_compat ], - [ 'sector-mode.sh', sector_mode ], - [ 'inject-error.sh', inject_error ], - [ 'btt-errors.sh', btt_errors ], - [ 'hugetlb', hugetlb ], - [ 'btt-pad-compat.sh', btt_pad_compat ], - [ 'firmware-update.sh', firmware_update ], - [ 'ack-shutdown-count-set', ack_shutdown_count ], - [ 'rescan-partitions.sh', rescan_partitions ], - [ 'inject-smart.sh', inject_smart ], - [ 'monitor.sh', monitor ], - [ 'max_extent_ns', max_extent ], - [ 'pfn-meta-errors.sh', pfn_meta_errors ], - [ 'track-uuid.sh', track_uuid ], + [ 'libndctl', libndctl, 'ndctl' ], + [ 'dsm-fail', dsm_fail, 'ndctl' ], + [ 'create.sh', create, 'ndctl' ], + [ 'clear.sh', clear, 'ndctl' ], + [ 'pmem-errors.sh', pmem_errors, 'ndctl' ], + [ 'daxdev-errors.sh', daxdev_errors_sh, 'dax' ], + [ 'multi-dax.sh', multi_dax, 'dax' ], + [ 'btt-check.sh', btt_check, 'ndctl' ], + [ 'label-compat.sh', label_compat, 'ndctl' ], + [ 'sector-mode.sh', sector_mode, 'ndctl' ], + [ 'inject-error.sh', inject_error, 'ndctl' ], + [ 'btt-errors.sh', btt_errors, 'ndctl' ], + [ 'hugetlb', hugetlb, 'ndctl' ], + [ 'btt-pad-compat.sh', btt_pad_compat, 'ndctl' ], + [ 'firmware-update.sh', firmware_update, 'ndctl' ], + [ 'ack-shutdown-count-set', ack_shutdown_count, 'ndctl' ], + [ 'rescan-partitions.sh', rescan_partitions, 'ndctl' ], + [ 'inject-smart.sh', inject_smart, 'ndctl' ], + [ 'monitor.sh', monitor, 'ndctl' ], + [ 'max_extent_ns', max_extent, 'ndctl' ], + [ 'pfn-meta-errors.sh', pfn_meta_errors, 'ndctl' ], + [ 'track-uuid.sh', track_uuid, 'ndctl' ], ] if get_option('destructive').enabled() @@ -188,26 +188,26 @@ if get_option('destructive').enabled() mmap_test = find_program('mmap.sh') tests += [ - [ 'pmem-ns', pmem_ns ], - [ 'sub-section.sh', sub_section ], - [ 'dax-dev', dax_dev ], - [ 'dax-ext4.sh', dax_ext4 ], - [ 'dax-xfs.sh', dax_xfs ], - [ 'align.sh', align ], - [ 'device-dax', device_dax ], - [ 'revoke-devmem', revoke_devmem ], - [ 'device-dax-fio.sh', device_dax_fio ], - [ 'daxctl-devices.sh', daxctl_devices ], - [ 'daxctl-create.sh', daxctl_create ], - [ 'dm.sh', dm ], - [ 'mmap.sh', mmap_test ], + [ 'pmem-ns', pmem_ns, 'ndctl' ], + [ 'sub-section.sh', sub_section, 'dax' ], + [ 'dax-dev', dax_dev, 'dax' ], + [ 'dax-ext4.sh', dax_ext4, 'dax' ], + [ 'dax-xfs.sh', dax_xfs, 'dax' ], + [ 'align.sh', align, 'ndctl' ], + [ 'device-dax', device_dax, 'dax' ], + [ 'revoke-devmem', revoke_devmem, 'dax' ], + [ 'device-dax-fio.sh', device_dax_fio, 'dax' ], + [ 'daxctl-devices.sh', daxctl_devices, 'dax' ], + [ 'daxctl-create.sh', daxctl_create, 'dax' ], + [ 'dm.sh', dm, 'dax' ], + [ 'mmap.sh', mmap_test, 'dax' ], ] endif if get_option('keyutils').enabled() security = find_program('security.sh') tests += [ - [ 'security.sh', security ] + [ 'security.sh', security, 'ndctl' ] ] endif @@ -226,6 +226,7 @@ foreach t : tests dax_dev, mmap, ], + suite: t[2], timeout : 0, env : [ 'NDCTL=@0@'.format(ndctl_tool.full_path()), From patchwork Mon Jan 24 00:52:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721339 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 3841AC433EF for ; Mon, 24 Jan 2022 00:52:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235309AbiAXAwA (ORCPT ); Sun, 23 Jan 2022 19:52:00 -0500 Received: from mga17.intel.com ([192.55.52.151]:25163 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240634AbiAXAwA (ORCPT ); Sun, 23 Jan 2022 19:52:00 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985520; x=1674521520; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=RVmRRIwN+BtXP+wCKLSjlwKnd8pbAb9StJz+SREWbCA=; b=Uieen3y5WUngvH72b8o9t9EMLby5x/6441C+RFHoOIoqI5jJTN8/7N+6 AwuE1eNbCPfjMI8vv52TaGvQ8a+y5U0FNOl7lItn0AxSGe/eT2DGwqri0 qXWVCPrp2QjH8fpf/p3FTRW/Bzm3cweSjani03dS8z4yse8S9iHTWxfL9 0d7su+fOx6dVhQg45l6mBoHb+JaDTRvYlaB2my1r8tuWyLV5BWG6wxYsP yM73lJ1Jno3TxkogxRM4AM0ic4XfWrpOAKwLIsnkBJ7i7yY9NhBE3owHU wsS2cUfnAP1c6n6tJo2uERpz3hTfucyQHYoLmxSXMsFwX4B9wADuE0Aje g==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="226609534" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="226609534" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:00 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="596630560" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:00 -0800 Subject: [ndctl PATCH 02/37] ndctl: Rename util_filter to ndctl_filter From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:52:00 -0800 Message-ID: <164298552014.3021641.16369576632179722489.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org In preparation for introducing a cxl_filter_walk() implementation rename the current filter_walk infrastructure with an ndctl_ prefix. Signed-off-by: Dan Williams --- ndctl/filter.c | 4 ++-- ndctl/filter.h | 21 +++++++++++---------- ndctl/list.c | 14 +++++++------- ndctl/monitor.c | 12 ++++++------ test/list-smart-dimm.c | 12 ++++++------ 5 files changed, 32 insertions(+), 31 deletions(-) diff --git a/ndctl/filter.c b/ndctl/filter.c index 64d00ce87dd5..5b810dc5926d 100644 --- a/ndctl/filter.c +++ b/ndctl/filter.c @@ -338,8 +338,8 @@ const char *util_nsmode_name(enum ndctl_namespace_mode mode) return modes[mode]; } -int util_filter_walk(struct ndctl_ctx *ctx, struct util_filter_ctx *fctx, - struct util_filter_params *param) +int ndctl_filter_walk(struct ndctl_ctx *ctx, struct ndctl_filter_ctx *fctx, + struct ndctl_filter_params *param) { struct ndctl_bus *bus; unsigned int type = 0; diff --git a/ndctl/filter.h b/ndctl/filter.h index 9800cc230865..f6fe325acdc1 100644 --- a/ndctl/filter.h +++ b/ndctl/filter.h @@ -31,7 +31,7 @@ const char *util_nsmode_name(enum ndctl_namespace_mode mode); struct json_object; -/* json object hierarchy for the util_filter_walk() performed by cmd_list() */ +/* json object hierarchy for the ndctl_filter_walk() performed by cmd_list() */ struct list_filter_arg { struct json_object *jnamespaces; struct json_object *jregions; @@ -50,19 +50,20 @@ struct monitor_filter_arg { }; /* - * struct util_filter_ctx - control and callbacks for util_filter_walk() + * struct ndctl_filter_ctx - control and callbacks for ndctl_filter_walk() * ->filter_bus() and ->filter_region() return bool because the * child-object filter routines can not be called if the parent context * is not established. ->filter_dimm() and ->filter_namespace() are leaf * objects, so no child dependencies to check. */ -struct util_filter_ctx { - bool (*filter_bus)(struct ndctl_bus *bus, struct util_filter_ctx *ctx); - void (*filter_dimm)(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx); +struct ndctl_filter_ctx { + bool (*filter_bus)(struct ndctl_bus *bus, struct ndctl_filter_ctx *ctx); + void (*filter_dimm)(struct ndctl_dimm *dimm, + struct ndctl_filter_ctx *ctx); bool (*filter_region)(struct ndctl_region *region, - struct util_filter_ctx *ctx); + struct ndctl_filter_ctx *ctx); void (*filter_namespace)(struct ndctl_namespace *ndns, - struct util_filter_ctx *ctx); + struct ndctl_filter_ctx *ctx); union { void *arg; struct list_filter_arg *list; @@ -70,7 +71,7 @@ struct util_filter_ctx { }; }; -struct util_filter_params { +struct ndctl_filter_params { const char *bus; const char *region; const char *type; @@ -81,6 +82,6 @@ struct util_filter_params { }; struct ndctl_ctx; -int util_filter_walk(struct ndctl_ctx *ctx, struct util_filter_ctx *fctx, - struct util_filter_params *param); +int ndctl_filter_walk(struct ndctl_ctx *ctx, struct ndctl_filter_ctx *fctx, + struct ndctl_filter_params *param); #endif /* _NDCTL_UTIL_FILTER_H_ */ diff --git a/ndctl/list.c b/ndctl/list.c index 869edde4fc65..d89801946a0d 100644 --- a/ndctl/list.c +++ b/ndctl/list.c @@ -55,7 +55,7 @@ static unsigned long listopts_to_flags(void) return flags; } -static struct util_filter_params param; +static struct ndctl_filter_params param; static int did_fail; @@ -234,7 +234,7 @@ static struct json_object *region_to_json(struct ndctl_region *region, } static void filter_namespace(struct ndctl_namespace *ndns, - struct util_filter_ctx *ctx) + struct ndctl_filter_ctx *ctx) { struct json_object *jndns; struct list_filter_arg *lfa = ctx->list; @@ -272,7 +272,7 @@ static void filter_namespace(struct ndctl_namespace *ndns, } static bool filter_region(struct ndctl_region *region, - struct util_filter_ctx *ctx) + struct ndctl_filter_ctx *ctx) { struct list_filter_arg *lfa = ctx->list; struct json_object *jbus = lfa->jbus; @@ -318,7 +318,7 @@ static bool filter_region(struct ndctl_region *region, return true; } -static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx) +static void filter_dimm(struct ndctl_dimm *dimm, struct ndctl_filter_ctx *ctx) { struct list_filter_arg *lfa = ctx->list; struct json_object *jdimm; @@ -367,7 +367,7 @@ static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx) json_object_array_add(lfa->jdimms, jdimm); } -static bool filter_bus(struct ndctl_bus *bus, struct util_filter_ctx *ctx) +static bool filter_bus(struct ndctl_bus *bus, struct ndctl_filter_ctx *ctx) { struct list_filter_arg *lfa = ctx->list; @@ -489,7 +489,7 @@ int cmd_list(int argc, const char **argv, struct ndctl_ctx *ctx) NULL }; bool lint = !!secure_getenv("NDCTL_LIST_LINT"); - struct util_filter_ctx fctx = { 0 }; + struct ndctl_filter_ctx fctx = { 0 }; struct list_filter_arg lfa = { 0 }; int i, rc; @@ -544,7 +544,7 @@ int cmd_list(int argc, const char **argv, struct ndctl_ctx *ctx) fctx.list = &lfa; lfa.flags = listopts_to_flags(); - rc = util_filter_walk(ctx, &fctx, ¶m); + rc = ndctl_filter_walk(ctx, &fctx, ¶m); if (rc) return rc; diff --git a/ndctl/monitor.c b/ndctl/monitor.c index ae694c614593..3e6a42527088 100644 --- a/ndctl/monitor.c +++ b/ndctl/monitor.c @@ -49,7 +49,7 @@ struct monitor_dimm { struct list_node list; }; -static struct util_filter_params param; +static struct ndctl_filter_params param; static int did_fail; @@ -264,12 +264,12 @@ out: } static bool filter_region(struct ndctl_region *region, - struct util_filter_ctx *fctx) + struct ndctl_filter_ctx *fctx) { return true; } -static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *fctx) +static void filter_dimm(struct ndctl_dimm *dimm, struct ndctl_filter_ctx *fctx) { struct monitor_dimm *mdimm; struct monitor_filter_arg *mfa = fctx->monitor; @@ -317,7 +317,7 @@ static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *fctx) return; } -static bool filter_bus(struct ndctl_bus *bus, struct util_filter_ctx *fctx) +static bool filter_bus(struct ndctl_bus *bus, struct ndctl_filter_ctx *fctx) { return true; } @@ -602,7 +602,7 @@ int cmd_monitor(int argc, const char **argv, struct ndctl_ctx *ctx) CONF_END(), }; const char *prefix = "./", *ndctl_configs; - struct util_filter_ctx fctx = { 0 }; + struct ndctl_filter_ctx fctx = { 0 }; struct monitor_filter_arg mfa = { 0 }; int i, rc; @@ -672,7 +672,7 @@ int cmd_monitor(int argc, const char **argv, struct ndctl_ctx *ctx) mfa.maxfd_dimm = -1; mfa.flags = 0; - rc = util_filter_walk(ctx, &fctx, ¶m); + rc = ndctl_filter_walk(ctx, &fctx, ¶m); if (rc) goto out; diff --git a/test/list-smart-dimm.c b/test/list-smart-dimm.c index 47b711e63670..f94277e8febd 100644 --- a/test/list-smart-dimm.c +++ b/test/list-smart-dimm.c @@ -11,7 +11,7 @@ #include #include -struct util_filter_params param; +struct ndctl_filter_params param; static int did_fail; static int jflag = JSON_C_TO_STRING_PRETTY; @@ -23,12 +23,12 @@ do { \ } while (0) static bool filter_region(struct ndctl_region *region, - struct util_filter_ctx *ctx) + struct ndctl_filter_ctx *ctx) { return true; } -static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx) +static void filter_dimm(struct ndctl_dimm *dimm, struct ndctl_filter_ctx *ctx) { struct list_filter_arg *lfa = ctx->list; struct json_object *jdimm; @@ -57,7 +57,7 @@ static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx) json_object_array_add(lfa->jdimms, jdimm); } -static bool filter_bus(struct ndctl_bus *bus, struct util_filter_ctx *ctx) +static bool filter_bus(struct ndctl_bus *bus, struct ndctl_filter_ctx *ctx) { return true; } @@ -89,7 +89,7 @@ int main(int argc, const char *argv[]) "list-smart-dimm []", NULL }; - struct util_filter_ctx fctx = { 0 }; + struct ndctl_filter_ctx fctx = { 0 }; struct list_filter_arg lfa = { 0 }; rc = ndctl_new(&ctx); @@ -108,7 +108,7 @@ int main(int argc, const char *argv[]) fctx.list = &lfa; lfa.flags = 0; - rc = util_filter_walk(ctx, &fctx, ¶m); + rc = ndctl_filter_walk(ctx, &fctx, ¶m); if (rc) return rc; From patchwork Mon Jan 24 00:52:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721340 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 EFD59C433F5 for ; Mon, 24 Jan 2022 00:52:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240647AbiAXAwG (ORCPT ); Sun, 23 Jan 2022 19:52:06 -0500 Received: from mga02.intel.com ([134.134.136.20]:37224 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240634AbiAXAwF (ORCPT ); Sun, 23 Jan 2022 19:52:05 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985525; x=1674521525; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=/n08efVd4FlVzj6lSAF+42Bux11O+fcmeLoS0iVckmA=; b=EYEf4soOHj0l9tPNww0TlfQ5+weGmYSOfFGg/yDzanr70yE6m4DkGzgc w5xJFO/MTg32JA6XfVC9epqmv684FEt3uZSkZ5HpWgV4yilehRIy0u5q4 wNBZIyftTsfsTUAHfNDEVV0Dbrh3aFBphCAP/YWBgKFYMfDUFJmijOKlw SHlzc/hSIQtl8HZSK9GOsEDWbxpl8uHW1rwhcM1aICNH1bt8XCqEtsMm6 88jDYKiAW6WE7Re6BY9QTvxKexG/q8nOKWpCV+f510YrSH+dlXrLUF7G2 u7wHMrNnxCgjbZzT0v0hNKUVc+VXLzD6XNvOgoxmf4Q9ymR4ECM6ta3Lz w==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="233293921" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="233293921" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:05 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="519735695" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:05 -0800 Subject: [ndctl PATCH 03/37] build: Add tags From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:52:05 -0800 Message-ID: <164298552547.3021641.2951502977152843738.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Copy the systemd approach to generating tags with a file listing from git. Signed-off-by: Dan Williams --- meson.build | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/meson.build b/meson.build index b22fb2e57f6b..68f3d0ceff1c 100644 --- a/meson.build +++ b/meson.build @@ -82,6 +82,7 @@ project_source_root = meson.current_source_dir() # Cleanup the leftover config.h files to avoid conflicts with the meson # generated config.h git = find_program('git', required : false) +env = find_program('env') if git.found() run_command('clean_config.sh', env : 'GIT_DIR=@0@/.git'.format(project_source_root), @@ -111,6 +112,24 @@ else ) endif +if git.found() + all_files = run_command( + env, '-u', 'GIT_WORK_TREE', + git, '--git-dir=@0@/.git'.format(project_source_root), + 'ls-files', ':/*.[ch]', + check : false) + if all_files.returncode() == 0 + all_files = files(all_files.stdout().split()) + custom_target( + 'tags', + output : 'tags', + command : [env, 'etags', '-o', '@0@/TAGS'.format(project_source_root)] + all_files) + run_target( + 'ctags', + command : [env, 'ctags', '-o', '@0@/tags'.format(project_source_root)] + all_files) + endif +endif + versiondep = declare_dependency( compile_args: ['-include', 'version.h'], sources: version_h From patchwork Mon Jan 24 00:52:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721341 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 13275C433EF for ; Mon, 24 Jan 2022 00:52:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240648AbiAXAwL (ORCPT ); Sun, 23 Jan 2022 19:52:11 -0500 Received: from mga03.intel.com ([134.134.136.65]:63513 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240634AbiAXAwK (ORCPT ); Sun, 23 Jan 2022 19:52:10 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985530; x=1674521530; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Tk1yFx6UY7Xg/YMi/NYFjfeJNxMktgdWvvkVGqFzrQw=; b=M4HNkmPOd7AFS/2t9hniZ5dP0n6LkceQgmHrmsPgLs7ZhkXQXP8XEG0w JtTR4s0Kyea4yS2M+N7BiFxSRIcN2MAA5VVCRr7YvYlSMusBOZWyqY6CA e6hCLhf1jql/cO9H/WXoTZwqpQw09lvJRYG1krsHdNV1+hg6YqIX5JdlJ wkrD5qdXtz+R7l7o41qBEXghkxBaXqnYUyVfx4EPP79Txpg9WqRknulLH cSRzo9ZRKnTuqXLSmrNTViwxmFFzQYly/xWEi9LKJizuZO5rfgWiLdAmw /RbD4gwCp2jp5lsrxFMQntD8dPRqhR4a/sfgx5ANTaKwYb12yYw4hTaEj A==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="245880848" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="245880848" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:10 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="478866108" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:10 -0800 Subject: [ndctl PATCH 04/37] json: Add support for json_object_new_uint64() From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:52:10 -0800 Message-ID: <164298553057.3021641.17232869374733997747.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Recent versions of json-c add a proper u64 type. However since ndctl still needs to build against older json-c add build infrastructure to fallback to s64. Signed-off-by: Dan Williams --- config.h.meson | 3 +++ cxl/json.c | 6 +++--- daxctl/json.c | 2 +- meson.build | 6 ++++++ ndctl/dimm.c | 2 +- ndctl/json.c | 10 +++++----- util/json.c | 2 +- util/json.h | 13 ++++++++++++- 8 files changed, 32 insertions(+), 12 deletions(-) diff --git a/config.h.meson b/config.h.meson index 98102251b494..2852f1e9cd8b 100644 --- a/config.h.meson +++ b/config.h.meson @@ -88,6 +88,9 @@ /* Define to 1 if you have the `__secure_getenv' function. */ #mesondefine HAVE___SECURE_GETENV +/* Define to 1 if you have json_object_new_uint64 in json-c */ +#mesondefine HAVE_JSON_U64 + /* Define to the sub-directory where libtool stores uninstalled libraries. */ #mesondefine LT_OBJDIR diff --git a/cxl/json.c b/cxl/json.c index e562502d9116..97ed76b65a6b 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -159,17 +159,17 @@ static struct json_object *util_cxl_memdev_health_to_json( } field = cxl_cmd_health_info_get_dirty_shutdowns(cmd); - jobj = json_object_new_int64(field); + jobj = util_json_new_u64(field); if (jobj) json_object_object_add(jhealth, "dirty_shutdowns", jobj); field = cxl_cmd_health_info_get_volatile_errors(cmd); - jobj = json_object_new_int64(field); + jobj = util_json_new_u64(field); if (jobj) json_object_object_add(jhealth, "volatile_errors", jobj); field = cxl_cmd_health_info_get_pmem_errors(cmd); - jobj = json_object_new_int64(field); + jobj = util_json_new_u64(field); if (jobj) json_object_object_add(jhealth, "pmem_errors", jobj); diff --git a/daxctl/json.c b/daxctl/json.c index 66a795e2e544..3cbce9dcd651 100644 --- a/daxctl/json.c +++ b/daxctl/json.c @@ -190,7 +190,7 @@ struct json_object *util_daxctl_region_to_json(struct daxctl_region *region, align = daxctl_region_get_align(region); if (align < ULONG_MAX) { - jobj = json_object_new_int64(align); + jobj = util_json_new_u64(align); if (!jobj) goto err; json_object_object_add(jregion, "align", jobj); diff --git a/meson.build b/meson.build index 68f3d0ceff1c..f25ec6c47e7b 100644 --- a/meson.build +++ b/meson.build @@ -241,6 +241,12 @@ foreach ident : ['secure_getenv', '__secure_getenv'] conf.set10('HAVE_' + ident.to_upper(), cc.has_function(ident)) endforeach +conf.set10('HAVE_JSON_U64', + cc.has_function('json_object_new_uint64', + prefix : '''#include ''', + dependencies : json, + ) +) ndctlconf_dir = sysconfdir / 'ndctl.conf.d' ndctlconf = ndctlconf_dir / 'monitor.conf' diff --git a/ndctl/dimm.c b/ndctl/dimm.c index 0f052644a46e..d9718a33b22f 100644 --- a/ndctl/dimm.c +++ b/ndctl/dimm.c @@ -168,7 +168,7 @@ static struct json_object *dump_label_json(struct ndctl_dimm *dimm, break; json_object_object_add(jlabel, "isetcookie", jobj); - jobj = json_object_new_int64(le64_to_cpu(nslabel.lbasize)); + jobj = util_json_new_u64(le64_to_cpu(nslabel.lbasize)); if (!jobj) break; json_object_object_add(jlabel, "lbasize", jobj); diff --git a/ndctl/json.c b/ndctl/json.c index c62e6cae01a9..23bad7fd7445 100644 --- a/ndctl/json.c +++ b/ndctl/json.c @@ -357,7 +357,7 @@ static struct json_object *util_##type##_build_size_array(struct ndctl_##type *a int64_t align; \ \ align = get_elem(arg, i); \ - jobj = json_object_new_int64(align); \ + jobj = util_json_new_u64(align); \ if (!jobj) \ goto err; \ json_object_array_add(arr, jobj); \ @@ -550,7 +550,7 @@ struct json_object *util_region_badblocks_to_json(struct ndctl_region *region, if (!jbb) goto err_array; - jobj = json_object_new_int64(bb->offset); + jobj = util_json_new_u64(bb->offset); if (!jobj) goto err; json_object_object_add(jbb, "offset", jobj); @@ -604,7 +604,7 @@ static struct json_object *util_namespace_badblocks_to_json( if (!jbb) goto err_array; - jobj = json_object_new_int64(bb->offset); + jobj = util_json_new_u64(bb->offset); if (!jobj) goto err; json_object_object_add(jbb, "offset", jobj); @@ -682,7 +682,7 @@ static struct json_object *dev_badblocks_to_json(struct ndctl_region *region, if (!jbb) goto err_array; - jobj = json_object_new_int64(offset); + jobj = util_json_new_u64(offset); if (!jobj) goto err; json_object_object_add(jbb, "offset", jobj); @@ -972,7 +972,7 @@ struct json_object *util_namespace_to_json(struct ndctl_namespace *ndns, } if (align) { - jobj = json_object_new_int64(align); + jobj = util_json_new_u64(align); if (!jobj) goto err; json_object_object_add(jndns, "align", jobj); diff --git a/util/json.c b/util/json.c index 9f0a8e137caa..bd5f8fc47a2b 100644 --- a/util/json.c +++ b/util/json.c @@ -82,7 +82,7 @@ struct json_object *util_json_object_size(unsigned long long size, struct json_object *util_json_object_hex(unsigned long long val, unsigned long flags) { - struct json_object *jobj = json_object_new_int64(val); + struct json_object *jobj = util_json_new_u64(val); if (jobj && (flags & UTIL_JSON_HUMAN)) json_object_set_serializer(jobj, display_hex, NULL, NULL); diff --git a/util/json.h b/util/json.h index 4ca2c890fa5c..061f0d423158 100644 --- a/util/json.h +++ b/util/json.h @@ -4,6 +4,7 @@ #define __UTIL_JSON_H__ #include #include +#include enum util_json_flags { UTIL_JSON_IDLE = (1 << 0), @@ -19,11 +20,21 @@ enum util_json_flags { UTIL_JSON_HEALTH = (1 << 10), }; -struct json_object; void util_display_json_array(FILE *f_out, struct json_object *jarray, unsigned long flags); struct json_object *util_json_object_size(unsigned long long size, unsigned long flags); struct json_object *util_json_object_hex(unsigned long long val, unsigned long flags); +#if HAVE_JSON_U64 +static inline struct json_object *util_json_new_u64(unsigned long long val) +{ + return json_object_new_uint64(val); +} +#else /* fallback to signed */ +static inline struct json_object *util_json_new_u64(unsigned long long val) +{ + return json_object_new_int64(val); +} +#endif /* HAVE_JSON_U64 */ #endif /* __UTIL_JSON_H__ */ From patchwork Mon Jan 24 00:52:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721342 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 BB2E9C433EF for ; Mon, 24 Jan 2022 00:52:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240646AbiAXAwQ (ORCPT ); Sun, 23 Jan 2022 19:52:16 -0500 Received: from mga06.intel.com ([134.134.136.31]:17039 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240634AbiAXAwQ (ORCPT ); Sun, 23 Jan 2022 19:52:16 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985535; x=1674521535; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Tl0B76NhTuz3dgMGjXjwas0s1oooQWVjsPp0B7rfZ+c=; b=V430JhHgezfj24wA97bQT3sQDg/1csiwMDkRv2kEGR4fdpXxDAWChzxq ZuAwtFBOj3hLNEAUhT0ekOhH/VUqEe0ChkhR0n8ilxHS7eUwRI/Lb9kYd rUC50WAAgNv/Mp3fsB41vVWWgMIDR382rlyj6syQp2JEu9bF7qC1gjbZu lBhwu1pCchwcfGETimWt03bK3b7vhNMv7cy0pwj/ejUXHWABku5EmC90T Enl5ksswLYJBVMdK66X7OjtK0QOubQa+BQykGXn+2KDB7d764sPz5A8Zz KkQIdeceBTZCDYwlwm4Cs9xM6MDThJFOZVR0ngRL80ua84MIjwNFiNSiH Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="306652113" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="306652113" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:15 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="476540359" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:15 -0800 Subject: [ndctl PATCH 05/37] cxl/json: Cleanup object leak false positive From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:52:15 -0800 Message-ID: <164298553566.3021641.11858634436119663877.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org As written it is a leak of the json object to return if devname is NULL. However, the devname can not be NULL because the memdev would not have been enumerated. Drop the error checking. Signed-off-by: Dan Williams --- cxl/json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cxl/json.c b/cxl/json.c index 97ed76b65a6b..3ef9f7670510 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -190,7 +190,7 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev, struct json_object *jdev, *jobj; jdev = json_object_new_object(); - if (!devname || !jdev) + if (!jdev) return NULL; jobj = json_object_new_string(devname); From patchwork Mon Jan 24 00:52:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721343 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 7CD22C433F5 for ; Mon, 24 Jan 2022 00:52:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240649AbiAXAwV (ORCPT ); Sun, 23 Jan 2022 19:52:21 -0500 Received: from mga05.intel.com ([192.55.52.43]:8699 "EHLO mga05.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240634AbiAXAwV (ORCPT ); Sun, 23 Jan 2022 19:52:21 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985541; x=1674521541; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=gIl0LMGiyWB84AFs7TueUh77sY+5EatOxuI43f2vfPE=; b=kpr3RKNz/buLeF4yE5fXyAHt6ace+9vjAVXNU2JHNbrBJalfcorgLvBp pyPMaevfvTQzJ/HiWxvSbty7QK11Ayi8uRu0IpdRNfnS+29W30+yI3OTT d3nIZ4d3BXoYKWXwBGPYvAWYkVMTJtqomNg3LfjRRwpLeifH6ReXMZMBF cuY21M7dbbxO/VfVRwj45r60rSOhgjl1ioaZ0RMDRtw1o/l8+Q7Rnse/E vhAFT1WS38Dy4bw/Kg5noYDQIgxDHH8XfZYyBVXA/w5QWyUtM3obxrGkg ShHt/t3LYzEyJj0r9cSksmq7GM78sE7h2fMz2SaJx4bIpNrTjevUaCEp5 g==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="332290506" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="332290506" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:21 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="673456327" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:21 -0800 Subject: [ndctl PATCH 06/37] cxl/list: Support multiple memdev device name filter arguments From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:52:20 -0800 Message-ID: <164298554075.3021641.17678360870961637912.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Similar to 'ndctl list', allow for a syntax like: cxl list -m "$(seq -s ' ' 2 5)" ...to filter the output to just those 4 memdevs. Signed-off-by: Dan Williams --- Documentation/cxl/cxl-list.txt | 21 ++++++++++++++++++++- cxl/filter.c | 38 +++++++++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index c8d10fb5ef86..686e0ea768f0 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -30,7 +30,7 @@ OPTIONS ------- -m:: --memdev=:: - Specify a cxl memory device name to filter the listing. For example: + Specify CXL memory device name(s), or device id(s), to filter the listing. For example: ---- # cxl list --memdev=mem0 { @@ -38,6 +38,25 @@ OPTIONS "pmem_size":268435456, "ram_size":0, } + +# cxl list -m "0 mem1 2" +[ + { + "memdev":"mem0", + "pmem_size":268435456, + "ram_size":0 + }, + { + "memdev":"mem2", + "pmem_size":268435456, + "ram_size":268435456 + }, + { + "memdev":"mem1", + "pmem_size":268435456, + "ram_size":268435456 + } +] ---- -M:: diff --git a/cxl/filter.c b/cxl/filter.c index 21322ed4b4d0..efafaf5a3197 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -2,24 +2,40 @@ // Copyright (C) 2015-2020 Intel Corporation. All rights reserved. #include #include +#include #include #include "filter.h" struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, - const char *ident) + const char *__ident) { - int memdev_id; + char *ident, *save; + const char *name; + int memdev_id; - if (!ident || strcmp(ident, "all") == 0) - return memdev; + if (!__ident) + return memdev; - if (strcmp(ident, cxl_memdev_get_devname(memdev)) == 0) - return memdev; + ident = strdup(__ident); + if (!ident) + return NULL; - if ((sscanf(ident, "%d", &memdev_id) == 1 - || sscanf(ident, "mem%d", &memdev_id) == 1) - && cxl_memdev_get_id(memdev) == memdev_id) - return memdev; + for (name = strtok_r(ident, " ", &save); name; + name = strtok_r(NULL, " ", &save)) { + if (strcmp(name, "all") == 0) + break; - return NULL; + if ((sscanf(name, "%d", &memdev_id) == 1 || + sscanf(name, "mem%d", &memdev_id) == 1) && + cxl_memdev_get_id(memdev) == memdev_id) + break; + + if (strcmp(name, cxl_memdev_get_devname(memdev)) == 0) + break; + } + + free(ident); + if (name) + return memdev; + return NULL; } From patchwork Mon Jan 24 00:52:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721344 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 99803C433F5 for ; Mon, 24 Jan 2022 00:52:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240651AbiAXAw2 (ORCPT ); Sun, 23 Jan 2022 19:52:28 -0500 Received: from mga01.intel.com ([192.55.52.88]:60680 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240634AbiAXAw0 (ORCPT ); Sun, 23 Jan 2022 19:52:26 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985546; x=1674521546; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ZNGHY0cT9LQDpRcqY5thPwqY3sGbSI02GaDkgIUyU8w=; b=QCadECg11/R17m5yQCPA/3riYKgBvE55NLfHa2UG1JBLFOet3nM1/yv/ pJDnksAJ7aQAlwgt7zNMEcHm69IG4sJi0Wq4/kAE1GlwLARl2uVM6jyEl X4rLr4+YQwaAFJw7HcMItrX8SeGI0dXf7aONCqQS4eBY8S5OemnX5cE7j pKapAZRwhZGoU32mdnBf92yI02ZXMsG9td7vt5yrWp3ARxsdj7i9zcw6Z 5S5qQmst/gpgYSE6TVK6d6D3S1zW4ADJE02EAgj96G1XKgtELjAGn07f1 hy2rBIvFHMXcVlLL8sxFTJWSVcfs9Rut+HSOgCNCu8bJ7/adUH9nboHbu Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="270369960" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="270369960" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:26 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="627309169" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:26 -0800 Subject: [ndctl PATCH 07/37] cxl/list: Support comma separated lists From: Dan Williams To: linux-cxl@vger.kernel.org Cc: Vishal Verma Date: Sun, 23 Jan 2022 16:52:26 -0800 Message-ID: <164298554612.3021641.3315920699556984273.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org In addition to supporting a syntax like: cxl list -m "0 1 2" ...support: cxl list -m 0,1,2 Reported-by: Vishal Verma Signed-off-by: Dan Williams --- cxl/filter.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cxl/filter.c b/cxl/filter.c index efafaf5a3197..405b653d80b2 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -6,6 +6,15 @@ #include #include "filter.h" +static const char *which_sep(const char *filter) +{ + if (strchr(filter, ' ')) + return " "; + if (strchr(filter, ',')) + return ","; + return " "; +} + struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, const char *__ident) { @@ -20,8 +29,8 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, if (!ident) return NULL; - for (name = strtok_r(ident, " ", &save); name; - name = strtok_r(NULL, " ", &save)) { + for (name = strtok_r(ident, which_sep(__ident), &save); name; + name = strtok_r(NULL, which_sep(__ident), &save)) { if (strcmp(name, "all") == 0) break; From patchwork Mon Jan 24 00:52:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721345 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 E36F1C433F5 for ; Mon, 24 Jan 2022 00:52:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240650AbiAXAwf (ORCPT ); Sun, 23 Jan 2022 19:52:35 -0500 Received: from mga11.intel.com ([192.55.52.93]:50209 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240634AbiAXAwb (ORCPT ); Sun, 23 Jan 2022 19:52:31 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985551; x=1674521551; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=NF2XknFo78Bj2VyYzMjDGENQQPGTTQUgtgoGrzfXLiQ=; b=IZJZcRN1fQHXhZ8QTsm71j4EVk/aUT2a6OpgkdSNzm0O40bL5reiNWnI pCWfStAa56qFSmig8nnTFn0eI/0G7mjsfc3ei2Lk13EKzRoJFe5Kt8Jni lR/Lo67ZzBu66+p+5wpEU4zoUNq7YS4Pv82AOxfU26ut9MXWVYOMerYL5 XVgLn6nadOx/IK7LvIFmaN9S/pGSgwytrbVb5A8OM8t4SvQVkTt9eJnN5 uJgn+6ytOcl4/beEetimMaFTS+MbmBYS4H84yQF7lS/7fWM71VJDgoDMU lEfqyMjaRzFYWAOhW3sampcYTmiFRY+Uu74UUshxbjHuLheZ6eIj74oKI w==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="243530535" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="243530535" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:31 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="695243342" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:31 -0800 Subject: [ndctl PATCH 08/37] cxl/list: Introduce cxl_filter_walk() From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:52:31 -0800 Message-ID: <164298555121.3021641.16127840206319352254.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org In preparation for introducing more objects and filtering options for 'cxl list' introduce cxl_filter_walk() to centralize CXL topology walks. It fills the same role as ndctl_filter_walk() as a way to distribute topology interrogation beyond 'cxl list' to other commands, and serve as the template for CXL object hierarchy in JSON output payloads. Use the common dbg() logger for log messages. Signed-off-by: Dan Williams --- Documentation/cxl/cxl-list.txt | 2 + cxl/filter.c | 50 ++++++++++++++++++++ cxl/filter.h | 18 ++++++- cxl/list.c | 102 ++++++++-------------------------------- cxl/meson.build | 1 5 files changed, 90 insertions(+), 83 deletions(-) diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index 686e0ea768f0..4d409babb99a 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -15,6 +15,8 @@ SYNOPSIS Walk the CXL capable device hierarchy in the system and list all device instances along with some of their major attributes. +Options can be specified to limit the output to specific objects. + EXAMPLE ------- ---- diff --git a/cxl/filter.c b/cxl/filter.c index 405b653d80b2..d1ff4b62c806 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -1,10 +1,16 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2015-2020 Intel Corporation. All rights reserved. +#include #include #include #include +#include +#include #include +#include + #include "filter.h" +#include "json.h" static const char *which_sep(const char *filter) { @@ -48,3 +54,47 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, return memdev; return NULL; } + +static unsigned long params_to_flags(struct cxl_filter_params *param) +{ + unsigned long flags = 0; + + if (param->idle) + flags |= UTIL_JSON_IDLE; + if (param->human) + flags |= UTIL_JSON_HUMAN; + if (param->health) + flags |= UTIL_JSON_HEALTH; + return flags; +} + +int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) +{ + struct json_object *jplatform = json_object_new_array(); + unsigned long flags = params_to_flags(p); + struct cxl_memdev *memdev; + + if (!jplatform) { + dbg(p, "platform object allocation failure\n"); + return -ENOMEM; + } + + cxl_memdev_foreach(ctx, memdev) { + struct json_object *jdev; + + if (!util_cxl_memdev_filter(memdev, p->memdev_filter)) + continue; + if (p->memdevs) { + jdev = util_cxl_memdev_to_json(memdev, flags); + if (!jdev) { + dbg(p, "memdev object allocation failure\n"); + continue; + } + json_object_array_add(jplatform, jdev); + } + } + + util_display_json_array(stdout, jplatform, flags); + + return 0; +} diff --git a/cxl/filter.h b/cxl/filter.h index da800336b528..664b74b23b0a 100644 --- a/cxl/filter.h +++ b/cxl/filter.h @@ -1,7 +1,21 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */ +/* Copyright (C) 2021 Intel Corporation. All rights reserved. */ #ifndef _CXL_UTIL_FILTER_H_ #define _CXL_UTIL_FILTER_H_ + +#include +#include + +struct cxl_filter_params { + const char *memdev_filter; + bool memdevs; + bool idle; + bool human; + bool health; + struct log_ctx ctx; +}; + struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, - const char *ident); + const char *ident); +int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param); #endif /* _CXL_UTIL_FILTER_H_ */ diff --git a/cxl/list.c b/cxl/list.c index 7f7a04d9a6e5..17303073b49a 100644 --- a/cxl/list.c +++ b/cxl/list.c @@ -9,60 +9,27 @@ #include #include #include -#include -#include "json.h" #include "filter.h" -static struct { - bool memdevs; - bool idle; - bool human; - bool health; -} list; - -static unsigned long listopts_to_flags(void) -{ - unsigned long flags = 0; - - if (list.idle) - flags |= UTIL_JSON_IDLE; - if (list.human) - flags |= UTIL_JSON_HUMAN; - if (list.health) - flags |= UTIL_JSON_HEALTH; - return flags; -} - -static struct { - const char *memdev; -} param; - -static int did_fail; - -#define fail(fmt, ...) \ -do { \ - did_fail = 1; \ - fprintf(stderr, "cxl-%s:%s:%d: " fmt, \ - VERSION, __func__, __LINE__, ##__VA_ARGS__); \ -} while (0) +static struct cxl_filter_params param; static int num_list_flags(void) { - return list.memdevs; + return param.memdevs; } int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) { const struct option options[] = { - OPT_STRING('m', "memdev", ¶m.memdev, "memory device name", + OPT_STRING('m', "memdev", ¶m.memdev_filter, "memory device name", "filter by CXL memory device name"), - OPT_BOOLEAN('M', "memdevs", &list.memdevs, + OPT_BOOLEAN('M', "memdevs", ¶m.memdevs, "include CXL memory device info"), - OPT_BOOLEAN('i', "idle", &list.idle, "include idle devices"), - OPT_BOOLEAN('u', "human", &list.human, + OPT_BOOLEAN('i', "idle", ¶m.idle, "include disabled devices"), + OPT_BOOLEAN('u', "human", ¶m.human, "use human friendly number formats "), - OPT_BOOLEAN('H', "health", &list.health, + OPT_BOOLEAN('H', "health", ¶m.health, "include memory device health information "), OPT_END(), }; @@ -70,9 +37,6 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) "cxl list []", NULL }; - struct json_object *jdevs = NULL; - unsigned long list_flags; - struct cxl_memdev *memdev; int i; argc = parse_options(argc, argv, options, u, 0); @@ -83,46 +47,22 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) usage_with_options(u, options); 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); - } - - list_flags = listopts_to_flags(); - - cxl_memdev_foreach(ctx, memdev) { - struct json_object *jdev = NULL; - - if (!util_cxl_memdev_filter(memdev, param.memdev)) - continue; - - if (list.memdevs) { - if (!jdevs) { - jdevs = json_object_new_array(); - if (!jdevs) { - fail("\n"); - continue; - } - } - - jdev = util_cxl_memdev_to_json(memdev, list_flags); - if (!jdev) { - fail("\n"); - continue; - } - json_object_array_add(jdevs, jdev); + if (param.memdev_filter) + param.memdevs = true; + else { + /* + * 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); } } - if (jdevs) - util_display_json_array(stdout, jdevs, list_flags); + log_init(¶m.ctx, "cxl list", "CXL_LIST_LOG"); - if (did_fail) - return -ENOMEM; - return 0; + return cxl_filter_walk(ctx, ¶m); } diff --git a/cxl/meson.build b/cxl/meson.build index 805924b9df9b..fc7ee71b54f0 100644 --- a/cxl/meson.build +++ b/cxl/meson.build @@ -3,6 +3,7 @@ cxl_src = [ 'list.c', 'memdev.c', '../util/json.c', + '../util/log.c', 'json.c', 'filter.c', ] From patchwork Mon Jan 24 00:52:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721346 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 B84A4C433EF for ; Mon, 24 Jan 2022 00:52:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240652AbiAXAwh (ORCPT ); Sun, 23 Jan 2022 19:52:37 -0500 Received: from mga05.intel.com ([192.55.52.43]:8720 "EHLO mga05.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240634AbiAXAwg (ORCPT ); Sun, 23 Jan 2022 19:52:36 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985556; x=1674521556; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=zRZhMssWva2iAQrYOI28+YnglDuqKCXKGQfcfBO/qLw=; b=gbUGN5a3HVZJ/cc8WTYaCv8A/NOCVk2ccPnl0ZPfxdmEm1CS6D+tlP4h hcSgJ9Zh6RyE5JAsBZVgU+OD/MSTG2I6IHEUvDXOEo2d72M2MNwOp7YTp WTnD5ktaXqrvLpGr9fKuRk0/CzimrlkQA6/lXgU/WPUQm7TuwOMTTB8/J XKdOV1jgmO7FzzBPKQU4p1Tc2OfRMiAP4rjrNRtvj5uXAfSMAnR7n9Emx QOr5Br5nB30LwVjMW/dJ1qJAKrDm2lLOIYo4kj+kjTYwYfDuydNqQAp+Q eAW5KW/TIVElKbw/XVehPZraSEbKTMxGTGmuP+eLqjIA4yz56IGJEvoE9 w==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="332290515" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="332290515" Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:36 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="766233178" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:36 -0800 Subject: [ndctl PATCH 09/37] cxl/list: Emit device serial numbers From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:52:36 -0800 Message-ID: <164298555630.3021641.3246226448369816200.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Starting with the v5.17 kernel the CXL driver emits the mandatory device serial number for each memory device. Include it in the memory device listing. Signed-off-by: Dan Williams --- Documentation/cxl/cxl-list.txt | 15 +++++++++------ cxl/json.c | 11 ++++++++++- cxl/lib/libcxl.c | 11 +++++++++++ cxl/lib/libcxl.sym | 5 +++++ cxl/lib/private.h | 1 + cxl/libcxl.h | 1 + 6 files changed, 37 insertions(+), 7 deletions(-) diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index 4d409babb99a..bd0207e942cb 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -41,22 +41,25 @@ OPTIONS "ram_size":0, } -# cxl list -m "0 mem1 2" +# cxl list -M --memdev="0 mem3 5" [ { "memdev":"mem0", "pmem_size":268435456, - "ram_size":0 + "ram_size":0, + "serial":0 }, { - "memdev":"mem2", + "memdev":"mem3", "pmem_size":268435456, - "ram_size":268435456 + "ram_size":268435456, + "serial":2 }, { - "memdev":"mem1", + "memdev":"mem5", "pmem_size":268435456, - "ram_size":268435456 + "ram_size":268435456, + "serial":4 } ] ---- diff --git a/cxl/json.c b/cxl/json.c index 3ef9f7670510..d8e65df241a1 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2015-2020 Intel Corporation. All rights reserved. +// Copyright (C) 2015-2021 Intel Corporation. All rights reserved. +#include #include #include #include @@ -188,6 +189,7 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev, { const char *devname = cxl_memdev_get_devname(memdev); struct json_object *jdev, *jobj; + unsigned long long serial; jdev = json_object_new_object(); if (!jdev) @@ -210,5 +212,12 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev, if (jobj) json_object_object_add(jdev, "health", jobj); } + + serial = cxl_memdev_get_serial(memdev); + if (serial < ULLONG_MAX) { + jobj = util_json_object_hex(serial, flags); + if (jobj) + json_object_object_add(jdev, "serial", jobj); + } return jdev; } diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 3390eb91ecb5..8d3cf8092c8b 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -296,6 +296,12 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base) if (memdev->lsa_size == ULLONG_MAX) goto err_read; + sprintf(path, "%s/serial", cxlmem_base); + if (sysfs_read_attr(ctx, path, buf) < 0) + memdev->serial = ULLONG_MAX; + else + memdev->serial = strtoull(buf, NULL, 0); + memdev->dev_path = strdup(cxlmem_base); if (!memdev->dev_path) goto err_read; @@ -371,6 +377,11 @@ CXL_EXPORT int cxl_memdev_get_id(struct cxl_memdev *memdev) return memdev->id; } +CXL_EXPORT unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev) +{ + return memdev->serial; +} + CXL_EXPORT const char *cxl_memdev_get_devname(struct cxl_memdev *memdev) { return devpath_to_devname(memdev->dev_path); diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 077d10434cde..4411035f962a 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -73,3 +73,8 @@ global: local: *; }; + +LIBCXL_2 { +global: + cxl_memdev_get_serial; +} LIBCXL_1; diff --git a/cxl/lib/private.h b/cxl/lib/private.h index a1b8b507225e..28f7e16dbd04 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -31,6 +31,7 @@ struct cxl_memdev { size_t lsa_size; struct kmod_module *module; struct cxl_nvdimm_bridge *bridge; + unsigned long long serial; }; enum cxl_cmd_query_status { diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 89d35ba957e6..bcdede8f12e8 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -35,6 +35,7 @@ struct cxl_memdev; struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx); struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev); int cxl_memdev_get_id(struct cxl_memdev *memdev); +unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev); const char *cxl_memdev_get_devname(struct cxl_memdev *memdev); int cxl_memdev_get_major(struct cxl_memdev *memdev); int cxl_memdev_get_minor(struct cxl_memdev *memdev); From patchwork Mon Jan 24 00:52:41 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721347 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 EF192C433EF for ; Mon, 24 Jan 2022 00:52:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240653AbiAXAwm (ORCPT ); Sun, 23 Jan 2022 19:52:42 -0500 Received: from mga04.intel.com ([192.55.52.120]:43260 "EHLO mga04.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240634AbiAXAwm (ORCPT ); Sun, 23 Jan 2022 19:52:42 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985562; x=1674521562; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=7zMNhRBjiTSQdaDY2CzV/22LPa2Lkl0nVWHtOQVMAIA=; b=FcV5/0lO1iKzSky4bjFNSOVDPDHZytydphBN3khMB3e1u+t5Mx3cF0+E ZHQeDQA8LlRPpjxzRvmUawjho9TDifnAzgkFAk5EI7WBr9zE20EHCrHDr aMA4qPXFI2usxobwmmeOjyeVmiHBn+6ZjvmLEp4rGBCN3jAaCP08VPQ30 oFl331VxBeqWaMnR0d8NJv7q8lOkwYORDC9oGHqDmuCVPoRcvzq/K/+Dk jwcS74OqmtCKjDsLgvpflrnmCpyxRiP3de/7x63Z4Xaw4bCIrF5AdHd6r dXpjIba/zIloVRQ+gK8OER8KS9IPi2ejP0ZEUjoTA484A+FTiEVQNFbv0 A==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="244768252" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="244768252" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:42 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="596630632" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:41 -0800 Subject: [ndctl PATCH 10/37] cxl/list: Add filter by serial support From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:52:41 -0800 Message-ID: <164298556167.3021641.5470955268978068465.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Given that serial numbers are intended to be unique device identifiers, enable them as a memdev filter option. Signed-off-by: Dan Williams --- Documentation/cxl/cxl-list.txt | 4 ++++ cxl/filter.c | 38 ++++++++++++++++++++++++++++++++++---- cxl/filter.h | 4 +++- cxl/list.c | 4 +++- cxl/memdev.c | 2 +- 5 files changed, 45 insertions(+), 7 deletions(-) diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index bd0207e942cb..224c972498ea 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -64,6 +64,10 @@ OPTIONS ] ---- +-s:: +--serial=:: + Specify CXL memory device serial number(s) to filter the listing + -M:: --memdevs:: Include CXL memory devices in the listing diff --git a/cxl/filter.c b/cxl/filter.c index d1ff4b62c806..26efc65f4dd7 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -21,15 +21,45 @@ static const char *which_sep(const char *filter) return " "; } +static struct cxl_memdev * +util_cxl_memdev_serial_filter(struct cxl_memdev *memdev, const char *__serials) +{ + unsigned long long serial = 0; + char *serials, *save, *end; + const char *arg; + + if (!__serials) + return memdev; + + serials = strdup(__serials); + if (!serials) + return NULL; + + for (arg = strtok_r(serials, which_sep(__serials), &save); arg; + arg = strtok_r(NULL, which_sep(__serials), &save)) { + serial = strtoull(arg, &end, 0); + if (!arg[0] || end[0] != 0) + continue; + if (cxl_memdev_get_serial(memdev) == serial) + break; + } + + free(serials); + if (arg) + return memdev; + return NULL; +} + struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, - const char *__ident) + const char *__ident, + const char *serials) { char *ident, *save; const char *name; int memdev_id; if (!__ident) - return memdev; + return util_cxl_memdev_serial_filter(memdev, serials); ident = strdup(__ident); if (!ident) @@ -51,7 +81,7 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, free(ident); if (name) - return memdev; + return util_cxl_memdev_serial_filter(memdev, serials); return NULL; } @@ -82,7 +112,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) cxl_memdev_foreach(ctx, memdev) { struct json_object *jdev; - if (!util_cxl_memdev_filter(memdev, p->memdev_filter)) + if (!util_cxl_memdev_filter(memdev, p->memdev_filter, p->serial_filter)) continue; if (p->memdevs) { jdev = util_cxl_memdev_to_json(memdev, flags); diff --git a/cxl/filter.h b/cxl/filter.h index 664b74b23b0a..12d934474554 100644 --- a/cxl/filter.h +++ b/cxl/filter.h @@ -8,6 +8,7 @@ struct cxl_filter_params { const char *memdev_filter; + const char *serial_filter; bool memdevs; bool idle; bool human; @@ -16,6 +17,7 @@ struct cxl_filter_params { }; struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, - const char *ident); + const char *__ident, + const char *serials); int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param); #endif /* _CXL_UTIL_FILTER_H_ */ diff --git a/cxl/list.c b/cxl/list.c index 17303073b49a..6bc48df0ea84 100644 --- a/cxl/list.c +++ b/cxl/list.c @@ -24,6 +24,8 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) const struct option options[] = { OPT_STRING('m', "memdev", ¶m.memdev_filter, "memory device name", "filter by CXL memory device name"), + OPT_STRING('s', "serial", ¶m.serial_filter, "memory device serial", + "filter by CXL memory device serial number"), OPT_BOOLEAN('M', "memdevs", ¶m.memdevs, "include CXL memory device info"), OPT_BOOLEAN('i', "idle", ¶m.idle, "include disabled devices"), @@ -47,7 +49,7 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) usage_with_options(u, options); if (num_list_flags() == 0) { - if (param.memdev_filter) + if (param.memdev_filter || param.serial_filter) param.memdevs = true; else { /* diff --git a/cxl/memdev.c b/cxl/memdev.c index d063d51cc571..b9141be62c87 100644 --- a/cxl/memdev.c +++ b/cxl/memdev.c @@ -248,7 +248,7 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx, continue; cxl_memdev_foreach (ctx, memdev) { - if (!util_cxl_memdev_filter(memdev, argv[i])) + if (!util_cxl_memdev_filter(memdev, argv[i], NULL)) continue; if (action == action_write) { From patchwork Mon Jan 24 00:52:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721348 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 D16B2C433F5 for ; Mon, 24 Jan 2022 00:52:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240654AbiAXAws (ORCPT ); Sun, 23 Jan 2022 19:52:48 -0500 Received: from mga09.intel.com ([134.134.136.24]:11532 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240634AbiAXAws (ORCPT ); Sun, 23 Jan 2022 19:52:48 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985568; x=1674521568; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=zWYipVByTuY3zBAnr0pn5fQsJ62AcQBWrPkSpJwd+6I=; b=lWAP6FD2bSVkal1lMg7mw9rnydIP+TnK/x601VfjlIxZynFh1R59WX4J GEvujwY3OnXrs6hw8yCuUVUXQMYo4BrwbGEEbobKE5F/n1DBrPlk9WCvT WqemmD6/DaIN+WUsx/+Y+Hpx9d/ENn8caA3kS55ScN7B+FqLTRlGHyUp+ TuBf171xR+tD9s4v5dxLSU7ulGaq0MRlJ+o6AES5yCOr431uzqPsyIGQq jE4k71K9Lvn8d2iP48TY37ELA2ThNiAYrrya6ofhPlF8LKCZyyT3mOXRC aFe9nG3Gaj9rA+EtUf1QBuQHHR2TqsGYLk/VtbGWzujGlgedF0XUGIY1G A==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="245716854" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="245716854" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:47 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="673456353" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:47 -0800 Subject: [ndctl PATCH 11/37] cxl/lib: Rename nvdimm bridge to pmem From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:52:47 -0800 Message-ID: <164298556712.3021641.15612755067301105130.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org The kernel has 2 object classes for connecting CXL to NVDIMM. There is an 'nvdimm-bridge' object (one per root CXL port) that represents a CXL NVDIMM Bus, and there are 'pmem' object that represent CXL NVDIMM DIMM devices. The object that the library is currently calling an nvdimm-bridge is actually the 'pmem' object. Rename accordingly. The exported function cxl_memdev_nvdimm_bridge_active() is not renamed, but since it is a cxl_memdev operation and 'struct cxl_pmem' is an implementation detail it is fine as is. Signed-off-by: Dan Williams --- cxl/lib/libcxl.c | 56 +++++++++++++++++++++++++++-------------------------- cxl/lib/private.h | 4 ++-- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 8d3cf8092c8b..9839f26f9507 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -45,11 +45,11 @@ struct cxl_ctx { void *private_data; }; -static void free_bridge(struct cxl_nvdimm_bridge *bridge) +static void free_pmem(struct cxl_pmem *pmem) { - free(bridge->dev_buf); - free(bridge->dev_path); - free(bridge); + free(pmem->dev_buf); + free(pmem->dev_path); + free(pmem); } static void free_memdev(struct cxl_memdev *memdev, struct list_head *head) @@ -57,7 +57,7 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head) if (head) list_del_from(head, &memdev->list); kmod_module_unref(memdev->module); - free_bridge(memdev->bridge); + free_pmem(memdev->pmem); free(memdev->firmware_version); free(memdev->dev_buf); free(memdev->dev_path); @@ -213,36 +213,36 @@ CXL_EXPORT void cxl_set_log_priority(struct cxl_ctx *ctx, int priority) ctx->ctx.log_priority = priority; } -static void *add_cxl_bridge(void *parent, int id, const char *br_base) +static void *add_cxl_pmem(void *parent, int id, const char *br_base) { const char *devname = devpath_to_devname(br_base); struct cxl_memdev *memdev = parent; struct cxl_ctx *ctx = memdev->ctx; - struct cxl_nvdimm_bridge *bridge; + struct cxl_pmem *pmem; - dbg(ctx, "%s: bridge_base: \'%s\'\n", devname, br_base); + dbg(ctx, "%s: pmem_base: \'%s\'\n", devname, br_base); - bridge = calloc(1, sizeof(*bridge)); - if (!bridge) + pmem = calloc(1, sizeof(*pmem)); + if (!pmem) goto err_dev; - bridge->id = id; + pmem->id = id; - bridge->dev_path = strdup(br_base); - if (!bridge->dev_path) + pmem->dev_path = strdup(br_base); + if (!pmem->dev_path) goto err_read; - bridge->dev_buf = calloc(1, strlen(br_base) + 50); - if (!bridge->dev_buf) + pmem->dev_buf = calloc(1, strlen(br_base) + 50); + if (!pmem->dev_buf) goto err_read; - bridge->buf_len = strlen(br_base) + 50; + pmem->buf_len = strlen(br_base) + 50; - memdev->bridge = bridge; - return bridge; + memdev->pmem = pmem; + return pmem; err_read: - free(bridge->dev_buf); - free(bridge->dev_path); - free(bridge); + free(pmem->dev_buf); + free(pmem->dev_path); + free(pmem); err_dev: return NULL; } @@ -319,7 +319,7 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base) goto err_read; memdev->buf_len = strlen(cxlmem_base) + 50; - sysfs_device_parse(ctx, cxlmem_base, "pmem", memdev, add_cxl_bridge); + sysfs_device_parse(ctx, cxlmem_base, "pmem", memdev, add_cxl_pmem); cxl_memdev_foreach(ctx, memdev_dup) if (memdev_dup->id == memdev->id) { @@ -430,18 +430,18 @@ static int is_enabled(const char *drvpath) CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev) { struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); - struct cxl_nvdimm_bridge *bridge = memdev->bridge; + struct cxl_pmem *pmem = memdev->pmem; char *path; int len; - if (!bridge) + if (!pmem) return 0; - path = bridge->dev_buf; - len = bridge->buf_len; + path = pmem->dev_buf; + len = pmem->buf_len; - if (snprintf(path, len, "%s/driver", bridge->dev_path) >= len) { - err(ctx, "%s: nvdimm bridge buffer too small!\n", + if (snprintf(path, len, "%s/driver", pmem->dev_path) >= len) { + err(ctx, "%s: nvdimm pmem buffer too small!\n", cxl_memdev_get_devname(memdev)); return 0; } diff --git a/cxl/lib/private.h b/cxl/lib/private.h index 28f7e16dbd04..7c81e24a6f79 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -10,7 +10,7 @@ #define CXL_EXPORT __attribute__ ((visibility("default"))) -struct cxl_nvdimm_bridge { +struct cxl_pmem { int id; void *dev_buf; size_t buf_len; @@ -30,7 +30,7 @@ struct cxl_memdev { int payload_max; size_t lsa_size; struct kmod_module *module; - struct cxl_nvdimm_bridge *bridge; + struct cxl_pmem *pmem; unsigned long long serial; }; From patchwork Mon Jan 24 00:52:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721349 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 318C7C433F5 for ; Mon, 24 Jan 2022 00:52:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240655AbiAXAwx (ORCPT ); Sun, 23 Jan 2022 19:52:53 -0500 Received: from mga05.intel.com ([192.55.52.43]:8732 "EHLO mga05.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240634AbiAXAwx (ORCPT ); Sun, 23 Jan 2022 19:52:53 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985573; x=1674521573; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=//x4eGYQcOOr3KJKveLHEa+jKASAHR988xPwtn56it8=; b=c/F67c+pCdhdlfnxPdF7DjkhsehgdyamtygwcV0bMiErO60DmpJsafyw sJFAP3L4OhPiylTyLMNyLzOlfAEmiivS7eGzaq07L72Z9+icDvfm00p4A UwJcduMZ9lVnG9YaGP4+X/oixs+IQ9fKtLeXahd1JVBgeTQAHgkE0epr2 6CPailAK8Djbwt9qC10rBOEEihXA9LEZJk5rFilg0TP7f8Ofwed2bsbze D6+pqbZkenuGJMOF6bkJ4CYYdEvQqQxLB06pn4UPRoCS007yoEUMob48a 7AR1VHSZubIqQ+hBVRnnvVhQmPajoJDhcwrzLGqJEV0931nWfcJYmC+gy Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="332290525" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="332290525" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:52 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="519735780" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:52 -0800 Subject: [ndctl PATCH 12/37] cxl/list: Cleanup options definitions From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:52:52 -0800 Message-ID: <164298557263.3021641.8121105326167408001.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Clarify which options take lists by adding a "(s)" to the object name, and move the option block out of cmd_list() to reduce the column-80 collisions. Signed-off-by: Dan Williams --- cxl/list.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/cxl/list.c b/cxl/list.c index 6bc48df0ea84..7e2744dd8b19 100644 --- a/cxl/list.c +++ b/cxl/list.c @@ -19,22 +19,24 @@ static int num_list_flags(void) return param.memdevs; } +static const struct option options[] = { + OPT_STRING('m', "memdev", ¶m.memdev_filter, "memory device name(s)", + "filter by CXL memory device name(s)"), + OPT_STRING('s', "serial", ¶m.serial_filter, + "memory device serial(s)", + "filter by CXL memory device serial number(s)"), + OPT_BOOLEAN('M', "memdevs", ¶m.memdevs, + "include CXL memory device info"), + OPT_BOOLEAN('i', "idle", ¶m.idle, "include disabled devices"), + OPT_BOOLEAN('u', "human", ¶m.human, + "use human friendly number formats "), + OPT_BOOLEAN('H', "health", ¶m.health, + "include memory device health information "), + OPT_END(), +}; + int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) { - const struct option options[] = { - OPT_STRING('m', "memdev", ¶m.memdev_filter, "memory device name", - "filter by CXL memory device name"), - OPT_STRING('s', "serial", ¶m.serial_filter, "memory device serial", - "filter by CXL memory device serial number"), - OPT_BOOLEAN('M', "memdevs", ¶m.memdevs, - "include CXL memory device info"), - OPT_BOOLEAN('i', "idle", ¶m.idle, "include disabled devices"), - OPT_BOOLEAN('u', "human", ¶m.human, - "use human friendly number formats "), - OPT_BOOLEAN('H', "health", ¶m.health, - "include memory device health information "), - OPT_END(), - }; const char * const u[] = { "cxl list []", NULL From patchwork Mon Jan 24 00:52:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721350 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 C8651C433F5 for ; Mon, 24 Jan 2022 00:53:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240634AbiAXAxA (ORCPT ); Sun, 23 Jan 2022 19:53:00 -0500 Received: from mga12.intel.com ([192.55.52.136]:42135 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240656AbiAXAw6 (ORCPT ); Sun, 23 Jan 2022 19:52:58 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985578; x=1674521578; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Zq2WaiqzPKS/ifBe6Ehti+Vw/s2fGHi8GnHTYg+ORg8=; b=SlTGK7NDgiPe6pN0OlAVqRWDMtgQYS9hqXCZCNhvyv6Bc9QuyIWqk4sY OG4nE8KsjpPdXBFIg1v3NF5Y6zdUkCjHPd7ejvf95k8+OoOofVFkdjldY DqkD8JNX0aVYlR8qMVUqRltt4zxfkPgVoN4eUtoRgmCD7J7gll4kGeOim mptBKgVsAXhX6g8hPoHRrtKR8MMm6M9bBYEmNK0fl+WciMunKl2fIiCLB 7r6vyo6FcaS6wUD2RuCgimS30aR6lSl/TsLMOlK77t65P+AiYYE61GdjN 0DChSb5l1hwEka+0o3XUp68K2jUNT0f9GOd6AqDW8Mply24J4hsrr6zEt Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="225916668" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208,217";a="225916668" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:57 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208,217";a="695243370" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:52:57 -0800 Subject: [ndctl PATCH 13/37] Documentation: Enhance libcxl memdev API documentation From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:52:57 -0800 Message-ID: <164298557771.3021641.14904324834528700206.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org In preparation for adding documentation for more objects, organize the current into subsections and flesh out descriptions for the current APIs. Signed-off-by: Dan Williams --- Documentation/copyright.txt | 2 - Documentation/cxl/lib/libcxl.txt | 111 ++++++++++++++++++++++++++++++++++---- 2 files changed, 99 insertions(+), 14 deletions(-) diff --git a/Documentation/copyright.txt b/Documentation/copyright.txt index a9380e199750..af9caf7ba22a 100644 --- a/Documentation/copyright.txt +++ b/Documentation/copyright.txt @@ -2,7 +2,7 @@ COPYRIGHT --------- -Copyright (C) 2016 - 2020, Intel Corporation. License GPLv2: GNU GPL +Copyright (C) 2016 - 2022, Intel Corporation. License GPLv2: GNU GPL version 2 . This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index 2539369e8111..c127326a2840 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -20,27 +20,100 @@ libcxl provides interfaces to interact with CXL devices in Linux, using sysfs interfaces for most kernel interactions, and the ioctl() interface for command submission. -The starting point for all library interfaces is a 'cxl_ctx' object, returned -by linklibcxl:cxl_new[3]. CXL 'Type 3' memory devices are children of the -cxl_ctx object, and can be iterated through using an iterator API. +The starting point for all library interfaces is a 'cxl_ctx' object, +returned by linklibcxl:cxl_new[3]. CXL 'Type 3' memory devices and other +CXL device objects are descendants of the cxl_ctx object, and can be +iterated via an object an iterator API of the form +cxl__foreach(, ). -Library level interfaces that are agnostic to any device, or a specific -subclass of operations have the prefix 'cxl_' +MEMDEVS +------- +The object representing a CXL memory expander (Type 3 device) is 'struct +cxl_memdev'. Library interfaces related to these devices have the prefix +'cxl_memdev_'. These interfaces are mostly associated with sysfs +interactions (unless otherwise noted in their respective documentation +sections). They are typically used to retrieve data published by the +kernel, or to send data or trigger kernel operations for a given device. -The object representing a CXL Type 3 device is 'cxl_memdev'. Library interfaces -related to these devices have the prefix 'cxl_memdev_'. These interfaces are -mostly associated with sysfs interactions (unless otherwise noted in their -respective documentation pages). They are typically used to retrieve data -published by the kernel, or to send data or trigger kernel operations for a -given device. +=== MEMDEV: Enumeration +---- +struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx); +struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev); +struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev); + +#define cxl_memdev_foreach(ctx, memdev) \ + for (memdev = cxl_memdev_get_first(ctx); \ + memdev != NULL; \ + memdev = cxl_memdev_get_next(memdev)) + +---- + +CXL memdev instances are enumerated from the global library context +'struct cxl_ctx'. By default a memdev only offers a portal to submit +memory device commands, see the port, decoder, and endpoint APIs to +determine what if any CXL Memory Resources are reachable given a +specific memdev. + +=== MEMDEV: Attributes +---- +int cxl_memdev_get_id(struct cxl_memdev *memdev); +unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev); +const char *cxl_memdev_get_devname(struct cxl_memdev *memdev); +int cxl_memdev_get_major(struct cxl_memdev *memdev); +int cxl_memdev_get_minor(struct cxl_memdev *memdev); +unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev); +unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev); +const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev); +size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev); +int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev); +---- + +A memdev is given a kernel device name of the form "mem%d" where an id +(cxl_memdev_get_id()) is dynamically allocated as devices are +discovered. Note that there are no guarantees that ids / kernel device +names for memdevs are stable from one boot to the next, devices are +enumerated asynchronously. If a stable identifier is use +cxl_memdev_get_serial() which returns a value according to the 'Device +Serial Number Extended Capability' in the PCIe 5.0 Base Specification. + +The character device node for command submission can be found by default +at /dev/cxl/mem%d, or created with a major / minor returned from +cxl_memdev_get_{major,minor}(). + +The 'pmem_size' and 'ram_size' attributes return the current +provisioning of DPA (Device Physical Address / local capacity) in the +device. + +=== MEMDEV: Commands +---- +struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode); +struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev); +struct cxl_cmd *cxl_cmd_new_get_health_info(struct cxl_memdev *memdev); +struct cxl_cmd *cxl_cmd_new_read_label(struct cxl_memdev *memdev, + unsigned int offset, unsigned int length); +struct cxl_cmd *cxl_cmd_new_write_label(struct cxl_memdev *memdev, void *buf, + unsigned int offset, unsigned int length); +int cxl_memdev_zero_label(struct cxl_memdev *memdev, size_t length, + size_t offset); +int cxl_memdev_read_label(struct cxl_memdev *memdev, void *buf, size_t length, + size_t offset); +int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf, size_t length, + size_t offset); + +---- A 'cxl_cmd' is a reference counted object which is used to perform 'Mailbox' commands as described in the CXL Specification. A 'cxl_cmd' object is tied to a 'cxl_memdev'. Associated library interfaces have the prefix 'cxl_cmd_'. Within this sub-class of interfaces, there are: - * 'cxl_cmd_new_*' interfaces that allocate a new cxl_cmd object for a given - command type. + * 'cxl_cmd_new_*()' interfaces that allocate a new cxl_cmd object for a given + command type targeted at a given memdev. As part of the command + instantiation process the library validates that the command is + supported by the memory device, otherwise it returns NULL to indicate + 'no support'. The libcxl command id is translated by the kernel into + a CXL standard opcode. See the potential command ids in + /usr/include/linux/cxl_mem.h. * 'cxl_cmd_submit' which submits the command via ioctl() @@ -49,6 +122,18 @@ this sub-class of interfaces, there are: * 'cxl_cmd_get_*' interfaces to get general command related information. +cxl_cmd_new_raw() supports so called 'RAW' commands where the command id +is 'RAW' and it carries an unmodified CXL memory device command payload +associated with the 'opcode' argument. Given the kernel does minimal +input validation on these commands typically raw commands are not +supported by the kernel outside debug build scenarios. libcxl is limited +to supporting commands that appear in the CXL standard / public +specifications. + +cxl_memdev{read,write,zero}_label() are helpers for marshaling multiple +label access commands over an arbitrary extent of the device's label +area. + include::../../copyright.txt[] SEE ALSO From patchwork Mon Jan 24 00:53:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721351 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 98BA6C433EF for ; Mon, 24 Jan 2022 00:53:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240657AbiAXAxE (ORCPT ); Sun, 23 Jan 2022 19:53:04 -0500 Received: from mga02.intel.com ([134.134.136.20]:61596 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240656AbiAXAxD (ORCPT ); Sun, 23 Jan 2022 19:53:03 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985583; x=1674521583; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=JnHduQG5BOLWR0yGJscT3N4kg/GA5bSN96rM5mcMzQU=; b=Cy7HqlMQSEKvyG3WTa84d07PV8wZaWd04SwuwfhdieQWC2a6KvnstTo3 sQp6iXagwdpG4VV9bu4jPPd1ZgFzX93BkALqlT2hxmqq5Zx3fIdbKznoJ cMq/Qjgu81Hua1aQ8ShB5erKHzqYShXyVLB6SnOA3xDzHzQ4ePeFJco9Z uA24NLBU7lqOyQqwBk4kOMMYgnnFHzQekjVdELWTIk5LcrBLH69zXTwJD DLH7t+mnduJfJQ0lCnXcu6IhrpSTd8TQvuCWyClvth5rTUXrqIF4lHRUs GKlvMvwIlEGJy8QoUUkm8AOUegLyT/0z1I0KNLoLr/eoPE2rTZMo8a+D0 A==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="233293964" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="233293964" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:03 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="673456418" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:02 -0800 Subject: [ndctl PATCH 14/37] cxl/list: Add bus objects From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:53:02 -0800 Message-ID: <164298558278.3021641.16323855851736615358.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org A 'struct cxl_bus' represents a CXL.mem domain. It is the root of a Host-managed Device Memory (HDM) hierarchy. When memory devices are enabled for CXL operation they appear underneath a bus in a 'cxl list -BM' listing, otherwise they display as disconnected. A 'bus' is identical to the kernel's CXL root port object, but given the confusion between CXL root ports, and PCIe root ports, the 'bus' name is less ambiguous. It also serves a similar role in the object hierarchy as a 'struct ndctl_bus' object. It is also the case that the "root" name will appear as the kernel device-name, so the association will be clear. Signed-off-by: Dan Williams --- .clang-format | 1 Documentation/cxl/cxl-list.txt | 88 ++++++++++++++++++++---- Documentation/cxl/lib/libcxl.txt | 30 ++++++++ cxl/filter.c | 117 +++++++++++++++++++++++++++++++ cxl/filter.h | 2 + cxl/json.c | 21 ++++++ cxl/json.h | 5 + cxl/lib/libcxl.c | 142 ++++++++++++++++++++++++++++++++++++++ cxl/lib/libcxl.sym | 5 + cxl/lib/private.h | 14 ++++ cxl/libcxl.h | 11 +++ cxl/list.c | 19 +++-- 12 files changed, 431 insertions(+), 24 deletions(-) diff --git a/.clang-format b/.clang-format index d2e77d0e0b4b..1154c76b1399 100644 --- a/.clang-format +++ b/.clang-format @@ -78,6 +78,7 @@ ExperimentalAutoDetectBinPacking: false # | sort -u) ForEachMacros: - 'cxl_memdev_foreach' + - 'cxl_bus_foreach' - 'daxctl_dev_foreach' - 'daxctl_mapping_foreach' - 'daxctl_region_foreach' diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index 224c972498ea..be131ae7b02a 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -15,17 +15,60 @@ SYNOPSIS Walk the CXL capable device hierarchy in the system and list all device instances along with some of their major attributes. -Options can be specified to limit the output to specific objects. +Options can be specified to limit the output to specific objects. When a +single object type is specified the return json object is an array of +just those objects, when multiple objects types are specified the +returned the returned object may be an array of arrays with the inner +array named for the given object type. + +Filters can by specifed as either a single identidier, a space separated +quoted string, or a comma separated list. When multiple filter +identifiers are specified within a filter string, like "-m +mem0,mem1,mem2", they are combined as an 'OR' filter. When multiple +filter string types are specified, like "-m mem0,mem1,mem2 -p port10", +they are combined as an 'AND' filter. So, "-m mem0,mem1,mem2 -p port10" +would only list objects that are beneath port10 AND map mem0, mem1, OR +mem2. + +The --human option in addition to reformatting some fields to more human +friendly strings also unwraps the array to reduce the number of lines of +output. EXAMPLE ------- ---- # cxl list --memdevs -{ - "memdev":"mem0", - "pmem_size":268435456, - "ram_size":0, -} +[ + { + "memdev":"mem0", + "pmem_size":268435456, + "ram_size":0, + "serial":0 + } +] + +# cxl list -BMu +[ + { + "anon memdevs":[ + { + "memdev":"mem0", + "pmem_size":"256.00 MiB (268.44 MB)", + "ram_size":0, + "serial":"0" + } + ] + }, + { + "buses":[ + { + "bus":"root0", + "provider":"ACPI.CXL" + } + ] + } +] + ---- OPTIONS @@ -34,13 +77,6 @@ OPTIONS --memdev=:: Specify CXL memory device name(s), or device id(s), to filter the listing. For example: ---- -# cxl list --memdev=mem0 -{ - "memdev":"mem0", - "pmem_size":268435456, - "ram_size":0, -} - # cxl list -M --memdev="0 mem3 5" [ { @@ -114,6 +150,32 @@ OPTIONS ] ---- +-B:: +--buses:: + Include 'bus' / CXL root object(s) in the listing. Typically, on ACPI + systems the bus object is a singleton associated with the ACPI0017 + device, but there are test scenerios where there may be multiple CXL + memory hierarchies. +---- +# cxl list -B +[ + { + "bus":"root3", + "provider":"cxl_test" + }, + { + "bus":"root0", + "provider":"ACPI.CXL" + } +] +---- + +-b:: +--bus=:: + Specify CXL root device name(s), device id(s), and / or CXL bus provider + names to filter the listing. The supported provider names are "ACPI.CXL" + and "cxl_test". + include::human-option.txt[] include::verbose-option.txt[] diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index c127326a2840..84af66a3a7bd 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -134,6 +134,36 @@ cxl_memdev{read,write,zero}_label() are helpers for marshaling multiple label access commands over an arbitrary extent of the device's label area. +BUSES +----- +The CXL Memory space is CPU and Device coherent. The address ranges that +support coherent access are described by platform firmware and +communicated to the operating system via a CXL root object 'struct +cxl_bus'. + +=== BUS: Enumeration +---- +struct cxl_bus *cxl_bus_get_first(struct cxl_ctx *ctx); +struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus); + +#define cxl_bus_foreach(ctx, bus) \ + for (bus = cxl_bus_get_first(ctx); bus != NULL; \ + bus = cxl_bus_get_next(bus)) +---- + +=== BUS: Attributes +---- +const char *cxl_bus_get_provider(struct cxl_bus *bus); +const char *cxl_bus_get_devname(struct cxl_bus *bus); +int cxl_bus_get_id(struct cxl_bus *bus); +---- + +The provider name of a bus is a persistent name that is independent of +discovery order. The possible provider names are 'ACPI.CXL' and +'cxl_test'. The devname and id attributes, like other objects, are just +the kernel device names that are subject to change based on discovery +order. + include::../../copyright.txt[] SEE ALSO diff --git a/cxl/filter.c b/cxl/filter.c index 26efc65f4dd7..5f4844b4cab9 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2015-2020 Intel Corporation. All rights reserved. +// Copyright (C) 2015-2022 Intel Corporation. All rights reserved. #include #include #include @@ -21,6 +21,43 @@ static const char *which_sep(const char *filter) return " "; } +static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus, + const char *__ident) +{ + char *ident, *save; + const char *arg; + int bus_id; + + if (!__ident) + return bus; + + ident = strdup(__ident); + if (!ident) + return NULL; + + for (arg = strtok_r(ident, which_sep(__ident), &save); arg; + arg = strtok_r(NULL, which_sep(__ident), &save)) { + if (strcmp(arg, "all") == 0) + break; + + if ((sscanf(arg, "%d", &bus_id) == 1 || + sscanf(arg, "root%d", &bus_id) == 1) && + cxl_bus_get_id(bus) == bus_id) + break; + + if (strcmp(arg, cxl_bus_get_devname(bus)) == 0) + break; + + if (strcmp(arg, cxl_bus_get_provider(bus)) == 0) + break; + } + + free(ident); + if (arg) + return bus; + return NULL; +} + static struct cxl_memdev * util_cxl_memdev_serial_filter(struct cxl_memdev *memdev, const char *__serials) { @@ -98,21 +135,67 @@ static unsigned long params_to_flags(struct cxl_filter_params *param) return flags; } +static void splice_array(struct cxl_filter_params *p, struct json_object *jobjs, + struct json_object *platform, + const char *container_name, bool do_container) +{ + size_t count; + + if (!json_object_array_length(jobjs)) { + json_object_put(jobjs); + return; + } + + if (do_container) { + struct json_object *container = json_object_new_object(); + + if (!container) { + err(p, "failed to list: %s\n", container_name); + return; + } + + json_object_object_add(container, container_name, jobjs); + json_object_array_add(platform, container); + return; + } + + for (count = json_object_array_length(jobjs); count; count--) { + struct json_object *jobj = json_object_array_get_idx(jobjs, 0); + + json_object_get(jobj); + json_object_array_del_idx(jobjs, 0, 1); + json_object_array_add(platform, jobj); + } + json_object_put(jobjs); +} + int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) { struct json_object *jplatform = json_object_new_array(); + struct json_object *jdevs = NULL, *jbuses = NULL; unsigned long flags = params_to_flags(p); struct cxl_memdev *memdev; + int top_level_objs = 0; + struct cxl_bus *bus; if (!jplatform) { dbg(p, "platform object allocation failure\n"); return -ENOMEM; } + jdevs = json_object_new_array(); + if (!jdevs) + goto err; + + jbuses = json_object_new_array(); + if (!jbuses) + goto err; + cxl_memdev_foreach(ctx, memdev) { struct json_object *jdev; - if (!util_cxl_memdev_filter(memdev, p->memdev_filter, p->serial_filter)) + if (!util_cxl_memdev_filter(memdev, p->memdev_filter, + p->serial_filter)) continue; if (p->memdevs) { jdev = util_cxl_memdev_to_json(memdev, flags); @@ -120,11 +203,39 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) dbg(p, "memdev object allocation failure\n"); continue; } - json_object_array_add(jplatform, jdev); + json_object_array_add(jdevs, jdev); + } + } + + cxl_bus_foreach(ctx, bus) { + struct json_object *jbus; + + if (!util_cxl_bus_filter(bus, p->bus_filter)) + continue; + if (p->buses) { + jbus = util_cxl_bus_to_json(bus, flags); + if (!jbus) { + dbg(p, "bus object allocation failure\n"); + continue; + } + json_object_array_add(jbuses, jbus); } } + if (json_object_array_length(jdevs)) + top_level_objs++; + if (json_object_array_length(jbuses)) + top_level_objs++; + + splice_array(p, jdevs, jplatform, "anon memdevs", top_level_objs > 1); + splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1); + util_display_json_array(stdout, jplatform, flags); return 0; +err: + json_object_put(jdevs); + json_object_put(jbuses); + json_object_put(jplatform); + return -ENOMEM; } diff --git a/cxl/filter.h b/cxl/filter.h index 12d934474554..d41e757cf51d 100644 --- a/cxl/filter.h +++ b/cxl/filter.h @@ -9,7 +9,9 @@ struct cxl_filter_params { const char *memdev_filter; const char *serial_filter; + const char *bus_filter; bool memdevs; + bool buses; bool idle; bool human; bool health; diff --git a/cxl/json.c b/cxl/json.c index d8e65df241a1..a58459482360 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -221,3 +221,24 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev, } return jdev; } + +struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus, + unsigned long flags) +{ + const char *devname = cxl_bus_get_devname(bus); + struct json_object *jbus, *jobj; + + jbus = json_object_new_object(); + if (!jbus) + return NULL; + + jobj = json_object_new_string(devname); + if (jobj) + json_object_object_add(jbus, "bus", jobj); + + jobj = json_object_new_string(cxl_bus_get_provider(bus)); + if (jobj) + json_object_object_add(jbus, "provider", jobj); + + return jbus; +} diff --git a/cxl/json.h b/cxl/json.h index 3abcfe6661bf..4abf6e500f0b 100644 --- a/cxl/json.h +++ b/cxl/json.h @@ -1,8 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2015-2020 Intel Corporation. All rights reserved. */ +/* Copyright (C) 2015-2022 Intel Corporation. All rights reserved. */ #ifndef __CXL_UTIL_JSON_H__ #define __CXL_UTIL_JSON_H__ struct cxl_memdev; struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev, unsigned long flags); +struct cxl_bus; +struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus, + unsigned long flags); #endif /* __CXL_UTIL_JSON_H__ */ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 9839f26f9507..8548a458b131 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -40,7 +40,9 @@ struct cxl_ctx { int refcount; void *userdata; int memdevs_init; + int buses_init; struct list_head memdevs; + struct list_head buses; struct kmod_ctx *kmod_ctx; void *private_data; }; @@ -64,6 +66,21 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head) free(memdev); } +static void __free_port(struct cxl_port *port, struct list_head *head) +{ + if (head) + list_del_from(head, &port->list); + free(port->dev_buf); + free(port->dev_path); + free(port->uport); +} + +static void free_bus(struct cxl_bus *bus, struct list_head *head) +{ + __free_port(&bus->port, head); + free(bus); +} + /** * cxl_get_userdata - retrieve stored data pointer from library context * @ctx: cxl library context @@ -130,6 +147,7 @@ CXL_EXPORT int cxl_new(struct cxl_ctx **ctx) dbg(c, "log_priority=%d\n", c->ctx.log_priority); *ctx = c; list_head_init(&c->memdevs); + list_head_init(&c->buses); c->kmod_ctx = kmod_ctx; return 0; @@ -160,6 +178,7 @@ CXL_EXPORT struct cxl_ctx *cxl_ref(struct cxl_ctx *ctx) CXL_EXPORT void cxl_unref(struct cxl_ctx *ctx) { struct cxl_memdev *memdev, *_d; + struct cxl_bus *bus, *_b; if (ctx == NULL) return; @@ -170,6 +189,9 @@ CXL_EXPORT void cxl_unref(struct cxl_ctx *ctx) list_for_each_safe(&ctx->memdevs, memdev, _d, list) free_memdev(memdev, &ctx->memdevs); + list_for_each_safe(&ctx->buses, bus, _b, port.list) + free_bus(bus, &ctx->buses); + kmod_unref(ctx->kmod_ctx); info(ctx, "context %p released\n", ctx); free(ctx); @@ -449,6 +471,126 @@ CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev) return is_enabled(path); } +static int cxl_port_init(struct cxl_port *port, struct cxl_ctx *ctx, int id, + const char *cxlport_base) +{ + char *path = calloc(1, strlen(cxlport_base) + 100); + size_t rc; + + if (!path) + return -ENOMEM; + + port->id = id; + port->ctx = ctx; + + port->dev_path = strdup(cxlport_base); + if (!port->dev_path) + goto err; + + port->dev_buf = calloc(1, strlen(cxlport_base) + 50); + if (!port->dev_buf) + goto err; + port->buf_len = strlen(cxlport_base) + 50; + + rc = snprintf(port->dev_buf, port->buf_len, "%s/uport", cxlport_base); + if (rc >= port->buf_len) + goto err; + port->uport = realpath(port->dev_buf, NULL); + if (!port->uport) + goto err; + + return 0; +err: + free(port->dev_path); + free(port->dev_buf); + free(path); + return -ENOMEM; +} + +static void *add_cxl_bus(void *parent, int id, const char *cxlbus_base) +{ + const char *devname = devpath_to_devname(cxlbus_base); + struct cxl_bus *bus, *bus_dup; + struct cxl_ctx *ctx = parent; + struct cxl_port *port; + int rc; + + dbg(ctx, "%s: base: \'%s\'\n", devname, cxlbus_base); + + bus = calloc(1, sizeof(*bus)); + if (!bus) + return NULL; + + port = &bus->port; + rc = cxl_port_init(port, ctx, id, cxlbus_base); + if (rc) + goto err; + + cxl_bus_foreach(ctx, bus_dup) + if (bus_dup->port.id == bus->port.id) { + free_bus(bus, NULL); + return bus_dup; + } + + list_add(&ctx->buses, &port->list); + return bus; + +err: + free(bus); + return NULL; +} + +static void cxl_buses_init(struct cxl_ctx *ctx) +{ + if (ctx->buses_init) + return; + + ctx->buses_init = 1; + + sysfs_device_parse(ctx, "/sys/bus/cxl/devices", "root", ctx, + add_cxl_bus); +} + +CXL_EXPORT struct cxl_bus *cxl_bus_get_first(struct cxl_ctx *ctx) +{ + cxl_buses_init(ctx); + + return list_top(&ctx->buses, struct cxl_bus, port.list); +} + +CXL_EXPORT struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus) +{ + struct cxl_ctx *ctx = bus->port.ctx; + + return list_next(&ctx->buses, bus, port.list); +} + +CXL_EXPORT const char *cxl_bus_get_devname(struct cxl_bus *bus) +{ + struct cxl_port *port = &bus->port; + + return devpath_to_devname(port->dev_path); +} + +CXL_EXPORT int cxl_bus_get_id(struct cxl_bus *bus) +{ + struct cxl_port *port = &bus->port; + + return port->id; +} + +CXL_EXPORT const char *cxl_bus_get_provider(struct cxl_bus *bus) +{ + struct cxl_port *port = &bus->port; + const char *devname = devpath_to_devname(port->uport); + + if (strcmp(devname, "ACPI0017:00") == 0) + return "ACPI.CXL"; + if (strcmp(devname, "cxl_acpi.0") == 0) + return "cxl_test"; + return devname; +} + CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd) { if (!cmd) diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 4411035f962a..781ff996af73 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -77,4 +77,9 @@ local: LIBCXL_2 { global: cxl_memdev_get_serial; + cxl_bus_get_first; + cxl_bus_get_next; + cxl_bus_get_provider; + cxl_bus_get_devname; + cxl_bus_get_id; } LIBCXL_1; diff --git a/cxl/lib/private.h b/cxl/lib/private.h index 7c81e24a6f79..0758d0578acf 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -34,6 +34,20 @@ struct cxl_memdev { unsigned long long serial; }; +struct cxl_port { + int id; + void *dev_buf; + size_t buf_len; + char *dev_path; + char *uport; + struct cxl_ctx *ctx; + struct list_node list; +}; + +struct cxl_bus { + struct cxl_port port; +}; + enum cxl_cmd_query_status { CXL_CMD_QUERY_NOT_RUN = 0, CXL_CMD_QUERY_OK, diff --git a/cxl/libcxl.h b/cxl/libcxl.h index bcdede8f12e8..da66eb298ab8 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -57,6 +57,17 @@ int cxl_memdev_write_label(struct cxl_memdev *memdev, void *buf, size_t length, memdev != NULL; \ memdev = cxl_memdev_get_next(memdev)) +struct cxl_bus; +struct cxl_bus *cxl_bus_get_first(struct cxl_ctx *ctx); +struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus); +const char *cxl_bus_get_provider(struct cxl_bus *bus); +const char *cxl_bus_get_devname(struct cxl_bus *bus); +int cxl_bus_get_id(struct cxl_bus *bus); + +#define cxl_bus_foreach(ctx, bus) \ + for (bus = cxl_bus_get_first(ctx); bus != NULL; \ + bus = cxl_bus_get_next(bus)) + 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/cxl/list.c b/cxl/list.c index 7e2744dd8b19..9500e610e0ca 100644 --- a/cxl/list.c +++ b/cxl/list.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2020-2021 Intel Corporation. All rights reserved. */ +/* Copyright (C) 2020-2022 Intel Corporation. All rights reserved. */ #include #include #include @@ -14,11 +14,6 @@ static struct cxl_filter_params param; -static int num_list_flags(void) -{ - return param.memdevs; -} - static const struct option options[] = { OPT_STRING('m', "memdev", ¶m.memdev_filter, "memory device name(s)", "filter by CXL memory device name(s)"), @@ -27,6 +22,9 @@ static const struct option options[] = { "filter by CXL memory device serial number(s)"), OPT_BOOLEAN('M', "memdevs", ¶m.memdevs, "include CXL memory device info"), + OPT_STRING('b', "bus", ¶m.bus_filter, "bus device name", + "filter by CXL bus device name(s)"), + OPT_BOOLEAN('B', "buses", ¶m.buses, "include CXL bus info"), OPT_BOOLEAN('i', "idle", ¶m.idle, "include disabled devices"), OPT_BOOLEAN('u', "human", ¶m.human, "use human friendly number formats "), @@ -35,6 +33,11 @@ static const struct option options[] = { OPT_END(), }; +static int num_list_flags(void) +{ + return !!param.memdevs + !!param.buses; +} + int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) { const char * const u[] = { @@ -53,7 +56,9 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) if (num_list_flags() == 0) { if (param.memdev_filter || param.serial_filter) param.memdevs = true; - else { + if (param.bus_filter) + param.buses = 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 From patchwork Mon Jan 24 00:53:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721352 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 7F707C433EF for ; Mon, 24 Jan 2022 00:53:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240658AbiAXAxK (ORCPT ); Sun, 23 Jan 2022 19:53:10 -0500 Received: from mga14.intel.com ([192.55.52.115]:46164 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240659AbiAXAxJ (ORCPT ); Sun, 23 Jan 2022 19:53:09 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985588; x=1674521588; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=bEzuoGO/1UwU2IYMoBZPOwl3z+8b5Pi3SGWpWbyq8rI=; b=egZIiV8AQc/lMxD2+wABHIvD9cIbBiwKVc5Q4DqB/lPHiivyU/ugLupt ERKi5xJDVwZTp4EDAHPdmT4dtfEpaRTIi/BySnuxOaimAxMOzM526TeJS FvhMGrpupDA3KbB/FQpanWzib+lsSG+l8qym0dv0GAPp8XSO8BzJWXV9v suYWJaLbTU7bzG9Jae16FQmQXRNL30D58AC0LGBgqFod4PuwUfwCBMSND 4J3aUNFPYm4UWA9FHclqxOG9tKjy/f62wUhi2Am95WCDx/yCXr2ui5Lk9 DxFywFQuqYVPn7oeKWlO4dcHO7DWfqBn3S2tI+bec2mdkASa+3LWtPi3x A==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="246153046" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="246153046" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:08 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="596630693" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:08 -0800 Subject: [ndctl PATCH 15/37] util/json: Warn on stderr about empty list results From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:53:08 -0800 Message-ID: <164298558814.3021641.13051269428355986099.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Help interactive users notice something is wrong with the list parameters by warning that no devices matched the specified filter settings. Signed-off-by: Dan Williams --- util/json.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/util/json.c b/util/json.c index bd5f8fc47a2b..f8cc81f6e706 100644 --- a/util/json.c +++ b/util/json.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -95,9 +96,11 @@ void util_display_json_array(FILE *f_out, struct json_object *jarray, int len = json_object_array_length(jarray); int jflag = JSON_C_TO_STRING_PRETTY; - if (json_object_array_length(jarray) > 1 || !(flags & UTIL_JSON_HUMAN)) + if (len > 1 || !(flags & UTIL_JSON_HUMAN)) { + if (len == 0) + warning("no matching devices found\n"); fprintf(f_out, "%s\n", json_object_to_json_string_ext(jarray, jflag)); - else if (len) { + } else if (len) { struct json_object *jobj; jobj = json_object_array_get_idx(jarray, 0); From patchwork Mon Jan 24 00:53:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721353 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 F2168C433F5 for ; Mon, 24 Jan 2022 00:53:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240659AbiAXAxO (ORCPT ); Sun, 23 Jan 2022 19:53:14 -0500 Received: from mga02.intel.com ([134.134.136.20]:61605 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240656AbiAXAxO (ORCPT ); Sun, 23 Jan 2022 19:53:14 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985594; x=1674521594; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=f4TsbY0arBy9TgsxhRBAhOeC2o6qnZZlY2sCaYSITdo=; b=W2wKOrV9jlyP3sCsxYUK0KgN6bsbX5qBYbqrWzSg3Ukng6Sl5b45Afxo JhALvPn7xd5LY/Ln1HYSZPESjqH21y3PKJUr55Wdx6/TW4glGaqd1rd24 /jTp7IrV99j1VSlmJjdcqLrASHXwaBmV9FN6495J8eW1zZNpozYcS7iYz iEz2/7sWFeI9LL6tVLc0YduIyIB1Vr3AIsIouA/e852/DMhBx6+6gqHVA 0CzkuitHr9Ktt/n9n++kXcRsN1lPXWfWPeLprXCjUauqihXA9Q8hV9IA5 WdCGhpxBebRmvwkiEDyVYbj26W/iCi73P3UOYdj1v7iCB7oi0QVkjO+qM g==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="233293971" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="233293971" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:14 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="695243417" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:13 -0800 Subject: [ndctl PATCH 16/37] util/sysfs: Uplevel modalias lookup helper to util/ From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:53:13 -0800 Message-ID: <164298559346.3021641.11059026790676662837.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org The to_module() helper looks up modules relative to a modalias. Uplevel this to share with libcxl. Signed-off-by: Dan Williams --- ndctl/lib/libndctl.c | 33 +++++---------------------------- util/sysfs.c | 27 +++++++++++++++++++++++++++ util/sysfs.h | 8 ++++++++ 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c index 47a234ccc8ce..1374ad9e504f 100644 --- a/ndctl/lib/libndctl.c +++ b/ndctl/lib/libndctl.c @@ -1668,7 +1668,6 @@ static enum ndctl_fwa_result fwa_result_to_result(const char *result) static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module, const char *devname); static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath); -static struct kmod_module *to_module(struct ndctl_ctx *ctx, const char *alias); static int populate_dimm_attributes(struct ndctl_dimm *dimm, const char *dimm_base, @@ -1878,7 +1877,7 @@ static void *add_dimm(void *parent, int id, const char *dimm_base) sprintf(path, "%s/modalias", dimm_base); if (sysfs_read_attr(ctx, path, buf) < 0) goto err_read; - dimm->module = to_module(ctx, buf); + dimm->module = util_modalias_to_module(ctx, buf); dimm->handle = -1; dimm->phys_id = -1; @@ -2597,7 +2596,7 @@ static void *add_region(void *parent, int id, const char *region_base) sprintf(path, "%s/modalias", region_base); if (sysfs_read_attr(ctx, path, buf) < 0) goto err_read; - region->module = to_module(ctx, buf); + region->module = util_modalias_to_module(ctx, buf); sprintf(path, "%s/numa_node", region_base); if ((rc = sysfs_read_attr(ctx, path, buf)) == 0) @@ -3885,28 +3884,6 @@ NDCTL_EXPORT struct ndctl_ctx *ndctl_mapping_get_ctx( return ndctl_mapping_get_bus(mapping)->ctx; } -static struct kmod_module *to_module(struct ndctl_ctx *ctx, const char *alias) -{ - struct kmod_list *list = NULL; - struct kmod_module *mod; - int rc; - - if (!ctx->kmod_ctx) - return NULL; - - rc = kmod_module_new_from_lookup(ctx->kmod_ctx, alias, &list); - if (rc < 0 || !list) { - dbg(ctx, "failed to find module for alias: %s %d list: %s\n", - alias, rc, list ? "populated" : "empty"); - return NULL; - } - mod = kmod_module_get_module(list); - dbg(ctx, "alias: %s module: %s\n", alias, kmod_module_get_name(mod)); - kmod_module_unref_list(list); - - return mod; -} - static char *get_block_device(struct ndctl_ctx *ctx, const char *block_path) { char *bdev_name = NULL; @@ -4069,7 +4046,7 @@ static void *add_namespace(void *parent, int id, const char *ndns_base) sprintf(path, "%s/modalias", ndns_base); if (sysfs_read_attr(ctx, path, buf) < 0) goto err_read; - ndns->module = to_module(ctx, buf); + ndns->module = util_modalias_to_module(ctx, buf); ndctl_namespace_foreach(region, ndns_dup) if (ndns_dup->id == ndns->id) { @@ -5182,7 +5159,7 @@ static void *add_btt(void *parent, int id, const char *btt_base) sprintf(path, "%s/modalias", btt_base); if (sysfs_read_attr(ctx, path, buf) < 0) goto err_read; - btt->module = to_module(ctx, buf); + btt->module = util_modalias_to_module(ctx, buf); sprintf(path, "%s/uuid", btt_base); if (sysfs_read_attr(ctx, path, buf) < 0) @@ -5533,7 +5510,7 @@ static void *__add_pfn(struct ndctl_pfn *pfn, const char *pfn_base) sprintf(path, "%s/modalias", pfn_base); if (sysfs_read_attr(ctx, path, buf) < 0) goto err_read; - pfn->module = to_module(ctx, buf); + pfn->module = util_modalias_to_module(ctx, buf); sprintf(path, "%s/uuid", pfn_base); if (sysfs_read_attr(ctx, path, buf) < 0) diff --git a/util/sysfs.c b/util/sysfs.c index cfbab7da74e9..23330cb29002 100644 --- a/util/sysfs.c +++ b/util/sysfs.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -118,3 +119,29 @@ int __sysfs_device_parse(struct log_ctx *ctx, const char *base_path, return add_errors; } + +struct kmod_module *__util_modalias_to_module(struct kmod_ctx *kmod_ctx, + const char *alias, + struct log_ctx *log) +{ + struct kmod_list *list = NULL; + struct kmod_module *mod; + int rc; + + if (!kmod_ctx) + return NULL; + + rc = kmod_module_new_from_lookup(kmod_ctx, alias, &list); + if (rc < 0 || !list) { + log_dbg(log, + "failed to find module for alias: %s %d list: %s\n", + alias, rc, list ? "populated" : "empty"); + return NULL; + } + mod = kmod_module_get_module(list); + log_dbg(log, "alias: %s module: %s\n", alias, + kmod_module_get_name(mod)); + kmod_module_unref_list(list); + + return mod; +} diff --git a/util/sysfs.h b/util/sysfs.h index 6485a73d8ed7..bdee4f5c291d 100644 --- a/util/sysfs.h +++ b/util/sysfs.h @@ -27,4 +27,12 @@ static inline const char *devpath_to_devname(const char *devpath) { return strrchr(devpath, '/') + 1; } + +struct kmod_ctx; +struct kmod_module; +struct kmod_module *__util_modalias_to_module(struct kmod_ctx *kmod_ctx, + const char *alias, + struct log_ctx *log); +#define util_modalias_to_module(ctx, buf) \ + __util_modalias_to_module((ctx)->kmod_ctx, buf, &(ctx)->ctx) #endif /* __UTIL_SYSFS_H__ */ From patchwork Mon Jan 24 00:53:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721354 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 30963C433F5 for ; Mon, 24 Jan 2022 00:53:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240656AbiAXAxU (ORCPT ); Sun, 23 Jan 2022 19:53:20 -0500 Received: from mga14.intel.com ([192.55.52.115]:46177 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235202AbiAXAxT (ORCPT ); Sun, 23 Jan 2022 19:53:19 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985599; x=1674521599; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=nvCEOnK7FAiP8bxRt6EZGrcxcrnfj0QzRrgB1UV2nhc=; b=jmWrPbfUQMvV06UBZSe6WP0BDGwsywwqjUag3PFphzSSBGffnNxQBJXJ xQcTeQ+IjoFLp0HAeeyZPatBHkVnZe30PVQe+Utf8rO1iOYtBWevkYCWi 6ctTgXbzG+C2DwxU8y8hO+A/Ky35xUMY5B8+baFyyTv/78Ij6Jbq+05K4 J54+GIFO6NG+cpStdfYGtmM7s5Htyj1qtz8GTWBjpUKl0w+9hz7uCbevX /CmGNu+278Ucj6+9YZBYOTZGeaxhd20xTGxnwqIT6vYQBhscj4mwynnC4 aOQXTlyX+C0vd2HHIchlJ97g+ccXxNrvZHO2zCOA5lyzN6qcQmcPithX9 w==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="246153057" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="246153057" Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:19 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="768519539" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga005-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:18 -0800 Subject: [ndctl PATCH 17/37] cxl/list: Add port enumeration From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:53:18 -0800 Message-ID: <164298559854.3021641.17724828997703051001.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Between a cxl_bus (root port) and an endpoint there can be an arbitrary level of switches. Add enumeration for these ports at each level of the hierarchy. However, given the CXL root ports are also "ports" infer that if the port filter argument is the word "root" or "root%d" then include root ports in the listing. The keyword "switch" is also provided to filter only the ports beneath the root that are not endpoint ports. Signed-off-by: Dan Williams --- .clang-format | 1 Documentation/cxl/cxl-list.txt | 24 ++++ Documentation/cxl/lib/libcxl.txt | 42 +++++++ cxl/filter.c | 224 +++++++++++++++++++++++++++++++++++++- cxl/filter.h | 4 + cxl/json.c | 23 ++++ cxl/json.h | 3 + cxl/lib/libcxl.c | 160 +++++++++++++++++++++++++++ cxl/lib/libcxl.sym | 12 ++ cxl/lib/private.h | 11 ++ cxl/libcxl.h | 19 +++ cxl/list.c | 17 +++ 12 files changed, 534 insertions(+), 6 deletions(-) diff --git a/.clang-format b/.clang-format index 1154c76b1399..391cd3420947 100644 --- a/.clang-format +++ b/.clang-format @@ -79,6 +79,7 @@ ExperimentalAutoDetectBinPacking: false ForEachMacros: - 'cxl_memdev_foreach' - 'cxl_bus_foreach' + - 'cxl_port_foreach' - 'daxctl_dev_foreach' - 'daxctl_mapping_foreach' - 'daxctl_region_foreach' diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index be131ae7b02a..3076deb43b9e 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -176,6 +176,30 @@ OPTIONS names to filter the listing. The supported provider names are "ACPI.CXL" and "cxl_test". +-P:: +--ports:: + Include port objects (CXL / PCIe root ports + Upstream Switch Ports) in + the listing. + +-p:: +--port=:: + Specify CXL Port device name(s), device id(s), and or port type + names to filter the listing. The supported port type names are "root" + and "switch". Note that since a bus object is also a port, the following + two syntaxes are equivalent: +---- +# cxl list -B +# cxl list -P -p root +---- + By default, only 'switch' ports are listed. + +-S:: +--single:: + Specify whether the listing should emit all the objects that are + descendants of a port that matches the port filter, or only direct + descendants of the individual ports that match the filter. By default + all descendant objects are listed. + include::human-option.txt[] include::verbose-option.txt[] diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index 84af66a3a7bd..804e9ca1500e 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -164,6 +164,48 @@ discovery order. The possible provider names are 'ACPI.CXL' and the kernel device names that are subject to change based on discovery order. +PORTS +----- +CXL ports track the PCIe hierarchy between a platform firmware CXL root +object, through CXL / PCIe Host Bridges, CXL / PCIe Root Ports, and CXL +/ PCIe Switch Ports. + +=== PORT: Enumeration +---- +struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus); +struct cxl_port *cxl_port_get_first(struct cxl_port *parent); +struct cxl_port *cxl_port_get_next(struct cxl_port *port); +struct cxl_port *cxl_port_get_parent(struct cxl_port *port); +struct cxl_bus *cxl_port_get_bus(struct cxl_port *port); +struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port); + +#define cxl_port_foreach(parent, port) \ + for (port = cxl_port_get_first(parent); port != NULL; \ + port = cxl_port_get_next(port)) +---- +A bus object encapsulates a CXL port object. Use cxl_bus_get_port() to +use generic port APIs on root objects. + +Ports are hierarchical. All but the a root object have another CXL port +as a parent object retrievable via cxl_port_get_parent(). + +The root port of a hiearchy can be retrieved via any port instance in +that hierarchy via cxl_port_get_bus(). + +=== PORT: Attributes +---- +const char *cxl_port_get_devname(struct cxl_port *port); +int cxl_port_get_id(struct cxl_port *port); +int cxl_port_is_enabled(struct cxl_port *port); +bool cxl_port_is_root(struct cxl_port *port); +bool cxl_port_is_switch(struct cxl_port *port); +---- +The port type is communicated via cxl_port_is_(). An 'enabled' port +is one that has succeeded in discovering the CXL component registers in +the host device and has enumerated its downstream ports. In order for a +memdev to be enabled for CXL memory operation all CXL ports in its +ancestry must also be enabled. + include::../../copyright.txt[] SEE ALSO diff --git a/cxl/filter.c b/cxl/filter.c index 5f4844b4cab9..8b79db3dae8d 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -21,6 +21,101 @@ static const char *which_sep(const char *filter) return " "; } +bool cxl_filter_has(const char *__filter, const char *needle) +{ + char *filter, *save; + const char *arg; + + if (!needle) + return true; + + if (!__filter) + return false; + + filter = strdup(__filter); + if (!filter) + return false; + + for (arg = strtok_r(filter, which_sep(__filter), &save); arg; + arg = strtok_r(NULL, which_sep(__filter), &save)) + if (strstr(arg, needle)) + break; + + free(filter); + if (arg) + return true; + return false; +} + +static struct cxl_port *__util_cxl_port_filter(struct cxl_port *port, + const char *__ident) +{ + char *ident, *save; + const char *arg; + int port_id; + + if (!__ident) + return port; + + ident = strdup(__ident); + if (!ident) + return NULL; + + for (arg = strtok_r(ident, which_sep(__ident), &save); arg; + arg = strtok_r(NULL, which_sep(__ident), &save)) { + if (strcmp(arg, "all") == 0) + break; + + if (strcmp(arg, "root") == 0 && cxl_port_is_root(port)) + break; + + if (strcmp(arg, "switch") == 0 && cxl_port_is_switch(port)) + break; + + if ((sscanf(arg, "%d", &port_id) == 1 || + sscanf(arg, "port%d", &port_id) == 1) && + cxl_port_get_id(port) == port_id) + break; + + if (strcmp(arg, cxl_port_get_devname(port)) == 0) + break; + } + + free(ident); + if (arg) + return port; + return NULL; +} + +enum cxl_port_filter_mode { + CXL_PF_SINGLE, + CXL_PF_ANCESTRY, +}; + +static enum cxl_port_filter_mode pf_mode(struct cxl_filter_params *p) +{ + if (p->single) + return CXL_PF_SINGLE; + return CXL_PF_ANCESTRY; +} + +static struct cxl_port *util_cxl_port_filter(struct cxl_port *port, + const char *ident, + enum cxl_port_filter_mode mode) +{ + struct cxl_port *iter = port; + + while (iter) { + if (__util_cxl_port_filter(iter, ident)) + return port; + if (mode == CXL_PF_SINGLE) + return NULL; + iter = cxl_port_get_parent(iter); + } + + return NULL; +} + static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus, const char *__ident) { @@ -58,6 +153,31 @@ static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus, return NULL; } +static struct cxl_port *util_cxl_port_filter_by_bus(struct cxl_port *port, + const char *__ident) +{ + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + struct cxl_bus *bus; + + if (!__ident) + return port; + + if (cxl_port_is_root(port)) { + bus = cxl_port_to_bus(port); + bus = util_cxl_bus_filter(bus, __ident); + return bus ? port : NULL; + } + + cxl_bus_foreach(ctx, bus) { + if (!util_cxl_bus_filter(bus, __ident)) + continue; + if (bus == cxl_port_get_bus(port)) + return port; + } + + return NULL; +} + static struct cxl_memdev * util_cxl_memdev_serial_filter(struct cxl_memdev *memdev, const char *__serials) { @@ -169,10 +289,82 @@ static void splice_array(struct cxl_filter_params *p, struct json_object *jobjs, json_object_put(jobjs); } +static bool cond_add_put_array(struct json_object *jobj, const char *key, + struct json_object *array) +{ + if (jobj && array && json_object_array_length(array) > 0) { + json_object_object_add(jobj, key, array); + return true; + } else { + json_object_put(array); + return false; + } +} + +static bool cond_add_put_array_suffix(struct json_object *jobj, const char *key, + const char *suffix, + struct json_object *array) +{ + char *name; + bool rc; + + if (asprintf(&name, "%s:%s", key, suffix) < 0) + return false; + rc = cond_add_put_array(jobj, name, array); + free(name); + return rc; +} + +static struct json_object *pick_array(struct json_object *child, + struct json_object *container) +{ + if (child) + return child; + if (container) + return container; + return NULL; +} + +static void walk_child_ports(struct cxl_port *parent_port, + struct cxl_filter_params *p, + struct json_object *jports, + unsigned long flags) +{ + struct cxl_port *port; + + cxl_port_foreach(parent_port, port) { + const char *devname = cxl_port_get_devname(port); + struct json_object *jport = NULL; + struct json_object *jchildports = NULL; + + if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p))) + goto walk_children; + if (!util_cxl_port_filter_by_bus(port, p->bus_filter)) + goto walk_children; + if (!p->idle && !cxl_port_is_enabled(port)) + continue; + if (p->ports) + jport = util_cxl_port_to_json(port, flags); + if (!jport) + continue; + json_object_array_add(jports, jport); + jchildports = json_object_new_array(); + if (!jchildports) { + err(p, "%s: failed to enumerate child ports\n", + devname); + continue; + } +walk_children: + walk_child_ports(port, p, pick_array(jchildports, jports), + flags); + cond_add_put_array_suffix(jport, "ports", devname, jchildports); + } +} + int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) { + struct json_object *jdevs = NULL, *jbuses = NULL, *jports = NULL; struct json_object *jplatform = json_object_new_array(); - struct json_object *jdevs = NULL, *jbuses = NULL; unsigned long flags = params_to_flags(p); struct cxl_memdev *memdev; int top_level_objs = 0; @@ -191,6 +383,10 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) if (!jbuses) goto err; + jports = json_object_new_array(); + if (!jports) + goto err; + cxl_memdev_foreach(ctx, memdev) { struct json_object *jdev; @@ -208,10 +404,15 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) } cxl_bus_foreach(ctx, bus) { - struct json_object *jbus; + struct json_object *jbus = NULL; + struct json_object *jchildports = NULL; + struct cxl_port *port = cxl_bus_get_port(bus); + const char *devname = cxl_bus_get_devname(bus); if (!util_cxl_bus_filter(bus, p->bus_filter)) - continue; + goto walk_children; + if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p))) + goto walk_children; if (p->buses) { jbus = util_cxl_bus_to_json(bus, flags); if (!jbus) { @@ -219,16 +420,32 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) continue; } json_object_array_add(jbuses, jbus); + if (p->ports) { + jchildports = json_object_new_array(); + if (!jchildports) { + err(p, + "%s: failed to enumerate child ports\n", + devname); + continue; + } + } } +walk_children: + walk_child_ports(port, p, pick_array(jchildports, jports), + flags); + cond_add_put_array_suffix(jbus, "ports", devname, jchildports); } if (json_object_array_length(jdevs)) top_level_objs++; if (json_object_array_length(jbuses)) top_level_objs++; + if (json_object_array_length(jports)) + top_level_objs++; splice_array(p, jdevs, jplatform, "anon memdevs", top_level_objs > 1); splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1); + splice_array(p, jports, jplatform, "ports", top_level_objs > 1); util_display_json_array(stdout, jplatform, flags); @@ -236,6 +453,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) err: json_object_put(jdevs); json_object_put(jbuses); + json_object_put(jports); json_object_put(jplatform); return -ENOMEM; } diff --git a/cxl/filter.h b/cxl/filter.h index d41e757cf51d..0d83304bd612 100644 --- a/cxl/filter.h +++ b/cxl/filter.h @@ -10,7 +10,10 @@ struct cxl_filter_params { const char *memdev_filter; const char *serial_filter; const char *bus_filter; + const char *port_filter; + bool single; bool memdevs; + bool ports; bool buses; bool idle; bool human; @@ -22,4 +25,5 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, const char *__ident, const char *serials); int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param); +bool cxl_filter_has(const char *needle, const char *__filter); #endif /* _CXL_UTIL_FILTER_H_ */ diff --git a/cxl/json.c b/cxl/json.c index a58459482360..d9f864edb86b 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -242,3 +242,26 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus, return jbus; } + +struct json_object *util_cxl_port_to_json(struct cxl_port *port, + unsigned long flags) +{ + const char *devname = cxl_port_get_devname(port); + struct json_object *jport, *jobj; + + jport = json_object_new_object(); + if (!jport) + return NULL; + + jobj = json_object_new_string(devname); + if (jobj) + json_object_object_add(jport, "port", jobj); + + if (!cxl_port_is_enabled(port)) { + jobj = json_object_new_string("disabled"); + if (jobj) + json_object_object_add(jport, "state", jobj); + } + + return jport; +} diff --git a/cxl/json.h b/cxl/json.h index 4abf6e500f0b..36653db6ef6a 100644 --- a/cxl/json.h +++ b/cxl/json.h @@ -8,4 +8,7 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev, struct cxl_bus; struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus, unsigned long flags); +struct cxl_port; +struct json_object *util_cxl_port_to_json(struct cxl_port *port, + unsigned long flags); #endif /* __CXL_UTIL_JSON_H__ */ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 8548a458b131..03eff3cd6073 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -66,15 +66,27 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head) free(memdev); } +static void free_port(struct cxl_port *port, struct list_head *head); static void __free_port(struct cxl_port *port, struct list_head *head) { + struct cxl_port *child, *_c; + if (head) list_del_from(head, &port->list); + list_for_each_safe(&port->child_ports, child, _c, list) + free_port(child, &port->child_ports); + kmod_module_unref(port->module); free(port->dev_buf); free(port->dev_path); free(port->uport); } +static void free_port(struct cxl_port *port, struct list_head *head) +{ + __free_port(port, head); + free(port); +} + static void free_bus(struct cxl_bus *bus, struct list_head *head) { __free_port(&bus->port, head); @@ -471,10 +483,12 @@ CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev) return is_enabled(path); } -static int cxl_port_init(struct cxl_port *port, struct cxl_ctx *ctx, int id, +static int cxl_port_init(struct cxl_port *port, struct cxl_port *parent_port, + enum cxl_port_type type, struct cxl_ctx *ctx, int id, const char *cxlport_base) { char *path = calloc(1, strlen(cxlport_base) + 100); + char buf[SYSFS_ATTR_SIZE]; size_t rc; if (!path) @@ -482,6 +496,10 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_ctx *ctx, int id, port->id = id; port->ctx = ctx; + port->type = type; + port->parent = parent_port; + + list_head_init(&port->child_ports); port->dev_path = strdup(cxlport_base); if (!port->dev_path) @@ -499,6 +517,10 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_ctx *ctx, int id, if (!port->uport) goto err; + sprintf(path, "%s/modalias", cxlport_base); + if (sysfs_read_attr(ctx, path, buf) == 0) + port->module = util_modalias_to_module(ctx, buf); + return 0; err: free(port->dev_path); @@ -507,6 +529,135 @@ err: return -ENOMEM; } +static void *add_cxl_port(void *parent, int id, const char *cxlport_base) +{ + const char *devname = devpath_to_devname(cxlport_base); + struct cxl_port *port, *port_dup; + struct cxl_port *parent_port = parent; + struct cxl_ctx *ctx = cxl_port_get_ctx(parent_port); + int rc; + + dbg(ctx, "%s: base: \'%s\'\n", devname, cxlport_base); + + port = calloc(1, sizeof(*port)); + if (!port) + return NULL; + + rc = cxl_port_init(port, parent_port, CXL_PORT_SWITCH, ctx, id, + cxlport_base); + if (rc) + goto err; + + cxl_port_foreach(parent_port, port_dup) + if (port_dup->id == port->id) { + free_port(port, NULL); + return port_dup; + } + + list_add(&parent_port->child_ports, &port->list); + return port; + +err: + free(port); + return NULL; + +} + +static void cxl_ports_init(struct cxl_port *port) +{ + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + + if (port->ports_init) + return; + + port->ports_init = 1; + + sysfs_device_parse(ctx, port->dev_path, "port", port, add_cxl_port); +} + +CXL_EXPORT struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port) +{ + return port->ctx; +} + +CXL_EXPORT struct cxl_port *cxl_port_get_first(struct cxl_port *port) +{ + cxl_ports_init(port); + + return list_top(&port->child_ports, struct cxl_port, list); +} + +CXL_EXPORT struct cxl_port *cxl_port_get_next(struct cxl_port *port) +{ + struct cxl_port *parent_port = port->parent; + + return list_next(&parent_port->child_ports, port, list); +} + +CXL_EXPORT const char *cxl_port_get_devname(struct cxl_port *port) +{ + return devpath_to_devname(port->dev_path); +} + +CXL_EXPORT int cxl_port_get_id(struct cxl_port *port) +{ + return port->id; +} + +CXL_EXPORT struct cxl_port *cxl_port_get_parent(struct cxl_port *port) +{ + return port->parent; +} + +CXL_EXPORT bool cxl_port_is_root(struct cxl_port *port) +{ + return port->type == CXL_PORT_ROOT; +} + +CXL_EXPORT bool cxl_port_is_switch(struct cxl_port *port) +{ + return port->type == CXL_PORT_SWITCH; +} + +CXL_EXPORT struct cxl_bus *cxl_port_get_bus(struct cxl_port *port) +{ + struct cxl_bus *bus; + + if (!cxl_port_is_enabled(port)) + return NULL; + + if (port->bus) + return port->bus; + + while (port->parent) + port = port->parent; + + bus = container_of(port, typeof(*bus), port); + port->bus = bus; + return bus; +} + +CXL_EXPORT int cxl_port_is_enabled(struct cxl_port *port) +{ + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + char *path = port->dev_buf; + int len = port->buf_len; + + if (snprintf(path, len, "%s/driver", port->dev_path) >= len) { + err(ctx, "%s: buffer too small!\n", cxl_port_get_devname(port)); + return 0; + } + + return is_enabled(path); +} + +CXL_EXPORT struct cxl_bus *cxl_port_to_bus(struct cxl_port *port) +{ + if (!cxl_port_is_root(port)) + return NULL; + return container_of(port, struct cxl_bus, port); +} + static void *add_cxl_bus(void *parent, int id, const char *cxlbus_base) { const char *devname = devpath_to_devname(cxlbus_base); @@ -522,7 +673,7 @@ static void *add_cxl_bus(void *parent, int id, const char *cxlbus_base) return NULL; port = &bus->port; - rc = cxl_port_init(port, ctx, id, cxlbus_base); + rc = cxl_port_init(port, NULL, CXL_PORT_ROOT, ctx, id, cxlbus_base); if (rc) goto err; @@ -579,6 +730,11 @@ CXL_EXPORT int cxl_bus_get_id(struct cxl_bus *bus) return port->id; } +CXL_EXPORT struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus) +{ + return &bus->port; +} + CXL_EXPORT const char *cxl_bus_get_provider(struct cxl_bus *bus) { struct cxl_port *port = &bus->port; diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 781ff996af73..a7e923f7d721 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -82,4 +82,16 @@ global: cxl_bus_get_provider; cxl_bus_get_devname; cxl_bus_get_id; + cxl_bus_get_port; + cxl_port_get_first; + cxl_port_get_next; + cxl_port_get_devname; + cxl_port_get_id; + cxl_port_get_ctx; + cxl_port_is_enabled; + cxl_port_get_parent; + cxl_port_is_root; + cxl_port_is_switch; + cxl_port_to_bus; + cxl_port_get_bus; } LIBCXL_1; diff --git a/cxl/lib/private.h b/cxl/lib/private.h index 0758d0578acf..637f90d8dfa2 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -34,14 +34,25 @@ struct cxl_memdev { unsigned long long serial; }; +enum cxl_port_type { + CXL_PORT_ROOT, + CXL_PORT_SWITCH, +}; + struct cxl_port { int id; void *dev_buf; size_t buf_len; char *dev_path; char *uport; + int ports_init; struct cxl_ctx *ctx; + struct cxl_bus *bus; + enum cxl_port_type type; + struct cxl_port *parent; + struct kmod_module *module; struct list_node list; + struct list_head child_ports; }; struct cxl_bus { diff --git a/cxl/libcxl.h b/cxl/libcxl.h index da66eb298ab8..efbb397eb2be 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -5,6 +5,7 @@ #include #include +#include #ifdef HAVE_UUID #include @@ -63,11 +64,29 @@ struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus); const char *cxl_bus_get_provider(struct cxl_bus *bus); const char *cxl_bus_get_devname(struct cxl_bus *bus); int cxl_bus_get_id(struct cxl_bus *bus); +struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus); #define cxl_bus_foreach(ctx, bus) \ for (bus = cxl_bus_get_first(ctx); bus != NULL; \ bus = cxl_bus_get_next(bus)) +struct cxl_port; +struct cxl_port *cxl_port_get_first(struct cxl_port *parent); +struct cxl_port *cxl_port_get_next(struct cxl_port *port); +const char *cxl_port_get_devname(struct cxl_port *port); +int cxl_port_get_id(struct cxl_port *port); +struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port); +int cxl_port_is_enabled(struct cxl_port *port); +struct cxl_port *cxl_port_get_parent(struct cxl_port *port); +bool cxl_port_is_root(struct cxl_port *port); +bool cxl_port_is_switch(struct cxl_port *port); +struct cxl_bus *cxl_port_to_bus(struct cxl_port *port); +struct cxl_bus *cxl_port_get_bus(struct cxl_port *port); + +#define cxl_port_foreach(parent, port) \ + for (port = cxl_port_get_first(parent); port != NULL; \ + port = cxl_port_get_next(port)) + 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/cxl/list.c b/cxl/list.c index 9500e610e0ca..1ef91b44dca1 100644 --- a/cxl/list.c +++ b/cxl/list.c @@ -25,6 +25,11 @@ static const struct option options[] = { OPT_STRING('b', "bus", ¶m.bus_filter, "bus device name", "filter by CXL bus device name(s)"), OPT_BOOLEAN('B', "buses", ¶m.buses, "include CXL bus info"), + OPT_STRING('p', "port", ¶m.port_filter, "port device name", + "filter by CXL port device name(s)"), + OPT_BOOLEAN('P', "ports", ¶m.ports, "include CXL port info"), + OPT_BOOLEAN('S', "single", ¶m.single, + "skip listing descendant objects"), OPT_BOOLEAN('i', "idle", ¶m.idle, "include disabled devices"), OPT_BOOLEAN('u', "human", ¶m.human, "use human friendly number formats "), @@ -35,7 +40,7 @@ static const struct option options[] = { static int num_list_flags(void) { - return !!param.memdevs + !!param.buses; + return !!param.memdevs + !!param.buses + !!param.ports; } int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) @@ -53,11 +58,18 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) if (argc) usage_with_options(u, options); + if (param.single && !param.port_filter) { + error("-S/--single expects a port filter: -p/--port=\n"); + usage_with_options(u, options); + } + if (num_list_flags() == 0) { if (param.memdev_filter || param.serial_filter) param.memdevs = true; if (param.bus_filter) param.buses = true; + if (param.port_filter) + param.ports = true; if (num_list_flags() == 0) { /* * TODO: We likely want to list regions by default if @@ -73,5 +85,8 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) log_init(¶m.ctx, "cxl list", "CXL_LIST_LOG"); + if (cxl_filter_has(param.port_filter, "root") && param.ports) + param.buses = true; + return cxl_filter_walk(ctx, ¶m); } From patchwork Mon Jan 24 00:53:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721355 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 4D8BCC433EF for ; Mon, 24 Jan 2022 00:53:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235202AbiAXAxY (ORCPT ); Sun, 23 Jan 2022 19:53:24 -0500 Received: from mga01.intel.com ([192.55.52.88]:60764 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240660AbiAXAxY (ORCPT ); Sun, 23 Jan 2022 19:53:24 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985604; x=1674521604; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=T1lh8ubpQiuAYkDDTGax+rdEW8mXy9dtFolAomjgM3U=; b=N/TCeTFtOevntlbSrTJh1NKFV7ln55qrhFhAg7WWeM/g9C776mf8kOZp jwrgG20lco197Ce4LkVxJ6kpCIpQjIBVrOjaHzjqJAwj+pyz/WXvVoKwa r+YBtLx1/efyHpqBr2NYD5eR6ZXvMPe5PC7iS1iueIUXgJHBAguRkWGDI MxtOblLJxll7FwlIl8biaoJcr1aTNihHr9XS78qvvACn5dcJtQzHxG8ma XuRxPstAk2kqBRnI1ABYoG2aR1REFe/Sr2JN3Tsjt8xXUHGvElc/1bpYi +quhrOiWC6wud+sHfD8qHV54tUwir7Vq/5ZuB+KP59MduAeK7XV9lipPx A==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="270370012" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="270370012" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:24 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="695243441" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:24 -0800 Subject: [ndctl PATCH 18/37] cxl/list: Add --debug option From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:53:24 -0800 Message-ID: <164298560409.3021641.11040422738199381922.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Add an option to turn on libray and cxl_filter_walk() messages. Gate it based on the global ENABLE_DEBUG configuration setting. Signed-off-by: Dan Williams --- Documentation/cxl/cxl-list.txt | 6 ++++-- cxl/filter.c | 3 +++ cxl/list.c | 9 +++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index 3076deb43b9e..42b6de6e5c61 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -200,9 +200,11 @@ OPTIONS descendants of the individual ports that match the filter. By default all descendant objects are listed. -include::human-option.txt[] +--debug:: + If the cxl tool was built with debug enabled, turn on debug + messages. -include::verbose-option.txt[] +include::human-option.txt[] include::../copyright.txt[] diff --git a/cxl/filter.c b/cxl/filter.c index 8b79db3dae8d..32171a47e8d5 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -387,6 +387,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) if (!jports) goto err; + dbg(p, "walk memdevs\n"); cxl_memdev_foreach(ctx, memdev) { struct json_object *jdev; @@ -403,6 +404,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) } } + dbg(p, "walk buses\n"); cxl_bus_foreach(ctx, bus) { struct json_object *jbus = NULL; struct json_object *jchildports = NULL; @@ -431,6 +433,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) } } walk_children: + dbg(p, "walk ports\n"); walk_child_ports(port, p, pick_array(jchildports, jports), flags); cond_add_put_array_suffix(jbus, "ports", devname, jchildports); diff --git a/cxl/list.c b/cxl/list.c index 1ef91b44dca1..01ab19bff706 100644 --- a/cxl/list.c +++ b/cxl/list.c @@ -13,6 +13,7 @@ #include "filter.h" static struct cxl_filter_params param; +static bool debug; static const struct option options[] = { OPT_STRING('m', "memdev", ¶m.memdev_filter, "memory device name(s)", @@ -35,6 +36,9 @@ static const struct option options[] = { "use human friendly number formats "), OPT_BOOLEAN('H', "health", ¶m.health, "include memory device health information "), +#ifdef ENABLE_DEBUG + OPT_BOOLEAN(0, "debug", &debug, "debug list walk"), +#endif OPT_END(), }; @@ -84,9 +88,14 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) } log_init(¶m.ctx, "cxl list", "CXL_LIST_LOG"); + if (debug) { + cxl_set_log_priority(ctx, LOG_DEBUG); + param.ctx.log_priority = LOG_DEBUG; + } if (cxl_filter_has(param.port_filter, "root") && param.ports) param.buses = true; + dbg(¶m, "walk topology\n"); return cxl_filter_walk(ctx, ¶m); } From patchwork Mon Jan 24 00:53:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721356 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 8AD8BC433F5 for ; Mon, 24 Jan 2022 00:53:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240661AbiAXAxa (ORCPT ); Sun, 23 Jan 2022 19:53:30 -0500 Received: from mga11.intel.com ([192.55.52.93]:50270 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240660AbiAXAx3 (ORCPT ); Sun, 23 Jan 2022 19:53:29 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985609; x=1674521609; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=MGlDDmtZNcO8ieWQlpQT7zmj4zdRHjht25+tjsspKok=; b=AZQRUbL4JnIVVROAyFs2+l8AIc6vYZm7ymIHz4YHFcSt+G3jTEsX7uFQ 5ODvaJrjRFx06P0mvJTWg1GsZ7kf9KmrS7AuTVdAjdWeBlYLEilSZVEYF oszCHMzO7cQ6y/Sx4f9MNOMhPq/OvHXekVNeddnLyQWoyyXlI3LtDF7e2 /7K18nybYfUGv1C5eEkGulswtj4DUodytK3bq/MuOf6PsiK1yL3VOXL3i 7hwAd8KRe3SKNoC2V0OwvOKBBA7VckQPFm0TwH/OkJ+NVCWeIX5SAh6tC /HNfQx3i1xvOyI5lh0phB0+atGQq5nBW+hg4XvafOC4Hhx7wz31xWb0Ky Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="243530607" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="243530607" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:29 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="596630743" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:29 -0800 Subject: [ndctl PATCH 19/37] cxl/list: Add endpoints From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:53:29 -0800 Message-ID: <164298560917.3021641.13753578554905796298.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Endpoints are port-like objects that represent the HDM decoders at terminal end of a decode chain. Unlike port decoders that route to downstream ports, endpoint decoders route to endpoint DPA (Device Physical Address) ranges. Signed-off-by: Dan Williams --- .clang-format | 1 Documentation/cxl/cxl-list.txt | 16 ++++ Documentation/cxl/lib/libcxl.txt | 31 ++++++++ cxl/filter.c | 147 +++++++++++++++++++++++++++++++++++--- cxl/filter.h | 2 + cxl/json.c | 20 ++++- cxl/json.h | 2 + cxl/lib/libcxl.c | 107 ++++++++++++++++++++++++++++ cxl/lib/libcxl.sym | 9 ++ cxl/lib/private.h | 10 +++ cxl/libcxl.h | 15 ++++ cxl/list.c | 13 +++ 12 files changed, 355 insertions(+), 18 deletions(-) diff --git a/.clang-format b/.clang-format index 391cd3420947..106bc5e25434 100644 --- a/.clang-format +++ b/.clang-format @@ -80,6 +80,7 @@ ForEachMacros: - 'cxl_memdev_foreach' - 'cxl_bus_foreach' - 'cxl_port_foreach' + - 'cxl_endpoint_foreach' - 'daxctl_dev_foreach' - 'daxctl_mapping_foreach' - 'daxctl_region_foreach' diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index 42b6de6e5c61..d342da27d3da 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -190,6 +190,12 @@ OPTIONS ---- # cxl list -B # cxl list -P -p root +---- + Additionally, endpoint objects are also ports so the following commands + are also equivalent. +---- +# cxl list -E +# cxl list -P -p endpoint ---- By default, only 'switch' ports are listed. @@ -200,6 +206,16 @@ OPTIONS descendants of the individual ports that match the filter. By default all descendant objects are listed. +-E:: +--endpoints:: + Include endpoint objects (CXL Memory Device decoders) in the + listing. + +-e:: +--endpoint:: + Specify CXL endpoint device name(s), or device id(s) to filter + the emitted endpoint(s). + --debug:: If the cxl tool was built with debug enabled, turn on debug messages. diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index 804e9ca1500e..eebab37acb3d 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -199,12 +199,41 @@ int cxl_port_get_id(struct cxl_port *port); int cxl_port_is_enabled(struct cxl_port *port); bool cxl_port_is_root(struct cxl_port *port); bool cxl_port_is_switch(struct cxl_port *port); +bool cxl_port_is_endpoint(struct cxl_port *port); ---- The port type is communicated via cxl_port_is_(). An 'enabled' port is one that has succeeded in discovering the CXL component registers in the host device and has enumerated its downstream ports. In order for a memdev to be enabled for CXL memory operation all CXL ports in its -ancestry must also be enabled. +ancestry must also be enabled including a root port, an arbitrary number +of intervening switch ports, and a terminal endpoint port. + +ENDPOINTS +--------- +CXL endpoint objects encapsulate the set of host-managed device-memory +(HDM) decoders in a physical memory device. The endpoint is the last hop +in a decoder chain that translate SPA to DPA (system-physical-address to +device-local-physical-address). + +=== ENDPOINT: Enumeration +---- +struct cxl_endpoint *cxl_endpoint_get_first(struct cxl_port *parent); +struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint); +struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint); +struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint); +struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint); + +#define cxl_endpoint_foreach(port, endpoint) \ + for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \ + endpoint = cxl_endpoint_get_next(endpoint)) +---- + +=== ENDPOINT: Attributes +---- +const char *cxl_endpoint_get_devname(struct cxl_endpoint *endpoint); +int cxl_endpoint_get_id(struct cxl_endpoint *endpoint); +int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint); +---- include::../../copyright.txt[] diff --git a/cxl/filter.c b/cxl/filter.c index 32171a47e8d5..5d80d1b3922a 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -47,8 +47,42 @@ bool cxl_filter_has(const char *__filter, const char *needle) return false; } +static struct cxl_endpoint * +util_cxl_endpoint_filter(struct cxl_endpoint *endpoint, const char *__ident) +{ + char *ident, *save; + const char *arg; + int endpoint_id; + + if (!__ident) + return endpoint; + + ident = strdup(__ident); + if (!ident) + return NULL; + + for (arg = strtok_r(ident, which_sep(__ident), &save); arg; + arg = strtok_r(NULL, which_sep(__ident), &save)) { + if (strcmp(arg, "all") == 0) + break; + + if ((sscanf(arg, "%d", &endpoint_id) == 1 || + sscanf(arg, "endpoint%d", &endpoint_id) == 1) && + cxl_endpoint_get_id(endpoint) == endpoint_id) + break; + + if (strcmp(arg, cxl_endpoint_get_devname(endpoint)) == 0) + break; + } + + free(ident); + if (arg) + return endpoint; + return NULL; +} + static struct cxl_port *__util_cxl_port_filter(struct cxl_port *port, - const char *__ident) + const char *__ident) { char *ident, *save; const char *arg; @@ -72,6 +106,9 @@ static struct cxl_port *__util_cxl_port_filter(struct cxl_port *port, if (strcmp(arg, "switch") == 0 && cxl_port_is_switch(port)) break; + if (strcmp(arg, "endpoint") == 0 && cxl_port_is_endpoint(port)) + break; + if ((sscanf(arg, "%d", &port_id) == 1 || sscanf(arg, "port%d", &port_id) == 1) && cxl_port_get_id(port) == port_id) @@ -116,6 +153,24 @@ static struct cxl_port *util_cxl_port_filter(struct cxl_port *port, return NULL; } +static struct cxl_endpoint * +util_cxl_endpoint_filter_by_port(struct cxl_endpoint *endpoint, + const char *ident, + enum cxl_port_filter_mode mode) +{ + struct cxl_port *iter = cxl_endpoint_get_port(endpoint); + + if (util_cxl_port_filter(iter, ident, CXL_PF_SINGLE)) + return endpoint; + iter = cxl_port_get_parent(iter); + if (!iter) + return NULL; + if (util_cxl_port_filter(iter, ident, mode)) + return endpoint; + + return NULL; +} + static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus, const char *__ident) { @@ -325,10 +380,34 @@ static struct json_object *pick_array(struct json_object *child, return NULL; } +static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p, + struct json_object *jeps, unsigned long flags) +{ + struct cxl_endpoint *endpoint; + + cxl_endpoint_foreach(port, endpoint) { + struct cxl_port *ep_port = cxl_endpoint_get_port(endpoint); + struct json_object *jendpoint; + + if (!util_cxl_endpoint_filter(endpoint, p->endpoint_filter)) + continue; + if (!util_cxl_port_filter_by_bus(ep_port, p->bus_filter)) + continue; + if (!util_cxl_endpoint_filter_by_port(endpoint, p->port_filter, + pf_mode(p))) + continue; + if (!p->idle && !cxl_endpoint_is_enabled(endpoint)) + continue; + jendpoint = util_cxl_endpoint_to_json(endpoint, flags); + if (jendpoint) + json_object_array_add(jeps, jendpoint); + } +} + static void walk_child_ports(struct cxl_port *parent_port, struct cxl_filter_params *p, struct json_object *jports, - unsigned long flags) + struct json_object *jeps, unsigned long flags) { struct cxl_port *port; @@ -336,6 +415,7 @@ static void walk_child_ports(struct cxl_port *parent_port, const char *devname = cxl_port_get_devname(port); struct json_object *jport = NULL; struct json_object *jchildports = NULL; + struct json_object *jchildendpoints = NULL; if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p))) goto walk_children; @@ -343,21 +423,41 @@ static void walk_child_ports(struct cxl_port *parent_port, goto walk_children; if (!p->idle && !cxl_port_is_enabled(port)) continue; - if (p->ports) + if (p->ports) { jport = util_cxl_port_to_json(port, flags); - if (!jport) - continue; - json_object_array_add(jports, jport); - jchildports = json_object_new_array(); - if (!jchildports) { - err(p, "%s: failed to enumerate child ports\n", - devname); - continue; + if (!jport) { + err(p, "%s: failed to list\n", devname); + continue; + } + json_object_array_add(jports, jport); + jchildports = json_object_new_array(); + if (!jchildports) { + err(p, "%s: failed to enumerate child ports\n", + devname); + continue; + } + } + + if (p->ports && p->endpoints) { + jchildendpoints = json_object_new_array(); + if (!jchildendpoints) { + err(p, + "%s: failed to enumerate child endpoints\n", + devname); + continue; + } } + walk_children: + if (p->endpoints) + walk_endpoints(port, p, pick_array(jchildendpoints, jeps), + flags); + walk_child_ports(port, p, pick_array(jchildports, jports), - flags); + pick_array(jchildendpoints, jeps), flags); cond_add_put_array_suffix(jport, "ports", devname, jchildports); + cond_add_put_array_suffix(jport, "endpoints", devname, + jchildendpoints); } } @@ -366,6 +466,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) struct json_object *jdevs = NULL, *jbuses = NULL, *jports = NULL; struct json_object *jplatform = json_object_new_array(); unsigned long flags = params_to_flags(p); + struct json_object *jeps = NULL; struct cxl_memdev *memdev; int top_level_objs = 0; struct cxl_bus *bus; @@ -387,6 +488,10 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) if (!jports) goto err; + jeps = json_object_new_array(); + if (!jeps) + goto err; + dbg(p, "walk memdevs\n"); cxl_memdev_foreach(ctx, memdev) { struct json_object *jdev; @@ -408,6 +513,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) cxl_bus_foreach(ctx, bus) { struct json_object *jbus = NULL; struct json_object *jchildports = NULL; + struct json_object *jchildeps = NULL; struct cxl_port *port = cxl_bus_get_port(bus); const char *devname = cxl_bus_get_devname(bus); @@ -431,12 +537,23 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) continue; } } + if (p->endpoints) { + jchildeps = json_object_new_array(); + if (!jchildeps) { + err(p, + "%s: failed to enumerate child endpoints\n", + devname); + continue; + } + } } walk_children: dbg(p, "walk ports\n"); walk_child_ports(port, p, pick_array(jchildports, jports), - flags); + pick_array(jchildeps, jeps), flags); cond_add_put_array_suffix(jbus, "ports", devname, jchildports); + cond_add_put_array_suffix(jbus, "endpoints", devname, + jchildeps); } if (json_object_array_length(jdevs)) @@ -445,10 +562,13 @@ walk_children: top_level_objs++; if (json_object_array_length(jports)) top_level_objs++; + if (json_object_array_length(jeps)) + top_level_objs++; splice_array(p, jdevs, jplatform, "anon memdevs", top_level_objs > 1); splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1); splice_array(p, jports, jplatform, "ports", top_level_objs > 1); + splice_array(p, jeps, jplatform, "endpoints", top_level_objs > 1); util_display_json_array(stdout, jplatform, flags); @@ -457,6 +577,7 @@ err: json_object_put(jdevs); json_object_put(jbuses); json_object_put(jports); + json_object_put(jeps); json_object_put(jplatform); return -ENOMEM; } diff --git a/cxl/filter.h b/cxl/filter.h index 0d83304bd612..bbd341c71721 100644 --- a/cxl/filter.h +++ b/cxl/filter.h @@ -11,7 +11,9 @@ struct cxl_filter_params { const char *serial_filter; const char *bus_filter; const char *port_filter; + const char *endpoint_filter; bool single; + bool endpoints; bool memdevs; bool ports; bool buses; diff --git a/cxl/json.c b/cxl/json.c index d9f864edb86b..08f6192fe121 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -243,8 +243,9 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus, return jbus; } -struct json_object *util_cxl_port_to_json(struct cxl_port *port, - unsigned long flags) +static struct json_object *__util_cxl_port_to_json(struct cxl_port *port, + const char *name_key, + unsigned long flags) { const char *devname = cxl_port_get_devname(port); struct json_object *jport, *jobj; @@ -255,7 +256,7 @@ struct json_object *util_cxl_port_to_json(struct cxl_port *port, jobj = json_object_new_string(devname); if (jobj) - json_object_object_add(jport, "port", jobj); + json_object_object_add(jport, name_key, jobj); if (!cxl_port_is_enabled(port)) { jobj = json_object_new_string("disabled"); @@ -265,3 +266,16 @@ struct json_object *util_cxl_port_to_json(struct cxl_port *port, return jport; } + +struct json_object *util_cxl_port_to_json(struct cxl_port *port, + unsigned long flags) +{ + return __util_cxl_port_to_json(port, "port", flags); +} + +struct json_object *util_cxl_endpoint_to_json(struct cxl_endpoint *endpoint, + unsigned long flags) +{ + return __util_cxl_port_to_json(cxl_endpoint_get_port(endpoint), + "endpoint", flags); +} diff --git a/cxl/json.h b/cxl/json.h index 36653db6ef6a..8f45190f67e5 100644 --- a/cxl/json.h +++ b/cxl/json.h @@ -11,4 +11,6 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus, struct cxl_port; struct json_object *util_cxl_port_to_json(struct cxl_port *port, unsigned long flags); +struct json_object *util_cxl_endpoint_to_json(struct cxl_endpoint *endpoint, + unsigned long flags); #endif /* __CXL_UTIL_JSON_H__ */ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 03eff3cd6073..a25e7152af2a 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -67,14 +67,18 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head) } static void free_port(struct cxl_port *port, struct list_head *head); +static void free_endpoint(struct cxl_endpoint *endpoint, struct list_head *head); static void __free_port(struct cxl_port *port, struct list_head *head) { struct cxl_port *child, *_c; + struct cxl_endpoint *endpoint, *_e; if (head) list_del_from(head, &port->list); list_for_each_safe(&port->child_ports, child, _c, list) free_port(child, &port->child_ports); + list_for_each_safe(&port->endpoints, endpoint, _e, port.list) + free_endpoint(endpoint, &port->endpoints); kmod_module_unref(port->module); free(port->dev_buf); free(port->dev_path); @@ -87,6 +91,12 @@ static void free_port(struct cxl_port *port, struct list_head *head) free(port); } +static void free_endpoint(struct cxl_endpoint *endpoint, struct list_head *head) +{ + __free_port(&endpoint->port, head); + free(endpoint); +} + static void free_bus(struct cxl_bus *bus, struct list_head *head) { __free_port(&bus->port, head); @@ -500,6 +510,7 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_port *parent_port, port->parent = parent_port; list_head_init(&port->child_ports); + list_head_init(&port->endpoints); port->dev_path = strdup(cxlport_base); if (!port->dev_path) @@ -529,6 +540,97 @@ err: return -ENOMEM; } +static void *add_cxl_endpoint(void *parent, int id, const char *cxlep_base) +{ + const char *devname = devpath_to_devname(cxlep_base); + struct cxl_endpoint *endpoint, *endpoint_dup; + struct cxl_port *port = parent; + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + int rc; + + dbg(ctx, "%s: base: \'%s\'\n", devname, cxlep_base); + + endpoint = calloc(1, sizeof(*endpoint)); + if (!endpoint) + return NULL; + + rc = cxl_port_init(&endpoint->port, port, CXL_PORT_ENDPOINT, ctx, id, + cxlep_base); + if (rc) + goto err; + + cxl_endpoint_foreach(port, endpoint_dup) + if (endpoint_dup->port.id == endpoint->port.id) { + free_endpoint(endpoint, NULL); + return endpoint_dup; + } + + list_add(&port->endpoints, &endpoint->port.list); + return endpoint; + +err: + free(endpoint); + return NULL; + +} + +static void cxl_endpoints_init(struct cxl_port *port) +{ + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + + if (port->endpoints_init) + return; + + port->endpoints_init = 1; + + sysfs_device_parse(ctx, port->dev_path, "endpoint", port, + add_cxl_endpoint); +} + +CXL_EXPORT struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint) +{ + return endpoint->port.ctx; +} + +CXL_EXPORT struct cxl_endpoint *cxl_endpoint_get_first(struct cxl_port *port) +{ + cxl_endpoints_init(port); + + return list_top(&port->endpoints, struct cxl_endpoint, port.list); +} + +CXL_EXPORT struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint) +{ + struct cxl_port *port = endpoint->port.parent; + + return list_next(&port->endpoints, endpoint, port.list); +} + +CXL_EXPORT const char *cxl_endpoint_get_devname(struct cxl_endpoint *endpoint) +{ + return devpath_to_devname(endpoint->port.dev_path); +} + +CXL_EXPORT int cxl_endpoint_get_id(struct cxl_endpoint *endpoint) +{ + return endpoint->port.id; +} + +CXL_EXPORT struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint) +{ + return endpoint->port.parent; +} + +CXL_EXPORT struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint) +{ + return &endpoint->port; +} + +CXL_EXPORT int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint) +{ + return cxl_port_is_enabled(&endpoint->port); +} + static void *add_cxl_port(void *parent, int id, const char *cxlport_base) { const char *devname = devpath_to_devname(cxlport_base); @@ -619,6 +721,11 @@ CXL_EXPORT bool cxl_port_is_switch(struct cxl_port *port) return port->type == CXL_PORT_SWITCH; } +CXL_EXPORT bool cxl_port_is_endpoint(struct cxl_port *port) +{ + return port->type == CXL_PORT_ENDPOINT; +} + CXL_EXPORT struct cxl_bus *cxl_port_get_bus(struct cxl_port *port) { struct cxl_bus *bus; diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index a7e923f7d721..7a51a0c42069 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -93,5 +93,14 @@ global: cxl_port_is_root; cxl_port_is_switch; cxl_port_to_bus; + cxl_port_is_endpoint; cxl_port_get_bus; + cxl_endpoint_get_first; + cxl_endpoint_get_next; + cxl_endpoint_get_devname; + cxl_endpoint_get_id; + cxl_endpoint_get_ctx; + cxl_endpoint_is_enabled; + cxl_endpoint_get_parent; + cxl_endpoint_get_port; } LIBCXL_1; diff --git a/cxl/lib/private.h b/cxl/lib/private.h index 637f90d8dfa2..cedd2f2361a1 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -17,6 +17,7 @@ struct cxl_pmem { char *dev_path; }; +struct cxl_endpoint; struct cxl_memdev { int id, major, minor; void *dev_buf; @@ -32,11 +33,13 @@ struct cxl_memdev { struct kmod_module *module; struct cxl_pmem *pmem; unsigned long long serial; + struct cxl_endpoint *endpoint; }; enum cxl_port_type { CXL_PORT_ROOT, CXL_PORT_SWITCH, + CXL_PORT_ENDPOINT, }; struct cxl_port { @@ -46,6 +49,7 @@ struct cxl_port { char *dev_path; char *uport; int ports_init; + int endpoints_init; struct cxl_ctx *ctx; struct cxl_bus *bus; enum cxl_port_type type; @@ -53,12 +57,18 @@ struct cxl_port { struct kmod_module *module; struct list_node list; struct list_head child_ports; + struct list_head endpoints; }; struct cxl_bus { struct cxl_port port; }; +struct cxl_endpoint { + struct cxl_port port; + struct cxl_memdev *memdev; +}; + enum cxl_cmd_query_status { CXL_CMD_QUERY_NOT_RUN = 0, CXL_CMD_QUERY_OK, diff --git a/cxl/libcxl.h b/cxl/libcxl.h index efbb397eb2be..f6ba9a105168 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -81,12 +81,27 @@ struct cxl_port *cxl_port_get_parent(struct cxl_port *port); bool cxl_port_is_root(struct cxl_port *port); bool cxl_port_is_switch(struct cxl_port *port); struct cxl_bus *cxl_port_to_bus(struct cxl_port *port); +bool cxl_port_is_endpoint(struct cxl_port *port); struct cxl_bus *cxl_port_get_bus(struct cxl_port *port); #define cxl_port_foreach(parent, port) \ for (port = cxl_port_get_first(parent); port != NULL; \ port = cxl_port_get_next(port)) +struct cxl_endpoint; +struct cxl_endpoint *cxl_endpoint_get_first(struct cxl_port *parent); +struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint); +const char *cxl_endpoint_get_devname(struct cxl_endpoint *endpoint); +int cxl_endpoint_get_id(struct cxl_endpoint *endpoint); +struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint); +int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint); +struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint); +struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint); + +#define cxl_endpoint_foreach(port, endpoint) \ + for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \ + endpoint = cxl_endpoint_get_next(endpoint)) + 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/cxl/list.c b/cxl/list.c index 01ab19bff706..b15e01ce40f6 100644 --- a/cxl/list.c +++ b/cxl/list.c @@ -31,6 +31,11 @@ static const struct option options[] = { OPT_BOOLEAN('P', "ports", ¶m.ports, "include CXL port info"), OPT_BOOLEAN('S', "single", ¶m.single, "skip listing descendant objects"), + OPT_STRING('e', "endpoint", ¶m.endpoint_filter, + "endpoint device name", + "filter by CXL endpoint device name(s)"), + OPT_BOOLEAN('E', "endpoints", ¶m.endpoints, + "include CXL endpoint info"), OPT_BOOLEAN('i', "idle", ¶m.idle, "include disabled devices"), OPT_BOOLEAN('u', "human", ¶m.human, "use human friendly number formats "), @@ -44,7 +49,8 @@ static const struct option options[] = { static int num_list_flags(void) { - return !!param.memdevs + !!param.buses + !!param.ports; + return !!param.memdevs + !!param.buses + !!param.ports + + !!param.endpoints; } int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) @@ -74,6 +80,8 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) param.buses = true; if (param.port_filter) param.ports = true; + if (param.endpoint_filter) + param.endpoints = true; if (num_list_flags() == 0) { /* * TODO: We likely want to list regions by default if @@ -96,6 +104,9 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) if (cxl_filter_has(param.port_filter, "root") && param.ports) param.buses = true; + if (cxl_filter_has(param.port_filter, "endpoint") && param.ports) + param.endpoints = true; + dbg(¶m, "walk topology\n"); return cxl_filter_walk(ctx, ¶m); } From patchwork Mon Jan 24 00:53:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721357 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 DB5AFC433F5 for ; Mon, 24 Jan 2022 00:53:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240662AbiAXAxf (ORCPT ); Sun, 23 Jan 2022 19:53:35 -0500 Received: from mga09.intel.com ([134.134.136.24]:11570 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240660AbiAXAxf (ORCPT ); Sun, 23 Jan 2022 19:53:35 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985615; x=1674521615; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=nlNfJkKl8APMxEXgALkB1i3Sa/zDe5+OYQ/NpI1ky10=; b=dr690TEe/CTCcJvbgdlNmMtIC9hqmPd0Agws2OvQPWb3vyAFlCr+773s t7GlhWu4qC4On2haMeE4Dqsfp3bqQJaTQ+4AoItcnWCUQ/Rs3yX1lA4Ne oYK5/CF/iSCFIq89M3gB1ZGmw2mHOREkFbmgtwWsttyoj1lqJUrxmVmFZ Uwsj+8LXpZ+p85IPvgw/uf3GHSok6fVWZ8x1i7cSlkeImg4l05HnZ/s5P Yz0/YGw3UUD/vu8wxavXZTK4WQ3BXz7WVV3BfWr1YWJK/AruOiStOqa8S nKVeZ3Z8dh9caLSNNxTCmvRqoUm+iATh3AqNcEqSxHhhJDtIvjXGQzGho A==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="245716883" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="245716883" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:34 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="695243471" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:34 -0800 Subject: [ndctl PATCH 20/37] cxl/list: Add 'host' entries for port-like objects From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:53:34 -0800 Message-ID: <164298561473.3021641.16508989603599026269.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Add the device name of the "host" device for a given CXL port object. The kernel calls this the 'uport' attribute. Signed-off-by: Dan Williams --- Documentation/cxl/cxl-list.txt | 9 +++++++++ Documentation/cxl/lib/libcxl.txt | 5 +++++ cxl/json.c | 4 ++++ cxl/lib/libcxl.c | 10 ++++++++++ cxl/lib/libcxl.sym | 2 ++ cxl/libcxl.h | 2 ++ 6 files changed, 32 insertions(+) diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index d342da27d3da..30b61615644b 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -210,6 +210,15 @@ OPTIONS --endpoints:: Include endpoint objects (CXL Memory Device decoders) in the listing. +---- +# cxl list -E +[ + { + "endpoint":"endpoint2", + "host":"mem0" + } +] +---- -e:: --endpoint:: diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index eebab37acb3d..e4b372d781ec 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -178,6 +178,7 @@ struct cxl_port *cxl_port_get_next(struct cxl_port *port); struct cxl_port *cxl_port_get_parent(struct cxl_port *port); struct cxl_bus *cxl_port_get_bus(struct cxl_port *port); struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port); +const char *cxl_port_get_host(struct cxl_port *port); #define cxl_port_foreach(parent, port) \ for (port = cxl_port_get_first(parent); port != NULL; \ @@ -192,6 +193,9 @@ as a parent object retrievable via cxl_port_get_parent(). The root port of a hiearchy can be retrieved via any port instance in that hierarchy via cxl_port_get_bus(). +The host of a port is the corresponding device name of the PCIe Root +Port, or Switch Upstream Port with CXL capabilities. + === PORT: Attributes ---- const char *cxl_port_get_devname(struct cxl_port *port); @@ -222,6 +226,7 @@ struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint); struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint); struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint); struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint); +const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint); #define cxl_endpoint_foreach(port, endpoint) \ for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \ diff --git a/cxl/json.c b/cxl/json.c index 08f6192fe121..af3b4fe6a0eb 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -258,6 +258,10 @@ static struct json_object *__util_cxl_port_to_json(struct cxl_port *port, if (jobj) json_object_object_add(jport, name_key, jobj); + jobj = json_object_new_string(cxl_port_get_host(port)); + if (jobj) + json_object_object_add(jport, "host", jobj); + if (!cxl_port_is_enabled(port)) { jobj = json_object_new_string("disabled"); if (jobj) diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index a25e7152af2a..5f48202d7b93 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -626,6 +626,11 @@ CXL_EXPORT struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint) return &endpoint->port; } +CXL_EXPORT const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint) +{ + return cxl_port_get_host(&endpoint->port); +} + CXL_EXPORT int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint) { return cxl_port_is_enabled(&endpoint->port); @@ -744,6 +749,11 @@ CXL_EXPORT struct cxl_bus *cxl_port_get_bus(struct cxl_port *port) return bus; } +CXL_EXPORT const char *cxl_port_get_host(struct cxl_port *port) +{ + return devpath_to_devname(port->uport); +} + CXL_EXPORT int cxl_port_is_enabled(struct cxl_port *port) { struct cxl_ctx *ctx = cxl_port_get_ctx(port); diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 7a51a0c42069..dc2863e150cf 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -95,6 +95,7 @@ global: cxl_port_to_bus; cxl_port_is_endpoint; cxl_port_get_bus; + cxl_port_get_host; cxl_endpoint_get_first; cxl_endpoint_get_next; cxl_endpoint_get_devname; @@ -103,4 +104,5 @@ global: cxl_endpoint_is_enabled; cxl_endpoint_get_parent; cxl_endpoint_get_port; + cxl_endpoint_get_host; } LIBCXL_1; diff --git a/cxl/libcxl.h b/cxl/libcxl.h index f6ba9a105168..a60777ed0c7a 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -83,6 +83,7 @@ bool cxl_port_is_switch(struct cxl_port *port); struct cxl_bus *cxl_port_to_bus(struct cxl_port *port); bool cxl_port_is_endpoint(struct cxl_port *port); struct cxl_bus *cxl_port_get_bus(struct cxl_port *port); +const char *cxl_port_get_host(struct cxl_port *port); #define cxl_port_foreach(parent, port) \ for (port = cxl_port_get_first(parent); port != NULL; \ @@ -97,6 +98,7 @@ struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint); int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint); struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint); struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint); +const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint); #define cxl_endpoint_foreach(port, endpoint) \ for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \ From patchwork Mon Jan 24 00:53:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721358 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 6BEFDC433EF for ; Mon, 24 Jan 2022 00:53:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240663AbiAXAxm (ORCPT ); Sun, 23 Jan 2022 19:53:42 -0500 Received: from mga11.intel.com ([192.55.52.93]:50286 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240660AbiAXAxm (ORCPT ); Sun, 23 Jan 2022 19:53:42 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985622; x=1674521622; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=EWL74daI4RE7U3oJ2loKOce0BhS8tpZ+25y8801Ll3s=; b=g9pfv3pL+TU9c6fZDfvNkPVCU4sB4rmwDwEpuatqOa8u2uAt9l7vOKYT xam5dhn/GcrHtYDjahwMN/Cv666vKThdN02Bncse6elJtmI0zx3Ka9dp7 jlmAYpiQSneVS1I2tIIcZXnhJa06hO3eNMW/QuNxqK3pbNk+jYMmvsIZd FgkdLh5ikML1pyruaze2Lp9VXSENwK9tlHcLp88kRcT6/m9tjM69OuEJ+ lsvlS2Ib94XxjG5T8a5VhuvzvCJxwplZSAiNHVNa5tvEyIUksEWFXeyRu zcDPVBF1GM9grtC1ZMXr7QdsW+UyT0z3/JefSGEw9QRY8//7RbJ8hHaQm w==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="243530620" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="243530620" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:40 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="673456489" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga001-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:40 -0800 Subject: [ndctl PATCH 21/37] cxl/list: Add 'host' entries for memdevs From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:53:39 -0800 Message-ID: <164298561980.3021641.9636572507721689266.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org For debugging CXL port connectivity issues it will be useful to have the PCI device name for the memory expander in the 'memdev' listing. Signed-off-by: Dan Williams --- Documentation/cxl/cxl-list.txt | 3 ++- Documentation/cxl/lib/libcxl.txt | 4 ++++ cxl/json.c | 5 +++++ cxl/lib/libcxl.c | 24 ++++++++++++++++++++++++ cxl/lib/libcxl.sym | 1 + cxl/lib/private.h | 1 + cxl/libcxl.h | 1 + 7 files changed, 38 insertions(+), 1 deletion(-) diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index 30b61615644b..9c21ab7afd74 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -43,7 +43,8 @@ EXAMPLE "memdev":"mem0", "pmem_size":268435456, "ram_size":0, - "serial":0 + "serial":0, + "host":"0000:35:00.0" } ] diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index e4b372d781ec..91fd33e8b1ae 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -40,6 +40,7 @@ kernel, or to send data or trigger kernel operations for a given device. struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx); struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev); struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev); +const char *cxl_memdev_get_host(struct cxl_memdev *memdev) #define cxl_memdev_foreach(ctx, memdev) \ for (memdev = cxl_memdev_get_first(ctx); \ @@ -54,6 +55,9 @@ memory device commands, see the port, decoder, and endpoint APIs to determine what if any CXL Memory Resources are reachable given a specific memdev. +The host of a memdev is the PCIe Endpoint device that registered its CXL +capabilities with the Linux CXL core. + === MEMDEV: Attributes ---- int cxl_memdev_get_id(struct cxl_memdev *memdev); diff --git a/cxl/json.c b/cxl/json.c index af3b4fe6a0eb..18686867e0c5 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -219,6 +219,11 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev, if (jobj) json_object_object_add(jdev, "serial", jobj); } + + jobj = json_object_new_string(cxl_memdev_get_host(memdev)); + if (jobj) + json_object_object_add(jdev, "host", jobj); + return jdev; } diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 5f48202d7b93..c4ddc7d80cff 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -63,6 +63,7 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head) free(memdev->firmware_version); free(memdev->dev_buf); free(memdev->dev_path); + free(memdev->host); free(memdev); } @@ -297,6 +298,7 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base) char *path = calloc(1, strlen(cxlmem_base) + 100); struct cxl_ctx *ctx = parent; struct cxl_memdev *memdev, *memdev_dup; + char *host, *rpath = NULL; char buf[SYSFS_ATTR_SIZE]; struct stat st; @@ -350,6 +352,22 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base) if (!memdev->dev_path) goto err_read; + rpath = realpath(cxlmem_base, NULL); + if (!rpath) + goto err_read; + host = strrchr(rpath, '/'); + if (host) { + host[0] = '\0'; + host = strrchr(rpath, '/'); + } + if (!host) + goto err_read; + memdev->host = strdup(host + 1); + if (!memdev->host) + goto err_read; + free(rpath); + rpath = NULL; + sprintf(path, "%s/firmware_version", cxlmem_base); if (sysfs_read_attr(ctx, path, buf) < 0) goto err_read; @@ -381,6 +399,7 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base) free(memdev->dev_buf); free(memdev->dev_path); free(memdev); + free(rpath); err_dev: free(path); return NULL; @@ -431,6 +450,11 @@ CXL_EXPORT const char *cxl_memdev_get_devname(struct cxl_memdev *memdev) return devpath_to_devname(memdev->dev_path); } +CXL_EXPORT const char *cxl_memdev_get_host(struct cxl_memdev *memdev) +{ + return memdev->host; +} + CXL_EXPORT int cxl_memdev_get_major(struct cxl_memdev *memdev) { return memdev->major; diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index dc2863e150cf..8f0688a95f5d 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -77,6 +77,7 @@ local: LIBCXL_2 { global: cxl_memdev_get_serial; + cxl_memdev_get_host; cxl_bus_get_first; cxl_bus_get_next; cxl_bus_get_provider; diff --git a/cxl/lib/private.h b/cxl/lib/private.h index cedd2f2361a1..b097bdfbfd6b 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -22,6 +22,7 @@ struct cxl_memdev { int id, major, minor; void *dev_buf; size_t buf_len; + char *host; char *dev_path; char *firmware_version; struct cxl_ctx *ctx; diff --git a/cxl/libcxl.h b/cxl/libcxl.h index a60777ed0c7a..5487b55d2fc0 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -38,6 +38,7 @@ struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev); int cxl_memdev_get_id(struct cxl_memdev *memdev); unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev); const char *cxl_memdev_get_devname(struct cxl_memdev *memdev); +const char *cxl_memdev_get_host(struct cxl_memdev *memdev); int cxl_memdev_get_major(struct cxl_memdev *memdev); int cxl_memdev_get_minor(struct cxl_memdev *memdev); struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev); From patchwork Mon Jan 24 00:53:45 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721359 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 6AA5BC433EF for ; Mon, 24 Jan 2022 00:53:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240665AbiAXAxq (ORCPT ); Sun, 23 Jan 2022 19:53:46 -0500 Received: from mga11.intel.com ([192.55.52.93]:50286 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240664AbiAXAxp (ORCPT ); Sun, 23 Jan 2022 19:53:45 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985625; x=1674521625; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=QY9OEjQPopMeuj4Rq5NClpHoK0/HVipAGewHagXYzaM=; b=K0pkkRY3J17CmmIhTSoFROcaLAW7aeWecmw0Ut+u4+SbRU8AcIpaLm7O Qr5oa0tb4vVHixSkQK9EKeYAa1epWz7dtl5CG+olRezo2o6uvW0F0Fba4 hB9kLyvAY7n5JBYz1CDHxfzhzfKliOc33HUE3PRlxRpKl0IntSeRiF7ue tWPPARBgdkjKEWZOLFUOx6mTWPLLzpwdQ/27TV7THu7jdLGklLtRgYw+7 39oeP0yElYRFc0v4U9w/K8TZuZWOTb+HaqPz0KDa8PwvcE1uQXPVUE0ta 39nPoHK0YcqBQlKlMecfTEzuDgLbKUCsqWSEoJf3bz5T4NDvcLdfkSlfv w==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="243530625" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="243530625" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:45 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="562476419" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:45 -0800 Subject: [ndctl PATCH 22/37] cxl/list: Move enabled memdevs underneath their endpoint From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:53:45 -0800 Message-ID: <164298562531.3021641.10620937879296964476.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org When a memdev is enabled it means that the kernel was able to validate a CXL connection from the CXL root, through intervening switches, and to the endpoint. Reflect that state by listing memdevs as child objects of endpoints, or aggregated into an array if individual endpoints are not listed. Signed-off-by: Dan Williams --- Documentation/cxl/cxl-list.txt | 11 +++ Documentation/cxl/lib/libcxl.txt | 2 + cxl/filter.c | 130 ++++++++++++++++++++++++++++++-------- cxl/json.c | 6 ++ cxl/lib/libcxl.c | 97 ++++++++++++++++++++++++++++ cxl/lib/libcxl.sym | 3 + cxl/libcxl.h | 4 + 7 files changed, 223 insertions(+), 30 deletions(-) diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index 9c21ab7afd74..175186819312 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -19,7 +19,16 @@ Options can be specified to limit the output to specific objects. When a single object type is specified the return json object is an array of just those objects, when multiple objects types are specified the returned the returned object may be an array of arrays with the inner -array named for the given object type. +array named for the given object type. The top-level arrays are ellided +when the objects can nest under a higher object-type in the hierararchy. +The potential top-level array names and their nesting properties are: + +"anon memdevs":: (disabled memory devices) do not nest +"buses":: do not nest +"ports":: nest under buses +"endpoints":: nest under ports or buses (if ports are not emitted) +"memdevs":: nest under endpoints or ports (if endpoints are not + emitted) or buses (if endpoints and ports are not emitted) Filters can by specifed as either a single identidier, a space separated quoted string, or a comma separated list. When multiple filter diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index 91fd33e8b1ae..73b0fb9c2062 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -41,6 +41,7 @@ struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx); struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev); struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev); const char *cxl_memdev_get_host(struct cxl_memdev *memdev) +struct cxl_memdev *cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint); #define cxl_memdev_foreach(ctx, memdev) \ for (memdev = cxl_memdev_get_first(ctx); \ @@ -231,6 +232,7 @@ struct cxl_ctx *cxl_endpoint_get_ctx(struct cxl_endpoint *endpoint); struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint); struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint); const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint); +struct cxl_endpoint *cxl_memdev_get_endpoint(struct cxl_memdev *memdev); #define cxl_endpoint_foreach(port, endpoint) \ for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \ diff --git a/cxl/filter.c b/cxl/filter.c index 5d80d1b3922a..2130816931e5 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -381,13 +381,16 @@ static struct json_object *pick_array(struct json_object *child, } static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p, - struct json_object *jeps, unsigned long flags) + struct json_object *jeps, struct json_object *jdevs, + unsigned long flags) { struct cxl_endpoint *endpoint; cxl_endpoint_foreach(port, endpoint) { struct cxl_port *ep_port = cxl_endpoint_get_port(endpoint); - struct json_object *jendpoint; + const char *devname = cxl_endpoint_get_devname(endpoint); + struct json_object *jendpoint = NULL; + struct cxl_memdev *memdev; if (!util_cxl_endpoint_filter(endpoint, p->endpoint_filter)) continue; @@ -398,24 +401,54 @@ static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p, continue; if (!p->idle && !cxl_endpoint_is_enabled(endpoint)) continue; - jendpoint = util_cxl_endpoint_to_json(endpoint, flags); - if (jendpoint) + if (p->endpoints) { + jendpoint = util_cxl_endpoint_to_json(endpoint, flags); + if (!jendpoint) { + err(p, "%s: failed to list\n", devname); + continue; + } json_object_array_add(jeps, jendpoint); + } + if (p->memdevs) { + struct json_object *jobj; + + memdev = cxl_endpoint_get_memdev(endpoint); + if (!memdev) + continue; + if (!util_cxl_memdev_filter(memdev, p->memdev_filter, + p->serial_filter)) + continue; + if (!p->idle && !cxl_memdev_is_enabled(memdev)) + continue; + jobj = util_cxl_memdev_to_json(memdev, flags); + if (!jobj) { + err(p, "failed to json serialize %s\n", + cxl_memdev_get_devname(memdev)); + continue; + } + if (p->endpoints) + json_object_object_add(jendpoint, "memdev", + jobj); + else + json_object_array_add(jdevs, jobj); + } } } static void walk_child_ports(struct cxl_port *parent_port, struct cxl_filter_params *p, struct json_object *jports, - struct json_object *jeps, unsigned long flags) + struct json_object *jeps, + struct json_object *jdevs, unsigned long flags) { struct cxl_port *port; cxl_port_foreach(parent_port, port) { const char *devname = cxl_port_get_devname(port); struct json_object *jport = NULL; + struct json_object *jchilddevs = NULL; struct json_object *jchildports = NULL; - struct json_object *jchildendpoints = NULL; + struct json_object *jchildeps = NULL; if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p))) goto walk_children; @@ -436,28 +469,41 @@ static void walk_child_ports(struct cxl_port *parent_port, devname); continue; } - } - if (p->ports && p->endpoints) { - jchildendpoints = json_object_new_array(); - if (!jchildendpoints) { - err(p, - "%s: failed to enumerate child endpoints\n", - devname); - continue; + if (p->memdevs && !p->endpoints) { + jchilddevs = json_object_new_array(); + if (!jchilddevs) { + err(p, + "%s: failed to enumerate child memdevs\n", + devname); + continue; + } + } + + if (p->endpoints) { + jchildeps = json_object_new_array(); + if (!jchildeps) { + err(p, + "%s: failed to enumerate child endpoints\n", + devname); + continue; + } } } walk_children: - if (p->endpoints) - walk_endpoints(port, p, pick_array(jchildendpoints, jeps), - flags); + if (p->endpoints || p->memdevs) + walk_endpoints(port, p, pick_array(jchildeps, jeps), + pick_array(jchilddevs, jdevs), flags); walk_child_ports(port, p, pick_array(jchildports, jports), - pick_array(jchildendpoints, jeps), flags); + pick_array(jchildeps, jeps), + pick_array(jchilddevs, jdevs), flags); cond_add_put_array_suffix(jport, "ports", devname, jchildports); cond_add_put_array_suffix(jport, "endpoints", devname, - jchildendpoints); + jchildeps); + cond_add_put_array_suffix(jport, "memdevs", devname, + jchilddevs); } } @@ -466,6 +512,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) struct json_object *jdevs = NULL, *jbuses = NULL, *jports = NULL; struct json_object *jplatform = json_object_new_array(); unsigned long flags = params_to_flags(p); + struct json_object *janondevs = NULL; struct json_object *jeps = NULL; struct cxl_memdev *memdev; int top_level_objs = 0; @@ -476,8 +523,8 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) return -ENOMEM; } - jdevs = json_object_new_array(); - if (!jdevs) + janondevs = json_object_new_array(); + if (!janondevs) goto err; jbuses = json_object_new_array(); @@ -492,20 +539,28 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) if (!jeps) goto err; + jdevs = json_object_new_array(); + if (!jdevs) + goto err; + dbg(p, "walk memdevs\n"); cxl_memdev_foreach(ctx, memdev) { - struct json_object *jdev; + struct json_object *janondev; if (!util_cxl_memdev_filter(memdev, p->memdev_filter, p->serial_filter)) continue; + if (cxl_memdev_is_enabled(memdev)) + continue; + if (!p->idle) + continue; if (p->memdevs) { - jdev = util_cxl_memdev_to_json(memdev, flags); - if (!jdev) { + janondev = util_cxl_memdev_to_json(memdev, flags); + if (!janondev) { dbg(p, "memdev object allocation failure\n"); continue; } - json_object_array_add(jdevs, jdev); + json_object_array_add(janondevs, janondev); } } @@ -513,6 +568,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) cxl_bus_foreach(ctx, bus) { struct json_object *jbus = NULL; struct json_object *jchildports = NULL; + struct json_object *jchilddevs = NULL; struct json_object *jchildeps = NULL; struct cxl_port *port = cxl_bus_get_port(bus); const char *devname = cxl_bus_get_devname(bus); @@ -546,17 +602,29 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) continue; } } + + if (p->memdevs && !p->ports && !p->endpoints) { + jchilddevs = json_object_new_array(); + if (!jchilddevs) { + err(p, + "%s: failed to enumerate child memdevs\n", + devname); + continue; + } + } } walk_children: dbg(p, "walk ports\n"); walk_child_ports(port, p, pick_array(jchildports, jports), - pick_array(jchildeps, jeps), flags); + pick_array(jchildeps, jeps), + pick_array(jchilddevs, jdevs), flags); cond_add_put_array_suffix(jbus, "ports", devname, jchildports); cond_add_put_array_suffix(jbus, "endpoints", devname, jchildeps); + cond_add_put_array_suffix(jbus, "memdevs", devname, jchilddevs); } - if (json_object_array_length(jdevs)) + if (json_object_array_length(janondevs)) top_level_objs++; if (json_object_array_length(jbuses)) top_level_objs++; @@ -564,20 +632,24 @@ walk_children: top_level_objs++; if (json_object_array_length(jeps)) top_level_objs++; + if (json_object_array_length(jdevs)) + top_level_objs++; - splice_array(p, jdevs, jplatform, "anon memdevs", top_level_objs > 1); + splice_array(p, janondevs, jplatform, "anon memdevs", top_level_objs > 1); splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1); splice_array(p, jports, jplatform, "ports", top_level_objs > 1); splice_array(p, jeps, jplatform, "endpoints", top_level_objs > 1); + splice_array(p, jdevs, jplatform, "memdevs", top_level_objs > 1); util_display_json_array(stdout, jplatform, flags); return 0; err: - json_object_put(jdevs); + json_object_put(janondevs); json_object_put(jbuses); json_object_put(jports); json_object_put(jeps); + json_object_put(jdevs); json_object_put(jplatform); return -ENOMEM; } diff --git a/cxl/json.c b/cxl/json.c index 18686867e0c5..b809332b8d51 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -224,6 +224,12 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev, if (jobj) json_object_object_add(jdev, "host", jobj); + if (!cxl_memdev_is_enabled(memdev)) { + jobj = json_object_new_string("disabled"); + if (jobj) + json_object_object_add(jdev, "state", jobj); + } + return jdev; } diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index c4ddc7d80cff..4523ca630d11 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -480,6 +480,60 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev return memdev->firmware_version; } +static struct cxl_endpoint *cxl_port_find_endpoint(struct cxl_port *parent_port, + struct cxl_memdev *memdev) +{ + struct cxl_endpoint *endpoint; + struct cxl_port *port; + + cxl_port_foreach(parent_port, port) { + cxl_endpoint_foreach(port, endpoint) + if (strcmp(cxl_endpoint_get_host(endpoint), + cxl_memdev_get_devname(memdev)) == 0) + return endpoint; + endpoint = cxl_port_find_endpoint(port, memdev); + if (endpoint) + return endpoint; + } + + return NULL; +} + +CXL_EXPORT struct cxl_endpoint * +cxl_memdev_get_endpoint(struct cxl_memdev *memdev) +{ + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + struct cxl_endpoint *endpoint = NULL; + struct cxl_bus *bus; + + if (memdev->endpoint) + return memdev->endpoint; + + if (!cxl_memdev_is_enabled(memdev)) + return NULL; + + cxl_bus_foreach (ctx, bus) { + struct cxl_port *port = cxl_bus_get_port(bus); + + endpoint = cxl_port_find_endpoint(port, memdev); + if (endpoint) + break; + } + + if (!endpoint) + return NULL; + + if (endpoint->memdev && endpoint->memdev != memdev) + err(ctx, "%s assigned to %s not %s\n", + cxl_endpoint_get_devname(endpoint), + cxl_memdev_get_devname(endpoint->memdev), + cxl_memdev_get_devname(memdev)); + memdev->endpoint = endpoint; + endpoint->memdev = memdev; + + return endpoint; +} + CXL_EXPORT size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev) { return memdev->lsa_size; @@ -495,6 +549,21 @@ static int is_enabled(const char *drvpath) return 1; } +CXL_EXPORT int cxl_memdev_is_enabled(struct cxl_memdev *memdev) +{ + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + char *path = memdev->dev_buf; + int len = memdev->buf_len; + + if (snprintf(path, len, "%s/driver", memdev->dev_path) >= len) { + err(ctx, "%s: buffer too small!\n", + cxl_memdev_get_devname(memdev)); + return 0; + } + + return is_enabled(path); +} + CXL_EXPORT int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev) { struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); @@ -660,6 +729,34 @@ CXL_EXPORT int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint) return cxl_port_is_enabled(&endpoint->port); } +CXL_EXPORT struct cxl_memdev * +cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint) +{ + struct cxl_ctx *ctx = cxl_endpoint_get_ctx(endpoint); + struct cxl_memdev *memdev; + + if (endpoint->memdev) + return endpoint->memdev; + + if (!cxl_endpoint_is_enabled(endpoint)) + return NULL; + + cxl_memdev_foreach(ctx, memdev) + if (strcmp(cxl_memdev_get_devname(memdev), + cxl_endpoint_get_host(endpoint)) == 0) { + if (memdev->endpoint && memdev->endpoint != endpoint) + err(ctx, "%s assigned to %s not %s\n", + cxl_memdev_get_devname(memdev), + cxl_endpoint_get_devname(memdev->endpoint), + cxl_endpoint_get_devname(endpoint)); + endpoint->memdev = memdev; + memdev->endpoint = endpoint; + return memdev; + } + + return NULL; +} + static void *add_cxl_port(void *parent, int id, const char *cxlport_base) { const char *devname = devpath_to_devname(cxlport_base); diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 8f0688a95f5d..321acac57e3e 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -106,4 +106,7 @@ global: cxl_endpoint_get_parent; cxl_endpoint_get_port; cxl_endpoint_get_host; + cxl_endpoint_get_memdev; + cxl_memdev_get_endpoint; + cxl_memdev_is_enabled; } LIBCXL_1; diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 5487b55d2fc0..790ece86529d 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -46,6 +46,8 @@ unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev); unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev); const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev); size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev); +struct cxl_endpoint; +struct cxl_endpoint *cxl_memdev_get_endpoint(struct cxl_memdev *memdev); int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev); int cxl_memdev_zero_label(struct cxl_memdev *memdev, size_t length, size_t offset); @@ -100,6 +102,8 @@ int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint); struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint); struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint); const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint); +struct cxl_memdev *cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint); +int cxl_memdev_is_enabled(struct cxl_memdev *memdev); #define cxl_endpoint_foreach(port, endpoint) \ for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \ From patchwork Mon Jan 24 00:53:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721360 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 45F2EC433EF for ; Mon, 24 Jan 2022 00:53:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240664AbiAXAxv (ORCPT ); Sun, 23 Jan 2022 19:53:51 -0500 Received: from mga09.intel.com ([134.134.136.24]:11583 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240660AbiAXAxu (ORCPT ); Sun, 23 Jan 2022 19:53:50 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985630; x=1674521630; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=NA9Ba8PwrBwR9ysJrgDyr6L43DP0dVHrC+G6evTqk+k=; b=NmjvHSWVq4w+eXoT+zqXCrlIouj5UYms6mY8gMiZUVYGnGTpN/I5xepI Q0pn/xzmZx6w2aHBG3CupNPiWWS5SYGPd9B1MQsn0ZnrGOlU+oUL/EYUR T7MQ+ESt4y1pVJktm+5Bdr+1Mf/XrobQZFCXhNrhqG/j/xG2stTMyPwuA EezmwBh4Nc2/hJXkPLwS+WjJdYkNerUVjhgndBJ+v14HSxeQ7n665MjFr gfVSaAAoLTLJTTChNLAjzSmfpcYtLrCxdFQXbA9QxnDK9w10yIH1Iaoxt giynWr8VuZklyYnNJUR8mTV5SAuRd37g+dGQx6+NBEPzN2rI8+TA6/vGj A==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="245716899" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="245716899" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:50 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="519735908" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:50 -0800 Subject: [ndctl PATCH 23/37] cxl/list: Filter memdev by ancestry From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:53:50 -0800 Message-ID: <164298563039.3021641.5253222797042241091.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Whenever a memdev filter is specified limit output of buses, ports and endpoints to those that are in the memdev's ancestry. Signed-off-by: Dan Williams --- Documentation/cxl/cxl-list.txt | 19 ++++++++++ Documentation/cxl/lib/libcxl.txt | 11 ++++++ cxl/filter.c | 69 ++++++++++++++++++++++++++++++++++++++ cxl/lib/libcxl.c | 36 ++++++++++++++++++++ cxl/lib/libcxl.sym | 5 +++ cxl/libcxl.h | 4 ++ 6 files changed, 144 insertions(+) diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index 175186819312..bac27c7b70a1 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -39,6 +39,25 @@ they are combined as an 'AND' filter. So, "-m mem0,mem1,mem2 -p port10" would only list objects that are beneath port10 AND map mem0, mem1, OR mem2. +Given that many topology queries seek to answer questions relative to a +given memdev, buses, ports, and endpoints can be filtered by one or more +memdevs. For example: +---- +# cxl list -P -p switch,endpoint -m mem0 +[ + { + "port":"port1", + "host":"ACPI0016:00", + "endpoints:port1":[ + { + "endpoint":"endpoint2", + "host":"mem0" + } + ] + } +] +---- + The --human option in addition to reformatting some fields to more human friendly strings also unwraps the array to reduce the number of lines of output. diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index 73b0fb9c2062..b0253d7be07c 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -150,11 +150,18 @@ cxl_bus'. ---- struct cxl_bus *cxl_bus_get_first(struct cxl_ctx *ctx); struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus); +struct cxl_ctx *cxl_bus_get_ctx(struct cxl_bus *bus); +struct cxl_bus *cxl_memdev_get_bus(struct cxl_memdev *memdev); +struct cxl_bus *cxl_endpoint_get_bus(struct cxl_endpoint *endpoint); #define cxl_bus_foreach(ctx, bus) \ for (bus = cxl_bus_get_first(ctx); bus != NULL; \ bus = cxl_bus_get_next(bus)) ---- +When a memdev is active it has established a CXL port hierarchy between +itself and the root of its associated CXL topology. The +cxl_{memdev,endpoint}_get_bus() helpers walk that topology to retrieve +the associated bus object. === BUS: Attributes ---- @@ -209,6 +216,7 @@ int cxl_port_is_enabled(struct cxl_port *port); bool cxl_port_is_root(struct cxl_port *port); bool cxl_port_is_switch(struct cxl_port *port); bool cxl_port_is_endpoint(struct cxl_port *port); +bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev); ---- The port type is communicated via cxl_port_is_(). An 'enabled' port is one that has succeeded in discovering the CXL component registers in @@ -217,6 +225,9 @@ memdev to be enabled for CXL memory operation all CXL ports in its ancestry must also be enabled including a root port, an arbitrary number of intervening switch ports, and a terminal endpoint port. +cxl_port_hosts_memdev() returns true if the port's host appears in the +memdev host's device topology ancestry. + ENDPOINTS --------- CXL endpoint objects encapsulate the set of host-managed device-memory diff --git a/cxl/filter.c b/cxl/filter.c index 2130816931e5..6dc61a135351 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -297,6 +297,66 @@ struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, return NULL; } +static struct cxl_bus *util_cxl_bus_filter_by_memdev(struct cxl_bus *bus, + const char *ident, + const char *serial) +{ + struct cxl_ctx *ctx = cxl_bus_get_ctx(bus); + struct cxl_memdev *memdev; + + if (!ident && !serial) + return bus; + + cxl_memdev_foreach(ctx, memdev) { + if (!util_cxl_memdev_filter(memdev, ident, serial)) + continue; + if (cxl_memdev_get_bus(memdev) == bus) + return bus; + } + + return NULL; +} + +static struct cxl_endpoint * +util_cxl_endpoint_filter_by_memdev(struct cxl_endpoint *endpoint, + const char *ident, const char *serial) +{ + struct cxl_ctx *ctx = cxl_endpoint_get_ctx(endpoint); + struct cxl_memdev *memdev; + + if (!ident && !serial) + return endpoint; + + cxl_memdev_foreach(ctx, memdev) { + if (!util_cxl_memdev_filter(memdev, ident, serial)) + continue; + if (cxl_memdev_get_endpoint(memdev) == endpoint) + return endpoint; + } + + return NULL; +} + +static struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port, + const char *ident, + const char *serial) +{ + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + struct cxl_memdev *memdev; + + if (!ident && !serial) + return port; + + cxl_memdev_foreach(ctx, memdev) { + if (!util_cxl_memdev_filter(memdev, ident, serial)) + continue; + if (cxl_port_hosts_memdev(port, memdev)) + return port; + } + + return NULL; +} + static unsigned long params_to_flags(struct cxl_filter_params *param) { unsigned long flags = 0; @@ -399,6 +459,9 @@ static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p, if (!util_cxl_endpoint_filter_by_port(endpoint, p->port_filter, pf_mode(p))) continue; + if (!util_cxl_endpoint_filter_by_memdev( + endpoint, p->memdev_filter, p->serial_filter)) + continue; if (!p->idle && !cxl_endpoint_is_enabled(endpoint)) continue; if (p->endpoints) { @@ -450,6 +513,9 @@ static void walk_child_ports(struct cxl_port *parent_port, struct json_object *jchildports = NULL; struct json_object *jchildeps = NULL; + if (!util_cxl_port_filter_by_memdev(port, p->memdev_filter, + p->serial_filter)) + continue; if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p))) goto walk_children; if (!util_cxl_port_filter_by_bus(port, p->bus_filter)) @@ -573,6 +639,9 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) struct cxl_port *port = cxl_bus_get_port(bus); const char *devname = cxl_bus_get_devname(bus); + if (!util_cxl_bus_filter_by_memdev(bus, p->memdev_filter, + p->serial_filter)) + continue; if (!util_cxl_bus_filter(bus, p->bus_filter)) goto walk_children; if (!util_cxl_port_filter(port, p->port_filter, pf_mode(p))) diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 4523ca630d11..0065f6baeead 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -455,6 +455,15 @@ CXL_EXPORT const char *cxl_memdev_get_host(struct cxl_memdev *memdev) return memdev->host; } +CXL_EXPORT struct cxl_bus *cxl_memdev_get_bus(struct cxl_memdev *memdev) +{ + struct cxl_endpoint *endpoint = cxl_memdev_get_endpoint(memdev); + + if (!endpoint) + return NULL; + return cxl_endpoint_get_bus(endpoint); +} + CXL_EXPORT int cxl_memdev_get_major(struct cxl_memdev *memdev) { return memdev->major; @@ -724,6 +733,13 @@ CXL_EXPORT const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint) return cxl_port_get_host(&endpoint->port); } +CXL_EXPORT struct cxl_bus *cxl_endpoint_get_bus(struct cxl_endpoint *endpoint) +{ + struct cxl_port *port = &endpoint->port; + + return cxl_port_get_bus(port); +} + CXL_EXPORT int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint) { return cxl_port_is_enabled(&endpoint->port); @@ -875,6 +891,21 @@ CXL_EXPORT const char *cxl_port_get_host(struct cxl_port *port) return devpath_to_devname(port->uport); } +CXL_EXPORT bool cxl_port_hosts_memdev(struct cxl_port *port, + struct cxl_memdev *memdev) +{ + struct cxl_endpoint *endpoint = cxl_memdev_get_endpoint(memdev); + struct cxl_port *iter; + + if (!endpoint) + return false; + + iter = cxl_endpoint_get_port(endpoint); + while (iter && iter != port) + iter = iter->parent; + return iter != NULL; +} + CXL_EXPORT int cxl_port_is_enabled(struct cxl_port *port) { struct cxl_ctx *ctx = cxl_port_get_ctx(port); @@ -985,6 +1016,11 @@ CXL_EXPORT const char *cxl_bus_get_provider(struct cxl_bus *bus) return devname; } +CXL_EXPORT struct cxl_ctx *cxl_bus_get_ctx(struct cxl_bus *bus) +{ + return cxl_port_get_ctx(&bus->port); +} + CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd) { if (!cmd) diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 321acac57e3e..29f34988e42f 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -84,6 +84,7 @@ global: cxl_bus_get_devname; cxl_bus_get_id; cxl_bus_get_port; + cxl_bus_get_ctx; cxl_port_get_first; cxl_port_get_next; cxl_port_get_devname; @@ -97,6 +98,8 @@ global: cxl_port_is_endpoint; cxl_port_get_bus; cxl_port_get_host; + cxl_port_get_bus; + cxl_port_hosts_memdev; cxl_endpoint_get_first; cxl_endpoint_get_next; cxl_endpoint_get_devname; @@ -107,6 +110,8 @@ global: cxl_endpoint_get_port; cxl_endpoint_get_host; cxl_endpoint_get_memdev; + cxl_endpoint_get_bus; cxl_memdev_get_endpoint; cxl_memdev_is_enabled; + cxl_memdev_get_bus; } LIBCXL_1; diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 790ece86529d..e7b675e5328f 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -39,6 +39,7 @@ int cxl_memdev_get_id(struct cxl_memdev *memdev); unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev); const char *cxl_memdev_get_devname(struct cxl_memdev *memdev); const char *cxl_memdev_get_host(struct cxl_memdev *memdev); +struct cxl_bus *cxl_memdev_get_bus(struct cxl_memdev *memdev); int cxl_memdev_get_major(struct cxl_memdev *memdev); int cxl_memdev_get_minor(struct cxl_memdev *memdev); struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev); @@ -68,6 +69,7 @@ const char *cxl_bus_get_provider(struct cxl_bus *bus); const char *cxl_bus_get_devname(struct cxl_bus *bus); int cxl_bus_get_id(struct cxl_bus *bus); struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus); +struct cxl_ctx *cxl_bus_get_ctx(struct cxl_bus *bus); #define cxl_bus_foreach(ctx, bus) \ for (bus = cxl_bus_get_first(ctx); bus != NULL; \ @@ -87,6 +89,7 @@ struct cxl_bus *cxl_port_to_bus(struct cxl_port *port); bool cxl_port_is_endpoint(struct cxl_port *port); struct cxl_bus *cxl_port_get_bus(struct cxl_port *port); const char *cxl_port_get_host(struct cxl_port *port); +bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev); #define cxl_port_foreach(parent, port) \ for (port = cxl_port_get_first(parent); port != NULL; \ @@ -102,6 +105,7 @@ int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint); struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint); struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint); const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint); +struct cxl_bus *cxl_endpoint_get_bus(struct cxl_endpoint *endpoint); struct cxl_memdev *cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint); int cxl_memdev_is_enabled(struct cxl_memdev *memdev); From patchwork Mon Jan 24 00:53:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721361 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 26663C433EF for ; Mon, 24 Jan 2022 00:53:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240660AbiAXAx4 (ORCPT ); Sun, 23 Jan 2022 19:53:56 -0500 Received: from mga03.intel.com ([134.134.136.65]:63601 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240666AbiAXAx4 (ORCPT ); Sun, 23 Jan 2022 19:53:56 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985636; x=1674521636; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=sMsLzmYBgttFdjviGx5xgfqy1//K1RcepiYwrO8ge/Q=; b=Z/qGEbaAm8djPLVcwvzLlghTNkcrNWLeMR6canqJ8HXhQJHaCQLEQitC ZEe4w30adw54wU492mJ11dtvfdg3bj1P/W3j8SzpMOxR218pyRUwF0slW dv56WtrRh9BGz92d/62Zb2FqX1r3oUD8i4VUvom+3LGUp5eG/+FsxLuWa eaWoduSAvl4Ffqd6liZ6TEowhttcptiy4r6mzMCdJ0qL0kQhpejcTXjvH /eVG4MS71Qei36RtnMMU0tE+I6eBFCiZ74pVW0cvDntxl02zx/s+I+M+h MlTkd37zpT2QobqK1x+E8YjqLT04jZ96bS5TQaCRxitPWDbvBRqCKhzT5 w==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="245880918" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="245880918" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:56 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="617065085" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:53:55 -0800 Subject: [ndctl PATCH 24/37] cxl/memdev: Use a local logger for debug From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:53:55 -0800 Message-ID: <164298563547.3021641.16504008034705274247.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org The "fail()" macro skips some of the nicer features of the centralized logger. Add one to supplement the library logger. Signed-off-by: Dan Williams --- cxl/memdev.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/cxl/memdev.c b/cxl/memdev.c index b9141be62c87..327c2608f179 100644 --- a/cxl/memdev.c +++ b/cxl/memdev.c @@ -26,11 +26,7 @@ static struct parameters { bool verbose; } param; -#define fail(fmt, ...) \ -do { \ - fprintf(stderr, "cxl-%s:%s:%d: " fmt, \ - VERSION, __func__, __LINE__, ##__VA_ARGS__); \ -} while (0) +static struct log_ctx ml; #define BASE_OPTIONS() \ OPT_BOOLEAN('v',"verbose", ¶m.verbose, "turn on debug") @@ -79,7 +75,7 @@ static int action_zero(struct cxl_memdev *memdev, struct action_context *actx) size = cxl_memdev_get_label_size(memdev); if (cxl_memdev_nvdimm_bridge_active(memdev)) { - fprintf(stderr, + log_err(&ml, "%s: has active nvdimm bridge, abort label write\n", cxl_memdev_get_devname(memdev)); return -EBUSY; @@ -87,7 +83,7 @@ static int action_zero(struct cxl_memdev *memdev, struct action_context *actx) rc = cxl_memdev_zero_label(memdev, size, param.offset); if (rc < 0) - fprintf(stderr, "%s: label zeroing failed: %s\n", + log_err(&ml, "%s: label zeroing failed: %s\n", cxl_memdev_get_devname(memdev), strerror(-rc)); return rc; @@ -100,7 +96,7 @@ static int action_write(struct cxl_memdev *memdev, struct action_context *actx) int rc; if (cxl_memdev_nvdimm_bridge_active(memdev)) { - fprintf(stderr, + log_err(&ml, "%s: has active nvdimm bridge, abort label write\n", cxl_memdev_get_devname(memdev)); return -EBUSY; @@ -114,7 +110,7 @@ static int action_write(struct cxl_memdev *memdev, struct action_context *actx) fseek(actx->f_in, 0L, SEEK_SET); if (size > label_size) { - fprintf(stderr, + log_err(&ml, "File size (%zu) greater than label area size (%zu), aborting\n", size, label_size); return -EINVAL; @@ -133,7 +129,7 @@ static int action_write(struct cxl_memdev *memdev, struct action_context *actx) rc = cxl_memdev_write_label(memdev, buf, size, param.offset); if (rc < 0) - fprintf(stderr, "%s: label write failed: %s\n", + log_err(&ml, "%s: label write failed: %s\n", cxl_memdev_get_devname(memdev), strerror(-rc)); out: @@ -158,7 +154,7 @@ static int action_read(struct cxl_memdev *memdev, struct action_context *actx) rc = cxl_memdev_read_label(memdev, buf, size, param.offset); if (rc < 0) { - fprintf(stderr, "%s: label read failed: %s\n", + log_err(&ml, "%s: label read failed: %s\n", cxl_memdev_get_devname(memdev), strerror(-rc)); goto out; } @@ -188,6 +184,7 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx, }; unsigned long id; + log_init(&ml, "cxl memdev", "CXL_MEMDEV_LOG"); argc = parse_options(argc, argv, options, u, 0); if (argc == 0) @@ -200,8 +197,8 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx, } if (sscanf(argv[i], "mem%lu", &id) != 1) { - fprintf(stderr, "'%s' is not a valid memdev name\n", - argv[i]); + log_err(&ml, "'%s' is not a valid memdev name\n", + argv[i]); err++; } } @@ -216,8 +213,8 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx, else { actx.f_out = fopen(param.outfile, "w+"); if (!actx.f_out) { - fprintf(stderr, "failed to open: %s: (%s)\n", - param.outfile, strerror(errno)); + log_err(&ml, "failed to open: %s: (%s)\n", + param.outfile, strerror(errno)); rc = -errno; goto out; } @@ -228,15 +225,18 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx, } else { actx.f_in = fopen(param.infile, "r"); if (!actx.f_in) { - fprintf(stderr, "failed to open: %s: (%s)\n", - param.infile, strerror(errno)); + log_err(&ml, "failed to open: %s: (%s)\n", param.infile, + strerror(errno)); rc = -errno; goto out_close_fout; } } - if (param.verbose) + if (param.verbose) { cxl_set_log_priority(ctx, LOG_DEBUG); + ml.log_priority = LOG_DEBUG; + } else + ml.log_priority = LOG_INFO; rc = 0; err = 0; @@ -299,8 +299,8 @@ int cmd_write_labels(int argc, const char **argv, struct cxl_ctx *ctx) int count = memdev_action(argc, argv, ctx, action_write, write_options, "cxl write-labels [-i ]"); - fprintf(stderr, "wrote %d mem%s\n", count >= 0 ? count : 0, - count > 1 ? "s" : ""); + log_info(&ml, "wrote %d mem%s\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); return count >= 0 ? 0 : EXIT_FAILURE; } @@ -309,8 +309,8 @@ int cmd_read_labels(int argc, const char **argv, struct cxl_ctx *ctx) int count = memdev_action(argc, argv, ctx, action_read, read_options, "cxl read-labels [..] [-o ]"); - fprintf(stderr, "read %d mem%s\n", count >= 0 ? count : 0, - count > 1 ? "s" : ""); + log_info(&ml, "read %d mem%s\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); return count >= 0 ? 0 : EXIT_FAILURE; } @@ -319,7 +319,7 @@ int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx) int count = memdev_action(argc, argv, ctx, action_zero, zero_options, "cxl zero-labels [..] []"); - fprintf(stderr, "zeroed %d mem%s\n", count >= 0 ? count : 0, - count > 1 ? "s" : ""); + log_info(&ml, "zeroed %d mem%s\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); return count >= 0 ? 0 : EXIT_FAILURE; } From patchwork Mon Jan 24 00:54:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721362 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 EE83BC433F5 for ; Mon, 24 Jan 2022 00:54:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240667AbiAXAyC (ORCPT ); Sun, 23 Jan 2022 19:54:02 -0500 Received: from mga06.intel.com ([134.134.136.31]:17142 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240666AbiAXAyB (ORCPT ); Sun, 23 Jan 2022 19:54:01 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985641; x=1674521641; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=JxQHq++cKcwYuG64L4PjCHaXOd/DYu1/ChwrclgFe10=; b=JzqlTkWada0K65Rt7+QAbYzlY/unMH7z1lBB0NNnCXpntJJkvf6knK0t hU6z3W8dtUOjnYyRVxe9UFEj0P1pXjdwLQot6029KFkJmPjt5em9VsQW8 n9bTps1Oi3XGokW1TIXg39+5mph2mDXqpRdOg/NPDZzBYa+ltfbwkE3r5 NcHP+idLQkxfjx1roSaFFUDE7xzjjUMc6iO/aO38FNgydKm3UbpMeOzmT glJhpo4ZLaciOR3NLbQ9X7W15c7LdB7ZhZapg/J8KNxxUc9TtIspAtOV2 oePZkJZLUSsWLxHe20DUlNjMd7WsrtWTyWTv/CU+LZYAnb2j0b1d2u4RL g==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="306652180" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="306652180" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:01 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="623906052" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga002-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:01 -0800 Subject: [ndctl PATCH 25/37] cxl/memdev: Cleanup memdev filter From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:54:01 -0800 Message-ID: <164298564100.3021641.9410483964085163708.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org util_cxl_memdev_filter() already handles the difference between 'mem%d', '%d', and 'all' for the identifier format. Drop the duplicate / incomplete format checking. If the checking for bad formats was dropped too then this command could support "0,1,2" syntax in addition to "0 1 2" like 'cxl list'. However, it is not clear that's worthwhile since 'list' is ok to be imprecise, but memdev commands need to be stricter. Signed-off-by: Dan Williams --- cxl/memdev.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/cxl/memdev.c b/cxl/memdev.c index 327c2608f179..4cca8b8c10be 100644 --- a/cxl/memdev.c +++ b/cxl/memdev.c @@ -191,16 +191,16 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx, usage_with_options(u, options); for (i = 0; i < argc; i++) { if (strcmp(argv[i], "all") == 0) { - argv[0] = "all"; argc = 1; break; } + if (sscanf(argv[i], "mem%lu", &id) == 1) + continue; + if (sscanf(argv[i], "%lu", &id) == 1) + continue; - if (sscanf(argv[i], "mem%lu", &id) != 1) { - log_err(&ml, "'%s' is not a valid memdev name\n", - argv[i]); - err++; - } + log_err(&ml, "'%s' is not a valid memdev name\n", argv[i]); + err++; } if (err == argc) { @@ -243,11 +243,7 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx, count = 0; for (i = 0; i < argc; i++) { - if (sscanf(argv[i], "mem%lu", &id) != 1 - && strcmp(argv[i], "all") != 0) - continue; - - cxl_memdev_foreach (ctx, memdev) { + cxl_memdev_foreach(ctx, memdev) { if (!util_cxl_memdev_filter(memdev, argv[i], NULL)) continue; From patchwork Mon Jan 24 00:54:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721363 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 54D3FC433F5 for ; Mon, 24 Jan 2022 00:54:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240666AbiAXAyH (ORCPT ); Sun, 23 Jan 2022 19:54:07 -0500 Received: from mga07.intel.com ([134.134.136.100]:6530 "EHLO mga07.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240668AbiAXAyG (ORCPT ); Sun, 23 Jan 2022 19:54:06 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985646; x=1674521646; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=bz+nZmy5ZWyfZbPxruY+qRQpcN773rl+hSXf6yyFCuw=; b=nHOyRB51G655oA5CyuSzlFWgkElt6+gsQ93FfQsoN3L/gAkfSzDSWeXM S9XVf+re3I/1pAIgewYSSDTpk5uRpvlf6Sl5FAKZLE977aqA/1PHoQVMm mG6Zk7ROukiph+e2LxI17O19DbkxRCDm/KQIiVfXdquM9LXkpczXetcJh isRE3MG1ibuUHRamW8UtkxRTqcYZgU8MRx8iX7I1RFYr2naj5bTYtMli4 aGJD4O6wSg3lSKdrjMMUI8OTR84sl8AW2gJrBjJ+oUIfAOj+bGixf4xO9 x6ThvQPrJVdTfPzuGyy8HxO4xFVrzukqI+A7mJqARl7CGr90ZVj382ucD Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="309257415" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="309257415" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:06 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="534005241" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:06 -0800 Subject: [ndctl PATCH 26/37] cxl/memdev: Add serial support for memdev-related commands From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:54:06 -0800 Message-ID: <164298564631.3021641.5552442288217413180.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Allow for a "-s, --serial" option to turn the argument list into serial identifiers. Signed-off-by: Dan Williams --- Documentation/cxl/memdev-option.txt | 5 ++++ Documentation/cxl/meson.build | 4 ++- cxl/memdev.c | 45 ++++++++++++++++++++++++++--------- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/Documentation/cxl/memdev-option.txt b/Documentation/cxl/memdev-option.txt index e7785827ab4c..64348bed1791 100644 --- a/Documentation/cxl/memdev-option.txt +++ b/Documentation/cxl/memdev-option.txt @@ -2,3 +2,8 @@ A 'memX' device name, or a memdev id number. Restrict the operation to the specified memdev(s). The keyword 'all' can be specified to indicate the lack of any restriction. + +-S:: +--serial:: + Rather an a memdev id number, interpret the argument(s) + as a list of serial numbers. diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build index 64ce13f59012..0a6346bc47ca 100644 --- a/Documentation/cxl/meson.build +++ b/Documentation/cxl/meson.build @@ -19,7 +19,9 @@ else endif filedeps = [ - '../copyright.txt', + '../copyright.txt', + 'memdev-option.txt', + 'labels-options.txt', ] cxl_manpages = [ diff --git a/cxl/memdev.c b/cxl/memdev.c index 4cca8b8c10be..ef5343ad892b 100644 --- a/cxl/memdev.c +++ b/cxl/memdev.c @@ -24,12 +24,14 @@ static struct parameters { unsigned len; unsigned offset; bool verbose; + bool serial; } param; static struct log_ctx ml; #define BASE_OPTIONS() \ -OPT_BOOLEAN('v',"verbose", ¶m.verbose, "turn on debug") +OPT_BOOLEAN('v',"verbose", ¶m.verbose, "turn on debug"), \ +OPT_BOOLEAN('S', "serial", ¶m.serial, "user serials numbers to id memdevs") #define READ_OPTIONS() \ OPT_STRING('o', "output", ¶m.outfile, "output-file", \ @@ -172,8 +174,9 @@ out: } static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx, - int (*action)(struct cxl_memdev *memdev, struct action_context *actx), - const struct option *options, const char *usage) + int (*action)(struct cxl_memdev *memdev, + struct action_context *actx), + const struct option *options, const char *usage) { struct cxl_memdev *memdev, *single = NULL; struct action_context actx = { 0 }; @@ -190,16 +193,25 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx, if (argc == 0) usage_with_options(u, options); for (i = 0; i < argc; i++) { - if (strcmp(argv[i], "all") == 0) { - argc = 1; - break; + if (param.serial) { + char *end; + + strtoull(argv[i], &end, 0); + if (end[0] == 0) + continue; + } else { + if (strcmp(argv[i], "all") == 0) { + argc = 1; + break; + } + if (sscanf(argv[i], "mem%lu", &id) == 1) + continue; + if (sscanf(argv[i], "%lu", &id) == 1) + continue; } - if (sscanf(argv[i], "mem%lu", &id) == 1) - continue; - if (sscanf(argv[i], "%lu", &id) == 1) - continue; - log_err(&ml, "'%s' is not a valid memdev name\n", argv[i]); + log_err(&ml, "'%s' is not a valid memdev %s\n", argv[i], + param.serial ? "serial number" : "name"); err++; } @@ -244,7 +256,16 @@ static int memdev_action(int argc, const char **argv, struct cxl_ctx *ctx, for (i = 0; i < argc; i++) { cxl_memdev_foreach(ctx, memdev) { - if (!util_cxl_memdev_filter(memdev, argv[i], NULL)) + const char *memdev_filter = NULL; + const char *serial_filter = NULL; + + if (param.serial) + serial_filter = argv[i]; + else + memdev_filter = argv[i]; + + if (!util_cxl_memdev_filter(memdev, memdev_filter, + serial_filter)) continue; if (action == action_write) { From patchwork Mon Jan 24 00:54:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721364 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 32E1AC433EF for ; Mon, 24 Jan 2022 00:54:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240669AbiAXAyN (ORCPT ); Sun, 23 Jan 2022 19:54:13 -0500 Received: from mga11.intel.com ([192.55.52.93]:50319 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235351AbiAXAyN (ORCPT ); Sun, 23 Jan 2022 19:54:13 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985653; x=1674521653; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=N5krYuICLkseMYpurEurIFF8ViUohFRRZLYVobxhBIM=; b=XgEJeuyR84IyY3F45UtPs+CCGgfy0ZCZOg+h02rkSflguJ4cbDH21IJz fLMvQ3eT1LsKI8zVxwyKyQ69bakZgEupd6icl3ukzzSQXUKGBs4ctbVG9 oCV1tGNRWf8USu6XP8RkUBDaZNjQuzalsrqMTlpkVPvafiofrXEIYS6j+ aupNs54GFaE44GV6K1Ld2OrIJCIJTuudtwBpf71Rg1Bmi1lpYIxQwfuns VKc3SsRnpfJ/p28SrwhXphVYYg2BOPDzGWvBrR6NZiHu63B8gCiw9bpaw d+5KwC/v41IN36+NZGkgjFnipzlpZgksYtCmgGOYv4UfgCAhkFmU4VGg5 g==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="243530647" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="243530647" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:12 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="596630808" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:11 -0800 Subject: [ndctl PATCH 27/37] cxl/list: Add 'numa_node' to memdev listings From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:54:11 -0800 Message-ID: <164298565156.3021641.14097226245654611710.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org If the kernel exports a valid numa_node, >= 0, include it in memdev objects listings. Signed-off-by: Dan Williams --- Documentation/cxl/lib/libcxl.txt | 4 ++++ cxl/json.c | 8 ++++++++ cxl/lib/libcxl.c | 11 +++++++++++ cxl/lib/libcxl.sym | 1 + cxl/lib/private.h | 1 + cxl/libcxl.h | 1 + 6 files changed, 26 insertions(+) diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index b0253d7be07c..de88d192523a 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -71,6 +71,7 @@ unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev); const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev); size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev); int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev); +int cxl_memdev_get_numa_node(struct cxl_memdev *memdev); ---- A memdev is given a kernel device name of the form "mem%d" where an id @@ -89,6 +90,9 @@ The 'pmem_size' and 'ram_size' attributes return the current provisioning of DPA (Device Physical Address / local capacity) in the device. +cxl_memdev_get_numa_node() returns the affinitized CPU node number if +available or -1 otherwise. + === MEMDEV: Commands ---- struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode); diff --git a/cxl/json.c b/cxl/json.c index b809332b8d51..51918d65f671 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -190,6 +190,7 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev, const char *devname = cxl_memdev_get_devname(memdev); struct json_object *jdev, *jobj; unsigned long long serial; + int numa_node; jdev = json_object_new_object(); if (!jdev) @@ -220,6 +221,13 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev, json_object_object_add(jdev, "serial", jobj); } + numa_node = cxl_memdev_get_numa_node(memdev); + if (numa_node >= 0) { + jobj = json_object_new_int(numa_node); + if (jobj) + json_object_object_add(jdev, "numa_node", jobj); + } + jobj = json_object_new_string(cxl_memdev_get_host(memdev)); if (jobj) json_object_object_add(jdev, "host", jobj); diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 0065f6baeead..14c7db88ff5e 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -348,6 +348,12 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base) else memdev->serial = strtoull(buf, NULL, 0); + sprintf(path, "%s/numa_node", cxlmem_base); + if (sysfs_read_attr(ctx, path, buf) < 0) + memdev->numa_node = -1; + else + memdev->numa_node = strtol(buf, NULL, 0); + memdev->dev_path = strdup(cxlmem_base); if (!memdev->dev_path) goto err_read; @@ -445,6 +451,11 @@ CXL_EXPORT unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev) return memdev->serial; } +CXL_EXPORT int cxl_memdev_get_numa_node(struct cxl_memdev *memdev) +{ + return memdev->numa_node; +} + CXL_EXPORT const char *cxl_memdev_get_devname(struct cxl_memdev *memdev) { return devpath_to_devname(memdev->dev_path); diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 29f34988e42f..b13a2d6d25d1 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -77,6 +77,7 @@ local: LIBCXL_2 { global: cxl_memdev_get_serial; + cxl_memdev_get_numa_node; cxl_memdev_get_host; cxl_bus_get_first; cxl_bus_get_next; diff --git a/cxl/lib/private.h b/cxl/lib/private.h index b097bdfbfd6b..c00bb3600138 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -20,6 +20,7 @@ struct cxl_pmem { struct cxl_endpoint; struct cxl_memdev { int id, major, minor; + int numa_node; void *dev_buf; size_t buf_len; char *host; diff --git a/cxl/libcxl.h b/cxl/libcxl.h index e7b675e5328f..be656ed0d90d 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -37,6 +37,7 @@ struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx); struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev); int cxl_memdev_get_id(struct cxl_memdev *memdev); unsigned long long cxl_memdev_get_serial(struct cxl_memdev *memdev); +int cxl_memdev_get_numa_node(struct cxl_memdev *memdev); const char *cxl_memdev_get_devname(struct cxl_memdev *memdev); const char *cxl_memdev_get_host(struct cxl_memdev *memdev); struct cxl_bus *cxl_memdev_get_bus(struct cxl_memdev *memdev); From patchwork Mon Jan 24 00:54:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721365 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 39BAAC433F5 for ; Mon, 24 Jan 2022 00:54:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235351AbiAXAyV (ORCPT ); Sun, 23 Jan 2022 19:54:21 -0500 Received: from mga12.intel.com ([192.55.52.136]:3972 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240670AbiAXAyR (ORCPT ); Sun, 23 Jan 2022 19:54:17 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985657; x=1674521657; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=vHekN5lP0FydPCqtjPLuBuMRkc4Fj1Bhsd2qWnFJ8v4=; b=m3tdmZuXbvo7zj6bhu70Ql3ZUZgUOhb96NK2J5FH6azHdtwAkRGVCgXi C5qaBEkqwmsA+OE980i65tpMyKnQvwKorvM3jkgZ4YQrfmCur4ZLJ78ep WPVE2eLEvDmPeeelPOxV+6SQjzrObKQqqQqffzbFJCJdIY6dd6bjWKppm afvMN4Vwiph1IjHmZbtKy7a2ornPq+H9RwG9MTUmD/PYyduhMx3kgahrV xvHQcWKwYqIPHC2s9LtsuQcTAhgXKf/oTEk3NVzLrvV6PYghkWLsPSCW5 EGy8aD0bnt+LXMrY08va5bhcLx3kzYF4q0Fz+ziH6NYDNsj18UxAEBxbU A==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="225916746" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="225916746" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:17 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="596630819" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:17 -0800 Subject: [ndctl PATCH 28/37] util: Implement common bind/unbind helpers From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:54:17 -0800 Message-ID: <164298565707.3021641.7763459936156744907.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Refactor ndctl_{bind,unbind}() into util_{bind,unbind}() for libcxl to reuse. daxctl can not join the party for now as it needs to play games with 'new_id'. Signed-off-by: Dan Williams --- ndctl/lib/libndctl.c | 103 ++++++-------------------------------------------- util/sysfs.c | 76 +++++++++++++++++++++++++++++++++++++ util/sysfs.h | 8 ++++ 3 files changed, 96 insertions(+), 91 deletions(-) diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c index 1374ad9e504f..98d184ba1bf8 100644 --- a/ndctl/lib/libndctl.c +++ b/ndctl/lib/libndctl.c @@ -1665,10 +1665,6 @@ static enum ndctl_fwa_result fwa_result_to_result(const char *result) return NDCTL_FWA_RESULT_INVALID; } -static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module, - const char *devname); -static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath); - static int populate_dimm_attributes(struct ndctl_dimm *dimm, const char *dimm_base, const char *bus_prefix) @@ -2305,7 +2301,7 @@ NDCTL_EXPORT int ndctl_dimm_disable(struct ndctl_dimm *dimm) if (!ndctl_dimm_is_enabled(dimm)) return 0; - ndctl_unbind(ctx, dimm->dimm_path); + util_unbind(dimm->dimm_path, ctx); if (ndctl_dimm_is_enabled(dimm)) { err(ctx, "%s: failed to disable\n", devname); @@ -2324,7 +2320,7 @@ NDCTL_EXPORT int ndctl_dimm_enable(struct ndctl_dimm *dimm) if (ndctl_dimm_is_enabled(dimm)) return 0; - ndctl_bind(ctx, dimm->module, devname); + util_bind(devname, dimm->module, "nd", ctx); if (!ndctl_dimm_is_enabled(dimm)) { err(ctx, "%s: failed to enable\n", devname); @@ -3573,7 +3569,7 @@ NDCTL_EXPORT int ndctl_region_enable(struct ndctl_region *region) if (ndctl_region_is_enabled(region)) return 0; - ndctl_bind(ctx, region->module, devname); + util_bind(devname, region->module, "nd", ctx); if (!ndctl_region_is_enabled(region)) { err(ctx, "%s: failed to enable\n", devname); @@ -3610,7 +3606,7 @@ static int ndctl_region_disable(struct ndctl_region *region, int cleanup) if (!ndctl_region_is_enabled(region)) return 0; - ndctl_unbind(ctx, region->region_path); + util_unbind(region->region_path, ctx); if (ndctl_region_is_enabled(region)) { err(ctx, "%s: failed to disable\n", devname); @@ -4373,81 +4369,6 @@ NDCTL_EXPORT struct badblock *ndctl_namespace_get_first_badblock( return badblocks_iter_first(&ndns->bb_iter, ctx, path); } -static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module, - const char *devname) -{ - DIR *dir; - int rc = 0; - char path[200]; - struct dirent *de; - const int len = sizeof(path); - - if (!devname) { - err(ctx, "missing devname\n"); - return -EINVAL; - } - - if (module) { - rc = kmod_module_probe_insert_module(module, - KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL, - NULL); - if (rc < 0) { - err(ctx, "%s: insert failure: %d\n", __func__, rc); - return rc; - } - } - - if (snprintf(path, len, "/sys/bus/nd/drivers") >= len) { - err(ctx, "%s: buffer too small!\n", devname); - return -ENXIO; - } - - dir = opendir(path); - if (!dir) { - err(ctx, "%s: opendir(\"%s\") failed\n", devname, path); - return -ENXIO; - } - - while ((de = readdir(dir)) != NULL) { - char *drv_path; - - if (de->d_ino == 0) - continue; - if (de->d_name[0] == '.') - continue; - if (asprintf(&drv_path, "%s/%s/bind", path, de->d_name) < 0) { - err(ctx, "%s: path allocation failure\n", devname); - continue; - } - - rc = sysfs_write_attr_quiet(ctx, drv_path, devname); - free(drv_path); - if (rc == 0) - break; - } - closedir(dir); - - if (rc) { - dbg(ctx, "%s: bind failed\n", devname); - return -ENXIO; - } - return 0; -} - -static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath) -{ - const char *devname = devpath_to_devname(devpath); - char path[200]; - const int len = sizeof(path); - - if (snprintf(path, len, "%s/driver/unbind", devpath) >= len) { - err(ctx, "%s: buffer too small!\n", devname); - return -ENXIO; - } - - return sysfs_write_attr(ctx, path, devname); -} - static void *add_btt(void *parent, int id, const char *btt_base); static void *add_pfn(void *parent, int id, const char *pfn_base); static void *add_dax(void *parent, int id, const char *dax_base); @@ -4533,7 +4454,7 @@ NDCTL_EXPORT int ndctl_namespace_enable(struct ndctl_namespace *ndns) if (ndctl_namespace_is_enabled(ndns)) return 0; - rc = ndctl_bind(ctx, ndns->module, devname); + rc = util_bind(devname, ndns->module, "nd", ctx); /* * Rescan now as successfully enabling a namespace device leads @@ -4581,7 +4502,7 @@ NDCTL_EXPORT int ndctl_namespace_disable(struct ndctl_namespace *ndns) if (!ndctl_namespace_is_enabled(ndns)) return 0; - ndctl_unbind(ctx, ndns->ndns_path); + util_unbind(ndns->ndns_path, ctx); if (ndctl_namespace_is_enabled(ndns)) { err(ctx, "%s: failed to disable\n", devname); @@ -5420,7 +5341,7 @@ NDCTL_EXPORT int ndctl_btt_enable(struct ndctl_btt *btt) if (ndctl_btt_is_enabled(btt)) return 0; - ndctl_bind(ctx, btt->module, devname); + util_bind(devname, btt->module, "nd", ctx); if (!ndctl_btt_is_enabled(btt)) { err(ctx, "%s: failed to enable\n", devname); @@ -5457,7 +5378,7 @@ NDCTL_EXPORT int ndctl_btt_delete(struct ndctl_btt *btt) return 0; } - ndctl_unbind(ctx, btt->btt_path); + util_unbind(btt->btt_path, ctx); rc = ndctl_btt_set_namespace(btt, NULL); if (rc) { @@ -5908,7 +5829,7 @@ NDCTL_EXPORT int ndctl_pfn_enable(struct ndctl_pfn *pfn) if (ndctl_pfn_is_enabled(pfn)) return 0; - ndctl_bind(ctx, pfn->module, devname); + util_bind(devname, pfn->module, "nd", ctx); if (!ndctl_pfn_is_enabled(pfn)) { err(ctx, "%s: failed to enable\n", devname); @@ -5945,7 +5866,7 @@ NDCTL_EXPORT int ndctl_pfn_delete(struct ndctl_pfn *pfn) return 0; } - ndctl_unbind(ctx, pfn->pfn_path); + util_unbind(pfn->pfn_path, ctx); rc = ndctl_pfn_set_namespace(pfn, NULL); if (rc) { @@ -6101,7 +6022,7 @@ NDCTL_EXPORT int ndctl_dax_enable(struct ndctl_dax *dax) if (ndctl_dax_is_enabled(dax)) return 0; - ndctl_bind(ctx, pfn->module, devname); + util_bind(devname, pfn->module, "nd", ctx); if (!ndctl_dax_is_enabled(dax)) { err(ctx, "%s: failed to enable\n", devname); @@ -6132,7 +6053,7 @@ NDCTL_EXPORT int ndctl_dax_delete(struct ndctl_dax *dax) return 0; } - ndctl_unbind(ctx, pfn->pfn_path); + util_unbind(pfn->pfn_path, ctx); rc = ndctl_dax_set_namespace(dax, NULL); if (rc) { diff --git a/util/sysfs.c b/util/sysfs.c index 23330cb29002..968683b19f4e 100644 --- a/util/sysfs.c +++ b/util/sysfs.c @@ -145,3 +145,79 @@ struct kmod_module *__util_modalias_to_module(struct kmod_ctx *kmod_ctx, return mod; } + +int __util_bind(const char *devname, struct kmod_module *module, + const char *bus, struct log_ctx *ctx) +{ + DIR *dir; + int rc = 0; + char path[200]; + struct dirent *de; + const int len = sizeof(path); + + if (!devname) { + log_err(ctx, "missing devname\n"); + return -EINVAL; + } + + if (module) { + rc = kmod_module_probe_insert_module(module, + KMOD_PROBE_APPLY_BLACKLIST, + NULL, NULL, NULL, NULL); + if (rc < 0) { + log_err(ctx, "%s: insert failure: %d\n", __func__, rc); + return rc; + } + } + + if (snprintf(path, len, "/sys/bus/%s/drivers", bus) >= len) { + log_err(ctx, "%s: buffer too small!\n", devname); + return -ENXIO; + } + + dir = opendir(path); + if (!dir) { + log_err(ctx, "%s: opendir(\"%s\") failed\n", devname, path); + return -ENXIO; + } + + while ((de = readdir(dir)) != NULL) { + char *drv_path; + + if (de->d_ino == 0) + continue; + if (de->d_name[0] == '.') + continue; + + if (asprintf(&drv_path, "%s/%s/bind", path, de->d_name) < 0) { + log_err(ctx, "%s: path allocation failure\n", devname); + continue; + } + + rc = __sysfs_write_attr_quiet(ctx, drv_path, devname); + free(drv_path); + if (rc == 0) + break; + } + closedir(dir); + + if (rc) { + log_dbg(ctx, "%s: bind failed\n", devname); + return -ENXIO; + } + return 0; +} + +int __util_unbind(const char *devpath, struct log_ctx *ctx) +{ + const char *devname = devpath_to_devname(devpath); + char path[200]; + const int len = sizeof(path); + + if (snprintf(path, len, "%s/driver/unbind", devpath) >= len) { + log_err(ctx, "%s: buffer too small!\n", devname); + return -ENXIO; + } + + return __sysfs_write_attr(ctx, path, devname); +} diff --git a/util/sysfs.h b/util/sysfs.h index bdee4f5c291d..4c95c70558ba 100644 --- a/util/sysfs.h +++ b/util/sysfs.h @@ -35,4 +35,12 @@ struct kmod_module *__util_modalias_to_module(struct kmod_ctx *kmod_ctx, struct log_ctx *log); #define util_modalias_to_module(ctx, buf) \ __util_modalias_to_module((ctx)->kmod_ctx, buf, &(ctx)->ctx) + +int __util_bind(const char *devname, struct kmod_module *module, const char *bus, + struct log_ctx *ctx); +#define util_bind(n, m, b, c) __util_bind(n, m, b, &(c)->ctx) + +int __util_unbind(const char *devpath, struct log_ctx *ctx); +#define util_unbind(p, c) __util_unbind(p, &(c)->ctx) + #endif /* __UTIL_SYSFS_H__ */ From patchwork Mon Jan 24 00:54:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721366 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 05112C433F5 for ; Mon, 24 Jan 2022 00:54:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240672AbiAXAyY (ORCPT ); Sun, 23 Jan 2022 19:54:24 -0500 Received: from mga09.intel.com ([134.134.136.24]:11614 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240668AbiAXAyW (ORCPT ); Sun, 23 Jan 2022 19:54:22 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985662; x=1674521662; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=NIFLWaazWmXou71PyrkU4h+JkBSI/vrVxQL4ujxEz24=; b=ZHRBosPTHnW11u17yg53C1Mgb8c+M0/SjbSfE0faZNbjByDs/cENNUyD Pt+7HS3by+JQ5z50MGHHv4fgSPmq5sR309A9CNmx4WZNWXcs23Bj3tlkH 3GXxf5X43yON9/dnIXoB5G/afn383Rc+DJ4QNjtDiI04o/3idHFawC0R/ Hjh3sm69JmegUU1cQiHfjXERwxBbrHxMcksH/7Zc/digtiwnSGaNrTRXV rZ9rBqRKePfWTHFuj9tUXj2Duuo8v2/uGRZwb3CBXAPMfPRqMuuINVOt6 YvRjmCxvzpCTYM+OFUGzN/ZG4lMwLFAQnlwEQ8kTnyElktmx9Z7pRd2iZ Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="245716924" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="245716924" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:22 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="695243556" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:22 -0800 Subject: [ndctl PATCH 29/37] cxl/memdev: Enable / disable support From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:54:22 -0800 Message-ID: <164298566245.3021641.12696907310209056878.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Introduce the 'cxl {enable,disable}-memdev' commands. When a memdev is disabled the ports in the topology may be unregistered. CXL memory regions require each endpoint in the interleave to attach to the cxl_mem driver before regions are activated. Note that this starts out with the deliberate bug that it has false positive detection of active memdevs. The fix for that bug requires kernel support to detect the device's active participation in a region, until then require all disable attempts to specify the --force override. This way there are never any releases of cxl-cli that lack disable-memdev safety. Signed-off-by: Dan Williams --- Documentation/cxl/cxl-disable-memdev.txt | 37 +++++++++++++++++++ Documentation/cxl/cxl-enable-memdev.txt | 34 +++++++++++++++++ Documentation/cxl/lib/libcxl.txt | 23 ++++++++++++ Documentation/cxl/meson.build | 2 + cxl/builtin.h | 2 + cxl/cxl.c | 2 + cxl/lib/libcxl.c | 58 +++++++++++++++++++++++++++++ cxl/lib/libcxl.sym | 2 + cxl/libcxl.h | 2 + cxl/memdev.c | 60 ++++++++++++++++++++++++++++++ 10 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 Documentation/cxl/cxl-disable-memdev.txt create mode 100644 Documentation/cxl/cxl-enable-memdev.txt diff --git a/Documentation/cxl/cxl-disable-memdev.txt b/Documentation/cxl/cxl-disable-memdev.txt new file mode 100644 index 000000000000..edd538578b14 --- /dev/null +++ b/Documentation/cxl/cxl-disable-memdev.txt @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 + +cxl-disable-memdev(1) +===================== + +NAME +---- +cxl-disable-memdev - deactivate / hot-remove a given CXL memdev + +SYNOPSIS +-------- +[verse] +'cxl disable-memdev' [..] [] + + +OPTIONS +------- +:: +include::memdev-option.txt[] + +-f:: +--force:: + DANGEROUS: Override the safety measure that blocks attempts to disable + a device if the tool determines the memdev is in active usage. Recall + that CXL memory ranges might have been established by platform + firmware and disabling an active device is akin to force removing + memory from a running system. + +-v:: + Turn on verbose debug messages in the library (if libcxl was built with + logging and debug enabled). + +include::../copyright.txt[] + +SEE ALSO +-------- +linkcxl:cxl-enable-memdev[1] diff --git a/Documentation/cxl/cxl-enable-memdev.txt b/Documentation/cxl/cxl-enable-memdev.txt new file mode 100644 index 000000000000..088d5e0a4a3c --- /dev/null +++ b/Documentation/cxl/cxl-enable-memdev.txt @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 + +cxl-enable-memdev(1) +==================== + +NAME +---- +cxl-enable-memdev - activate / hot-add a given CXL memdev + +SYNOPSIS +-------- +[verse] +'cxl enable-memdev' [..] [] + +A memdev typically autoenables at initial device discovery. However, if +it was manually disabled this command can trigger the kernel to activate +it again. This involves detecting the state of the HDM (Host Managed +Device Memory) Decoders and validating that CXL.mem is enabled for each +port in the device's hierarchy. + +OPTIONS +------- +:: +include::memdev-option.txt[] + +-v:: + Turn on verbose debug messages in the library (if libcxl was built with + logging and debug enabled). + +include::../copyright.txt[] + +SEE ALSO +-------- +linkcxl:cxl-disable-memdev[1] diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index de88d192523a..49edb71b1f97 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -93,6 +93,29 @@ device. cxl_memdev_get_numa_node() returns the affinitized CPU node number if available or -1 otherwise. +=== MEMDEV: Control +---- +int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev); +int cxl_memdev_enable(struct cxl_memdev *memdev); +---- +When a memory device is disabled it unregisters its associated endpoints +and potentially intervening switch ports if there are no other memdevs +pinning that port active. That means that any existing port objects that +the library has previously returned are in valid and need to be re-read. +Callers must be careful to re-retrieve port objects after +cxl_memdev_disable_invalidate(). Any usage of a previously obtained port +object after a cxl_memdev_disable_invalidate() call is a use-after-free +programming error. It follows that after cxl_memdev_enable() new ports +may appear in the topology that were not previously enumerable. + +NOTE: cxl_memdev_disable_invalidate() will force disable the memdev +regardless of whether the memory provided by the device is in active use +by the operating system. Callers take responisbility for assuring that +it is safe to disable the memory device. Otherwise, this call can be as +destructive as ripping a DIMM out of a running system. Like all other +libcxl calls that mutate the system state or divulge security sensitive +information this call requires root / CAP_SYS_ADMIN. + === MEMDEV: Commands ---- struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev, int opcode); diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build index 0a6346bc47ca..7618c97278b4 100644 --- a/Documentation/cxl/meson.build +++ b/Documentation/cxl/meson.build @@ -30,6 +30,8 @@ cxl_manpages = [ 'cxl-read-labels.txt', 'cxl-write-labels.txt', 'cxl-zero-labels.txt', + 'cxl-enable-memdev.txt', + 'cxl-disable-memdev.txt', ] foreach man : cxl_manpages diff --git a/cxl/builtin.h b/cxl/builtin.h index 78eca6e2faf9..621c85c2ffcc 100644 --- a/cxl/builtin.h +++ b/cxl/builtin.h @@ -10,4 +10,6 @@ int cmd_read_labels(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_init_labels(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_check_labels(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_disable_memdev(int argc, const char **argv, struct cxl_ctx *ctx); +int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx); #endif /* _CXL_BUILTIN_H_ */ diff --git a/cxl/cxl.c b/cxl/cxl.c index 4b1661d8d4c1..78d2e9aec0bd 100644 --- a/cxl/cxl.c +++ b/cxl/cxl.c @@ -64,6 +64,8 @@ static struct cmd_struct commands[] = { { "zero-labels", .c_fn = cmd_zero_labels }, { "read-labels", .c_fn = cmd_read_labels }, { "write-labels", .c_fn = cmd_write_labels }, + { "disable-memdev", .c_fn = cmd_disable_memdev }, + { "enable-memdev", .c_fn = cmd_enable_memdev }, }; int main(int argc, const char **argv) diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 14c7db88ff5e..2fdaf71bb837 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -500,6 +500,64 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev return memdev->firmware_version; } +CXL_EXPORT int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev) +{ + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + const char *devname = cxl_memdev_get_devname(memdev); + struct cxl_port *port, *_p, *bus_port; + struct cxl_bus *bus; + + if (!cxl_memdev_is_enabled(memdev)) + return 0; + + bus = cxl_memdev_get_bus(memdev); + if (!bus) { + err(ctx, "%s: failed to invalidate\n", devname); + return -ENXIO; + } + + util_unbind(memdev->dev_path, ctx); + + if (cxl_memdev_is_enabled(memdev)) { + err(ctx, "%s: failed to disable\n", devname); + return -EBUSY; + } + + /* + * The state of all ports is now indeterminate, delete them all + * and start over. + */ + bus_port = cxl_bus_get_port(bus); + list_for_each_safe(&bus_port->child_ports, port, _p, list) + free_port(port, &bus_port->child_ports); + bus_port->ports_init = 0; + memdev->endpoint = NULL; + + dbg(ctx, "%s: disabled\n", devname); + + return 0; +} + +CXL_EXPORT int cxl_memdev_enable(struct cxl_memdev *memdev) +{ + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + const char *devname = cxl_memdev_get_devname(memdev); + + if (cxl_memdev_is_enabled(memdev)) + return 0; + + util_bind(devname, memdev->module, "cxl", ctx); + + if (!cxl_memdev_is_enabled(memdev)) { + err(ctx, "%s: failed to enable\n", devname); + return -ENXIO; + } + + dbg(ctx, "%s: enabled\n", devname); + + return 0; +} + static struct cxl_endpoint *cxl_port_find_endpoint(struct cxl_port *parent_port, struct cxl_memdev *memdev) { diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index b13a2d6d25d1..f235e99e3bf0 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -115,4 +115,6 @@ global: cxl_memdev_get_endpoint; cxl_memdev_is_enabled; cxl_memdev_get_bus; + cxl_memdev_disable_invalidate; + cxl_memdev_enable; } LIBCXL_1; diff --git a/cxl/libcxl.h b/cxl/libcxl.h index be656ed0d90d..53f68dde2770 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -48,6 +48,8 @@ unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev); unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev); const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev); size_t cxl_memdev_get_label_size(struct cxl_memdev *memdev); +int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev); +int cxl_memdev_enable(struct cxl_memdev *memdev); struct cxl_endpoint; struct cxl_endpoint *cxl_memdev_get_endpoint(struct cxl_memdev *memdev); int cxl_memdev_nvdimm_bridge_active(struct cxl_memdev *memdev); diff --git a/cxl/memdev.c b/cxl/memdev.c index ef5343ad892b..90b33e1b4195 100644 --- a/cxl/memdev.c +++ b/cxl/memdev.c @@ -25,13 +25,14 @@ static struct parameters { unsigned offset; bool verbose; bool serial; + bool force; } param; static struct log_ctx ml; #define BASE_OPTIONS() \ OPT_BOOLEAN('v',"verbose", ¶m.verbose, "turn on debug"), \ -OPT_BOOLEAN('S', "serial", ¶m.serial, "user serials numbers to id memdevs") +OPT_BOOLEAN('S', "serial", ¶m.serial, "use serial numbers to id memdevs") #define READ_OPTIONS() \ OPT_STRING('o', "output", ¶m.outfile, "output-file", \ @@ -46,6 +47,10 @@ OPT_UINTEGER('s', "size", ¶m.len, "number of label bytes to operate"), \ OPT_UINTEGER('O', "offset", ¶m.offset, \ "offset into the label area to start operation") +#define DISABLE_OPTIONS() \ +OPT_BOOLEAN('f', "force", ¶m.force, \ + "DANGEROUS: override active memdev safety checks") + static const struct option read_options[] = { BASE_OPTIONS(), LABEL_OPTIONS(), @@ -66,6 +71,37 @@ static const struct option zero_options[] = { OPT_END(), }; +static const struct option disable_options[] = { + BASE_OPTIONS(), + DISABLE_OPTIONS(), + OPT_END(), +}; + +static const struct option enable_options[] = { + BASE_OPTIONS(), + OPT_END(), +}; + +static int action_disable(struct cxl_memdev *memdev, struct action_context *actx) +{ + if (!cxl_memdev_is_enabled(memdev)) + return 0; + + if (!param.force) { + /* TODO: actually detect rather than assume active */ + log_err(&ml, "%s is part of an active region\n", + cxl_memdev_get_devname(memdev)); + return -EBUSY; + } + + return cxl_memdev_disable_invalidate(memdev); +} + +static int action_enable(struct cxl_memdev *memdev, struct action_context *actx) +{ + return cxl_memdev_enable(memdev); +} + static int action_zero(struct cxl_memdev *memdev, struct action_context *actx) { size_t size; @@ -340,3 +376,25 @@ int cmd_zero_labels(int argc, const char **argv, struct cxl_ctx *ctx) count > 1 ? "s" : ""); return count >= 0 ? 0 : EXIT_FAILURE; } + +int cmd_disable_memdev(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int count = memdev_action( + argc, argv, ctx, action_disable, disable_options, + "cxl disable-memdev [..] []"); + + log_info(&ml, "disabled %d mem%s\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); + return count >= 0 ? 0 : EXIT_FAILURE; +} + +int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx) +{ + int count = memdev_action( + argc, argv, ctx, action_enable, enable_options, + "cxl enable-memdev [..] []"); + + log_info(&ml, "enabled %d mem%s\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); + return count >= 0 ? 0 : EXIT_FAILURE; +} From patchwork Mon Jan 24 00:54:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721367 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 EAAB7C433EF for ; Mon, 24 Jan 2022 00:54:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240674AbiAXAyc (ORCPT ); Sun, 23 Jan 2022 19:54:32 -0500 Received: from mga06.intel.com ([134.134.136.31]:17172 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235269AbiAXAya (ORCPT ); Sun, 23 Jan 2022 19:54:30 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985670; x=1674521670; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=5PFL38jG5eXJUsn1KAQSMs8F09ZasROzCiTHPTI1y14=; b=ehCNNqZrvJbtHQFIon7SFqMvn+iizobmKJkwEZcf35zIjf+DsKvadyqi gGhvxnuU3KC84nf5o8HQkKG80Ni/NaidIZFdDh1WqbUfiNL3mx0WaiFJP WcWYzAOUH70XxGw8ZMaPr2+N4D3iK+0366zPcWIjWq37fB8XLC9pyu0TI CTyRCg8Pp+kOK3w2LYzIgqLEi2xjmc3yg+x3CdDvFiAZwZ57EQKgQJqbg xuToIeNc7EZ98f0g9mlmus0V0lDBP43EDezzUyi2Des/myC+DUMYKQDr1 zNhIQrwMaFCKpfoowT2cqGFifcR5nbEEXHADoZTdzfSBOiQ6gw5+tV2t1 A==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="306652200" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="306652200" Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:29 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="531921985" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:28 -0800 Subject: [ndctl PATCH 30/37] cxl/list: Add decoder support From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:54:27 -0800 Message-ID: <164298566760.3021641.3999006903066004615.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Decoder objects exist at each level of a CXL port topology and map a physical address range a set of interleaved ports at each level of the hierarchy. Typically end users mostly care about the root-level decoders which enumerate the potential CXL address space in the system, and the endpoint decoders that indicate which address ranges a given device contributes resources. Intermediate switch-level decoders are typically only useful for debugging decode problems. $ cxl list -D -d 3.1 -u { "decoder":"decoder3.1", "resource":"0x8030000000", "size":"512.00 MiB (536.87 MB)", "volatile_capable":true } Signed-off-by: Dan Williams --- .clang-format | 1 Documentation/cxl/cxl-list.txt | 18 +++ Documentation/cxl/lib/libcxl.txt | 70 +++++++++++ cxl/filter.c | 194 ++++++++++++++++++++++++++++++- cxl/filter.h | 2 cxl/json.c | 62 ++++++++++ cxl/json.h | 2 cxl/lib/libcxl.c | 239 +++++++++++++++++++++++++++++++++++--- cxl/lib/libcxl.sym | 14 ++ cxl/lib/private.h | 31 +++++ cxl/libcxl.h | 28 ++++ cxl/list.c | 9 + util/json.h | 1 13 files changed, 643 insertions(+), 28 deletions(-) diff --git a/.clang-format b/.clang-format index 106bc5e25434..16e28ac86959 100644 --- a/.clang-format +++ b/.clang-format @@ -80,6 +80,7 @@ ForEachMacros: - 'cxl_memdev_foreach' - 'cxl_bus_foreach' - 'cxl_port_foreach' + - 'cxl_decoder_foreach' - 'cxl_endpoint_foreach' - 'daxctl_dev_foreach' - 'daxctl_mapping_foreach' diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index bac27c7b70a1..84872b912975 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -5,7 +5,7 @@ cxl-list(1) NAME ---- -cxl-list - List CXL capable memory devices, and their attributes in json. +cxl-list - List platform CXL objects, and their attributes, in json. SYNOPSIS -------- @@ -29,6 +29,10 @@ The potential top-level array names and their nesting properties are: "endpoints":: nest under ports or buses (if ports are not emitted) "memdevs":: nest under endpoints or ports (if endpoints are not emitted) or buses (if endpoints and ports are not emitted) +"root decoders":: nest under buses +"port decoders":: nest under ports, or buses (if ports are not emitted) +"endpoint decoders":: nest under endpoints, or ports (if endpoints are + not emitted) or buses (if endpoints and ports are not emitted) Filters can by specifed as either a single identidier, a space separated quoted string, or a comma separated list. When multiple filter @@ -254,6 +258,18 @@ OPTIONS Specify CXL endpoint device name(s), or device id(s) to filter the emitted endpoint(s). +-D:: +--decoders:: + Include decoder objects (CXL Memory decode capability instances + in buses, ports, and endpoints) in the listing. + +-d:: +--decoder:: + Specify CXL decoder device name(s), device id(s), or decoder type names + to filter the emitted decoder(s). The format for a decoder name is + "decoder.". The possible decoder type names are + "root", "switch", or "endpoint", similar to the port filter syntax. + --debug:: If the cxl tool was built with debug enabled, turn on debug messages. diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index 49edb71b1f97..73af3d03b108 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -179,6 +179,7 @@ struct cxl_bus *cxl_bus_get_first(struct cxl_ctx *ctx); struct cxl_bus *cxl_bus_get_next(struct cxl_bus *bus); struct cxl_ctx *cxl_bus_get_ctx(struct cxl_bus *bus); struct cxl_bus *cxl_memdev_get_bus(struct cxl_memdev *memdev); +struct cxl_bus *cxl_port_get_bus(struct cxl_port *port); struct cxl_bus *cxl_endpoint_get_bus(struct cxl_endpoint *endpoint); #define cxl_bus_foreach(ctx, bus) \ @@ -215,9 +216,9 @@ struct cxl_port *cxl_bus_get_port(struct cxl_bus *bus); struct cxl_port *cxl_port_get_first(struct cxl_port *parent); struct cxl_port *cxl_port_get_next(struct cxl_port *port); struct cxl_port *cxl_port_get_parent(struct cxl_port *port); -struct cxl_bus *cxl_port_get_bus(struct cxl_port *port); struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port); const char *cxl_port_get_host(struct cxl_port *port); +struct cxl_port *cxl_decoder_get_port(struct cxl_decoder *decoder); #define cxl_port_foreach(parent, port) \ for (port = cxl_port_get_first(parent); port != NULL; \ @@ -284,6 +285,73 @@ int cxl_endpoint_get_id(struct cxl_endpoint *endpoint); int cxl_endpoint_is_enabled(struct cxl_endpoint *endpoint); ---- +DECODERS +-------- +Decoder objects are associated with the "HDM Decoder Capability" +published in Port devices and CXL capable PCIe endpoints. The kernel +additionally models platform firmware described CXL memory ranges (like +the ACPI CEDT.CFMWS) as static decoder objects. They route System +Physical Addresses through a port topology to an endpoint decoder that +does the final translation from SPA to DPA (system-physical-address to +device-local-physical-address). + +=== DECODER: Enumeration +---- +struct cxl_decoder *cxl_decoder_get_first(struct cxl_port *port); +struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder); +struct cxl_ctx *cxl_decoder_get_ctx(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)) +---- +The definition of a CXL port in libcxl is an object that hosts one or +more CXL decoder objects. + +=== DECODER: Attributes +---- +unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder); +unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder); +const char *cxl_decoder_get_devname(struct cxl_decoder *decoder); +int cxl_decoder_get_id(struct cxl_decoder *decoder); + +enum cxl_decoder_target_type { + CXL_DECODER_TTYPE_UNKNOWN, + CXL_DECODER_TTYPE_EXPANDER, + CXL_DECODER_TTYPE_ACCELERATOR, +}; + +cxl_decoder_get_target_type(struct cxl_decoder *decoder); +bool cxl_decoder_is_pmem_capable(struct cxl_decoder *decoder); +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); +---- +The kernel protects the enumeration of the physical address layout of +the system. Without CAP_SYS_ADMIN cxl_decoder_get_resource() returns +ULLONG_MAX to indicate that the address information was not retrievable. +Otherwise, cxl_decoder_get_resource() returns the currently programmed +value of the base of the decoder's decode range. A zero-sized decoder +indicates a disabled decoder. + +Root level decoders only support limited set of memory types in their +address range. The cxl_decoder_is__capable() helpers identify +what is supported. Switch level decoders, in contrast are capable of +routing any memory type, i.e. they just forward along the memory type +support from their parent port. Endpoint decoders follow the +capabilities of their host memory device. + +The capabilities of a decoder are not to be confused with their type / +mode. The type ultimately depends on the endpoint. For example an +accelerator requires all decoders in its ancestry to be set to +CXL_DECODER_TTYPE_ACCELERATOR, and conversely plain memory expander +devices require CXL_DECODER_TTYPE_EXPANDER. + +Platform firmware may setup the CXL decode hierarchy before the OS +boots, and may additionally require that the OS not change the decode +settings. This property is indicated by the cxl_decoder_is_locked() API. + include::../../copyright.txt[] SEE ALSO diff --git a/cxl/filter.c b/cxl/filter.c index 6dc61a135351..dc052f63d0c5 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -171,6 +171,17 @@ util_cxl_endpoint_filter_by_port(struct cxl_endpoint *endpoint, return NULL; } +static struct cxl_decoder * +util_cxl_decoder_filter_by_port(struct cxl_decoder *decoder, const char *ident, + enum cxl_port_filter_mode mode) +{ + struct cxl_port *port = cxl_decoder_get_port(decoder); + + if (util_cxl_port_filter(port, ident, mode)) + return decoder; + return NULL; +} + static struct cxl_bus *util_cxl_bus_filter(struct cxl_bus *bus, const char *__ident) { @@ -233,6 +244,16 @@ static struct cxl_port *util_cxl_port_filter_by_bus(struct cxl_port *port, return NULL; } +static struct cxl_decoder * +util_cxl_decoder_filter_by_bus(struct cxl_decoder *decoder, const char *__ident) +{ + struct cxl_port *port = cxl_decoder_get_port(decoder); + + if (!util_cxl_port_filter_by_bus(port, __ident)) + return NULL; + return decoder; +} + static struct cxl_memdev * util_cxl_memdev_serial_filter(struct cxl_memdev *memdev, const char *__serials) { @@ -357,6 +378,49 @@ static struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port, return NULL; } +static struct cxl_decoder *util_cxl_decoder_filter(struct cxl_decoder *decoder, + const char *__ident) +{ + struct cxl_port *port = cxl_decoder_get_port(decoder); + int pid, did; + char *ident, *save; + const char *name; + + if (!__ident) + return decoder; + + 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 (strcmp(name, "root") == 0 && cxl_port_is_root(port)) + break; + if (strcmp(name, "switch") == 0 && cxl_port_is_switch(port)) + break; + if (strcmp(name, "endpoint") == 0 && cxl_port_is_endpoint(port)) + break; + + if ((sscanf(name, "%d.%d", &pid, &did) == 2 || + sscanf(name, "decoder%d.%d", &pid, &did) == 2) && + cxl_port_get_id(port) == pid && + cxl_decoder_get_id(decoder) == did) + break; + + if (strcmp(name, cxl_decoder_get_devname(decoder)) == 0) + break; + } + + free(ident); + if (name) + return decoder; + return NULL; +} + static unsigned long params_to_flags(struct cxl_filter_params *param) { unsigned long flags = 0; @@ -440,15 +504,44 @@ static struct json_object *pick_array(struct json_object *child, return NULL; } +static void walk_decoders(struct cxl_port *port, struct cxl_filter_params *p, + struct json_object *jdecoders, unsigned long flags) +{ + struct cxl_decoder *decoder; + + cxl_decoder_foreach(port, decoder) { + struct json_object *jdecoder; + + if (!p->decoders) + continue; + if (!util_cxl_decoder_filter(decoder, p->decoder_filter)) + continue; + if (!util_cxl_decoder_filter_by_bus(decoder, p->bus_filter)) + continue; + if (!util_cxl_decoder_filter_by_port(decoder, p->port_filter, + pf_mode(p))) + continue; + if (!p->idle && cxl_decoder_get_size(decoder) == 0) + continue; + jdecoder = util_cxl_decoder_to_json(decoder, flags); + if (!decoder) { + dbg(p, "decoder object allocation failure\n"); + continue; + } + json_object_array_add(jdecoders, jdecoder); + } +} + static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p, struct json_object *jeps, struct json_object *jdevs, - unsigned long flags) + struct json_object *jdecoders, unsigned long flags) { struct cxl_endpoint *endpoint; cxl_endpoint_foreach(port, endpoint) { struct cxl_port *ep_port = cxl_endpoint_get_port(endpoint); const char *devname = cxl_endpoint_get_devname(endpoint); + struct json_object *jchilddecoders = NULL; struct json_object *jendpoint = NULL; struct cxl_memdev *memdev; @@ -495,14 +588,31 @@ static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p, else json_object_array_add(jdevs, jobj); } + + if (p->decoders && p->endpoints) { + jchilddecoders = json_object_new_array(); + if (!jchilddecoders) { + err(p, + "%s: failed to enumerate child decoders\n", + devname); + continue; + } + } + + if (!p->decoders) + continue; + walk_decoders(cxl_endpoint_get_port(endpoint), p, + pick_array(jchilddecoders, jdecoders), flags); + cond_add_put_array_suffix(jendpoint, "decoders", devname, + jchilddecoders); } } -static void walk_child_ports(struct cxl_port *parent_port, - struct cxl_filter_params *p, - struct json_object *jports, - struct json_object *jeps, - struct json_object *jdevs, unsigned long flags) +static void +walk_child_ports(struct cxl_port *parent_port, struct cxl_filter_params *p, + struct json_object *jports, struct json_object *jportdecoders, + struct json_object *jeps, struct json_object *jepdecoders, + struct json_object *jdevs, unsigned long flags) { struct cxl_port *port; @@ -512,6 +622,7 @@ static void walk_child_ports(struct cxl_port *parent_port, struct json_object *jchilddevs = NULL; struct json_object *jchildports = NULL; struct json_object *jchildeps = NULL; + struct json_object *jchilddecoders = NULL; if (!util_cxl_port_filter_by_memdev(port, p->memdev_filter, p->serial_filter)) @@ -555,19 +666,37 @@ static void walk_child_ports(struct cxl_port *parent_port, continue; } } + + if (p->decoders) { + jchilddecoders = json_object_new_array(); + if (!jchilddecoders) { + err(p, + "%s: failed to enumerate child decoders\n", + devname); + continue; + } + } } walk_children: - if (p->endpoints || p->memdevs) + if (p->endpoints || p->memdevs || p->decoders) walk_endpoints(port, p, pick_array(jchildeps, jeps), - pick_array(jchilddevs, jdevs), flags); + pick_array(jchilddevs, jdevs), + pick_array(jchilddecoders, jepdecoders), + flags); + walk_decoders(port, p, + pick_array(jchilddecoders, jportdecoders), flags); walk_child_ports(port, p, pick_array(jchildports, jports), + pick_array(jchilddecoders, jportdecoders), pick_array(jchildeps, jeps), + pick_array(jchilddecoders, jepdecoders), pick_array(jchilddevs, jdevs), flags); cond_add_put_array_suffix(jport, "ports", devname, jchildports); cond_add_put_array_suffix(jport, "endpoints", devname, jchildeps); + cond_add_put_array_suffix(jport, "decoders", devname, + jchilddecoders); cond_add_put_array_suffix(jport, "memdevs", devname, jchilddevs); } @@ -578,6 +707,9 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) struct json_object *jdevs = NULL, *jbuses = NULL, *jports = NULL; struct json_object *jplatform = json_object_new_array(); unsigned long flags = params_to_flags(p); + struct json_object *jportdecoders = NULL; + struct json_object *jbusdecoders = NULL; + struct json_object *jepdecoders = NULL; struct json_object *janondevs = NULL; struct json_object *jeps = NULL; struct cxl_memdev *memdev; @@ -609,6 +741,18 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) if (!jdevs) goto err; + jbusdecoders = json_object_new_array(); + if (!jbusdecoders) + goto err; + + jportdecoders = json_object_new_array(); + if (!jportdecoders) + goto err; + + jepdecoders = json_object_new_array(); + if (!jepdecoders) + goto err; + dbg(p, "walk memdevs\n"); cxl_memdev_foreach(ctx, memdev) { struct json_object *janondev; @@ -633,6 +777,7 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) dbg(p, "walk buses\n"); cxl_bus_foreach(ctx, bus) { struct json_object *jbus = NULL; + struct json_object *jchilddecoders = NULL; struct json_object *jchildports = NULL; struct json_object *jchilddevs = NULL; struct json_object *jchildeps = NULL; @@ -681,15 +826,33 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) continue; } } + if (p->decoders) { + jchilddecoders = json_object_new_array(); + if (!jchilddecoders) { + err(p, + "%s: failed to enumerate child decoders\n", + devname); + continue; + } + } + } walk_children: + dbg(p, "walk decoders\n"); + walk_decoders(port, p, pick_array(jchilddecoders, jbusdecoders), + flags); + dbg(p, "walk ports\n"); walk_child_ports(port, p, pick_array(jchildports, jports), + pick_array(jchilddecoders, jportdecoders), pick_array(jchildeps, jeps), + pick_array(jchilddecoders, jepdecoders), pick_array(jchilddevs, jdevs), flags); cond_add_put_array_suffix(jbus, "ports", devname, jchildports); cond_add_put_array_suffix(jbus, "endpoints", devname, jchildeps); + cond_add_put_array_suffix(jbus, "decoders", devname, + jchilddecoders); cond_add_put_array_suffix(jbus, "memdevs", devname, jchilddevs); } @@ -703,12 +866,24 @@ walk_children: top_level_objs++; if (json_object_array_length(jdevs)) top_level_objs++; + if (json_object_array_length(jbusdecoders)) + top_level_objs++; + if (json_object_array_length(jportdecoders)) + top_level_objs++; + if (json_object_array_length(jepdecoders)) + top_level_objs++; splice_array(p, janondevs, jplatform, "anon memdevs", top_level_objs > 1); splice_array(p, jbuses, jplatform, "buses", top_level_objs > 1); splice_array(p, jports, jplatform, "ports", top_level_objs > 1); splice_array(p, jeps, jplatform, "endpoints", top_level_objs > 1); splice_array(p, jdevs, jplatform, "memdevs", top_level_objs > 1); + splice_array(p, jbusdecoders, jplatform, "root decoders", + top_level_objs > 1); + splice_array(p, jportdecoders, jplatform, "port decoders", + top_level_objs > 1); + splice_array(p, jepdecoders, jplatform, "endpoint decoders", + top_level_objs > 1); util_display_json_array(stdout, jplatform, flags); @@ -719,6 +894,9 @@ err: json_object_put(jports); json_object_put(jeps); json_object_put(jdevs); + json_object_put(jbusdecoders); + json_object_put(jportdecoders); + json_object_put(jepdecoders); json_object_put(jplatform); return -ENOMEM; } diff --git a/cxl/filter.h b/cxl/filter.h index bbd341c71721..5d7bf45f3301 100644 --- a/cxl/filter.h +++ b/cxl/filter.h @@ -12,8 +12,10 @@ struct cxl_filter_params { const char *bus_filter; const char *port_filter; const char *endpoint_filter; + const char *decoder_filter; bool single; bool endpoints; + bool decoders; bool memdevs; bool ports; bool buses; diff --git a/cxl/json.c b/cxl/json.c index 51918d65f671..548bc52f2d16 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -262,6 +262,68 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus, return jbus; } +struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder, + unsigned long flags) +{ + const char *devname = cxl_decoder_get_devname(decoder); + struct cxl_port *port = cxl_decoder_get_port(decoder); + struct json_object *jdecoder, *jobj; + u64 val; + + jdecoder = json_object_new_object(); + if (!jdecoder) + return NULL; + + jobj = json_object_new_string(devname); + if (jobj) + json_object_object_add(jdecoder, "decoder", jobj); + + val = cxl_decoder_get_resource(decoder); + if (val < ULLONG_MAX) { + jobj = util_json_object_hex(val, flags); + if (jobj) + json_object_object_add(jdecoder, "resource", jobj); + } + + val = cxl_decoder_get_size(decoder); + if (val < ULLONG_MAX) { + jobj = util_json_object_size(val, flags); + if (jobj) + json_object_object_add(jdecoder, "size", jobj); + } + + if (val == 0) { + jobj = json_object_new_string("disabled"); + if (jobj) + json_object_object_add(jdecoder, "state", jobj); + } + + if (cxl_port_is_root(port) && cxl_decoder_is_mem_capable(decoder)) { + if (cxl_decoder_is_pmem_capable(decoder)) { + jobj = json_object_new_boolean(true); + if (jobj) + json_object_object_add(jdecoder, "pmem_capable", + jobj); + } + if (cxl_decoder_is_volatile_capable(decoder)) { + jobj = json_object_new_boolean(true); + if (jobj) + json_object_object_add( + jdecoder, "volatile_capable", jobj); + } + } + + if (cxl_port_is_root(port) && + cxl_decoder_is_accelmem_capable(decoder)) { + jobj = json_object_new_boolean(true); + if (jobj) + json_object_object_add(jdecoder, "accelmem_capable", + jobj); + } + + return jdecoder; +} + static struct json_object *__util_cxl_port_to_json(struct cxl_port *port, const char *name_key, unsigned long flags) diff --git a/cxl/json.h b/cxl/json.h index 8f45190f67e5..fcca2e6e9cb6 100644 --- a/cxl/json.h +++ b/cxl/json.h @@ -13,4 +13,6 @@ struct json_object *util_cxl_port_to_json(struct cxl_port *port, unsigned long flags); 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); #endif /* __CXL_UTIL_JSON_H__ */ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 2fdaf71bb837..5e3092364e4a 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -63,16 +63,26 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head) free(memdev->firmware_version); free(memdev->dev_buf); free(memdev->dev_path); - free(memdev->host); + free(memdev->host_path); free(memdev); } +static void free_decoder(struct cxl_decoder *decoder, struct list_head *head) +{ + if (head) + list_del_from(head, &decoder->list); + free(decoder->dev_buf); + free(decoder->dev_path); + free(decoder); +} + static void free_port(struct cxl_port *port, struct list_head *head); static void free_endpoint(struct cxl_endpoint *endpoint, struct list_head *head); static void __free_port(struct cxl_port *port, struct list_head *head) { struct cxl_port *child, *_c; struct cxl_endpoint *endpoint, *_e; + struct cxl_decoder *decoder, *_d; if (head) list_del_from(head, &port->list); @@ -80,6 +90,8 @@ static void __free_port(struct cxl_port *port, struct list_head *head) free_port(child, &port->child_ports); list_for_each_safe(&port->endpoints, endpoint, _e, port.list) free_endpoint(endpoint, &port->endpoints); + list_for_each_safe(&port->decoders, decoder, _d, list) + free_decoder(decoder, &port->decoders); kmod_module_unref(port->module); free(port->dev_buf); free(port->dev_path); @@ -298,9 +310,9 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base) char *path = calloc(1, strlen(cxlmem_base) + 100); struct cxl_ctx *ctx = parent; struct cxl_memdev *memdev, *memdev_dup; - char *host, *rpath = NULL; char buf[SYSFS_ATTR_SIZE]; struct stat st; + char *host; if (!path) return NULL; @@ -358,21 +370,13 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base) if (!memdev->dev_path) goto err_read; - rpath = realpath(cxlmem_base, NULL); - if (!rpath) + memdev->host_path = realpath(cxlmem_base, NULL); + if (!memdev->host_path) goto err_read; - host = strrchr(rpath, '/'); - if (host) { - host[0] = '\0'; - host = strrchr(rpath, '/'); - } + host = strrchr(memdev->host_path, '/'); if (!host) goto err_read; - memdev->host = strdup(host + 1); - if (!memdev->host) - goto err_read; - free(rpath); - rpath = NULL; + host[0] = '\0'; sprintf(path, "%s/firmware_version", cxlmem_base); if (sysfs_read_attr(ctx, path, buf) < 0) @@ -404,8 +408,8 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base) free(memdev->firmware_version); free(memdev->dev_buf); free(memdev->dev_path); + free(memdev->host_path); free(memdev); - free(rpath); err_dev: free(path); return NULL; @@ -463,7 +467,7 @@ CXL_EXPORT const char *cxl_memdev_get_devname(struct cxl_memdev *memdev) CXL_EXPORT const char *cxl_memdev_get_host(struct cxl_memdev *memdev) { - return memdev->host; + return devpath_to_devname(memdev->host_path); } CXL_EXPORT struct cxl_bus *cxl_memdev_get_bus(struct cxl_memdev *memdev) @@ -679,9 +683,11 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_port *parent_port, port->ctx = ctx; port->type = type; port->parent = parent_port; + port->type = type; list_head_init(&port->child_ports); list_head_init(&port->endpoints); + list_head_init(&port->decoders); port->dev_path = strdup(cxlport_base); if (!port->dev_path) @@ -842,6 +848,207 @@ cxl_endpoint_get_memdev(struct cxl_endpoint *endpoint) return NULL; } +static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base) +{ + const char *devname = devpath_to_devname(cxldecoder_base); + char *path = calloc(1, strlen(cxldecoder_base) + 100); + struct cxl_decoder *decoder, *decoder_dup; + struct cxl_port *port = parent; + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + char buf[SYSFS_ATTR_SIZE]; + size_t i; + + dbg(ctx, "%s: base: \'%s\'\n", devname, cxldecoder_base); + + if (!path) + return NULL; + + decoder = calloc(1, sizeof(*decoder)); + if (!decoder) + goto err; + + decoder->id = id; + decoder->ctx = ctx; + decoder->port = port; + + decoder->dev_path = strdup(cxldecoder_base); + if (!decoder->dev_path) + goto err; + + decoder->dev_buf = calloc(1, strlen(cxldecoder_base) + 50); + if (!decoder->dev_buf) + goto err; + decoder->buf_len = strlen(cxldecoder_base) + 50; + + sprintf(path, "%s/start", cxldecoder_base); + if (sysfs_read_attr(ctx, path, buf) < 0) + decoder->start = ULLONG_MAX; + else + decoder->start = strtoull(buf, NULL, 0); + + sprintf(path, "%s/size", cxldecoder_base); + if (sysfs_read_attr(ctx, path, buf) < 0) + decoder->size = ULLONG_MAX; + else + decoder->size = strtoull(buf, NULL, 0); + + switch (port->type) { + case CXL_PORT_SWITCH: + case CXL_PORT_ENDPOINT: + decoder->pmem_capable = true; + decoder->volatile_capable = true; + decoder->mem_capable = true; + decoder->accelmem_capable = true; + sprintf(path, "%s/locked", cxldecoder_base); + if (sysfs_read_attr(ctx, path, buf) == 0) + decoder->locked = !!strtoul(buf, NULL, 0); + sprintf(path, "%s/target_type", cxldecoder_base); + if (sysfs_read_attr(ctx, path, buf) == 0) { + if (strcmp(buf, "accelerator") == 0) + decoder->target_type = + CXL_DECODER_TTYPE_ACCELERATOR; + if (strcmp(buf, "expander") == 0) + decoder->target_type = + CXL_DECODER_TTYPE_EXPANDER; + } + break; + case CXL_PORT_ROOT: { + struct cxl_decoder_flag { + char *name; + bool *flag; + } flags[] = { + { "cap_type2", &decoder->accelmem_capable }, + { "cap_type3", &decoder->mem_capable }, + { "cap_ram", &decoder->volatile_capable }, + { "cap_pmem", &decoder->pmem_capable }, + { "locked", &decoder->locked }, + }; + + for (i = 0; i < ARRAY_SIZE(flags); i++) { + struct cxl_decoder_flag *flag = &flags[i]; + + sprintf(path, "%s/%s", cxldecoder_base, flag->name); + if (sysfs_read_attr(ctx, path, buf) == 0) + *(flag->flag) = !!strtoul(buf, NULL, 0); + } + break; + } + } + + cxl_decoder_foreach(port, decoder_dup) + if (decoder_dup->id == decoder->id) { + free_decoder(decoder, NULL); + return decoder_dup; + } + + list_add(&port->decoders, &decoder->list); + + return decoder; +err: + free(decoder->dev_path); + free(decoder->dev_buf); + free(decoder); + free(path); + return NULL; +} + +static void cxl_decoders_init(struct cxl_port *port) +{ + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + char *decoder_fmt; + + if (port->decoders_init) + return; + + if (asprintf(&decoder_fmt, "decoder%d.", cxl_port_get_id(port)) < 0) { + err(ctx, "%s: failed to add decoder(s)\n", + cxl_port_get_devname(port)); + return; + } + + port->decoders_init = 1; + + sysfs_device_parse(ctx, port->dev_path, decoder_fmt, port, + add_cxl_decoder); + + free(decoder_fmt); +} + +CXL_EXPORT struct cxl_decoder *cxl_decoder_get_first(struct cxl_port *port) +{ + cxl_decoders_init(port); + + return list_top(&port->decoders, struct cxl_decoder, list); +} + +CXL_EXPORT struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder) +{ + struct cxl_port *port = decoder->port; + + return list_next(&port->decoders, decoder, list); +} + +CXL_EXPORT struct cxl_ctx *cxl_decoder_get_ctx(struct cxl_decoder *decoder) +{ + return decoder->ctx; +} + +CXL_EXPORT int cxl_decoder_get_id(struct cxl_decoder *decoder) +{ + return decoder->id; +} + +CXL_EXPORT struct cxl_port *cxl_decoder_get_port(struct cxl_decoder *decoder) +{ + return decoder->port; +} + +CXL_EXPORT unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder) +{ + return decoder->start; +} + +CXL_EXPORT unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder) +{ + return decoder->size; +} + +CXL_EXPORT enum cxl_decoder_target_type +cxl_decoder_get_target_type(struct cxl_decoder *decoder) +{ + return decoder->target_type; +} + +CXL_EXPORT bool cxl_decoder_is_pmem_capable(struct cxl_decoder *decoder) +{ + return decoder->pmem_capable; +} + +CXL_EXPORT bool cxl_decoder_is_volatile_capable(struct cxl_decoder *decoder) +{ + return decoder->volatile_capable; +} + +CXL_EXPORT bool cxl_decoder_is_mem_capable(struct cxl_decoder *decoder) +{ + return decoder->mem_capable; +} + +CXL_EXPORT bool cxl_decoder_is_accelmem_capable(struct cxl_decoder *decoder) +{ + return decoder->accelmem_capable; +} + +CXL_EXPORT bool cxl_decoder_is_locked(struct cxl_decoder *decoder) +{ + return decoder->locked; +} + +CXL_EXPORT const char *cxl_decoder_get_devname(struct cxl_decoder *decoder) +{ + return devpath_to_devname(decoder->dev_path); +} + static void *add_cxl_port(void *parent, int id, const char *cxlport_base) { const char *devname = devpath_to_devname(cxlport_base); diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index f235e99e3bf0..22babb760f23 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -117,4 +117,18 @@ global: cxl_memdev_get_bus; cxl_memdev_disable_invalidate; cxl_memdev_enable; + cxl_decoder_get_first; + cxl_decoder_get_next; + cxl_decoder_get_ctx; + cxl_decoder_get_id; + cxl_decoder_get_port; + cxl_decoder_get_resource; + cxl_decoder_get_size; + cxl_decoder_get_devname; + cxl_decoder_get_target_type; + cxl_decoder_is_pmem_capable; + cxl_decoder_is_volatile_capable; + cxl_decoder_is_mem_capable; + cxl_decoder_is_accelmem_capable; + cxl_decoder_is_locked; } LIBCXL_1; diff --git a/cxl/lib/private.h b/cxl/lib/private.h index c00bb3600138..1743a244877a 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -23,7 +23,7 @@ struct cxl_memdev { int numa_node; void *dev_buf; size_t buf_len; - char *host; + char *host_path; char *dev_path; char *firmware_version; struct cxl_ctx *ctx; @@ -52,6 +52,7 @@ struct cxl_port { char *uport; int ports_init; int endpoints_init; + int decoders_init; struct cxl_ctx *ctx; struct cxl_bus *bus; enum cxl_port_type type; @@ -60,6 +61,7 @@ struct cxl_port { struct list_node list; struct list_head child_ports; struct list_head endpoints; + struct list_head decoders; }; struct cxl_bus { @@ -71,6 +73,33 @@ struct cxl_endpoint { struct cxl_memdev *memdev; }; +struct cxl_target { + struct list_node list; + struct cxl_decoder *decoder; + char *dev_path; + int id, position; +}; + +struct cxl_decoder { + struct cxl_port *port; + struct list_node list; + struct cxl_ctx *ctx; + u64 start; + u64 size; + void *dev_buf; + size_t buf_len; + char *dev_path; + int nr_targets; + int id; + bool pmem_capable; + bool volatile_capable; + bool mem_capable; + bool accelmem_capable; + bool locked; + enum cxl_decoder_target_type target_type; + struct list_head targets; +}; + enum cxl_cmd_query_status { CXL_CMD_QUERY_NOT_RUN = 0, CXL_CMD_QUERY_OK, diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 53f68dde2770..439ed9305397 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -98,6 +98,34 @@ bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev); for (port = cxl_port_get_first(parent); port != NULL; \ port = cxl_port_get_next(port)) +struct cxl_decoder; +struct cxl_decoder *cxl_decoder_get_first(struct cxl_port *port); +struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder); +unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder); +unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder); +const char *cxl_decoder_get_devname(struct cxl_decoder *decoder); +struct cxl_ctx *cxl_decoder_get_ctx(struct cxl_decoder *decoder); +int cxl_decoder_get_id(struct cxl_decoder *decoder); +struct cxl_port *cxl_decoder_get_port(struct cxl_decoder *decoder); + +enum cxl_decoder_target_type { + CXL_DECODER_TTYPE_UNKNOWN, + CXL_DECODER_TTYPE_EXPANDER, + CXL_DECODER_TTYPE_ACCELERATOR, +}; + +enum cxl_decoder_target_type +cxl_decoder_get_target_type(struct cxl_decoder *decoder); +bool cxl_decoder_is_pmem_capable(struct cxl_decoder *decoder); +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); + +#define cxl_decoder_foreach(port, decoder) \ + for (decoder = cxl_decoder_get_first(port); decoder != NULL; \ + decoder = cxl_decoder_get_next(decoder)) + struct cxl_endpoint; struct cxl_endpoint *cxl_endpoint_get_first(struct cxl_port *parent); struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint); diff --git a/cxl/list.c b/cxl/list.c index b15e01ce40f6..d70192a8cecf 100644 --- a/cxl/list.c +++ b/cxl/list.c @@ -36,6 +36,11 @@ static const struct option options[] = { "filter by CXL endpoint device name(s)"), OPT_BOOLEAN('E', "endpoints", ¶m.endpoints, "include CXL endpoint info"), + OPT_STRING('d', "decoder", ¶m.decoder_filter, + "decoder device name", + "filter by CXL decoder device name(s) / class"), + OPT_BOOLEAN('D', "decoders", ¶m.decoders, + "include CXL decoder info"), OPT_BOOLEAN('i', "idle", ¶m.idle, "include disabled devices"), OPT_BOOLEAN('u', "human", ¶m.human, "use human friendly number formats "), @@ -50,7 +55,7 @@ static const struct option options[] = { static int num_list_flags(void) { return !!param.memdevs + !!param.buses + !!param.ports + - !!param.endpoints; + !!param.endpoints + !!param.decoders; } int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) @@ -82,6 +87,8 @@ int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx) param.ports = true; if (param.endpoint_filter) 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 diff --git a/util/json.h b/util/json.h index 061f0d423158..e026df1e1519 100644 --- a/util/json.h +++ b/util/json.h @@ -18,6 +18,7 @@ enum util_json_flags { UTIL_JSON_FIRMWARE = (1 << 8), UTIL_JSON_DAX_MAPPINGS = (1 << 9), UTIL_JSON_HEALTH = (1 << 10), + UTIL_JSON_TARGETS = (1 << 11), }; void util_display_json_array(FILE *f_out, struct json_object *jarray, From patchwork Mon Jan 24 00:54:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721368 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 767A5C433FE for ; Mon, 24 Jan 2022 00:54:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235260AbiAXAyf (ORCPT ); Sun, 23 Jan 2022 19:54:35 -0500 Received: from mga06.intel.com ([134.134.136.31]:17172 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240679AbiAXAye (ORCPT ); Sun, 23 Jan 2022 19:54:34 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985674; x=1674521674; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=QedveqbESZDCj0Mnw+nUuV7aW0a4MMNTtdVaLUocSIc=; b=QSjI9Teojzi8KfJLaX5dWiEwWOm31MVO07SPacfxvY2I8GDj0jGDZ53X bnXCMKh0b3EbSSv9XK7MLO/4aGqLHTURbsiM+6DegO4TfRhDDAqMwn4bI FwbH7yXokSUgRpRFK4n+k0ZHQjhBAiBdkoM7D08sPCL/b6yZ3BrDRr6/T eKaZDm9C1Cv702iOuqrBHbr8h44G8ayq9cY6ukG4aiCqTA40F2IdhgoSR KgbhQEM+VyzkosINOAlAyXsoelaO6xEg67VOWP8eIOsM0rkw1MnI8/8Lh tqEh+0CQF68shobgD/e8DuggxiJUxGOg4q7DOOX41RhgSSALG6czkhCGW A==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="306652202" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="306652202" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:34 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="627309455" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:34 -0800 Subject: [ndctl PATCH 31/37] cxl/list: Extend decoder objects with target information From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:54:34 -0800 Message-ID: <164298567435.3021641.3771899644901785666.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org A target combines information about a dport along with its position in the intereleave order. With targets enumerated decoders can also be filtered be memory devices by seeing which decoders have a dport in the memory-device's ancestry. $ cxl list -D -d 3.1 -T -u { "decoder":"decoder3.1", "resource":"0x8030000000", "size":"512.00 MiB (536.87 MB)", "volatile_capable":true, "nr_targets":2, "targets":[ { "target":"cxl_host_bridge.1", "position":1, "id":"0x1" }, { "target":"cxl_host_bridge.0", "position":0, "id":"0" } ] } Signed-off-by: Dan Williams --- .clang-format | 1 Documentation/cxl/cxl-list.txt | 8 ++- Documentation/cxl/lib/libcxl.txt | 58 +++++++++++++++++++ cxl/filter.c | 25 ++++++++ cxl/filter.h | 1 cxl/json.c | 46 +++++++++++++++ cxl/lib/libcxl.c | 115 ++++++++++++++++++++++++++++++++++++++ cxl/lib/libcxl.sym | 10 +++ cxl/libcxl.h | 19 ++++++ cxl/list.c | 2 + 10 files changed, 283 insertions(+), 2 deletions(-) diff --git a/.clang-format b/.clang-format index 16e28ac86959..47fb657ff09a 100644 --- a/.clang-format +++ b/.clang-format @@ -81,6 +81,7 @@ ForEachMacros: - 'cxl_bus_foreach' - 'cxl_port_foreach' - 'cxl_decoder_foreach' + - 'cxl_target_foreach' - 'cxl_endpoint_foreach' - 'daxctl_dev_foreach' - 'daxctl_mapping_foreach' diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index 84872b912975..20ff2cb54fcb 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -44,8 +44,8 @@ would only list objects that are beneath port10 AND map mem0, mem1, OR mem2. Given that many topology queries seek to answer questions relative to a -given memdev, buses, ports, and endpoints can be filtered by one or more -memdevs. For example: +given memdev, buses, ports, endpoints, and decoders can be filtered by +one or more memdevs. For example: ---- # cxl list -P -p switch,endpoint -m mem0 [ @@ -270,6 +270,10 @@ OPTIONS "decoder.". The possible decoder type names are "root", "switch", or "endpoint", similar to the port filter syntax. +-T:: +--targets:: + Extend decoder listings with downstream port target information. + --debug:: If the cxl tool was built with debug enabled, turn on debug messages. diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index 73af3d03b108..bd92fef962fa 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -300,6 +300,7 @@ device-local-physical-address). struct cxl_decoder *cxl_decoder_get_first(struct cxl_port *port); struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder); struct cxl_ctx *cxl_decoder_get_ctx(struct cxl_decoder *decoder); +struct cxl_decoder *cxl_target_get_decoder(struct cxl_target *target); #define cxl_decoder_foreach(port, decoder) \ for (decoder = cxl_decoder_get_first(port); decoder != NULL; \ @@ -314,6 +315,7 @@ unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder); unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder); const char *cxl_decoder_get_devname(struct cxl_decoder *decoder); int cxl_decoder_get_id(struct cxl_decoder *decoder); +int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder); enum cxl_decoder_target_type { CXL_DECODER_TTYPE_UNKNOWN, @@ -352,6 +354,62 @@ Platform firmware may setup the CXL decode hierarchy before the OS boots, and may additionally require that the OS not change the decode settings. This property is indicated by the cxl_decoder_is_locked() API. +==== TARGETS +A root or switch level decoder takes an SPA (system-physical-address) as +input and routes it to a downstream port. Which downstream port depends +on the downstream port's position in the interleave. A 'struct +cxl_target' object represents the properties of a given downstream port +relative to its interleave configuration. + +===== TARGET: Enumeration +---- +struct cxl_target *cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder, + struct cxl_memdev *memdev); +struct cxl_target * +cxl_decoder_get_target_by_position(struct cxl_decoder *decoder, int position); +struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder); +struct cxl_target *cxl_target_get_next(struct cxl_target *target); + +#define cxl_target_foreach(decoder, target) \ + for (target = cxl_target_get_first(decoder); target != NULL; \ + target = cxl_target_get_next(target)) +---- +Target objects can only be enumerated if the decoder has been +configured, for switch decoders. For root decoders they are always +available since the root decoder target mapping is static. The +cxl_decoder_get_target_by_memdev() helper walks the topology to validate +if the given memory device is capable of receiving cycles from this +upstream decoder. It does not validate if the memory device is currently +configured to participate in that decode. + +===== TARGET: Attributes +---- +int cxl_target_get_position(struct cxl_target *target); +unsigned long cxl_target_get_id(struct cxl_target *target); +const char *cxl_target_get_devname(struct cxl_target *target); +bool cxl_target_maps_memdev(struct cxl_target *target, + struct cxl_memdev *memdev); +---- +The position of a decoder along with the interleave granularity dictate +which address in the decoder's resource range map to which port. + +The target id is an identifier that the CXL port uses to reference this +downstream port. For CXL / PCIe downstream switch ports the id is +defined by the PCIe Link Capability Port Number field. For root decoders +the id is specified by platform firmware specific mechanism. For +ACPI.CXL defined root ports the id comes from the CEDT.CHBS / ACPI0016 +_UID. + +The device name of a target is the name of the host device for the +downstream port. For CXL / PCIe downstream ports the devname is +downstream switch port PCI device. For CXL root ports the devname is a +platform firmware object for the host bridge like a ACPI0016 device +instance. + +The cxl_target_maps_memdev() helper is the companion of +cxl_decoder_get_target_by_memdev() to determine which downstream ports / +targets are capable of mapping which memdevs. + include::../../copyright.txt[] SEE ALSO diff --git a/cxl/filter.c b/cxl/filter.c index dc052f63d0c5..05ede9116559 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -421,6 +421,26 @@ static struct cxl_decoder *util_cxl_decoder_filter(struct cxl_decoder *decoder, return NULL; } +static struct cxl_decoder * +util_cxl_decoder_filter_by_memdev(struct cxl_decoder *decoder, + const char *ident, const char *serial) +{ + struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder); + struct cxl_memdev *memdev; + + if (!ident && !serial) + return decoder; + + cxl_memdev_foreach(ctx, memdev) { + if (!util_cxl_memdev_filter(memdev, ident, serial)) + continue; + if (cxl_decoder_get_target_by_memdev(decoder, memdev)) + return decoder; + } + + return NULL; +} + static unsigned long params_to_flags(struct cxl_filter_params *param) { unsigned long flags = 0; @@ -431,6 +451,8 @@ static unsigned long params_to_flags(struct cxl_filter_params *param) flags |= UTIL_JSON_HUMAN; if (param->health) flags |= UTIL_JSON_HEALTH; + if (param->targets) + flags |= UTIL_JSON_TARGETS; return flags; } @@ -521,6 +543,9 @@ static void walk_decoders(struct cxl_port *port, struct cxl_filter_params *p, if (!util_cxl_decoder_filter_by_port(decoder, p->port_filter, pf_mode(p))) continue; + if (!util_cxl_decoder_filter_by_memdev( + decoder, p->memdev_filter, p->serial_filter)) + continue; if (!p->idle && cxl_decoder_get_size(decoder) == 0) continue; jdecoder = util_cxl_decoder_to_json(decoder, flags); diff --git a/cxl/filter.h b/cxl/filter.h index 5d7bf45f3301..6fd469f02ea2 100644 --- a/cxl/filter.h +++ b/cxl/filter.h @@ -16,6 +16,7 @@ struct cxl_filter_params { bool single; bool endpoints; bool decoders; + bool targets; bool memdevs; bool ports; bool buses; diff --git a/cxl/json.c b/cxl/json.c index 548bc52f2d16..3a3790955370 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -268,6 +268,8 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder, const char *devname = cxl_decoder_get_devname(decoder); struct cxl_port *port = cxl_decoder_get_port(decoder); struct json_object *jdecoder, *jobj; + struct json_object *jtargets; + struct cxl_target *target; u64 val; jdecoder = json_object_new_object(); @@ -321,7 +323,51 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder, jobj); } + /* Endpoints don't have targets, they *are* targets */ + if (cxl_port_is_endpoint(port)) + return jdecoder; + + val = cxl_decoder_get_nr_targets(decoder); + jobj = json_object_new_int(val); + if (jobj) + json_object_object_add(jdecoder, "nr_targets", jobj); + + if (!(flags & UTIL_JSON_TARGETS) || + !cxl_decoder_get_nr_targets(decoder)) + return jdecoder; + + jtargets = json_object_new_array(); + if (!jtargets) + return jdecoder; + + cxl_target_foreach(decoder, target) { + struct json_object *jtarget = json_object_new_object(); + + if (!jtarget) + continue; + + devname = cxl_target_get_devname(target); + jobj = json_object_new_string(devname); + if (jobj) + json_object_object_add(jtarget, "target", jobj); + + val = cxl_target_get_position(target); + jobj = json_object_new_int(val); + if (jobj) + json_object_object_add(jtarget, "position", jobj); + + val = cxl_target_get_id(target); + jobj = util_json_object_hex(val, flags); + if (jobj) + json_object_object_add(jtarget, "id", jobj); + + json_object_array_add(jtargets, jtarget); + } + + json_object_object_add(jdecoder, "targets", jtargets); + return jdecoder; + } static struct json_object *__util_cxl_port_to_json(struct cxl_port *port, diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 5e3092364e4a..877f42c9145e 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -67,10 +67,22 @@ static void free_memdev(struct cxl_memdev *memdev, struct list_head *head) free(memdev); } +static void free_target(struct cxl_target *target, struct list_head *head) +{ + if (head) + list_del_from(head, &target->list); + free(target->dev_path); + free(target); +} + static void free_decoder(struct cxl_decoder *decoder, struct list_head *head) { + struct cxl_target *target, *_t; + if (head) list_del_from(head, &decoder->list); + list_for_each_safe(&decoder->targets, target, _t, list) + free_target(target, &decoder->targets); free(decoder->dev_buf); free(decoder->dev_path); free(decoder); @@ -856,6 +868,7 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base) struct cxl_port *port = parent; struct cxl_ctx *ctx = cxl_port_get_ctx(port); char buf[SYSFS_ATTR_SIZE]; + char *target_id, *save; size_t i; dbg(ctx, "%s: base: \'%s\'\n", devname, cxldecoder_base); @@ -870,6 +883,7 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base) decoder->id = id; decoder->ctx = ctx; decoder->port = port; + list_head_init(&decoder->targets); decoder->dev_path = strdup(cxldecoder_base); if (!decoder->dev_path) @@ -935,6 +949,36 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base) } } + sprintf(path, "%s/target_list", cxldecoder_base); + if (sysfs_read_attr(ctx, path, buf) < 0) + buf[0] = '\0'; + + for (i = 0, target_id = strtok_r(buf, ",", &save); target_id; + target_id = strtok_r(NULL, ",", &save), i++) { + int did = strtoul(target_id, NULL, 0); + struct cxl_target *target = calloc(1, sizeof(*target)); + + if (!target) + break; + + target->id = did; + target->position = i; + target->decoder = decoder; + sprintf(port->dev_buf, "%s/dport%d", port->dev_path, did); + target->dev_path = realpath(port->dev_buf, NULL); + if (!target->dev_path) { + free(target); + break; + } + dbg(ctx, "%s: target%ld %s\n", devname, i, target->dev_path); + list_add(&decoder->targets, &target->list); + } + + if (target_id) + err(ctx, "%s: failed to parse target%ld\n", + devpath_to_devname(cxldecoder_base), i); + decoder->nr_targets = i; + cxl_decoder_foreach(port, decoder_dup) if (decoder_dup->id == decoder->id) { free_decoder(decoder, NULL); @@ -1044,11 +1088,82 @@ CXL_EXPORT bool cxl_decoder_is_locked(struct cxl_decoder *decoder) return decoder->locked; } +CXL_EXPORT int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder) +{ + return decoder->nr_targets; +} + CXL_EXPORT const char *cxl_decoder_get_devname(struct cxl_decoder *decoder) { return devpath_to_devname(decoder->dev_path); } +CXL_EXPORT struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder) +{ + return list_top(&decoder->targets, struct cxl_target, list); +} + +CXL_EXPORT struct cxl_decoder *cxl_target_get_decoder(struct cxl_target *target) +{ + return target->decoder; +} + +CXL_EXPORT struct cxl_target *cxl_target_get_next(struct cxl_target *target) +{ + struct cxl_decoder *decoder = cxl_target_get_decoder(target); + + return list_next(&decoder->targets, target, list); +} + +CXL_EXPORT const char *cxl_target_get_devname(struct cxl_target *target) +{ + return devpath_to_devname(target->dev_path); +} + +CXL_EXPORT unsigned long cxl_target_get_id(struct cxl_target *target) +{ + return target->id; +} + +CXL_EXPORT int cxl_target_get_position(struct cxl_target *target) +{ + return target->position; +} + +CXL_EXPORT bool cxl_target_maps_memdev(struct cxl_target *target, + struct cxl_memdev *memdev) +{ + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + + dbg(ctx, "memdev: %s target: %s\n", memdev->host_path, + target->dev_path); + + return !!strstr(memdev->host_path, target->dev_path); +} + +CXL_EXPORT struct cxl_target * +cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder, + struct cxl_memdev *memdev) +{ + struct cxl_target *target; + + cxl_target_foreach(decoder, target) + if (cxl_target_maps_memdev(target, memdev)) + return target; + return NULL; +} + +CXL_EXPORT struct cxl_target * +cxl_decoder_get_target_by_position(struct cxl_decoder *decoder, int position) +{ + struct cxl_target *target; + + cxl_target_foreach(decoder, target) + if (target->position == position) + return target; + return NULL; +} + static void *add_cxl_port(void *parent, int id, const char *cxlport_base) { const char *devname = devpath_to_devname(cxlport_base); diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 22babb760f23..cb33180c2aa8 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -125,10 +125,20 @@ global: cxl_decoder_get_resource; cxl_decoder_get_size; cxl_decoder_get_devname; + cxl_decoder_get_target_by_memdev; + cxl_decoder_get_target_by_position; + cxl_decoder_get_nr_targets; cxl_decoder_get_target_type; cxl_decoder_is_pmem_capable; cxl_decoder_is_volatile_capable; cxl_decoder_is_mem_capable; cxl_decoder_is_accelmem_capable; cxl_decoder_is_locked; + cxl_target_get_first; + cxl_target_get_next; + cxl_target_get_decoder; + cxl_target_get_position; + cxl_target_get_id; + cxl_target_get_devname; + cxl_target_maps_memdev; } LIBCXL_1; diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 439ed9305397..abda0e51644c 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -104,6 +104,11 @@ struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder); unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder); unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder); const char *cxl_decoder_get_devname(struct cxl_decoder *decoder); +struct cxl_target *cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder, + struct cxl_memdev *memdev); +struct cxl_target * +cxl_decoder_get_target_by_position(struct cxl_decoder *decoder, int position); +int cxl_decoder_get_nr_targets(struct cxl_decoder *decoder); struct cxl_ctx *cxl_decoder_get_ctx(struct cxl_decoder *decoder); int cxl_decoder_get_id(struct cxl_decoder *decoder); struct cxl_port *cxl_decoder_get_port(struct cxl_decoder *decoder); @@ -126,6 +131,20 @@ bool cxl_decoder_is_locked(struct cxl_decoder *decoder); for (decoder = cxl_decoder_get_first(port); decoder != NULL; \ decoder = cxl_decoder_get_next(decoder)) +struct cxl_target; +struct cxl_target *cxl_target_get_first(struct cxl_decoder *decoder); +struct cxl_target *cxl_target_get_next(struct cxl_target *target); +struct cxl_decoder *cxl_target_get_decoder(struct cxl_target *target); +int cxl_target_get_position(struct cxl_target *target); +unsigned long cxl_target_get_id(struct cxl_target *target); +const char *cxl_target_get_devname(struct cxl_target *target); +bool cxl_target_maps_memdev(struct cxl_target *target, + struct cxl_memdev *memdev); + +#define cxl_target_foreach(decoder, target) \ + for (target = cxl_target_get_first(decoder); target != NULL; \ + target = cxl_target_get_next(target)) + struct cxl_endpoint; struct cxl_endpoint *cxl_endpoint_get_first(struct cxl_port *parent); struct cxl_endpoint *cxl_endpoint_get_next(struct cxl_endpoint *endpoint); diff --git a/cxl/list.c b/cxl/list.c index d70192a8cecf..27c963a93aaa 100644 --- a/cxl/list.c +++ b/cxl/list.c @@ -41,6 +41,8 @@ static const struct option options[] = { "filter by CXL decoder device name(s) / class"), OPT_BOOLEAN('D', "decoders", ¶m.decoders, "include CXL decoder info"), + OPT_BOOLEAN('T', "targets", ¶m.targets, + "include CXL target data with decoders"), OPT_BOOLEAN('i', "idle", ¶m.idle, "include disabled devices"), OPT_BOOLEAN('u', "human", ¶m.human, "use human friendly number formats "), From patchwork Mon Jan 24 00:54:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721369 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 2D064C433F5 for ; Mon, 24 Jan 2022 00:54:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240668AbiAXAyk (ORCPT ); Sun, 23 Jan 2022 19:54:40 -0500 Received: from mga02.intel.com ([134.134.136.20]:61693 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235269AbiAXAyk (ORCPT ); Sun, 23 Jan 2022 19:54:40 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985680; x=1674521680; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=B0NdwC93ssfg88OI+v7HvqVpIZAZ5L44ySP0ZKcYAP4=; b=HhqR0HLTfAB0b/Pcuhm6n5f4q0HRZLxoBIRWYJIF7vIWYUUX4o/YexZI K5lXhewRsBVdhmZkkdMwkRl2/wR55XE8B/JcpziBk8KiHSRP+LFynJE2d fc7c2+hCkwoGs64EsVFPwxfnQym5fEdwifgnBTqLPdUjZ9GQ4ccA84QAt sfejIpDJ7RExEQosLMZPiPimWoPWuRNtxcHmChzrlIohd02OmJxQJOtRV 9613FRgLf6TzNgPZtnHwGRzUVhVgEGKHZeC84QzTIayVoTj/9XnxQdl1w ss/XtYa9BjkOQD4rbwhBYqtzGsVORLmlFOyV6O2O6tOiOFr82Nem2723U g==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="233294034" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="233294034" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:40 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="580175296" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:39 -0800 Subject: [ndctl PATCH 32/37] cxl/list: Use 'physical_node' for root port attachment detection From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:54:39 -0800 Message-ID: <164298567943.3021641.12696733268157328279.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Platform firmware objects like ACPI0016 link from /sys/bus/acpi to /sys/bus/pci via a 'physical_node' attribute. Consider that link when attempting to link memdevs to root ports. Emit it in the the target listing as the 'alias' for the listed target device. Signed-off-by: Dan Williams --- Documentation/cxl/lib/libcxl.txt | 6 ++++++ cxl/json.c | 8 ++++++++ cxl/lib/libcxl.c | 16 +++++++++++++++- cxl/lib/libcxl.sym | 1 + cxl/lib/private.h | 1 + cxl/libcxl.h | 1 + 6 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index bd92fef962fa..a68a58b06c5d 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -389,6 +389,7 @@ unsigned long cxl_target_get_id(struct cxl_target *target); const char *cxl_target_get_devname(struct cxl_target *target); bool cxl_target_maps_memdev(struct cxl_target *target, struct cxl_memdev *memdev); +const char *cxl_target_get_physical_node(struct cxl_target *target); ---- The position of a decoder along with the interleave granularity dictate which address in the decoder's resource range map to which port. @@ -410,6 +411,11 @@ The cxl_target_maps_memdev() helper is the companion of cxl_decoder_get_target_by_memdev() to determine which downstream ports / targets are capable of mapping which memdevs. +Some platform firmware implementations define an alias / companion +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. + include::../../copyright.txt[] SEE ALSO diff --git a/cxl/json.c b/cxl/json.c index 3a3790955370..d81aed8f7729 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -342,6 +342,7 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder, cxl_target_foreach(decoder, target) { struct json_object *jtarget = json_object_new_object(); + const char *phys_node; if (!jtarget) continue; @@ -351,6 +352,13 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder, if (jobj) json_object_object_add(jtarget, "target", jobj); + phys_node = cxl_target_get_physical_node(target); + if (phys_node) { + jobj = json_object_new_string(phys_node); + if (jobj) + json_object_object_add(jtarget, "alias", jobj); + } + val = cxl_target_get_position(target); jobj = json_object_new_int(val); if (jobj) diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 877f42c9145e..7bf79492ca88 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -72,6 +72,7 @@ static void free_target(struct cxl_target *target, struct list_head *head) if (head) list_del_from(head, &target->list); free(target->dev_path); + free(target->phys_path); free(target); } @@ -970,7 +971,11 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base) free(target); break; } - dbg(ctx, "%s: target%ld %s\n", devname, i, target->dev_path); + sprintf(port->dev_buf, "%s/dport%d/physical_node", port->dev_path, did); + target->phys_path = realpath(port->dev_buf, NULL); + dbg(ctx, "%s: target%ld %s phys_path: %s\n", devname, i, + target->dev_path, + target->phys_path ? target->phys_path : "none"); list_add(&decoder->targets, &target->list); } @@ -1138,9 +1143,18 @@ CXL_EXPORT bool cxl_target_maps_memdev(struct cxl_target *target, dbg(ctx, "memdev: %s target: %s\n", memdev->host_path, target->dev_path); + if (target->phys_path) + return !!strstr(memdev->host_path, target->phys_path); return !!strstr(memdev->host_path, target->dev_path); } +CXL_EXPORT const char *cxl_target_get_physical_node(struct cxl_target *target) +{ + if (!target->phys_path) + return NULL; + return devpath_to_devname(target->phys_path); +} + CXL_EXPORT struct cxl_target * cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder, struct cxl_memdev *memdev) diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index cb33180c2aa8..ce01298d8b43 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -141,4 +141,5 @@ global: cxl_target_get_id; cxl_target_get_devname; cxl_target_maps_memdev; + cxl_target_get_physical_node; } LIBCXL_1; diff --git a/cxl/lib/private.h b/cxl/lib/private.h index 1743a244877a..7e7742d523f3 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -77,6 +77,7 @@ struct cxl_target { struct list_node list; struct cxl_decoder *decoder; char *dev_path; + char *phys_path; int id, position; }; diff --git a/cxl/libcxl.h b/cxl/libcxl.h index abda0e51644c..0e484cc79f28 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -140,6 +140,7 @@ unsigned long cxl_target_get_id(struct cxl_target *target); const char *cxl_target_get_devname(struct cxl_target *target); bool cxl_target_maps_memdev(struct cxl_target *target, struct cxl_memdev *memdev); +const char *cxl_target_get_physical_node(struct cxl_target *target); #define cxl_target_foreach(decoder, target) \ for (target = cxl_target_get_first(decoder); target != NULL; \ From patchwork Mon Jan 24 00:54:44 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721370 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 DE689C433F5 for ; Mon, 24 Jan 2022 00:54:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235269AbiAXAyp (ORCPT ); Sun, 23 Jan 2022 19:54:45 -0500 Received: from mga11.intel.com ([192.55.52.93]:50352 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235402AbiAXAyp (ORCPT ); Sun, 23 Jan 2022 19:54:45 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985685; x=1674521685; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Kzl+mNcmg6hRO7PNlyPucEvX/AvTuhDJjAXMnkTJZXo=; b=RM8tx1ozh9/0MJ1Qouix7aILupYKO444zjR5eG0WS9bipyTMko58J1UZ SpfBYJL3/QOQ5ETpj6MPvgZkzdT2zbbVjnRdcWraEvYciyZWxrJ5suDBk XWhgg5hjV7I19OZwDS3AobErWYGPXc4Fiugi7nopWJqVmgaaNcJlbTDXi rgS5NvV/pG/A7aZnN6OoV/lgiJqpdUSsHOLX9dMiraIrCWAyU2zh6/00n A0vLoRf03XcRIxz+UjeL/70NZD0h1Dn+hZ6ufd+0zPr7N9/aljIdrSrym xY0ET7QyBpWcfXRezIZymtM1GzHY576h0TExeepXpHVfQ5XUXZ9rM3pf/ w==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="243530672" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="243530672" Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:45 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="531922020" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:45 -0800 Subject: [ndctl PATCH 33/37] cxl/list: Reuse the --target option for ports From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:54:44 -0800 Message-ID: <164298568481.3021641.4632086646702812643.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org It is useful to be able to dump the dport-id to host-device-name. Rather than introduce a new option, just interpret --target as "list dports" for port objects. $ cxl list -BTu -b ACPI.CXL { "bus":"root0", "provider":"ACPI.CXL", "nr_dports":1, "dports":[ { "dport":"ACPI0016:00", "alias":"pci0000:34", "id":"0" } ] } Signed-off-by: Dan Williams --- .clang-format | 1 Documentation/cxl/cxl-list.txt | 18 ++++++ Documentation/cxl/lib/libcxl.txt | 27 +++++++++ cxl/json.c | 56 +++++++++++++++++++- cxl/lib/libcxl.c | 109 ++++++++++++++++++++++++++++++++++++++ cxl/lib/libcxl.sym | 7 ++ cxl/lib/private.h | 13 +++++ cxl/libcxl.h | 12 ++++ cxl/list.c | 2 - 9 files changed, 240 insertions(+), 5 deletions(-) diff --git a/.clang-format b/.clang-format index 47fb657ff09a..c75348764105 100644 --- a/.clang-format +++ b/.clang-format @@ -82,6 +82,7 @@ ForEachMacros: - 'cxl_port_foreach' - 'cxl_decoder_foreach' - 'cxl_target_foreach' + - 'cxl_dport_foreach' - 'cxl_endpoint_foreach' - 'daxctl_dev_foreach' - 'daxctl_mapping_foreach' diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index 20ff2cb54fcb..e1299d9fbd84 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -272,7 +272,23 @@ OPTIONS -T:: --targets:: - Extend decoder listings with downstream port target information. + Extend decoder listings with downstream port target information, and / + or port and bus listings with the downstream port information. +---- +# cxl list -BTu -b ACPI.CXL +{ + "bus":"root0", + "provider":"ACPI.CXL", + "nr_dports":1, + "dports":[ + { + "dport":"ACPI0016:00", + "alias":"pci0000:34", + "id":"0" + } + ] +} +---- --debug:: If the cxl tool was built with debug enabled, turn on debug diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index a68a58b06c5d..2e8570d18a86 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -245,6 +245,7 @@ bool cxl_port_is_root(struct cxl_port *port); bool cxl_port_is_switch(struct cxl_port *port); bool cxl_port_is_endpoint(struct cxl_port *port); bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev); +int cxl_port_get_nr_dports(struct cxl_port *port); ---- The port type is communicated via cxl_port_is_(). An 'enabled' port is one that has succeeded in discovering the CXL component registers in @@ -256,6 +257,32 @@ of intervening switch ports, and a terminal endpoint port. cxl_port_hosts_memdev() returns true if the port's host appears in the memdev host's device topology ancestry. +==== DPORTS +A CXL dport object represents a CXL / PCIe Switch Downstream Port, or a +CXL / PCIe host bridge. + +===== DPORT: Enumeration +---- +struct cxl_dport *cxl_dport_get_first(struct cxl_port *port); +struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport); + +#define cxl_dport_foreach(port, dport) \ + for (dport = cxl_dport_get_first(port); dport != NULL; \ + dport = cxl_dport_get_next(dport)) + +---- + +===== DPORT: Attributes +---- +const char *cxl_dport_get_devname(struct cxl_dport *dport); +const char *cxl_dport_get_physical_node(struct cxl_dport *dport); +int cxl_dport_get_id(struct cxl_dport *dport); +---- +The id of a dport is the hardware idenfifier used by an upstream port to +reference a downstream port. The physical node of a dport is only +available for platform firmware defined downstream ports and alias the +companion object, like a PCI host bridge, in the PCI device hierarchy. + ENDPOINTS --------- CXL endpoint objects encapsulate the set of host-managed device-memory diff --git a/cxl/json.c b/cxl/json.c index d81aed8f7729..4fb5eec11077 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -241,6 +241,58 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev, return jdev; } +static struct json_object *util_cxl_dports_to_json(struct json_object *jport, + struct cxl_port *port, + unsigned long flags) +{ + struct json_object *jobj, *jdports; + struct cxl_dport *dport; + int val; + + val = cxl_port_get_nr_dports(port); + if (!val || !(flags & UTIL_JSON_TARGETS)) + return jport; + + jobj = json_object_new_int(val); + if (jobj) + json_object_object_add(jport, "nr_dports", jobj); + + jdports = json_object_new_array(); + if (!jdports) + return jport; + + cxl_dport_foreach(port, dport) { + struct json_object *jdport; + const char *phys_node; + + jdport = json_object_new_object(); + if (!jdport) + continue; + + jobj = json_object_new_string(cxl_dport_get_devname(dport)); + if (jobj) + json_object_object_add(jdport, "dport", jobj); + + phys_node = cxl_dport_get_physical_node(dport); + if (phys_node) { + jobj = json_object_new_string(phys_node); + if (jobj) + json_object_object_add(jdport, "alias", jobj); + } + + val = cxl_dport_get_id(dport); + jobj = util_json_object_hex(val, flags); + if (jobj) + json_object_object_add(jdport, "id", jobj); + + json_object_array_add(jdports, jdport); + } + + json_object_object_add(jport, "dports", jdports); + + return jport; +} + struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus, unsigned long flags) { @@ -259,7 +311,7 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus, if (jobj) json_object_object_add(jbus, "provider", jobj); - return jbus; + return util_cxl_dports_to_json(jbus, cxl_bus_get_port(bus), flags); } struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder, @@ -403,7 +455,7 @@ static struct json_object *__util_cxl_port_to_json(struct cxl_port *port, json_object_object_add(jport, "state", jobj); } - return jport; + return util_cxl_dports_to_json(jport, port, flags); } struct json_object *util_cxl_port_to_json(struct cxl_port *port, diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 7bf79492ca88..d7a3f1084465 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -89,13 +89,24 @@ static void free_decoder(struct cxl_decoder *decoder, struct list_head *head) free(decoder); } +static void free_dport(struct cxl_dport *dport, struct list_head *head) +{ + if (head) + list_del_from(head, &dport->list); + free(dport->dev_buf); + free(dport->dev_path); + free(dport->phys_path); + free(dport); +} + static void free_port(struct cxl_port *port, struct list_head *head); static void free_endpoint(struct cxl_endpoint *endpoint, struct list_head *head); static void __free_port(struct cxl_port *port, struct list_head *head) { - struct cxl_port *child, *_c; struct cxl_endpoint *endpoint, *_e; struct cxl_decoder *decoder, *_d; + struct cxl_dport *dport, *_dp; + struct cxl_port *child, *_c; if (head) list_del_from(head, &port->list); @@ -105,6 +116,8 @@ static void __free_port(struct cxl_port *port, struct list_head *head) free_endpoint(endpoint, &port->endpoints); list_for_each_safe(&port->decoders, decoder, _d, list) free_decoder(decoder, &port->decoders); + list_for_each_safe(&port->dports, dport, _dp, list) + free_dport(dport , &port->dports); kmod_module_unref(port->module); free(port->dev_buf); free(port->dev_path); @@ -701,6 +714,7 @@ static int cxl_port_init(struct cxl_port *port, struct cxl_port *parent_port, list_head_init(&port->child_ports); list_head_init(&port->endpoints); list_head_init(&port->decoders); + list_head_init(&port->dports); port->dev_path = strdup(cxlport_base); if (!port->dev_path) @@ -1332,6 +1346,99 @@ CXL_EXPORT struct cxl_bus *cxl_port_to_bus(struct cxl_port *port) return container_of(port, struct cxl_bus, port); } +static void *add_cxl_dport(void *parent, int id, const char *cxldport_base) +{ + const char *devname = devpath_to_devname(cxldport_base); + struct cxl_dport *dport, *dport_dup; + struct cxl_port *port = parent; + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + + dbg(ctx, "%s: base: \'%s\'\n", devname, cxldport_base); + + dport = calloc(1, sizeof(*dport)); + if (!dport) + return NULL; + + dport->id = id; + dport->port = port; + + dport->dev_path = realpath(cxldport_base, NULL); + if (!dport->dev_path) + goto err; + + dport->dev_buf = calloc(1, strlen(cxldport_base) + 50); + if (!dport->dev_buf) + goto err; + dport->buf_len = strlen(cxldport_base) + 50; + + sprintf(dport->dev_buf, "%s/physical_node", cxldport_base); + dport->phys_path = realpath(dport->dev_buf, NULL); + + cxl_dport_foreach(port, dport_dup) + if (dport_dup->id == dport->id) { + free_dport(dport, NULL); + return dport_dup; + } + + port->nr_dports++; + list_add(&port->dports, &dport->list); + return dport; + +err: + free_dport(dport, NULL); + return NULL; +} + +static void cxl_dports_init(struct cxl_port *port) +{ + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + + if (port->dports_init) + return; + + port->dports_init = 1; + + sysfs_device_parse(ctx, port->dev_path, "dport", port, add_cxl_dport); +} + +CXL_EXPORT int cxl_port_get_nr_dports(struct cxl_port *port) +{ + if (!port->dports_init) + cxl_dports_init(port); + return port->nr_dports; +} + +CXL_EXPORT struct cxl_dport *cxl_dport_get_first(struct cxl_port *port) +{ + cxl_dports_init(port); + + return list_top(&port->dports, struct cxl_dport, list); +} + +CXL_EXPORT struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport) +{ + struct cxl_port *port = dport->port; + + return list_next(&port->dports, dport, list); +} + +CXL_EXPORT const char *cxl_dport_get_devname(struct cxl_dport *dport) +{ + return devpath_to_devname(dport->dev_path); +} + +CXL_EXPORT const char *cxl_dport_get_physical_node(struct cxl_dport *dport) +{ + if (!dport->phys_path) + return NULL; + return devpath_to_devname(dport->phys_path); +} + +CXL_EXPORT int cxl_dport_get_id(struct cxl_dport *dport) +{ + return dport->id; +} + static void *add_cxl_bus(void *parent, int id, const char *cxlbus_base) { const char *devname = devpath_to_devname(cxlbus_base); diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index ce01298d8b43..0190b132d3d6 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -101,6 +101,8 @@ global: cxl_port_get_host; cxl_port_get_bus; cxl_port_hosts_memdev; + cxl_port_get_nr_dports; + cxl_port_get_next_all; cxl_endpoint_get_first; cxl_endpoint_get_next; cxl_endpoint_get_devname; @@ -142,4 +144,9 @@ global: cxl_target_get_devname; cxl_target_maps_memdev; cxl_target_get_physical_node; + cxl_dport_get_first; + cxl_dport_get_next; + cxl_dport_get_devname; + cxl_dport_get_physical_node; + cxl_dport_get_id; } LIBCXL_1; diff --git a/cxl/lib/private.h b/cxl/lib/private.h index 7e7742d523f3..f483c308a8b5 100644 --- a/cxl/lib/private.h +++ b/cxl/lib/private.h @@ -38,6 +38,16 @@ struct cxl_memdev { struct cxl_endpoint *endpoint; }; +struct cxl_dport { + int id; + void *dev_buf; + size_t buf_len; + char *dev_path; + char *phys_path; + struct cxl_port *port; + struct list_node list; +}; + enum cxl_port_type { CXL_PORT_ROOT, CXL_PORT_SWITCH, @@ -53,6 +63,8 @@ struct cxl_port { int ports_init; int endpoints_init; int decoders_init; + int dports_init; + int nr_dports; struct cxl_ctx *ctx; struct cxl_bus *bus; enum cxl_port_type type; @@ -62,6 +74,7 @@ struct cxl_port { struct list_head child_ports; struct list_head endpoints; struct list_head decoders; + struct list_head dports; }; struct cxl_bus { diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 0e484cc79f28..07f4a311d29d 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -93,11 +93,23 @@ bool cxl_port_is_endpoint(struct cxl_port *port); struct cxl_bus *cxl_port_get_bus(struct cxl_port *port); const char *cxl_port_get_host(struct cxl_port *port); bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev); +int cxl_port_get_nr_dports(struct cxl_port *port); #define cxl_port_foreach(parent, port) \ for (port = cxl_port_get_first(parent); port != NULL; \ port = cxl_port_get_next(port)) +struct cxl_dport; +struct cxl_dport *cxl_dport_get_first(struct cxl_port *port); +struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport); +const char *cxl_dport_get_devname(struct cxl_dport *dport); +const char *cxl_dport_get_physical_node(struct cxl_dport *dport); +int cxl_dport_get_id(struct cxl_dport *dport); + +#define cxl_dport_foreach(port, dport) \ + for (dport = cxl_dport_get_first(port); dport != NULL; \ + dport = cxl_dport_get_next(dport)) + struct cxl_decoder; struct cxl_decoder *cxl_decoder_get_first(struct cxl_port *port); struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder); diff --git a/cxl/list.c b/cxl/list.c index 27c963a93aaa..de96ff91fb5d 100644 --- a/cxl/list.c +++ b/cxl/list.c @@ -42,7 +42,7 @@ 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"), + "include CXL target data with decoders or ports"), OPT_BOOLEAN('i', "idle", ¶m.idle, "include disabled devices"), OPT_BOOLEAN('u', "human", ¶m.human, "use human friendly number formats "), From patchwork Mon Jan 24 00:54:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721371 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 308D8C433F5 for ; Mon, 24 Jan 2022 00:54:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240675AbiAXAyv (ORCPT ); Sun, 23 Jan 2022 19:54:51 -0500 Received: from mga06.intel.com ([134.134.136.31]:17188 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235402AbiAXAyv (ORCPT ); Sun, 23 Jan 2022 19:54:51 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985691; x=1674521691; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Mom4QJ/T0FQt2B0JiML3zf5EjbhEX5NfzRqjfX09kS0=; b=fGlZkR9/N/K+SzuJ3pnlPVv//biyOMaT38lEj5Ku4H0yUvLg5D8MQ+jf sresHGOnJACoT48A1aNBe9WFuB65V/aCcfxSTJH5OYFIhneMWTea0mCJb w13aNZnU+6yp7MyD640QYQYxSMP4CykmwirnSdYwnQA51nHITJi2tNjZy UQTNODBp7GEFgjikRKIsTquDFv/9LqJPGz1kj1GZZCbVmU9SxWX5U5i+v Lvv8gsRsaTcuChuC0d8QU1Oc9KziXncvGF+/V7HXwmJa+5KEAToCRDYQ3 LJCDvgXmJXxebhU8tK3QLtKRhrgomRojmtVTgbtvQQCCSSF9jXOdXCy/m A==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="306652216" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="306652216" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:50 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="617065202" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:50 -0800 Subject: [ndctl PATCH 34/37] cxl/list: Support filtering memdevs by decoders From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:54:50 -0800 Message-ID: <164298569017.3021641.15558596583530530035.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org In order to filter memdevs by decoders all the ports in the hierarchy need to be iterated, so introduce cxl_port_foreach_all() that starts at the bus and does a depth first iteration of all the descendant ports. Signed-off-by: Dan Williams --- .clang-format | 1 + Documentation/cxl/cxl-list.txt | 13 ++++++++++ Documentation/cxl/lib/libcxl.txt | 11 +++++++++ cxl/filter.c | 48 ++++++++++++++++++++++++++++++++++++++ cxl/lib/libcxl.c | 13 ++++++++++ cxl/libcxl.h | 6 +++++ 6 files changed, 92 insertions(+) diff --git a/.clang-format b/.clang-format index c75348764105..6aabcb68e6a9 100644 --- a/.clang-format +++ b/.clang-format @@ -84,6 +84,7 @@ ForEachMacros: - 'cxl_target_foreach' - 'cxl_dport_foreach' - 'cxl_endpoint_foreach' + - 'cxl_port_foreach_all' - 'daxctl_dev_foreach' - 'daxctl_mapping_foreach' - 'daxctl_region_foreach' diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index e1299d9fbd84..04e831ed3f34 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -61,6 +61,19 @@ one or more memdevs. For example: } ] ---- +Additionally, when provisioning new interleave configurations it is +useful to know which memdevs can be referenced by a given decoder like a +root decoder: +---- +# cxl list -Mu -d decoder0.0 +{ + "memdev":"mem0", + "pmem_size":"256.00 MiB (268.44 MB)", + "ram_size":0, + "serial":"0", + "host":"0000:35:00.0" +} +---- The --human option in addition to reformatting some fields to more human friendly strings also unwraps the array to reduce the number of lines of diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index 2e8570d18a86..5ad3027acd24 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -219,10 +219,18 @@ struct cxl_port *cxl_port_get_parent(struct cxl_port *port); struct cxl_ctx *cxl_port_get_ctx(struct cxl_port *port); const char *cxl_port_get_host(struct cxl_port *port); struct cxl_port *cxl_decoder_get_port(struct cxl_decoder *decoder); +struct cxl_port *cxl_port_get_next_all(struct cxl_port *port, + const struct cxl_port *top); #define cxl_port_foreach(parent, port) \ for (port = cxl_port_get_first(parent); port != NULL; \ port = cxl_port_get_next(port)) + +#define cxl_port_foreach_all(top, port) \ + for (port = cxl_port_get_first(top); port != NULL; \ + port = cxl_port_get_next_all(port, top)) + + ---- A bus object encapsulates a CXL port object. Use cxl_bus_get_port() to use generic port APIs on root objects. @@ -236,6 +244,9 @@ that hierarchy via cxl_port_get_bus(). The host of a port is the corresponding device name of the PCIe Root Port, or Switch Upstream Port with CXL capabilities. +The cxl_port_foreach_all() helper does a depth first iteration of all +ports beneath the 'top' port argument. + === PORT: Attributes ---- const char *cxl_port_get_devname(struct cxl_port *port); diff --git a/cxl/filter.c b/cxl/filter.c index 05ede9116559..c972545eb0de 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -441,6 +441,51 @@ util_cxl_decoder_filter_by_memdev(struct cxl_decoder *decoder, return NULL; } +static bool __memdev_filter_by_decoder(struct cxl_memdev *memdev, + struct cxl_port *port, const char *ident) +{ + struct cxl_decoder *decoder; + struct cxl_endpoint *endpoint; + + cxl_decoder_foreach(port, decoder) { + if (!util_cxl_decoder_filter(decoder, ident)) + continue; + if (cxl_decoder_get_target_by_memdev(decoder, memdev)) + return true; + } + + cxl_endpoint_foreach(port, endpoint) + if (__memdev_filter_by_decoder( + memdev, cxl_endpoint_get_port(endpoint), ident)) + return true; + return false; +} + +static struct cxl_memdev * +util_cxl_memdev_filter_by_decoder(struct cxl_memdev *memdev, const char *ident) +{ + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + struct cxl_bus *bus; + + if (!ident) + return memdev; + + cxl_bus_foreach(ctx, bus) { + struct cxl_port *port, *top; + + port = cxl_bus_get_port(bus); + if (__memdev_filter_by_decoder(memdev, port, ident)) + return memdev; + + top = port; + cxl_port_foreach_all(top, port) + if (__memdev_filter_by_decoder(memdev, port, ident)) + return memdev; + } + + return NULL; +} + static unsigned long params_to_flags(struct cxl_filter_params *param) { unsigned long flags = 0; @@ -599,6 +644,9 @@ static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p, if (!util_cxl_memdev_filter(memdev, p->memdev_filter, p->serial_filter)) continue; + if (!util_cxl_memdev_filter_by_decoder( + memdev, p->decoder_filter)) + continue; if (!p->idle && !cxl_memdev_is_enabled(memdev)) continue; jobj = util_cxl_memdev_to_json(memdev, flags); diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index d7a3f1084465..4ebb8b9a5e7f 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -1257,6 +1257,19 @@ CXL_EXPORT struct cxl_port *cxl_port_get_next(struct cxl_port *port) return list_next(&parent_port->child_ports, port, list); } +CXL_EXPORT struct cxl_port *cxl_port_get_next_all(struct cxl_port *port, + const struct cxl_port *top) +{ + struct cxl_port *child, *iter = port; + + child = cxl_port_get_first(iter); + if (child) + return child; + while (!cxl_port_get_next(iter) && iter->parent && iter->parent != top) + iter = iter->parent; + return cxl_port_get_next(iter); +} + CXL_EXPORT const char *cxl_port_get_devname(struct cxl_port *port) { return devpath_to_devname(port->dev_path); diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 07f4a311d29d..874c38188a2c 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -94,11 +94,17 @@ struct cxl_bus *cxl_port_get_bus(struct cxl_port *port); const char *cxl_port_get_host(struct cxl_port *port); bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev); int cxl_port_get_nr_dports(struct cxl_port *port); +struct cxl_port *cxl_port_get_next_all(struct cxl_port *port, + const struct cxl_port *top); #define cxl_port_foreach(parent, port) \ for (port = cxl_port_get_first(parent); port != NULL; \ port = cxl_port_get_next(port)) +#define cxl_port_foreach_all(top, port) \ + for (port = cxl_port_get_first(top); port != NULL; \ + port = cxl_port_get_next_all(port, top)) + struct cxl_dport; struct cxl_dport *cxl_dport_get_first(struct cxl_port *port); struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport); From patchwork Mon Jan 24 00:54:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721372 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 92F5EC433F5 for ; Mon, 24 Jan 2022 00:54:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240676AbiAXAy5 (ORCPT ); Sun, 23 Jan 2022 19:54:57 -0500 Received: from mga17.intel.com ([192.55.52.151]:25351 "EHLO mga17.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231628AbiAXAy4 (ORCPT ); Sun, 23 Jan 2022 19:54:56 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985696; x=1674521696; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=FJcfpXnGz+jKXO1P3sWn4Vu3HfzGvee4hTeCss78DO8=; b=aE8WByyEJbhgU8KQfjxJ7IC1FwDUS7MKvcW6+UT4873qCaqvydVUssZN wclyNX4VGRjxlXcO/Wp/t1hq5abIJ+h9c2QFCI2kuYEKCN3AdDO43pfqK 0SHF61cUevl3jGUBvFZ9B7A0vwHTCfTdPA/pzo0pzFQDPgGWoA0YZ9KW7 NkPDlq9/K0PjKV7z6EAjowCYiM6R/dPsBuZRHt+IvK9j0Y5CqcQPXoz08 Xul7sexVWPmMJ5sOFSJXQ7Hb7JbKfpBF29CxIb8PfWu17c62FalxRIv93 Y38z0JIauMa0aWzYD9xKGd/LCVqxaq1snf1ucPvUuezDqs+WVANfu6nGW g==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="226609738" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="226609738" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:56 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="596630878" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:54:56 -0800 Subject: [ndctl PATCH 35/37] cxl/list: Support filtering memdevs by ports From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:54:55 -0800 Message-ID: <164298569568.3021641.888802471376117408.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org The ability to filter memdevs by decoders falls short when the decoder does not have its target list programmed. So, introduce a by port filter to show the potential memdevs that can be targeted by the decoder. Signed-off-by: Dan Williams --- Documentation/cxl/cxl-list.txt | 3 ++ Documentation/cxl/lib/libcxl.txt | 7 +++++ cxl/filter.c | 50 ++++++++++++++++++++++++++++++++++++++ cxl/lib/libcxl.c | 23 +++++++++++++++++ cxl/lib/libcxl.sym | 2 ++ cxl/libcxl.h | 3 ++ 6 files changed, 86 insertions(+), 2 deletions(-) diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt index 04e831ed3f34..90e6d9f9658b 100644 --- a/Documentation/cxl/cxl-list.txt +++ b/Documentation/cxl/cxl-list.txt @@ -63,7 +63,8 @@ one or more memdevs. For example: ---- Additionally, when provisioning new interleave configurations it is useful to know which memdevs can be referenced by a given decoder like a -root decoder: +root decoder, or mapped by a given port if the decoders are not +configured. ---- # cxl list -Mu -d decoder0.0 { diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index 5ad3027acd24..a0fcee987b03 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -276,11 +276,12 @@ CXL / PCIe host bridge. ---- struct cxl_dport *cxl_dport_get_first(struct cxl_port *port); struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport); +struct cxl_dport *cxl_port_get_dport_by_memdev(struct cxl_port *port, + struct cxl_memdev *memdev); #define cxl_dport_foreach(port, dport) \ for (dport = cxl_dport_get_first(port); dport != NULL; \ dport = cxl_dport_get_next(dport)) - ---- ===== DPORT: Attributes @@ -288,12 +289,16 @@ struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport); const char *cxl_dport_get_devname(struct cxl_dport *dport); const char *cxl_dport_get_physical_node(struct cxl_dport *dport); int cxl_dport_get_id(struct cxl_dport *dport); +bool cxl_dport_maps_memdev(struct cxl_dport *dport, struct cxl_memdev *memdev); ---- The id of a dport is the hardware idenfifier used by an upstream port to reference a downstream port. The physical node of a dport is only available for platform firmware defined downstream ports and alias the companion object, like a PCI host bridge, in the PCI device hierarchy. +The cxl_dport_maps_memdev() helper checks if a dport is an ancestor of a +given memdev. + ENDPOINTS --------- CXL endpoint objects encapsulate the set of host-managed device-memory diff --git a/cxl/filter.c b/cxl/filter.c index c972545eb0de..c691edf9501e 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -486,6 +486,53 @@ util_cxl_memdev_filter_by_decoder(struct cxl_memdev *memdev, const char *ident) return NULL; } +static bool __memdev_filter_by_port(struct cxl_memdev *memdev, + struct cxl_port *port, + const char *port_ident) +{ + struct cxl_endpoint *endpoint; + + if (util_cxl_port_filter(port, port_ident, CXL_PF_SINGLE) && + cxl_port_get_dport_by_memdev(port, memdev)) + return true; + + cxl_endpoint_foreach(port, endpoint) + if (__memdev_filter_by_port(memdev, + cxl_endpoint_get_port(endpoint), + port_ident)) + return true; + return false; +} + +static struct cxl_memdev * +util_cxl_memdev_filter_by_port(struct cxl_memdev *memdev, const char *bus_ident, + const char *port_ident) +{ + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + struct cxl_bus *bus; + + if (!bus_ident && !port_ident) + return memdev; + + cxl_bus_foreach(ctx, bus) { + struct cxl_port *port, *top; + + port = cxl_bus_get_port(bus); + if (util_cxl_bus_filter(bus, bus_ident)) + if (__memdev_filter_by_port(memdev, port, + cxl_bus_get_devname(bus))) + return memdev; + if (__memdev_filter_by_port(memdev, port, port_ident)) + return memdev; + top = port; + cxl_port_foreach_all(top, port) + if (__memdev_filter_by_port(memdev, port, port_ident)) + return memdev; + } + + return NULL; +} + static unsigned long params_to_flags(struct cxl_filter_params *param) { unsigned long flags = 0; @@ -647,6 +694,9 @@ static void walk_endpoints(struct cxl_port *port, struct cxl_filter_params *p, if (!util_cxl_memdev_filter_by_decoder( memdev, p->decoder_filter)) continue; + if (!util_cxl_memdev_filter_by_port( + memdev, p->bus_filter, p->port_filter)) + continue; if (!p->idle && !cxl_memdev_is_enabled(memdev)) continue; jobj = util_cxl_memdev_to_json(memdev, flags); diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 4ebb8b9a5e7f..dcfc82689ca9 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -1452,6 +1452,29 @@ CXL_EXPORT int cxl_dport_get_id(struct cxl_dport *dport) return dport->id; } +CXL_EXPORT bool cxl_dport_maps_memdev(struct cxl_dport *dport, + struct cxl_memdev *memdev) +{ + struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); + + dbg(ctx, "memdev: %s dport: %s\n", memdev->host_path, dport->dev_path); + + if (dport->phys_path) + return !!strstr(memdev->host_path, dport->phys_path); + return !!strstr(memdev->host_path, dport->dev_path); +} + +CXL_EXPORT struct cxl_dport * +cxl_port_get_dport_by_memdev(struct cxl_port *port, struct cxl_memdev *memdev) +{ + struct cxl_dport *dport; + + cxl_dport_foreach(port, dport) + if (cxl_dport_maps_memdev(dport, memdev)) + return dport; + return NULL; +} + static void *add_cxl_bus(void *parent, int id, const char *cxlbus_base) { const char *devname = devpath_to_devname(cxlbus_base); diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 0190b132d3d6..2c8358e1683e 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -149,4 +149,6 @@ global: cxl_dport_get_devname; cxl_dport_get_physical_node; cxl_dport_get_id; + cxl_port_get_dport_by_memdev; + cxl_dport_maps_memdev; } LIBCXL_1; diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 874c38188a2c..c8d07bb4efc4 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -111,6 +111,9 @@ struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport); const char *cxl_dport_get_devname(struct cxl_dport *dport); const char *cxl_dport_get_physical_node(struct cxl_dport *dport); int cxl_dport_get_id(struct cxl_dport *dport); +bool cxl_dport_maps_memdev(struct cxl_dport *dport, struct cxl_memdev *memdev); +struct cxl_dport *cxl_port_get_dport_by_memdev(struct cxl_port *port, + struct cxl_memdev *memdev); #define cxl_dport_foreach(port, dport) \ for (dport = cxl_dport_get_first(port); dport != NULL; \ From patchwork Mon Jan 24 00:55:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721373 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 E567DC433EF for ; Mon, 24 Jan 2022 00:55:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235402AbiAXAzC (ORCPT ); Sun, 23 Jan 2022 19:55:02 -0500 Received: from mga11.intel.com ([192.55.52.93]:50379 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231628AbiAXAzB (ORCPT ); Sun, 23 Jan 2022 19:55:01 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985701; x=1674521701; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=h/AlBThBayLThdfqjmRrP/hV0X5eoBkDPBmdYaAPrPs=; b=aOQXdMgX32smsTBTdtOXVfM8/nfY3YlIuUP9OruEp3TE0T79jYshkUod +oU+me7f4+omux4L6sybexh5uQuESRvlXsJelC19MmDccr/f5/ENWUqsz 7eCfHIx+6I/OcSmdXhkhmFV01B7zVm//rmzbUc/wpnUOL5Pz51SuStrXI tQOFFcUj9ifFTnSwI/YYXJPEk4goMYf7vAUZRe5n8KjT8M+GNPsSxexMP 7rwiqrrXrCMgN2sq9EpeHgfIwhH6j7ogmpv2psSdWqR18VTlQWNHCR9ZE zVgIyeIBiiInVfQh+2ee0WmrTgpBtTWF0/dp0CpsgakxM9sfjhvzImIb2 g==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="243530689" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="243530689" Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:55:01 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="476540839" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:55:01 -0800 Subject: [ndctl PATCH 36/37] cxl/port: Add {disable,enable}-port command From: Dan Williams To: linux-cxl@vger.kernel.org Cc: vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:55:01 -0800 Message-ID: <164298570117.3021641.14546710754812021284.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org The {disable,enable}-port commands are used for debugging port enumeration corner cases and testing the kernel CXL device hotplug implementation. In addition to unbinding the port from its driver, which also kicks of unregistration of descendent ports, the disable operation also flushes the kernels delayed workqueue for memory device removal. Signed-off-by: Dan Williams --- Documentation/cxl/cxl-disable-port.txt | 46 ++++++ Documentation/cxl/cxl-enable-port.txt | 43 +++++ Documentation/cxl/lib/libcxl.txt | 11 + Documentation/cxl/meson.build | 2 cxl/builtin.h | 2 cxl/cxl.c | 2 cxl/filter.c | 21 +-- cxl/filter.h | 13 ++ cxl/lib/libcxl.c | 95 +++++++++++- cxl/lib/libcxl.sym | 3 cxl/libcxl.h | 3 cxl/meson.build | 1 cxl/port.c | 253 ++++++++++++++++++++++++++++++++ 13 files changed, 471 insertions(+), 24 deletions(-) create mode 100644 Documentation/cxl/cxl-disable-port.txt create mode 100644 Documentation/cxl/cxl-enable-port.txt create mode 100644 cxl/port.c diff --git a/Documentation/cxl/cxl-disable-port.txt b/Documentation/cxl/cxl-disable-port.txt new file mode 100644 index 000000000000..de13c07d149b --- /dev/null +++ b/Documentation/cxl/cxl-disable-port.txt @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 + +cxl-disable-port(1) +=================== + +NAME +---- +cxl-disable-port - activate / hot-add a given CXL port + +SYNOPSIS +-------- +[verse] +'cxl disable-port' [..] [] + +For test and debug scenarios, disable a CXL port and any memory devices +dependent on this port being active for CXL.mem operation. + +OPTIONS +------- +-e:: +--endpoint:: + Toggle from treating the port arguments as Switch Port identifiers to + Endpoint Port identifiers. + + +-f:: +--force:: + DANGEROUS: Override the safety measure that blocks attempts to disable a + port if the tool determines a descendent memdev is in active usage. + Recall that CXL memory ranges might have been established by platform + firmware and disabling an active device is akin to force removing memory + from a running system. + + Toggle from treating the port arguments as Switch Port identifiers to + Endpoint Port identifiers. + +--debug:: + If the cxl tool was built with debug disabled, turn on debug + messages. + + +include::../copyright.txt[] + +SEE ALSO +-------- +linkcxl:cxl-disable-port[1] diff --git a/Documentation/cxl/cxl-enable-port.txt b/Documentation/cxl/cxl-enable-port.txt new file mode 100644 index 000000000000..9a37cef0c4d4 --- /dev/null +++ b/Documentation/cxl/cxl-enable-port.txt @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 + +cxl-enable-port(1) +================== + +NAME +---- +cxl-enable-port - activate / hot-add a given CXL port + +SYNOPSIS +-------- +[verse] +'cxl enable-port' [..] [] + +A port typically autoenables at initial device discovery. However, if it +was manually disabled this command can trigger the kernel to activate it +again. This involves detecting the state of the HDM (Host Managed Device +Memory) Decoders and validating that CXL.mem is enabled for each port in +the device's hierarchy. + +OPTIONS +------- +-e:: +--endpoint:: + Toggle from treating the port arguments as Switch Port identifiers to + Endpoint Port identifiers. + +-m:: +--enable-memdevs:: + Try to enable descendant memdevs after enabling the port. Recall that a + 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::../copyright.txt[] + +SEE ALSO +-------- +linkcxl:cxl-disable-port[1] diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index a0fcee987b03..27eb29ed2bae 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -247,6 +247,16 @@ Port, or Switch Upstream Port with CXL capabilities. The cxl_port_foreach_all() helper does a depth first iteration of all ports beneath the 'top' port argument. +=== PORT: Control +--- +int cxl_port_disable_invalidate(struct cxl_port *port); +int cxl_port_enable(struct cxl_port *port); +--- +cxl_port_disable_invalidate() is a violent operation that disables +entire sub-tree of CXL Memory Device and Ports, only use it for test / +debug scenarios, or ensuring that all impacted devices are deactivated +first. + === PORT: Attributes ---- const char *cxl_port_get_devname(struct cxl_port *port); @@ -315,6 +325,7 @@ struct cxl_port *cxl_endpoint_get_parent(struct cxl_endpoint *endpoint); struct cxl_port *cxl_endpoint_get_port(struct cxl_endpoint *endpoint); const char *cxl_endpoint_get_host(struct cxl_endpoint *endpoint); struct cxl_endpoint *cxl_memdev_get_endpoint(struct cxl_memdev *memdev); +struct cxl_endpoint *cxl_port_to_endpoint(struct cxl_port *port); #define cxl_endpoint_foreach(port, endpoint) \ for (endpoint = cxl_endpoint_get_first(port); endpoint != NULL; \ diff --git a/Documentation/cxl/meson.build b/Documentation/cxl/meson.build index 7618c97278b4..96f4666a828d 100644 --- a/Documentation/cxl/meson.build +++ b/Documentation/cxl/meson.build @@ -32,6 +32,8 @@ cxl_manpages = [ 'cxl-zero-labels.txt', 'cxl-enable-memdev.txt', 'cxl-disable-memdev.txt', + 'cxl-enable-port.txt', + 'cxl-disable-port.txt', ] foreach man : cxl_manpages diff --git a/cxl/builtin.h b/cxl/builtin.h index 621c85c2ffcc..3123d5e0d4ed 100644 --- a/cxl/builtin.h +++ b/cxl/builtin.h @@ -12,4 +12,6 @@ int cmd_init_labels(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_check_labels(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_disable_memdev(int argc, const char **argv, struct cxl_ctx *ctx); int cmd_enable_memdev(int argc, const char **argv, struct cxl_ctx *ctx); +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); #endif /* _CXL_BUILTIN_H_ */ diff --git a/cxl/cxl.c b/cxl/cxl.c index 78d2e9aec0bd..c20c5693fd2b 100644 --- a/cxl/cxl.c +++ b/cxl/cxl.c @@ -66,6 +66,8 @@ static struct cmd_struct commands[] = { { "write-labels", .c_fn = cmd_write_labels }, { "disable-memdev", .c_fn = cmd_disable_memdev }, { "enable-memdev", .c_fn = cmd_enable_memdev }, + { "disable-port", .c_fn = cmd_disable_port }, + { "enable-port", .c_fn = cmd_enable_port }, }; int main(int argc, const char **argv) diff --git a/cxl/filter.c b/cxl/filter.c index c691edf9501e..f6a23b7ff864 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -47,8 +47,8 @@ bool cxl_filter_has(const char *__filter, const char *needle) return false; } -static struct cxl_endpoint * -util_cxl_endpoint_filter(struct cxl_endpoint *endpoint, const char *__ident) +struct cxl_endpoint *util_cxl_endpoint_filter(struct cxl_endpoint *endpoint, + const char *__ident) { char *ident, *save; const char *arg; @@ -124,11 +124,6 @@ static struct cxl_port *__util_cxl_port_filter(struct cxl_port *port, return NULL; } -enum cxl_port_filter_mode { - CXL_PF_SINGLE, - CXL_PF_ANCESTRY, -}; - static enum cxl_port_filter_mode pf_mode(struct cxl_filter_params *p) { if (p->single) @@ -136,9 +131,8 @@ static enum cxl_port_filter_mode pf_mode(struct cxl_filter_params *p) return CXL_PF_ANCESTRY; } -static struct cxl_port *util_cxl_port_filter(struct cxl_port *port, - const char *ident, - enum cxl_port_filter_mode mode) +struct cxl_port *util_cxl_port_filter(struct cxl_port *port, const char *ident, + enum cxl_port_filter_mode mode) { struct cxl_port *iter = port; @@ -358,9 +352,9 @@ util_cxl_endpoint_filter_by_memdev(struct cxl_endpoint *endpoint, return NULL; } -static struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port, - const char *ident, - const char *serial) +struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port, + const char *ident, + const char *serial) { struct cxl_ctx *ctx = cxl_port_get_ctx(port); struct cxl_memdev *memdev; @@ -958,7 +952,6 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) continue; } } - } walk_children: dbg(p, "walk decoders\n"); diff --git a/cxl/filter.h b/cxl/filter.h index 6fd469f02ea2..850df70da964 100644 --- a/cxl/filter.h +++ b/cxl/filter.h @@ -29,6 +29,19 @@ struct cxl_filter_params { struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev, const char *__ident, const char *serials); +struct cxl_port *util_cxl_port_filter_by_memdev(struct cxl_port *port, + const char *ident, + const char *serial); + +enum cxl_port_filter_mode { + CXL_PF_SINGLE, + CXL_PF_ANCESTRY, +}; + +struct cxl_port *util_cxl_port_filter(struct cxl_port *port, const char *ident, + enum cxl_port_filter_mode mode); +struct cxl_endpoint *util_cxl_endpoint_filter(struct cxl_endpoint *endpoint, + const char *__ident); int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param); bool cxl_filter_has(const char *needle, const char *__filter); #endif /* _CXL_UTIL_FILTER_H_ */ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index dcfc82689ca9..1a7dccb245d8 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -258,6 +258,11 @@ CXL_EXPORT void cxl_unref(struct cxl_ctx *ctx) free(ctx); } +static int cxl_flush(struct cxl_ctx *ctx) +{ + return sysfs_write_attr(ctx, "/sys/bus/cxl/flush", "1\n"); +} + /** * cxl_set_log_fn - override default log routine * @ctx: cxl library context @@ -530,11 +535,31 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev return memdev->firmware_version; } +static void bus_invalidate(struct cxl_bus *bus) +{ + struct cxl_ctx *ctx = cxl_bus_get_ctx(bus); + struct cxl_port *bus_port, *port, *_p; + struct cxl_memdev *memdev; + + /* + * Something happend to cause the state of all ports to be + * indeterminate, delete them all and start over. + */ + cxl_memdev_foreach(ctx, memdev) + if (cxl_memdev_get_bus(memdev) == bus) + memdev->endpoint = NULL; + + bus_port = cxl_bus_get_port(bus); + list_for_each_safe(&bus_port->child_ports, port, _p, list) + free_port(port, &bus_port->child_ports); + bus_port->ports_init = 0; + cxl_flush(ctx); +} + CXL_EXPORT int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev) { struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev); const char *devname = cxl_memdev_get_devname(memdev); - struct cxl_port *port, *_p, *bus_port; struct cxl_bus *bus; if (!cxl_memdev_is_enabled(memdev)) @@ -553,15 +578,7 @@ CXL_EXPORT int cxl_memdev_disable_invalidate(struct cxl_memdev *memdev) return -EBUSY; } - /* - * The state of all ports is now indeterminate, delete them all - * and start over. - */ - bus_port = cxl_bus_get_port(bus); - list_for_each_safe(&bus_port->child_ports, port, _p, list) - free_port(port, &bus_port->child_ports); - bus_port->ports_init = 0; - memdev->endpoint = NULL; + bus_invalidate(bus); dbg(ctx, "%s: disabled\n", devname); @@ -1352,6 +1369,57 @@ CXL_EXPORT int cxl_port_is_enabled(struct cxl_port *port) return is_enabled(path); } +CXL_EXPORT int cxl_port_disable_invalidate(struct cxl_port *port) +{ + const char *devname = cxl_port_get_devname(port); + struct cxl_bus *bus = cxl_port_get_bus(port); + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + + if (cxl_port_is_root(port)) { + err(ctx, "%s: can not be disabled through this interface\n", + devname); + return -EINVAL; + } + + if (!bus) { + err(ctx, "%s: failed to invalidate\n", devname); + return -ENXIO; + } + + util_unbind(port->dev_path, ctx); + + if (cxl_port_is_enabled(port)) { + err(ctx, "%s: failed to disable\n", devname); + return -EBUSY; + } + + dbg(ctx, "%s: disabled\n", devname); + + bus_invalidate(bus); + + return 0; +} + +CXL_EXPORT int cxl_port_enable(struct cxl_port *port) +{ + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + const char *devname = cxl_port_get_devname(port); + + if (cxl_port_is_enabled(port)) + return 0; + + util_bind(devname, port->module, "cxl", ctx); + + if (!cxl_port_is_enabled(port)) { + err(ctx, "%s: failed to enable\n", devname); + return -ENXIO; + } + + dbg(ctx, "%s: enabled\n", devname); + + return 0; +} + CXL_EXPORT struct cxl_bus *cxl_port_to_bus(struct cxl_port *port) { if (!cxl_port_is_root(port)) @@ -1359,6 +1427,13 @@ CXL_EXPORT struct cxl_bus *cxl_port_to_bus(struct cxl_port *port) return container_of(port, struct cxl_bus, port); } +CXL_EXPORT struct cxl_endpoint *cxl_port_to_endpoint(struct cxl_port *port) +{ + if (!cxl_port_is_endpoint(port)) + return NULL; + return container_of(port, struct cxl_endpoint, port); +} + static void *add_cxl_dport(void *parent, int id, const char *cxldport_base) { const char *devname = devpath_to_devname(cxldport_base); diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 2c8358e1683e..67c7fd57c35c 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -97,11 +97,14 @@ global: cxl_port_is_switch; cxl_port_to_bus; cxl_port_is_endpoint; + cxl_port_to_endpoint; cxl_port_get_bus; cxl_port_get_host; cxl_port_get_bus; cxl_port_hosts_memdev; cxl_port_get_nr_dports; + cxl_port_disable_invalidate; + cxl_port_enable; cxl_port_get_next_all; cxl_endpoint_get_first; cxl_endpoint_get_next; diff --git a/cxl/libcxl.h b/cxl/libcxl.h index c8d07bb4efc4..1aac39618371 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -90,10 +90,13 @@ bool cxl_port_is_root(struct cxl_port *port); bool cxl_port_is_switch(struct cxl_port *port); struct cxl_bus *cxl_port_to_bus(struct cxl_port *port); bool cxl_port_is_endpoint(struct cxl_port *port); +struct cxl_endpoint *cxl_port_to_endpoint(struct cxl_port *port); struct cxl_bus *cxl_port_get_bus(struct cxl_port *port); const char *cxl_port_get_host(struct cxl_port *port); bool cxl_port_hosts_memdev(struct cxl_port *port, struct cxl_memdev *memdev); int cxl_port_get_nr_dports(struct cxl_port *port); +int cxl_port_disable_invalidate(struct cxl_port *port); +int cxl_port_enable(struct cxl_port *port); struct cxl_port *cxl_port_get_next_all(struct cxl_port *port, const struct cxl_port *top); diff --git a/cxl/meson.build b/cxl/meson.build index fc7ee71b54f0..87cfea73e40b 100644 --- a/cxl/meson.build +++ b/cxl/meson.build @@ -1,6 +1,7 @@ cxl_src = [ 'cxl.c', 'list.c', + 'port.c', 'memdev.c', '../util/json.c', '../util/log.c', diff --git a/cxl/port.c b/cxl/port.c new file mode 100644 index 000000000000..46a8f32df8e1 --- /dev/null +++ b/cxl/port.c @@ -0,0 +1,253 @@ +// 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 "filter.h" + +static struct parameters { + bool debug; + bool force; + bool memdevs; + bool endpoint; +} param; + +static struct log_ctx pl; + +#define BASE_OPTIONS() \ +OPT_BOOLEAN(0, "debug", ¶m.debug, "turn on debug"), \ +OPT_BOOLEAN('e', "endpoint", ¶m.endpoint, \ + "target endpoints instead of switch ports") + +#define ENABLE_OPTIONS() \ +OPT_BOOLEAN('m', "enable-memdevs", ¶m.memdevs, \ + "enable downstream memdev(s)") + +#define DISABLE_OPTIONS() \ +OPT_BOOLEAN('f', "force", ¶m.force, \ + "DANGEROUS: override active memdev safety checks") + +static const struct option disable_options[] = { + BASE_OPTIONS(), + DISABLE_OPTIONS(), + OPT_END(), +}; + +static const struct option enable_options[] = { + BASE_OPTIONS(), + ENABLE_OPTIONS(), + OPT_END(), +}; + +static int action_disable(struct cxl_port *port) +{ + const char *devname = cxl_port_get_devname(port); + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + struct cxl_memdev *memdev; + int active_memdevs = 0; + + if (!cxl_port_is_enabled(port)) { + log_dbg(&pl, "%s already disabled\n", devname); + return 0; + } + + if (param.endpoint) { + struct cxl_endpoint *endpoint = cxl_port_to_endpoint(port); + + if (cxl_endpoint_get_memdev(endpoint)) + active_memdevs++; + } + + cxl_memdev_foreach(ctx, memdev) { + if (!cxl_port_get_dport_by_memdev(port, memdev)) + continue; + if (cxl_memdev_is_enabled(memdev)) + active_memdevs++; + } + + if (active_memdevs && !param.force) { + /* + * TODO: actually detect rather than assume active just + * because the memdev is enabled + */ + log_err(&pl, + "%s hosts %d memdev%s which %s part of an active region\n", + devname, active_memdevs, active_memdevs > 1 ? "s" : "", + active_memdevs > 1 ? "are" : "is"); + log_err(&pl, + "See 'cxl list -M -p %s' to see impacted device%s\n", + devname, active_memdevs > 1 ? "s" : ""); + return -EBUSY; + } + + return cxl_port_disable_invalidate(port); +} + +static int action_enable(struct cxl_port *port) +{ + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + struct cxl_memdev *memdev; + int rc; + + rc = cxl_port_enable(port); + if (rc || !param.memdevs) + return rc; + + cxl_memdev_foreach(ctx, memdev) + if (cxl_port_get_dport_by_memdev(port, memdev)) + cxl_memdev_enable(memdev); + return 0; +} + +static struct cxl_port *find_cxl_port(struct cxl_ctx *ctx, const char *ident) +{ + struct cxl_bus *bus; + struct cxl_port *port; + + cxl_bus_foreach(ctx, bus) + cxl_port_foreach_all(cxl_bus_get_port(bus), port) + if (util_cxl_port_filter(port, ident, CXL_PF_SINGLE)) + return port; + return NULL; +} + +static struct cxl_endpoint *find_cxl_endpoint(struct cxl_ctx *ctx, + const char *ident) +{ + struct cxl_bus *bus; + struct cxl_port *port; + struct cxl_endpoint *endpoint; + + cxl_bus_foreach(ctx, bus) + cxl_port_foreach_all(cxl_bus_get_port(bus), port) + cxl_endpoint_foreach(port, endpoint) + if (util_cxl_endpoint_filter(endpoint, ident)) + return endpoint; + return NULL; +} + + + +static int port_action(int argc, const char **argv, struct cxl_ctx *ctx, + int (*action)(struct cxl_port *port), + const struct option *options, const char *usage) +{ + int i, rc = 0, count = 0, err = 0; + const char * const u[] = { + usage, + NULL + }; + unsigned long id; + + log_init(&pl, "cxl port", "CXL_PORT_LOG"); + argc = parse_options(argc, argv, options, u, 0); + + if (argc == 0) + usage_with_options(u, options); + for (i = 0; i < argc; i++) { + const char *fmt; + + if (strcmp(argv[i], "all") == 0) { + argc = 1; + break; + } + + if (param.endpoint) + fmt = "endpoint%lu"; + else + fmt = "port%lu"; + + if (sscanf(argv[i], fmt, &id) == 1) + continue; + if (sscanf(argv[i], "%lu", &id) == 1) + continue; + + log_err(&pl, "'%s' is not a valid %s identifer\n", argv[i], + param.endpoint ? "endpoint" : "port"); + err++; + } + + if (err == argc) { + usage_with_options(u, options); + return -EINVAL; + } + + if (param.debug) { + cxl_set_log_priority(ctx, LOG_DEBUG); + pl.log_priority = LOG_DEBUG; + } else + pl.log_priority = LOG_INFO; + + rc = 0; + err = 0; + count = 0; + + for (i = 0; i < argc; i++) { + struct cxl_port *port; + + if (param.endpoint) { + struct cxl_endpoint *endpoint; + + endpoint = find_cxl_endpoint(ctx, argv[i]); + if (!endpoint) { + log_dbg(&pl, "endpoint: %s not found\n", + argv[i]); + continue; + } + port = cxl_endpoint_get_port(endpoint); + } else { + port = find_cxl_port(ctx, argv[i]); + if (!port) { + log_dbg(&pl, "port: %s not found\n", argv[i]); + continue; + } + } + + log_dbg(&pl, "run action on port: %s\n", + cxl_port_get_devname(port)); + rc = action(port); + if (rc == 0) + count++; + else if (rc && !err) + err = rc; + } + rc = err; + + /* + * count if some actions succeeded, 0 if none were attempted, + * negative error code otherwise. + */ + if (count > 0) + return count; + return rc; + } + + int cmd_disable_port(int argc, const char **argv, struct cxl_ctx *ctx) + { + int count = port_action( + argc, argv, ctx, action_disable, disable_options, + "cxl disable-port [..] []"); + + log_info(&pl, "disabled %d port%s\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); + return count >= 0 ? 0 : EXIT_FAILURE; + } + + int cmd_enable_port(int argc, const char **argv, struct cxl_ctx *ctx) + { + int count = port_action( + argc, argv, ctx, action_enable, enable_options, + "cxl enable-port [..] []"); + + log_info(&pl, "enabled %d port%s\n", count >= 0 ? count : 0, + count > 1 ? "s" : ""); + return count >= 0 ? 0 : EXIT_FAILURE; + } From patchwork Mon Jan 24 00:55:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 12721374 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 046C6C433F5 for ; Mon, 24 Jan 2022 00:55:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231628AbiAXAzH (ORCPT ); Sun, 23 Jan 2022 19:55:07 -0500 Received: from mga14.intel.com ([192.55.52.115]:46273 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240677AbiAXAzG (ORCPT ); Sun, 23 Jan 2022 19:55:06 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1642985706; x=1674521706; h=subject:from:to:cc:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=3Tz+sC3aMaksL6nXTZI4KTBwoq4BpvovLwJRN2RUthw=; b=GTKhbp5xUo1MJ/HKuwM/9WzkbpO+GrnOpM9YE7Q/7sn9BJBi/udo2+Do Rha4eUViR7MIwfsqDjsBwtyY9l9qccRi1TIPsSW0k+T2ETIm/jtg9dJKd Ja+MGPTFX60/ypQ/N4pUk4rimHUQ9VwtmCbNG46wvajf55Vus4NbnGuli 3GO6OVCfaIz+HOQ0HiZ71r0jDej+KOETIzLKFUuUk+vESp7u0ZGBARGHP ERAoFuoNHd2NR/TuADigqxiM52GmGSz7eEuiiLmMj5DbUcqet5g3FhCJC 16irE9/vevxAr26+NjH49ia/GubDbzldkaMWb0B4ZRDh9mSvcNLfHIPZv w==; X-IronPort-AV: E=McAfee;i="6200,9189,10236"; a="246153193" X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="246153193" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:55:06 -0800 X-IronPort-AV: E=Sophos;i="5.88,311,1635231600"; d="scan'208";a="596630905" Received: from dwillia2-desk3.jf.intel.com (HELO dwillia2-desk3.amr.corp.intel.com) ([10.54.39.25]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2022 16:55:06 -0800 Subject: [ndctl PATCH 37/37] cxl/list: Filter dports and targets by memdevs From: Dan Williams To: linux-cxl@vger.kernel.org Cc: Ben Widawsky , vishal.l.verma@intel.com Date: Sun, 23 Jan 2022 16:55:06 -0800 Message-ID: <164298570626.3021641.18034728333613142555.stgit@dwillia2-desk3.amr.corp.intel.com> In-Reply-To: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> References: <164298550885.3021641.11210386002804544864.stgit@dwillia2-desk3.amr.corp.intel.com> User-Agent: StGit/0.18-3-g996c MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-cxl@vger.kernel.org Trim dport / target information by the memdev filter. This is useful when validating connectivity and decoder programming. Reported-by: Ben Widawsky Signed-off-by: Dan Williams --- Documentation/cxl/lib/libcxl.txt | 1 + cxl/filter.c | 51 ++++++++++++++++++++++++++++++++++++++ cxl/filter.h | 6 ++++ cxl/json.c | 51 +++++++++++++++++++++++++------------- cxl/json.h | 7 +++++ cxl/lib/libcxl.c | 5 ++++ cxl/lib/libcxl.sym | 1 + cxl/libcxl.h | 1 + 8 files changed, 105 insertions(+), 18 deletions(-) diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt index 27eb29ed2bae..4392b47e6ece 100644 --- a/Documentation/cxl/lib/libcxl.txt +++ b/Documentation/cxl/lib/libcxl.txt @@ -221,6 +221,7 @@ const char *cxl_port_get_host(struct cxl_port *port); struct cxl_port *cxl_decoder_get_port(struct cxl_decoder *decoder); struct cxl_port *cxl_port_get_next_all(struct cxl_port *port, const struct cxl_port *top); +struct cxl_port *cxl_dport_get_port(struct cxl_dport *dport); #define cxl_port_foreach(parent, port) \ for (port = cxl_port_get_first(parent); port != NULL; \ diff --git a/cxl/filter.c b/cxl/filter.c index f6a23b7ff864..925bf3a1c62d 100644 --- a/cxl/filter.c +++ b/cxl/filter.c @@ -435,6 +435,48 @@ util_cxl_decoder_filter_by_memdev(struct cxl_decoder *decoder, return NULL; } +struct cxl_target *util_cxl_target_filter_by_memdev(struct cxl_target *target, + const char *ident, + const char *serial) +{ + struct cxl_decoder *decoder = cxl_target_get_decoder(target); + struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder); + struct cxl_memdev *memdev; + + if (!ident && !serial) + return target; + + cxl_memdev_foreach(ctx, memdev) { + if (!util_cxl_memdev_filter(memdev, ident, serial)) + continue; + if (cxl_target_maps_memdev(target, memdev)) + return target; + } + + return NULL; +} + +struct cxl_dport *util_cxl_dport_filter_by_memdev(struct cxl_dport *dport, + const char *ident, + const char *serial) +{ + struct cxl_port *port = cxl_dport_get_port(dport); + struct cxl_ctx *ctx = cxl_port_get_ctx(port); + struct cxl_memdev *memdev; + + if (!ident && !serial) + return dport; + + cxl_memdev_foreach (ctx, memdev) { + if (!util_cxl_memdev_filter(memdev, ident, serial)) + continue; + if (cxl_dport_maps_memdev(dport, memdev)) + return dport; + } + + return NULL; +} + static bool __memdev_filter_by_decoder(struct cxl_memdev *memdev, struct cxl_port *port, const char *ident) { @@ -639,6 +681,9 @@ static void walk_decoders(struct cxl_port *port, struct cxl_filter_params *p, dbg(p, "decoder object allocation failure\n"); continue; } + util_cxl_targets_append_json(jdecoder, decoder, + p->memdev_filter, p->serial_filter, + flags); json_object_array_add(jdecoders, jdecoder); } } @@ -756,6 +801,9 @@ walk_child_ports(struct cxl_port *parent_port, struct cxl_filter_params *p, err(p, "%s: failed to list\n", devname); continue; } + util_cxl_dports_append_json(jport, port, + p->memdev_filter, + p->serial_filter, flags); json_object_array_add(jports, jport); jchildports = json_object_new_array(); if (!jchildports) { @@ -914,6 +962,9 @@ int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *p) dbg(p, "bus object allocation failure\n"); continue; } + util_cxl_dports_append_json(jbus, port, + p->memdev_filter, + p->serial_filter, flags); json_object_array_add(jbuses, jbus); if (p->ports) { jchildports = json_object_new_array(); diff --git a/cxl/filter.h b/cxl/filter.h index 850df70da964..5deabb3d38fe 100644 --- a/cxl/filter.h +++ b/cxl/filter.h @@ -42,6 +42,12 @@ struct cxl_port *util_cxl_port_filter(struct cxl_port *port, const char *ident, enum cxl_port_filter_mode mode); struct cxl_endpoint *util_cxl_endpoint_filter(struct cxl_endpoint *endpoint, const char *__ident); +struct cxl_target *util_cxl_target_filter_by_memdev(struct cxl_target *target, + const char *ident, + const char *serial); +struct cxl_dport *util_cxl_dport_filter_by_memdev(struct cxl_dport *dport, + const char *ident, + const char *serial); int cxl_filter_walk(struct cxl_ctx *ctx, struct cxl_filter_params *param); bool cxl_filter_has(const char *needle, const char *__filter); #endif /* _CXL_UTIL_FILTER_H_ */ diff --git a/cxl/json.c b/cxl/json.c index 4fb5eec11077..f3b536e1d4fa 100644 --- a/cxl/json.c +++ b/cxl/json.c @@ -8,6 +8,7 @@ #include #include +#include "filter.h" #include "json.h" static struct json_object *util_cxl_memdev_health_to_json( @@ -241,9 +242,9 @@ struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev, return jdev; } -static struct json_object *util_cxl_dports_to_json(struct json_object *jport, - struct cxl_port *port, - unsigned long flags) +void util_cxl_dports_append_json(struct json_object *jport, + struct cxl_port *port, const char *ident, + const char *serial, unsigned long flags) { struct json_object *jobj, *jdports; struct cxl_dport *dport; @@ -251,7 +252,7 @@ static struct json_object *util_cxl_dports_to_json(struct json_object *jport, val = cxl_port_get_nr_dports(port); if (!val || !(flags & UTIL_JSON_TARGETS)) - return jport; + return; jobj = json_object_new_int(val); if (jobj) @@ -259,12 +260,15 @@ static struct json_object *util_cxl_dports_to_json(struct json_object *jport, jdports = json_object_new_array(); if (!jdports) - return jport; + return; cxl_dport_foreach(port, dport) { struct json_object *jdport; const char *phys_node; + if (!util_cxl_dport_filter_by_memdev(dport, ident, serial)) + continue; + jdport = json_object_new_object(); if (!jdport) continue; @@ -289,8 +293,6 @@ static struct json_object *util_cxl_dports_to_json(struct json_object *jport, } json_object_object_add(jport, "dports", jdports); - - return jport; } struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus, @@ -311,7 +313,7 @@ struct json_object *util_cxl_bus_to_json(struct cxl_bus *bus, if (jobj) json_object_object_add(jbus, "provider", jobj); - return util_cxl_dports_to_json(jbus, cxl_bus_get_port(bus), flags); + return jbus; } struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder, @@ -320,8 +322,6 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder, const char *devname = cxl_decoder_get_devname(decoder); struct cxl_port *port = cxl_decoder_get_port(decoder); struct json_object *jdecoder, *jobj; - struct json_object *jtargets; - struct cxl_target *target; u64 val; jdecoder = json_object_new_object(); @@ -375,9 +375,22 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder, jobj); } + return jdecoder; +} + +void util_cxl_targets_append_json(struct json_object *jdecoder, + struct cxl_decoder *decoder, + const char *ident, const char *serial, + unsigned long flags) +{ + struct cxl_port *port = cxl_decoder_get_port(decoder); + struct json_object *jobj, *jtargets; + struct cxl_target *target; + int val; + /* Endpoints don't have targets, they *are* targets */ if (cxl_port_is_endpoint(port)) - return jdecoder; + return; val = cxl_decoder_get_nr_targets(decoder); jobj = json_object_new_int(val); @@ -386,16 +399,21 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder, if (!(flags & UTIL_JSON_TARGETS) || !cxl_decoder_get_nr_targets(decoder)) - return jdecoder; + return; jtargets = json_object_new_array(); if (!jtargets) - return jdecoder; + return; cxl_target_foreach(decoder, target) { - struct json_object *jtarget = json_object_new_object(); + struct json_object *jtarget; const char *phys_node; + const char *devname; + + if (!util_cxl_target_filter_by_memdev(target, ident, serial)) + continue; + jtarget = json_object_new_object(); if (!jtarget) continue; @@ -425,9 +443,6 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder, } json_object_object_add(jdecoder, "targets", jtargets); - - return jdecoder; - } static struct json_object *__util_cxl_port_to_json(struct cxl_port *port, @@ -455,7 +470,7 @@ static struct json_object *__util_cxl_port_to_json(struct cxl_port *port, json_object_object_add(jport, "state", jobj); } - return util_cxl_dports_to_json(jport, port, flags); + return jport; } struct json_object *util_cxl_port_to_json(struct cxl_port *port, diff --git a/cxl/json.h b/cxl/json.h index fcca2e6e9cb6..9a5a845eebbb 100644 --- a/cxl/json.h +++ b/cxl/json.h @@ -15,4 +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); +void util_cxl_targets_append_json(struct json_object *jdecoder, + struct cxl_decoder *decoder, + const char *ident, const char *serial, + unsigned long flags); +void util_cxl_dports_append_json(struct json_object *jport, + struct cxl_port *port, const char *ident, + const char *serial, unsigned long flags); #endif /* __CXL_UTIL_JSON_H__ */ diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c index 1a7dccb245d8..e0b443fb0aa4 100644 --- a/cxl/lib/libcxl.c +++ b/cxl/lib/libcxl.c @@ -1527,6 +1527,11 @@ CXL_EXPORT int cxl_dport_get_id(struct cxl_dport *dport) return dport->id; } +CXL_EXPORT struct cxl_port *cxl_dport_get_port(struct cxl_dport *dport) +{ + return dport->port; +} + CXL_EXPORT bool cxl_dport_maps_memdev(struct cxl_dport *dport, struct cxl_memdev *memdev) { diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym index 67c7fd57c35c..e56a2bf96e22 100644 --- a/cxl/lib/libcxl.sym +++ b/cxl/lib/libcxl.sym @@ -152,6 +152,7 @@ global: cxl_dport_get_devname; cxl_dport_get_physical_node; cxl_dport_get_id; + cxl_dport_get_port; cxl_port_get_dport_by_memdev; cxl_dport_maps_memdev; } LIBCXL_1; diff --git a/cxl/libcxl.h b/cxl/libcxl.h index 1aac39618371..3b2293bbee84 100644 --- a/cxl/libcxl.h +++ b/cxl/libcxl.h @@ -113,6 +113,7 @@ struct cxl_dport *cxl_dport_get_first(struct cxl_port *port); struct cxl_dport *cxl_dport_get_next(struct cxl_dport *dport); const char *cxl_dport_get_devname(struct cxl_dport *dport); const char *cxl_dport_get_physical_node(struct cxl_dport *dport); +struct cxl_port *cxl_dport_get_port(struct cxl_dport *dport); int cxl_dport_get_id(struct cxl_dport *dport); bool cxl_dport_maps_memdev(struct cxl_dport *dport, struct cxl_memdev *memdev); struct cxl_dport *cxl_port_get_dport_by_memdev(struct cxl_port *port,