linux-cxl.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [ndctl PATCH v3 00/21] Initial CXL support
@ 2021-07-01 20:09 Vishal Verma
  2021-07-01 20:09 ` [ndctl PATCH v3 01/21] ndctl: add .clang-format Vishal Verma
                   ` (21 more replies)
  0 siblings, 22 replies; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Changes since v2[1]:

- Some minor cleanups and formatting (Ben)
- Update cxl_mem.h to the latest kernel version (Ben)
- Add .clang-format (Ben)
- Add label commands to cxl-clu - {read,write,zero}-labels
- Add libcxl and cxl-cli to the RPM spec
- Add bash-completion for cxl-cli
- 

[1]: https://lore.kernel.org/linux-cxl/20210219020331.725687-1-vishal.l.verma@intel.com/

---

These patches add a new utility and library to support CXL devices.
This comprehends the kernel's sysfs layout for CXL devices, and
implements a command submission harness for CXL mailbox commands via
ioctl()s definied by the cxl_mem driver. 

These patches include:
- libcxl representation of cxl_mem devices
- A command submission harness through libcxl
- A 'cxl-list' command which displays information about a device
- cxl-{read,write,zero}-labels commands for Label Storage Area
  manipulation
- Unit tests to exercise several libcxl APIs and perform mailbox
  commands.

Patch 15 is an RFC - maybe this should just be dropped entirely for now
until there is a concept of active/disabled memdevs. It is useful as a
placeholder as it allows for a way to pre-insert checks in places
we expect the device to be active or disabled.

An ndctl branch with these patches is also available at [2]

[2]: https://github.com/pmem/ndctl/tree/cxl-2.0v2

Ira Weiny (1):
  ndctl: Add CXL packages to the RPM spec

Vishal Verma (20):
  ndctl: add .clang-format
  cxl: add a cxl utility and libcxl library
  cxl: add a local copy of the cxl_mem UAPI header
  libcxl: add support for command query and submission
  libcxl: add support for the 'Identify Device' command
  test: rename 'ndctl_test' to 'test_ctx'
  test: rename 'ndctl_test_*' helpers to 'test_*'
  test: introduce a libcxl unit test
  libcxl: add GET_HEALTH_INFO mailbox command and accessors
  libcxl: add support for the 'GET_LSA' command
  util/hexdump: Add a util helper to print a buffer in hex
  test/libcxl: add a test for {set, get}_lsa commands
  test/libcxl: introduce a command size fuzzing test
  libcxl: add lsa_size to cxl_memdev, and an API to retrieve it
  libcxl: PLACEHOLDER: add an interface to determine whether a memdev is
    active
  libcxl: add interfaces for label operations
  test/libcxl: add a test for cxl_memdev_{get,set}_lsa
  cxl: add commands to read, write, and zero labels
  Documentation/cxl: add library API documentation
  cxl-cli: add bash completion

 Documentation/cxl/cxl-list.txt           |   64 ++
 Documentation/cxl/cxl-read-labels.txt    |   33 +
 Documentation/cxl/cxl-write-labels.txt   |   32 +
 Documentation/cxl/cxl-zero-labels.txt    |   29 +
 Documentation/cxl/cxl.txt                |   34 +
 Documentation/cxl/human-option.txt       |    8 +
 Documentation/cxl/labels-description.txt |    8 +
 Documentation/cxl/labels-options.txt     |   17 +
 Documentation/cxl/lib/cxl_new.txt        |   43 +
 Documentation/cxl/lib/libcxl.txt         |   56 ++
 Documentation/cxl/memdev-option.txt      |    4 +
 Documentation/cxl/verbose-option.txt     |    5 +
 configure.ac                             |    4 +
 Makefile.am                              |   14 +-
 Makefile.am.in                           |    5 +
 cxl/lib/private.h                        |  104 +++
 cxl/lib/libcxl.c                         | 1026 ++++++++++++++++++++++
 cxl/builtin.h                            |   13 +
 cxl/cxl_mem.h                            |  189 ++++
 cxl/libcxl.h                             |   91 ++
 test.h                                   |   40 +-
 test/libcxl-expect.h                     |   13 +
 util/filter.h                            |    2 +
 util/hexdump.h                           |    8 +
 util/json.h                              |    3 +
 util/main.h                              |    3 +
 cxl/cxl.c                                |   99 +++
 cxl/list.c                               |  113 +++
 cxl/memdev.c                             |  314 +++++++
 ndctl/bat.c                              |    8 +-
 ndctl/test.c                             |    8 +-
 test/ack-shutdown-count-set.c            |   16 +-
 test/blk_namespaces.c                    |   14 +-
 test/core.c                              |   32 +-
 test/dax-dev.c                           |   10 +-
 test/dax-pmd.c                           |   13 +-
 test/dax-poison.c                        |    6 +-
 test/daxdev-errors.c                     |    2 +-
 test/device-dax.c                        |   26 +-
 test/dpa-alloc.c                         |   14 +-
 test/dsm-fail.c                          |   14 +-
 test/libcxl.c                            |  553 ++++++++++++
 test/libndctl.c                          |   84 +-
 test/multi-pmem.c                        |   23 +-
 test/parent-uuid.c                       |   13 +-
 test/pmem_namespaces.c                   |   14 +-
 test/revoke-devmem.c                     |   12 +-
 util/filter.c                            |   20 +
 util/hexdump.c                           |   53 ++
 util/json.c                              |   26 +
 .clang-format                            |  162 ++++
 .gitignore                               |    7 +-
 Documentation/cxl/Makefile.am            |   61 ++
 Documentation/cxl/lib/Makefile.am        |   58 ++
 README.md                                |    2 +-
 contrib/ndctl                            |  109 +++
 cxl/Makefile.am                          |   22 +
 cxl/lib/Makefile.am                      |   32 +
 cxl/lib/libcxl.pc.in                     |   11 +
 cxl/lib/libcxl.sym                       |   67 ++
 ndctl.spec.in                            |   49 ++
 test/Makefile.am                         |   15 +-
 62 files changed, 3749 insertions(+), 181 deletions(-)
 create mode 100644 Documentation/cxl/cxl-list.txt
 create mode 100644 Documentation/cxl/cxl-read-labels.txt
 create mode 100644 Documentation/cxl/cxl-write-labels.txt
 create mode 100644 Documentation/cxl/cxl-zero-labels.txt
 create mode 100644 Documentation/cxl/cxl.txt
 create mode 100644 Documentation/cxl/human-option.txt
 create mode 100644 Documentation/cxl/labels-description.txt
 create mode 100644 Documentation/cxl/labels-options.txt
 create mode 100644 Documentation/cxl/lib/cxl_new.txt
 create mode 100644 Documentation/cxl/lib/libcxl.txt
 create mode 100644 Documentation/cxl/memdev-option.txt
 create mode 100644 Documentation/cxl/verbose-option.txt
 create mode 100644 cxl/lib/private.h
 create mode 100644 cxl/lib/libcxl.c
 create mode 100644 cxl/builtin.h
 create mode 100644 cxl/cxl_mem.h
 create mode 100644 cxl/libcxl.h
 create mode 100644 test/libcxl-expect.h
 create mode 100644 util/hexdump.h
 create mode 100644 cxl/cxl.c
 create mode 100644 cxl/list.c
 create mode 100644 cxl/memdev.c
 create mode 100644 test/libcxl.c
 create mode 100644 util/hexdump.c
 create mode 100644 .clang-format
 create mode 100644 Documentation/cxl/Makefile.am
 create mode 100644 Documentation/cxl/lib/Makefile.am
 create mode 100644 cxl/Makefile.am
 create mode 100644 cxl/lib/Makefile.am
 create mode 100644 cxl/lib/libcxl.pc.in
 create mode 100644 cxl/lib/libcxl.sym


base-commit: 4e646fa490ba4b782afa188dd8818b94c419924e
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 01/21] ndctl: add .clang-format
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-10  1:12   ` Dan Williams
  2021-07-01 20:09 ` [ndctl PATCH v3 02/21] cxl: add a cxl utility and libcxl library Vishal Verma
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Copy the Linux kernel's .clang-format and modify it for ndctl. Only the
'ForEachMacros' section has been modified from the original kernel copy.

Cc: Dan Williams <dan.j.williams@intel.com>
Reported-by: Ben Widawsky <ben.widawsky@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 .clang-format | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 161 insertions(+)
 create mode 100644 .clang-format

diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..4e00fff
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,161 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# clang-format configuration file. Intended for clang-format >= 4.
+# Copied from Linux's .clang-format
+#
+# For more information, see:
+#
+#   https://clang.llvm.org/docs/ClangFormat.html
+#   https://clang.llvm.org/docs/ClangFormatStyleOptions.html
+#
+---
+AccessModifierOffset: -4
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
+AlignOperands: true
+AlignTrailingComments: false
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: false
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+  AfterClass: false
+  AfterControlStatement: false
+  AfterEnum: false
+  AfterFunction: true
+  AfterNamespace: true
+  AfterObjCDeclaration: false
+  AfterStruct: false
+  AfterUnion: false
+  #AfterExternBlock: false # Unknown to clang-format-5.0
+  BeforeCatch: false
+  BeforeElse: false
+  IndentBraces: false
+  #SplitEmptyFunction: true # Unknown to clang-format-4.0
+  #SplitEmptyRecord: true # Unknown to clang-format-4.0
+  #SplitEmptyNamespace: true # Unknown to clang-format-4.0
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
+BreakBeforeTernaryOperators: false
+BreakConstructorInitializersBeforeComma: false
+#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: false
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+#CompactNamespaces: false # Unknown to clang-format-4.0
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 8
+ContinuationIndentWidth: 8
+Cpp11BracedListStyle: false
+DerivePointerAlignment: false
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+#FixNamespaceComments: false # Unknown to clang-format-4.0
+
+# Taken from:
+# while read -r sym; do
+# 	printf "  - '%s'\n" "$sym";
+# done < \
+# 	<(cscope -dL6 "foreach|for_each" \
+# 	| awk '{ print $4 $5 }' | grep -E 'foreach|for_each' \
+# 	| sed -e 's/#define//' \
+# 		-e 's/*//' \
+# 		-e 's/://' \
+# 		-e 's/\(.*for_each.*\)(.*/\1/' \
+# 		-e 's/\(.*foreach.*\)(.*/\1/' \
+# 	| sort -u)
+ForEachMacros:
+  - 'daxctl_dev_foreach'
+  - 'daxctl_mapping_foreach'
+  - 'daxctl_region_foreach'
+  - 'kmod_list_foreach'
+  - 'kmod_list_foreach_reverse'
+  - 'list_for_each'
+  - 'list_for_each_off'
+  - 'list_for_each_rev'
+  - 'list_for_each_safe'
+  - 'list_for_each_safe_off'
+  - 'ndctl_btt_foreach'
+  - 'ndctl_btt_foreach_safe'
+  - 'ndctl_bus_foreach'
+  - 'ndctl_dax_foreach'
+  - 'ndctl_dax_foreach_safe'
+  - 'ndctl_dimm_foreach'
+  - 'ndctl_dimm_foreach_in_interleave_set'
+  - 'ndctl_dimm_foreach_in_region'
+  - 'ndctl_interleave_set_foreach'
+  - 'ndctl_mapping_foreach'
+  - 'ndctl_namespace_badblock_foreach'
+  - 'ndctl_namespace_bb_foreach'
+  - 'ndctl_namespace_foreach'
+  - 'ndctl_namespace_foreach_safe'
+  - 'ndctl_pfn_foreach'
+  - 'ndctl_pfn_foreach_safe'
+  - 'ndctl_region_badblock_foreach'
+  - 'ndctl_region_foreach'
+  - 'udev_list_entry_foreach'
+
+#IncludeBlocks: Preserve # Unknown to clang-format-5.0
+IncludeCategories:
+  - Regex: '.*'
+    Priority: 1
+IncludeIsMainRegex: '(Test)?$'
+IndentCaseLabels: false
+#IndentPPDirectives: None # Unknown to clang-format-5.0
+IndentWidth: 8
+IndentWrappedFunctionNames: false
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
+ObjCBlockIndentWidth: 8
+ObjCSpaceAfterProperty: true
+ObjCSpaceBeforeProtocolList: true
+
+# Taken from git's rules
+#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
+PenaltyBreakBeforeFirstCallParameter: 30
+PenaltyBreakComment: 10
+PenaltyBreakFirstLessLess: 0
+PenaltyBreakString: 10
+PenaltyExcessCharacter: 100
+PenaltyReturnTypeOnItsOwnLine: 60
+
+PointerAlignment: Right
+ReflowComments: false
+SortIncludes: false
+#SortUsingDeclarations: false # Unknown to clang-format-4.0
+SpaceAfterCStyleCast: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
+#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
+SpaceBeforeParens: ControlStatements
+#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: false
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp03
+TabWidth: 8
+UseTab: Always
+...
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 02/21] cxl: add a cxl utility and libcxl library
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
  2021-07-01 20:09 ` [ndctl PATCH v3 01/21] ndctl: add .clang-format Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-10  1:12   ` Dan Williams
  2021-07-01 20:09 ` [ndctl PATCH v3 03/21] cxl: add a local copy of the cxl_mem UAPI header Vishal Verma
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

CXL - or Compute eXpress Link - is a new interconnect that extends PCIe
to support a wide range of devices, including cache coherent memory
expanders. As such, these devices can be new sources of 'persistent
memory', and the 'ndctl' umbrella of tools and libraries needs to be able
to interact with them.

Add a new utility and library for managing these CXL memory devices. This
is an initial bring-up for interacting with CXL devices, and only includes
adding the utility and library infrastructure, parsing device information
from sysfs for CXL devices, and providing a 'cxl-list' command to
display this information in JSON formatted output.

Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 Documentation/cxl/cxl-list.txt       |  64 +++++
 Documentation/cxl/cxl.txt            |  34 +++
 Documentation/cxl/human-option.txt   |   8 +
 Documentation/cxl/verbose-option.txt |   5 +
 configure.ac                         |   3 +
 Makefile.am                          |   8 +-
 Makefile.am.in                       |   4 +
 cxl/lib/private.h                    |  29 +++
 cxl/lib/libcxl.c                     | 345 +++++++++++++++++++++++++++
 cxl/builtin.h                        |   8 +
 cxl/libcxl.h                         |  55 +++++
 util/filter.h                        |   2 +
 util/json.h                          |   3 +
 util/main.h                          |   3 +
 cxl/cxl.c                            |  96 ++++++++
 cxl/list.c                           | 113 +++++++++
 util/filter.c                        |  20 ++
 util/json.c                          |  26 ++
 .clang-format                        |   1 +
 .gitignore                           |   4 +-
 Documentation/cxl/Makefile.am        |  58 +++++
 cxl/Makefile.am                      |  21 ++
 cxl/lib/Makefile.am                  |  32 +++
 cxl/lib/libcxl.pc.in                 |  11 +
 cxl/lib/libcxl.sym                   |  29 +++
 25 files changed, 978 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/cxl/cxl-list.txt
 create mode 100644 Documentation/cxl/cxl.txt
 create mode 100644 Documentation/cxl/human-option.txt
 create mode 100644 Documentation/cxl/verbose-option.txt
 create mode 100644 cxl/lib/private.h
 create mode 100644 cxl/lib/libcxl.c
 create mode 100644 cxl/builtin.h
 create mode 100644 cxl/libcxl.h
 create mode 100644 cxl/cxl.c
 create mode 100644 cxl/list.c
 create mode 100644 Documentation/cxl/Makefile.am
 create mode 100644 cxl/Makefile.am
 create mode 100644 cxl/lib/Makefile.am
 create mode 100644 cxl/lib/libcxl.pc.in
 create mode 100644 cxl/lib/libcxl.sym

diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
new file mode 100644
index 0000000..4e2be87
--- /dev/null
+++ b/Documentation/cxl/cxl-list.txt
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+
+cxl-list(1)
+===========
+
+NAME
+----
+cxl-list - List CXL capable memory devices, and their attributes in json.
+
+SYNOPSIS
+--------
+[verse]
+'cxl list' [<options>]
+
+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 devices.
+By default, 'cxl list' with no options is equivalent to:
+[verse]
+cxl list --devices
+
+EXAMPLE
+-------
+----
+# cxl list --devices
+{
+  "memdev":"mem0",
+  "pmem_size":268435456,
+  "ram_size":0,
+}
+----
+
+OPTIONS
+-------
+-d::
+--memdev=::
+	Specify a cxl memory device name to filter the listing. For example:
+----
+# cxl list --memdev=mem0
+{
+  "memdev":"mem0",
+  "pmem_size":268435456,
+  "ram_size":0,
+}
+----
+
+-D::
+--memdevs::
+	Include all CXL memory devices in the listing
+
+-i::
+--idle::
+	Include idle (not enabled / zero-sized) devices in the listing
+
+include::human-option.txt[]
+
+include::verbose-option.txt[]
+
+include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkcxl:ndctl-list[1]
diff --git a/Documentation/cxl/cxl.txt b/Documentation/cxl/cxl.txt
new file mode 100644
index 0000000..e99e61b
--- /dev/null
+++ b/Documentation/cxl/cxl.txt
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+
+cxl(1)
+======
+
+NAME
+----
+cxl - Provides enumeration and provisioning commands for CXL devices
+
+SYNOPSIS
+--------
+[verse]
+'cxl' [--version] [--help] COMMAND [ARGS]
+
+OPTIONS
+-------
+-v::
+--version::
+  Display the version of the 'cxl' utility.
+
+-h::
+--help::
+  Run the 'cxl help' command.
+
+DESCRIPTION
+-----------
+The cxl utility provides enumeration and provisioning commands for
+the CXL devices managed by the Linux kernel.
+
+include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkcxl:ndctl[1]
diff --git a/Documentation/cxl/human-option.txt b/Documentation/cxl/human-option.txt
new file mode 100644
index 0000000..2f4de7a
--- /dev/null
+++ b/Documentation/cxl/human-option.txt
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+
+-u::
+--human::
+	By default the command will output machine-friendly raw-integer
+	data. Instead, with this flag, numbers representing storage size
+	will be formatted as human readable strings with units, other
+	fields are converted to hexadecimal strings.
diff --git a/Documentation/cxl/verbose-option.txt b/Documentation/cxl/verbose-option.txt
new file mode 100644
index 0000000..cb62c8e
--- /dev/null
+++ b/Documentation/cxl/verbose-option.txt
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
+-v::
+--verbose::
+	Emit more debug messages
diff --git a/configure.ac b/configure.ac
index dc39dbe..dadae0a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -222,12 +222,15 @@ AC_CONFIG_HEADERS(config.h)
 AC_CONFIG_FILES([
         Makefile
         daxctl/lib/Makefile
+        cxl/lib/Makefile
         ndctl/lib/Makefile
         ndctl/Makefile
         daxctl/Makefile
+        cxl/Makefile
         test/Makefile
         Documentation/ndctl/Makefile
         Documentation/daxctl/Makefile
+        Documentation/cxl/Makefile
 ])
 
 AC_OUTPUT
diff --git a/Makefile.am b/Makefile.am
index 60a1998..428fd40 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,9 +1,9 @@
 include Makefile.am.in
 
 ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
-SUBDIRS = . daxctl/lib ndctl/lib ndctl daxctl
+SUBDIRS = . cxl/lib daxctl/lib ndctl/lib cxl ndctl daxctl
 if ENABLE_DOCS
-SUBDIRS += Documentation/ndctl Documentation/daxctl
+SUBDIRS += Documentation/ndctl Documentation/daxctl Documentation/cxl
 endif
 SUBDIRS += test
 
@@ -87,4 +87,6 @@ libutil_a_SOURCES = \
 	util/filter.h \
 	util/bitmap.h
 
-nobase_include_HEADERS = daxctl/libdaxctl.h
+nobase_include_HEADERS = \
+	daxctl/libdaxctl.h \
+	cxl/libcxl.h
diff --git a/Makefile.am.in b/Makefile.am.in
index bdceda9..aaeee53 100644
--- a/Makefile.am.in
+++ b/Makefile.am.in
@@ -42,3 +42,7 @@ LIBNDCTL_AGE=19
 LIBDAXCTL_CURRENT=6
 LIBDAXCTL_REVISION=0
 LIBDAXCTL_AGE=5
+
+LIBCXL_CURRENT=1
+LIBCXL_REVISION=0
+LIBCXL_AGE=0
diff --git a/cxl/lib/private.h b/cxl/lib/private.h
new file mode 100644
index 0000000..fc88fa1
--- /dev/null
+++ b/cxl/lib/private.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+/* Copyright (C) 2020-2021, Intel Corporation. All rights reserved. */
+#ifndef _LIBCXL_PRIVATE_H_
+#define _LIBCXL_PRIVATE_H_
+
+#include <libkmod.h>
+
+#define CXL_EXPORT __attribute__ ((visibility("default")))
+
+struct cxl_memdev {
+	int id, major, minor;
+	void *dev_buf;
+	size_t buf_len;
+	char *dev_path;
+	char *firmware_version;
+	struct cxl_ctx *ctx;
+	struct list_node list;
+	unsigned long long pmem_size;
+	unsigned long long ram_size;
+	int payload_max;
+	struct kmod_module *module;
+};
+
+static inline int check_kmod(struct kmod_ctx *kmod_ctx)
+{
+	return kmod_ctx ? 0 : -ENXIO;
+}
+
+#endif /* _LIBCXL_PRIVATE_H_ */
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
new file mode 100644
index 0000000..d34e7d0
--- /dev/null
+++ b/cxl/lib/libcxl.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: LGPL-2.1
+// Copyright (C) 2020-2021, Intel Corporation. All rights reserved.
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <uuid/uuid.h>
+#include <ccan/list/list.h>
+#include <ccan/array_size/array_size.h>
+
+#include <util/log.h>
+#include <util/sysfs.h>
+#include <util/bitmap.h>
+#include <cxl/libcxl.h>
+#include "private.h"
+
+/**
+ * struct cxl_ctx - library user context to find "nd" instances
+ *
+ * Instantiate with cxl_new(), which takes an initial reference.  Free
+ * the context by dropping the reference count to zero with
+ * cxl_unref(), or take additional references with cxl_ref()
+ * @timeout: default library timeout in milliseconds
+ */
+struct cxl_ctx {
+	/* log_ctx must be first member for cxl_set_log_fn compat */
+	struct log_ctx ctx;
+	int refcount;
+	void *userdata;
+	int memdevs_init;
+	struct list_head memdevs;
+	struct kmod_ctx *kmod_ctx;
+	void *private_data;
+};
+
+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(memdev->firmware_version);
+	free(memdev->dev_buf);
+	free(memdev->dev_path);
+	free(memdev);
+}
+
+/**
+ * cxl_get_userdata - retrieve stored data pointer from library context
+ * @ctx: cxl library context
+ *
+ * This might be useful to access from callbacks like a custom logging
+ * function.
+ */
+CXL_EXPORT void *cxl_get_userdata(struct cxl_ctx *ctx)
+{
+	if (ctx == NULL)
+		return NULL;
+	return ctx->userdata;
+}
+
+/**
+ * cxl_set_userdata - store custom @userdata in the library context
+ * @ctx: cxl library context
+ * @userdata: data pointer
+ */
+CXL_EXPORT void cxl_set_userdata(struct cxl_ctx *ctx, void *userdata)
+{
+	if (ctx == NULL)
+		return;
+	ctx->userdata = userdata;
+}
+
+CXL_EXPORT void cxl_set_private_data(struct cxl_ctx *ctx, void *data)
+{
+	ctx->private_data = data;
+}
+
+CXL_EXPORT void *cxl_get_private_data(struct cxl_ctx *ctx)
+{
+	return ctx->private_data;
+}
+
+/**
+ * cxl_new - instantiate a new library context
+ * @ctx: context to establish
+ *
+ * Returns zero on success and stores an opaque pointer in ctx.  The
+ * context is freed by cxl_unref(), i.e. cxl_new() implies an
+ * internal cxl_ref().
+ */
+CXL_EXPORT int cxl_new(struct cxl_ctx **ctx)
+{
+	struct kmod_ctx *kmod_ctx;
+	struct cxl_ctx *c;
+	int rc = 0;
+
+	c = calloc(1, sizeof(struct cxl_ctx));
+	if (!c)
+		return -ENOMEM;
+
+	kmod_ctx = kmod_new(NULL, NULL);
+	if (check_kmod(kmod_ctx) != 0) {
+		rc = -ENXIO;
+		goto out;
+	}
+
+	c->refcount = 1;
+	log_init(&c->ctx, "libcxl", "CXL_LOG");
+	info(c, "ctx %p created\n", c);
+	dbg(c, "log_priority=%d\n", c->ctx.log_priority);
+	*ctx = c;
+	list_head_init(&c->memdevs);
+	c->kmod_ctx = kmod_ctx;
+
+	return 0;
+out:
+	free(c);
+	return rc;
+}
+
+/**
+ * cxl_ref - take an additional reference on the context
+ * @ctx: context established by cxl_new()
+ */
+CXL_EXPORT struct cxl_ctx *cxl_ref(struct cxl_ctx *ctx)
+{
+	if (ctx == NULL)
+		return NULL;
+	ctx->refcount++;
+	return ctx;
+}
+
+/**
+ * cxl_unref - drop a context reference count
+ * @ctx: context established by cxl_new()
+ *
+ * Drop a reference and if the resulting reference count is 0 destroy
+ * the context.
+ */
+CXL_EXPORT void cxl_unref(struct cxl_ctx *ctx)
+{
+	struct cxl_memdev *memdev, *_d;
+
+	if (ctx == NULL)
+		return;
+	ctx->refcount--;
+	if (ctx->refcount > 0)
+		return;
+
+	list_for_each_safe(&ctx->memdevs, memdev, _d, list)
+		free_memdev(memdev, &ctx->memdevs);
+
+	kmod_unref(ctx->kmod_ctx);
+	info(ctx, "context %p released\n", ctx);
+	free(ctx);
+}
+
+/**
+ * cxl_set_log_fn - override default log routine
+ * @ctx: cxl library context
+ * @log_fn: function to be called for logging messages
+ *
+ * The built-in logging writes to stderr. It can be overridden by a
+ * custom function, to plug log messages into the user's logging
+ * functionality.
+ */
+CXL_EXPORT void cxl_set_log_fn(struct cxl_ctx *ctx,
+		void (*cxl_log_fn)(struct cxl_ctx *ctx, int priority,
+			const char *file, int line, const char *fn,
+			const char *format, va_list args))
+{
+	ctx->ctx.log_fn = (log_fn) cxl_log_fn;
+	info(ctx, "custom logging function %p registered\n", cxl_log_fn);
+}
+
+/**
+ * cxl_get_log_priority - retrieve current library loglevel (syslog)
+ * @ctx: cxl library context
+ */
+CXL_EXPORT int cxl_get_log_priority(struct cxl_ctx *ctx)
+{
+	return ctx->ctx.log_priority;
+}
+
+/**
+ * cxl_set_log_priority - set log verbosity
+ * @priority: from syslog.h, LOG_ERR, LOG_INFO, LOG_DEBUG
+ *
+ * Note: LOG_DEBUG requires library be built with "configure --enable-debug"
+ */
+CXL_EXPORT void cxl_set_log_priority(struct cxl_ctx *ctx, int priority)
+{
+	ctx->ctx.log_priority = priority;
+}
+
+static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)
+{
+	const char *devname = devpath_to_devname(cxlmem_base);
+	char *path = calloc(1, strlen(cxlmem_base) + 100);
+	struct cxl_ctx *ctx = parent;
+	struct cxl_memdev *memdev, *memdev_dup;
+	char buf[SYSFS_ATTR_SIZE];
+	struct stat st;
+
+	if (!path)
+		return NULL;
+	dbg(ctx, "%s: base: \'%s\'\n", __func__, cxlmem_base);
+
+	memdev = calloc(1, sizeof(*memdev));
+	if (!memdev)
+		goto err_dev;
+	memdev->id = id;
+	memdev->ctx = ctx;
+
+	sprintf(path, "/dev/cxl/%s", devname);
+	if (stat(path, &st) < 0)
+		goto err_read;
+	memdev->major = major(st.st_rdev);
+	memdev->minor = minor(st.st_rdev);
+
+	sprintf(path, "%s/pmem/size", cxlmem_base);
+	if (sysfs_read_attr(ctx, path, buf) < 0)
+		goto err_read;
+	memdev->pmem_size = strtoull(buf, NULL, 0);
+
+	sprintf(path, "%s/ram/size", cxlmem_base);
+	if (sysfs_read_attr(ctx, path, buf) < 0)
+		goto err_read;
+	memdev->ram_size = strtoull(buf, NULL, 0);
+
+	sprintf(path, "%s/payload_max", cxlmem_base);
+	if (sysfs_read_attr(ctx, path, buf) < 0)
+		goto err_read;
+	memdev->payload_max = strtoull(buf, NULL, 0);
+	if (memdev->payload_max < 0)
+		goto err_read;
+
+	memdev->dev_path = strdup(cxlmem_base);
+	if (!memdev->dev_path)
+		goto err_read;
+
+	sprintf(path, "%s/firmware_version", cxlmem_base);
+	if (sysfs_read_attr(ctx, path, buf) < 0)
+		goto err_read;
+
+	memdev->firmware_version = strdup(buf);
+	if (!memdev->firmware_version)
+		goto err_read;
+
+	memdev->dev_buf = calloc(1, strlen(cxlmem_base) + 50);
+	if (!memdev->dev_buf)
+		goto err_read;
+	memdev->buf_len = strlen(cxlmem_base) + 50;
+
+	cxl_memdev_foreach(ctx, memdev_dup)
+		if (memdev_dup->id == memdev->id) {
+			free_memdev(memdev, NULL);
+			free(path);
+			return memdev_dup;
+		}
+
+	list_add(&ctx->memdevs, &memdev->list);
+	free(path);
+	return memdev;
+
+ err_read:
+	free(memdev->firmware_version);
+	free(memdev->dev_buf);
+	free(memdev->dev_path);
+	free(memdev);
+ err_dev:
+	free(path);
+	return NULL;
+}
+
+static void cxl_memdevs_init(struct cxl_ctx *ctx)
+{
+	if (ctx->memdevs_init)
+		return;
+
+	ctx->memdevs_init = 1;
+
+	sysfs_device_parse(ctx, "/sys/bus/cxl/devices", "mem", ctx,
+			   add_cxl_memdev);
+}
+
+CXL_EXPORT struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev)
+{
+	return memdev->ctx;
+}
+
+CXL_EXPORT struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx)
+{
+	cxl_memdevs_init(ctx);
+
+	return list_top(&ctx->memdevs, struct cxl_memdev, list);
+}
+
+CXL_EXPORT struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev)
+{
+	struct cxl_ctx *ctx = memdev->ctx;
+
+	return list_next(&ctx->memdevs, memdev, list);
+}
+
+CXL_EXPORT int cxl_memdev_get_id(struct cxl_memdev *memdev)
+{
+	return memdev->id;
+}
+
+CXL_EXPORT const char *cxl_memdev_get_devname(struct cxl_memdev *memdev)
+{
+	return devpath_to_devname(memdev->dev_path);
+}
+
+CXL_EXPORT int cxl_memdev_get_major(struct cxl_memdev *memdev)
+{
+	return memdev->major;
+}
+
+CXL_EXPORT int cxl_memdev_get_minor(struct cxl_memdev *memdev)
+{
+	return memdev->minor;
+}
+
+CXL_EXPORT unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev)
+{
+	return memdev->pmem_size;
+}
+
+CXL_EXPORT unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev)
+{
+	return memdev->ram_size;
+}
+
+CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev)
+{
+	return memdev->firmware_version;
+}
diff --git a/cxl/builtin.h b/cxl/builtin.h
new file mode 100644
index 0000000..3797f98
--- /dev/null
+++ b/cxl/builtin.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2020-2021 Intel Corporation. All rights reserved. */
+#ifndef _CXL_BUILTIN_H_
+#define _CXL_BUILTIN_H_
+
+struct cxl_ctx;
+int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx);
+#endif /* _CXL_BUILTIN_H_ */
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
new file mode 100644
index 0000000..fd06790
--- /dev/null
+++ b/cxl/libcxl.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+/* Copyright (C) 2020-2021, Intel Corporation. All rights reserved. */
+#ifndef _LIBCXL_H_
+#define _LIBCXL_H_
+
+#include <stdarg.h>
+#include <unistd.h>
+
+#ifdef HAVE_UUID
+#include <uuid/uuid.h>
+#else
+typedef unsigned char uuid_t[16];
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct cxl_ctx;
+struct cxl_ctx *cxl_ref(struct cxl_ctx *ctx);
+void cxl_unref(struct cxl_ctx *ctx);
+int cxl_new(struct cxl_ctx **ctx);
+void cxl_set_log_fn(struct cxl_ctx *ctx,
+		void (*log_fn)(struct cxl_ctx *ctx, int priority,
+			const char *file, int line, const char *fn,
+			const char *format, va_list args));
+int cxl_get_log_priority(struct cxl_ctx *ctx);
+void cxl_set_log_priority(struct cxl_ctx *ctx, int priority);
+void cxl_set_userdata(struct cxl_ctx *ctx, void *userdata);
+void *cxl_get_userdata(struct cxl_ctx *ctx);
+void cxl_set_private_data(struct cxl_ctx *ctx, void *data);
+void *cxl_get_private_data(struct cxl_ctx *ctx);
+
+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);
+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);
+struct cxl_ctx *cxl_memdev_get_ctx(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);
+
+#define cxl_memdev_foreach(ctx, memdev) \
+        for (memdev = cxl_memdev_get_first(ctx); \
+             memdev != NULL; \
+             memdev = cxl_memdev_get_next(memdev))
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/util/filter.h b/util/filter.h
index 1e1a41c..9a80d65 100644
--- a/util/filter.h
+++ b/util/filter.h
@@ -29,6 +29,8 @@ struct daxctl_dev *util_daxctl_dev_filter(struct daxctl_dev *dev,
 		const char *ident);
 struct daxctl_region *util_daxctl_region_filter(struct daxctl_region *region,
 		const char *ident);
+struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
+		const char *ident);
 
 enum ndctl_namespace_mode util_nsmode(const char *mode);
 const char *util_nsmode_name(enum ndctl_namespace_mode mode);
diff --git a/util/json.h b/util/json.h
index 0f09e36..91918c8 100644
--- a/util/json.h
+++ b/util/json.h
@@ -55,4 +55,7 @@ struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm);
 struct json_object *util_dimm_firmware_to_json(struct ndctl_dimm *dimm,
 		unsigned long flags);
 struct json_object *util_region_capabilities_to_json(struct ndctl_region *region);
+struct cxl_memdev;
+struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
+		unsigned long flags);
 #endif /* __NDCTL_JSON_H__ */
diff --git a/util/main.h b/util/main.h
index c89a843..80b55c4 100644
--- a/util/main.h
+++ b/util/main.h
@@ -10,16 +10,19 @@
 enum program {
 	PROG_NDCTL,
 	PROG_DAXCTL,
+	PROG_CXL,
 };
 
 struct ndctl_ctx;
 struct daxctl_ctx;
+struct cxl_ctx;
 
 struct cmd_struct {
 	const char *cmd;
 	union {
 		int (*n_fn)(int, const char **, struct ndctl_ctx *ctx);
 		int (*d_fn)(int, const char **, struct daxctl_ctx *ctx);
+		int (*c_fn)(int, const char **, struct cxl_ctx *ctx);
 	};
 };
 
diff --git a/cxl/cxl.c b/cxl/cxl.c
new file mode 100644
index 0000000..a7725f8
--- /dev/null
+++ b/cxl/cxl.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2020-2021 Intel Corporation. All rights reserved. */
+/* Copyright (C) 2005 Andreas Ericsson. All rights reserved. */
+
+/* originally copied from perf and git */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <cxl/libcxl.h>
+#include <util/parse-options.h>
+#include <ccan/array_size/array_size.h>
+
+#include <util/strbuf.h>
+#include <util/util.h>
+#include <util/main.h>
+#include <cxl/builtin.h>
+
+const char cxl_usage_string[] = "cxl [--version] [--help] COMMAND [ARGS]";
+const char cxl_more_info_string[] =
+	"See 'cxl help COMMAND' for more information on a specific command.\n"
+	" cxl --list-cmds to see all available commands";
+
+static int cmd_version(int argc, const char **argv, struct cxl_ctx *ctx)
+{
+	printf("%s\n", VERSION);
+	return 0;
+}
+
+static int cmd_help(int argc, const char **argv, struct cxl_ctx *ctx)
+{
+	const char * const builtin_help_subcommands[] = {
+		"list",
+		NULL,
+	};
+	struct option builtin_help_options[] = {
+		OPT_END(),
+	};
+	const char *builtin_help_usage[] = {
+		"cxl help [command]",
+		NULL
+	};
+
+	argc = parse_options_subcommand(argc, argv, builtin_help_options,
+			builtin_help_subcommands, builtin_help_usage, 0);
+
+	if (!argv[0]) {
+		printf("\n usage: %s\n\n", cxl_usage_string);
+		printf("\n %s\n\n", cxl_more_info_string);
+		return 0;
+	}
+
+	return help_show_man_page(argv[0], "cxl", "CXL_MAN_VIEWER");
+}
+
+static struct cmd_struct commands[] = {
+	{ "version", .c_fn = cmd_version },
+	{ "list", .c_fn = cmd_list },
+	{ "help", .c_fn = cmd_help },
+};
+
+int main(int argc, const char **argv)
+{
+	struct cxl_ctx *ctx;
+	int rc;
+
+	/* Look for flags.. */
+	argv++;
+	argc--;
+	main_handle_options(&argv, &argc, cxl_usage_string, commands,
+			ARRAY_SIZE(commands));
+
+	if (argc > 0) {
+		if (!prefixcmp(argv[0], "--"))
+			argv[0] += 2;
+	} else {
+		/* The user didn't specify a command; give them help */
+		printf("\n usage: %s\n\n", cxl_usage_string);
+		printf("\n %s\n\n", cxl_more_info_string);
+		goto out;
+	}
+
+	rc = cxl_new(&ctx);
+	if (rc)
+		goto out;
+	main_handle_internal_command(argc, argv, ctx, commands,
+			ARRAY_SIZE(commands), PROG_CXL);
+	cxl_unref(ctx);
+	fprintf(stderr, "Unknown command: '%s'\n", argv[0]);
+out:
+	return 1;
+}
diff --git a/cxl/list.c b/cxl/list.c
new file mode 100644
index 0000000..3dea73f
--- /dev/null
+++ b/cxl/list.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2020-2021 Intel Corporation. All rights reserved. */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <util/json.h>
+#include <util/filter.h>
+#include <json-c/json.h>
+#include <cxl/libcxl.h>
+#include <util/parse-options.h>
+#include <ccan/array_size/array_size.h>
+
+static struct {
+	bool memdevs;
+	bool idle;
+	bool human;
+} 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;
+	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 int num_list_flags(void)
+{
+	return list.memdevs;
+}
+
+int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
+{
+	const struct option options[] = {
+		OPT_STRING('d', "memdev", &param.memdev, "memory device name",
+			   "filter by CXL memory device name"),
+		OPT_BOOLEAN('D', "memdevs", &list.memdevs,
+			    "include CXL memory device info"),
+		OPT_BOOLEAN('i', "idle", &list.idle, "include idle devices"),
+		OPT_BOOLEAN('u', "human", &list.human,
+				"use human friendly number formats "),
+		OPT_END(),
+	};
+	const char * const u[] = {
+		"cxl list [<options>]",
+		NULL
+	};
+	struct json_object *jdevs = NULL;
+	unsigned long list_flags;
+	struct cxl_memdev *memdev;
+	int i;
+
+	argc = parse_options(argc, argv, options, u, 0);
+	for (i = 0; i < argc; i++)
+		error("unknown parameter \"%s\"\n", argv[i]);
+
+	if (argc)
+		usage_with_options(u, options);
+
+	if (num_list_flags() == 0)
+		list.memdevs = true;
+
+	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 (jdevs)
+		util_display_json_array(stdout, jdevs, list_flags);
+
+	if (did_fail)
+		return -ENOMEM;
+	return 0;
+}
diff --git a/util/filter.c b/util/filter.c
index 8b4aad3..d81dade 100644
--- a/util/filter.c
+++ b/util/filter.c
@@ -12,6 +12,7 @@
 #include <util/filter.h>
 #include <ndctl/libndctl.h>
 #include <daxctl/libdaxctl.h>
+#include <cxl/libcxl.h>
 
 struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *__ident)
 {
@@ -339,6 +340,25 @@ struct daxctl_region *util_daxctl_region_filter(struct daxctl_region *region,
 	return NULL;
 }
 
+struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
+					  const char *ident)
+{
+	int memdev_id;
+
+	if (!ident || strcmp(ident, "all") == 0)
+		return memdev;
+
+	if (strcmp(ident, cxl_memdev_get_devname(memdev)) == 0)
+		return memdev;
+
+	if ((sscanf(ident, "%d", &memdev_id) == 1
+			|| sscanf(ident, "mem%d", &memdev_id) == 1)
+			&& cxl_memdev_get_id(memdev) == memdev_id)
+		return memdev;
+
+	return NULL;
+}
+
 enum ndctl_namespace_mode util_nsmode(const char *mode)
 {
 	if (!mode)
diff --git a/util/json.c b/util/json.c
index a8d2412..3be3a92 100644
--- a/util/json.c
+++ b/util/json.c
@@ -9,6 +9,7 @@
 #include <json-c/printbuf.h>
 #include <ndctl/libndctl.h>
 #include <daxctl/libdaxctl.h>
+#include <cxl/libcxl.h>
 #include <ccan/array_size/array_size.h>
 #include <ccan/short_types/short_types.h>
 #include <ndctl.h>
@@ -1440,3 +1441,28 @@ struct json_object *util_badblock_rec_to_json(u64 block, u64 count,
 	json_object_put(jerr);
 	return NULL;
 }
+
+struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
+		unsigned long flags)
+{
+	const char *devname = cxl_memdev_get_devname(memdev);
+	struct json_object *jdev, *jobj;
+
+	jdev = json_object_new_object();
+	if (!devname || !jdev)
+		return NULL;
+
+	jobj = json_object_new_string(devname);
+	if (jobj)
+		json_object_object_add(jdev, "memdev", jobj);
+
+	jobj = util_json_object_size(cxl_memdev_get_pmem_size(memdev), flags);
+	if (jobj)
+		json_object_object_add(jdev, "pmem_size", jobj);
+
+	jobj = util_json_object_size(cxl_memdev_get_ram_size(memdev), flags);
+	if (jobj)
+		json_object_object_add(jdev, "ram_size", jobj);
+
+	return jdev;
+}
diff --git a/.clang-format b/.clang-format
index 4e00fff..d2e77d0 100644
--- a/.clang-format
+++ b/.clang-format
@@ -77,6 +77,7 @@ ExperimentalAutoDetectBinPacking: false
 # 		-e 's/\(.*foreach.*\)(.*/\1/' \
 # 	| sort -u)
 ForEachMacros:
+  - 'cxl_memdev_foreach'
   - 'daxctl_dev_foreach'
   - 'daxctl_mapping_foreach'
   - 'daxctl_region_foreach'
diff --git a/.gitignore b/.gitignore
index 53512b2..6a97b92 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,9 +16,11 @@ Makefile.in
 *.1
 Documentation/daxctl/asciidoc.conf
 Documentation/ndctl/asciidoc.conf
-Documentation/ndctl/attrs.adoc
+Documentation/cxl/asciidoc.conf
 Documentation/daxctl/asciidoctor-extensions.rb
 Documentation/ndctl/asciidoctor-extensions.rb
+Documentation/cxl/asciidoctor-extensions.rb
+Documentation/ndctl/attrs.adoc
 .dirstamp
 daxctl/config.h
 daxctl/daxctl
diff --git a/Documentation/cxl/Makefile.am b/Documentation/cxl/Makefile.am
new file mode 100644
index 0000000..db98dd7
--- /dev/null
+++ b/Documentation/cxl/Makefile.am
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2020-2021 Intel Corporation. All rights reserved.
+
+if USE_ASCIIDOCTOR
+
+do_subst = sed -e 's,@Utility@,Cxl,g' -e's,@utility@,cxl,g'
+CONFFILE = asciidoctor-extensions.rb
+asciidoctor-extensions.rb: ../asciidoctor-extensions.rb.in
+	$(AM_V_GEN) $(do_subst) < $< > $@
+
+else
+
+do_subst = sed -e 's,UTILITY,cxl,g'
+CONFFILE = asciidoc.conf
+asciidoc.conf: ../asciidoc.conf.in
+	$(AM_V_GEN) $(do_subst) < $< > $@
+
+endif
+
+man1_MANS = \
+	cxl.1 \
+	cxl-list.1
+
+EXTRA_DIST = $(man1_MANS)
+
+CLEANFILES = $(man1_MANS)
+
+XML_DEPS = \
+	../../version.m4 \
+	../copyright.txt \
+	Makefile \
+	$(CONFFILE)
+
+RM ?= rm -f
+
+if USE_ASCIIDOCTOR
+
+%.1: %.txt $(XML_DEPS)
+	$(AM_V_GEN)$(RM) $@+ $@ && \
+		$(ASCIIDOC) -b manpage -d manpage -acompat-mode \
+		-I. -rasciidoctor-extensions \
+		-amansource=cxl -amanmanual="cxl Manual" \
+		-andctl_version=$(VERSION) -o $@+ $< && \
+		mv $@+ $@
+
+else
+
+%.xml: %.txt $(XML_DEPS)
+	$(AM_V_GEN)$(RM) $@+ $@ && \
+		$(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
+		--unsafe -acxl_version=$(VERSION) -o $@+ $< && \
+		mv $@+ $@
+
+%.1: %.xml $(XML_DEPS)
+	$(AM_V_GEN)$(RM) $@ && \
+		$(XMLTO) -o . -m ../manpage-normal.xsl man $<
+
+endif
diff --git a/cxl/Makefile.am b/cxl/Makefile.am
new file mode 100644
index 0000000..98606b9
--- /dev/null
+++ b/cxl/Makefile.am
@@ -0,0 +1,21 @@
+include $(top_srcdir)/Makefile.am.in
+
+bin_PROGRAMS = cxl
+
+DISTCLEANFILES = config.h
+BUILT_SOURCES = config.h
+config.h: $(srcdir)/Makefile.am
+	$(AM_V_GEN) echo "/* Autogenerated by cxl/Makefile.am */" >$@
+
+cxl_SOURCES =\
+		cxl.c \
+		list.c \
+		../util/json.c \
+		builtin.h
+
+cxl_LDADD =\
+	lib/libcxl.la \
+	../libutil.a \
+	$(UUID_LIBS) \
+	$(KMOD_LIBS) \
+	$(JSON_LIBS)
diff --git a/cxl/lib/Makefile.am b/cxl/lib/Makefile.am
new file mode 100644
index 0000000..277f0cd
--- /dev/null
+++ b/cxl/lib/Makefile.am
@@ -0,0 +1,32 @@
+include $(top_srcdir)/Makefile.am.in
+
+%.pc: %.pc.in Makefile
+	$(SED_PROCESS)
+
+pkginclude_HEADERS = ../libcxl.h
+lib_LTLIBRARIES = libcxl.la
+
+libcxl_la_SOURCES =\
+	../libcxl.h \
+	private.h \
+	../../util/sysfs.c \
+	../../util/sysfs.h \
+	../../util/log.c \
+	../../util/log.h \
+	libcxl.c
+
+libcxl_la_LIBADD =\
+	$(UUID_LIBS) \
+	$(KMOD_LIBS)
+
+EXTRA_DIST += libcxl.sym
+
+libcxl_la_LDFLAGS = $(AM_LDFLAGS) \
+	-version-info $(LIBCXL_CURRENT):$(LIBCXL_REVISION):$(LIBCXL_AGE) \
+	-Wl,--version-script=$(top_srcdir)/cxl/lib/libcxl.sym
+libcxl_la_DEPENDENCIES = libcxl.sym
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libcxl.pc
+EXTRA_DIST += libcxl.pc.in
+CLEANFILES += libcxl.pc
diff --git a/cxl/lib/libcxl.pc.in b/cxl/lib/libcxl.pc.in
new file mode 100644
index 0000000..949fcdc
--- /dev/null
+++ b/cxl/lib/libcxl.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libcxl
+Description: Manage CXL devices
+Version: @VERSION@
+Libs: -L${libdir} -lcxl
+Libs.private:
+Cflags: -I${includedir}
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
new file mode 100644
index 0000000..0f6ecad
--- /dev/null
+++ b/cxl/lib/libcxl.sym
@@ -0,0 +1,29 @@
+LIBCXL_1 {
+global:
+	cxl_get_userdata;
+	cxl_set_userdata;
+	cxl_get_private_data;
+	cxl_set_private_data;
+	cxl_ref;
+	cxl_get_log_priority;
+	cxl_set_log_fn;
+	cxl_unref;
+	cxl_set_log_priority;
+	cxl_new;
+local:
+        *;
+};
+
+LIBCXL_2 {
+global:
+	cxl_memdev_get_first;
+	cxl_memdev_get_next;
+	cxl_memdev_get_id;
+	cxl_memdev_get_devname;
+	cxl_memdev_get_major;
+	cxl_memdev_get_minor;
+	cxl_memdev_get_ctx;
+	cxl_memdev_get_pmem_size;
+	cxl_memdev_get_ram_size;
+	cxl_memdev_get_firmware_verison;
+} LIBCXL_1;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 03/21] cxl: add a local copy of the cxl_mem UAPI header
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
  2021-07-01 20:09 ` [ndctl PATCH v3 01/21] ndctl: add .clang-format Vishal Verma
  2021-07-01 20:09 ` [ndctl PATCH v3 02/21] cxl: add a cxl utility and libcxl library Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-10  1:13   ` Dan Williams
  2021-07-01 20:09 ` [ndctl PATCH v3 04/21] libcxl: add support for command query and submission Vishal Verma
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

While CXL functionality is under development, it is useful to have a
local copy of the UAPI header for cxl_mem definitions. This allows
building cxl and libcxl on systems where the appropriate kernel headers
are not installed in the usual locations.

Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 Makefile.am         |   3 +-
 Makefile.am.in      |   1 +
 cxl/cxl_mem.h       | 189 ++++++++++++++++++++++++++++++++++++++++++++
 cxl/lib/Makefile.am |   2 +-
 4 files changed, 193 insertions(+), 2 deletions(-)
 create mode 100644 cxl/cxl_mem.h

diff --git a/Makefile.am b/Makefile.am
index 428fd40..4904ee7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -89,4 +89,5 @@ libutil_a_SOURCES = \
 
 nobase_include_HEADERS = \
 	daxctl/libdaxctl.h \
-	cxl/libcxl.h
+	cxl/libcxl.h \
+	cxl/cxl_mem.h
diff --git a/Makefile.am.in b/Makefile.am.in
index aaeee53..a748128 100644
--- a/Makefile.am.in
+++ b/Makefile.am.in
@@ -11,6 +11,7 @@ AM_CPPFLAGS = \
 	-DNDCTL_MAN_PATH=\""$(mandir)"\" \
 	-I${top_srcdir}/ndctl/lib \
 	-I${top_srcdir}/ndctl \
+	-I${top_srcdir}/cxl \
 	-I${top_srcdir}/ \
 	$(KMOD_CFLAGS) \
 	$(UDEV_CFLAGS) \
diff --git a/cxl/cxl_mem.h b/cxl/cxl_mem.h
new file mode 100644
index 0000000..d38cc9c
--- /dev/null
+++ b/cxl/cxl_mem.h
@@ -0,0 +1,189 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+/* Copyright (C) 2020-2021, Intel Corporation. All rights reserved. */
+/*
+ * CXL IOCTLs for Memory Devices
+ */
+
+#ifndef _UAPI_CXL_MEM_H_
+#define _UAPI_CXL_MEM_H_
+
+#include <linux/types.h>
+#include <sys/user.h>
+#include <unistd.h>
+
+#define __user
+
+/**
+ * DOC: UAPI
+ *
+ * Not all of all commands that the driver supports are always available for use
+ * by userspace. Userspace must check the results from the QUERY command in
+ * order to determine the live set of commands.
+ */
+
+#define CXL_MEM_QUERY_COMMANDS _IOR(0xCE, 1, struct cxl_mem_query_commands)
+#define CXL_MEM_SEND_COMMAND _IOWR(0xCE, 2, struct cxl_send_command)
+
+#define CXL_CMDS                                                          \
+	___C(INVALID, "Invalid Command"),                                 \
+	___C(IDENTIFY, "Identify Command"),                               \
+	___C(RAW, "Raw device command"),                                  \
+	___C(GET_SUPPORTED_LOGS, "Get Supported Logs"),                   \
+	___C(GET_FW_INFO, "Get FW Info"),                                 \
+	___C(GET_PARTITION_INFO, "Get Partition Information"),            \
+	___C(GET_LSA, "Get Label Storage Area"),                          \
+	___C(GET_HEALTH_INFO, "Get Health Info"),                         \
+	___C(GET_LOG, "Get Log"),                                         \
+	___C(SET_PARTITION_INFO, "Set Partition Information"),            \
+	___C(SET_LSA, "Set Label Storage Area"),                          \
+	___C(GET_ALERT_CONFIG, "Get Alert Configuration"),                \
+	___C(SET_ALERT_CONFIG, "Set Alert Configuration"),                \
+	___C(GET_SHUTDOWN_STATE, "Get Shutdown State"),                   \
+	___C(SET_SHUTDOWN_STATE, "Set Shutdown State"),                   \
+	___C(GET_POISON, "Get Poison List"),                              \
+	___C(INJECT_POISON, "Inject Poison"),                             \
+	___C(CLEAR_POISON, "Clear Poison"),                               \
+	___C(GET_SCAN_MEDIA_CAPS, "Get Scan Media Capabilities"),         \
+	___C(SCAN_MEDIA, "Scan Media"),                                   \
+	___C(GET_SCAN_MEDIA, "Get Scan Media Results"),                   \
+	___C(MAX, "invalid / last command")
+
+#define ___C(a, b) CXL_MEM_COMMAND_ID_##a
+enum { CXL_CMDS };
+
+#undef ___C
+#define ___C(a, b) { b }
+static const struct {
+	const char *name;
+} cxl_command_names[] = { CXL_CMDS };
+
+/*
+ * Here's how this actually breaks out:
+ * cxl_command_names[] = {
+ *	[CXL_MEM_COMMAND_ID_INVALID] = { "Invalid Command" },
+ *	[CXL_MEM_COMMAND_ID_IDENTIFY] = { "Identify Command" },
+ *	...
+ *	[CXL_MEM_COMMAND_ID_MAX] = { "invalid / last command" },
+ * };
+ */
+
+#undef ___C
+
+/**
+ * struct cxl_command_info - Command information returned from a query.
+ * @id: ID number for the command.
+ * @flags: Flags that specify command behavior.
+ * @size_in: Expected input size, or -1 if variable length.
+ * @size_out: Expected output size, or -1 if variable length.
+ *
+ * Represents a single command that is supported by both the driver and the
+ * hardware. This is returned as part of an array from the query ioctl. The
+ * following would be a command that takes a variable length input and returns 0
+ * bytes of output.
+ *
+ *  - @id = 10
+ *  - @flags = 0
+ *  - @size_in = -1
+ *  - @size_out = 0
+ *
+ * See struct cxl_mem_query_commands.
+ */
+struct cxl_command_info {
+	__u32 id;
+
+	__u32 flags;
+#define CXL_MEM_COMMAND_FLAG_MASK GENMASK(0, 0)
+
+	__s32 size_in;
+	__s32 size_out;
+};
+
+/**
+ * struct cxl_mem_query_commands - Query supported commands.
+ * @n_commands: In/out parameter. When @n_commands is > 0, the driver will
+ *		return min(num_support_commands, n_commands). When @n_commands
+ *		is 0, driver will return the number of total supported commands.
+ * @rsvd: Reserved for future use.
+ * @commands: Output array of supported commands. This array must be allocated
+ *            by userspace to be at least min(num_support_commands, @n_commands)
+ *
+ * Allow userspace to query the available commands supported by both the driver,
+ * and the hardware. Commands that aren't supported by either the driver, or the
+ * hardware are not returned in the query.
+ *
+ * Examples:
+ *
+ *  - { .n_commands = 0 } // Get number of supported commands
+ *  - { .n_commands = 15, .commands = buf } // Return first 15 (or less)
+ *    supported commands
+ *
+ *  See struct cxl_command_info.
+ */
+struct cxl_mem_query_commands {
+	/*
+	 * Input: Number of commands to return (space allocated by user)
+	 * Output: Number of commands supported by the driver/hardware
+	 *
+	 * If n_commands is 0, kernel will only return number of commands and
+	 * not try to populate commands[], thus allowing userspace to know how
+	 * much space to allocate
+	 */
+	__u32 n_commands;
+	__u32 rsvd;
+
+	struct cxl_command_info __user commands[]; /* out: supported commands */
+};
+
+/**
+ * struct cxl_send_command - Send a command to a memory device.
+ * @id: The command to send to the memory device. This must be one of the
+ *	commands returned by the query command.
+ * @flags: Flags for the command (input).
+ * @raw: Special fields for raw commands
+ * @raw.opcode: Opcode passed to hardware when using the RAW command.
+ * @raw.rsvd: Must be zero.
+ * @rsvd: Must be zero.
+ * @retval: Return value from the memory device (output).
+ * @in: Parameters associated with input payload.
+ * @in.size: Size of the payload to provide to the device (input).
+ * @in.rsvd: Must be zero.
+ * @in.payload: Pointer to memory for payload input, payload is little endian.
+ * @out: Parameters associated with output payload.
+ * @out.size: Size of the payload received from the device (input/output). This
+ *	      field is filled in by userspace to let the driver know how much
+ *	      space was allocated for output. It is populated by the driver to
+ *	      let userspace know how large the output payload actually was.
+ * @out.rsvd: Must be zero.
+ * @out.payload: Pointer to memory for payload output, payload is little endian.
+ *
+ * Mechanism for userspace to send a command to the hardware for processing. The
+ * driver will do basic validation on the command sizes. In some cases even the
+ * payload may be introspected. Userspace is required to allocate large enough
+ * buffers for size_out which can be variable length in certain situations.
+ */
+struct cxl_send_command {
+	__u32 id;
+	__u32 flags;
+	union {
+		struct {
+			__u16 opcode;
+			__u16 rsvd;
+		} raw;
+		__u32 rsvd;
+	};
+	__u32 retval;
+
+	struct {
+		__s32 size;
+		__u32 rsvd;
+		__u64 payload;
+	} in;
+
+	struct {
+		__s32 size;
+		__u32 rsvd;
+		__u64 payload;
+	} out;
+};
+
+#endif
diff --git a/cxl/lib/Makefile.am b/cxl/lib/Makefile.am
index 277f0cd..72c9ccd 100644
--- a/cxl/lib/Makefile.am
+++ b/cxl/lib/Makefile.am
@@ -3,7 +3,7 @@ include $(top_srcdir)/Makefile.am.in
 %.pc: %.pc.in Makefile
 	$(SED_PROCESS)
 
-pkginclude_HEADERS = ../libcxl.h
+pkginclude_HEADERS = ../libcxl.h ../cxl_mem.h
 lib_LTLIBRARIES = libcxl.la
 
 libcxl_la_SOURCES =\
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 04/21] libcxl: add support for command query and submission
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (2 preceding siblings ...)
  2021-07-01 20:09 ` [ndctl PATCH v3 03/21] cxl: add a local copy of the cxl_mem UAPI header Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-13  5:12   ` Dan Williams
  2021-07-01 20:09 ` [ndctl PATCH v3 05/21] libcxl: add support for the 'Identify Device' command Vishal Verma
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Add a set of APIs around 'cxl_cmd' for querying the kernel for supported
commands, allocating and validating command structures against the
supported set, and submitting the commands.

'Query Commands' and 'Send Command' are implemented as IOCTLs in the
kernel. 'Query Commands' returns information about each supported
command, such as flags governing its use, or input and output payload
sizes. This information is used to validate command support, as well as
set up input and output buffers for command submission.

Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 cxl/lib/private.h  |  33 ++++
 cxl/lib/libcxl.c   | 388 +++++++++++++++++++++++++++++++++++++++++++++
 cxl/libcxl.h       |  11 ++
 cxl/lib/libcxl.sym |  13 ++
 4 files changed, 445 insertions(+)

diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index fc88fa1..87ca17e 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -4,6 +4,9 @@
 #define _LIBCXL_PRIVATE_H_
 
 #include <libkmod.h>
+#include <cxl/cxl_mem.h>
+#include <ccan/endian/endian.h>
+#include <ccan/short_types/short_types.h>
 
 #define CXL_EXPORT __attribute__ ((visibility("default")))
 
@@ -21,6 +24,36 @@ struct cxl_memdev {
 	struct kmod_module *module;
 };
 
+enum cxl_cmd_query_status {
+	CXL_CMD_QUERY_NOT_RUN = 0,
+	CXL_CMD_QUERY_OK,
+	CXL_CMD_QUERY_UNSUPPORTED,
+};
+
+/**
+ * struct cxl_cmd - CXL memdev command
+ * @memdev: the memory device to which the command is being sent
+ * @query_cmd: structure for the Linux 'Query commands' ioctl
+ * @send_cmd: structure for the Linux 'Send command' ioctl
+ * @input_payload: buffer for input payload managed by libcxl
+ * @output_payload: buffer for output payload managed by libcxl
+ * @refcount: reference for passing command buffer around
+ * @query_status: status from query_commands
+ * @query_idx: index of 'this' command in the query_commands array
+ * @status: command return status from the device
+ */
+struct cxl_cmd {
+	struct cxl_memdev *memdev;
+	struct cxl_mem_query_commands *query_cmd;
+	struct cxl_send_command *send_cmd;
+	void *input_payload;
+	void *output_payload;
+	int refcount;
+	int query_status;
+	int query_idx;
+	int status;
+};
+
 static inline int check_kmod(struct kmod_ctx *kmod_ctx)
 {
 	return kmod_ctx ? 0 : -ENXIO;
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index d34e7d0..3be4f3d 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -9,6 +9,7 @@
 #include <unistd.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/ioctl.h>
 #include <sys/sysmacros.h>
 #include <uuid/uuid.h>
 #include <ccan/list/list.h>
@@ -17,6 +18,7 @@
 #include <util/log.h>
 #include <util/sysfs.h>
 #include <util/bitmap.h>
+#include <cxl/cxl_mem.h>
 #include <cxl/libcxl.h>
 #include "private.h"
 
@@ -343,3 +345,389 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev
 {
 	return memdev->firmware_version;
 }
+
+CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd)
+{
+	if (!cmd)
+		return;
+	if (--cmd->refcount == 0) {
+		free(cmd->query_cmd);
+		free(cmd->send_cmd);
+		free(cmd->input_payload);
+		free(cmd->output_payload);
+		free(cmd);
+	}
+}
+
+CXL_EXPORT void cxl_cmd_ref(struct cxl_cmd *cmd)
+{
+	cmd->refcount++;
+}
+
+static int cxl_cmd_alloc_query(struct cxl_cmd *cmd, int num_cmds)
+{
+	size_t size;
+
+	if (!cmd)
+		return -EINVAL;
+
+	if (cmd->query_cmd != NULL)
+		free(cmd->query_cmd);
+
+	size = sizeof(struct cxl_mem_query_commands) +
+			(num_cmds * sizeof(struct cxl_command_info));
+	cmd->query_cmd = calloc(1, size);
+	if (!cmd->query_cmd)
+		return -ENOMEM;
+
+	cmd->query_cmd->n_commands = num_cmds;
+
+	return 0;
+}
+
+static struct cxl_cmd *cxl_cmd_new(struct cxl_memdev *memdev)
+{
+	struct cxl_cmd *cmd;
+	size_t size;
+
+	size = sizeof(*cmd);
+	cmd = calloc(1, size);
+	if (!cmd)
+		return NULL;
+
+	cxl_cmd_ref(cmd);
+	cmd->memdev = memdev;
+
+	return cmd;
+}
+
+static int __do_cmd(struct cxl_cmd *cmd, int ioctl_cmd, int fd)
+{
+	void *cmd_buf;
+	int rc;
+
+	switch (ioctl_cmd) {
+	case CXL_MEM_QUERY_COMMANDS:
+		cmd_buf = cmd->query_cmd;
+		break;
+	case CXL_MEM_SEND_COMMAND:
+		cmd_buf = cmd->send_cmd;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	rc = ioctl(fd, ioctl_cmd, cmd_buf);
+	if (rc < 0)
+		rc = -errno;
+
+	return rc;
+}
+
+static int do_cmd(struct cxl_cmd *cmd, int ioctl_cmd)
+{
+	char *path;
+	struct stat st;
+	unsigned int major, minor;
+	int rc = 0, fd;
+	struct cxl_memdev *memdev = cmd->memdev;
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+	const char *devname = cxl_memdev_get_devname(memdev);
+
+	major = cxl_memdev_get_major(memdev);
+	minor = cxl_memdev_get_minor(memdev);
+
+	if (asprintf(&path, "/dev/cxl/%s", devname) < 0)
+		return -ENOMEM;
+
+	fd = open(path, O_RDWR);
+	if (fd < 0) {
+		err(ctx, "failed to open %s: %s\n", path, strerror(errno));
+		rc = -errno;
+		goto out;
+	}
+
+	if (fstat(fd, &st) >= 0 && S_ISCHR(st.st_mode)
+			&& major(st.st_rdev) == major
+			&& minor(st.st_rdev) == minor) {
+		rc = __do_cmd(cmd, ioctl_cmd, fd);
+	} else {
+		err(ctx, "failed to validate %s as a CXL memdev node\n", path);
+		rc = -ENXIO;
+	}
+	close(fd);
+out:
+	free(path);
+	return rc;
+}
+
+static int alloc_do_query(struct cxl_cmd *cmd, int num_cmds)
+{
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(cmd->memdev);
+	int rc;
+
+	rc = cxl_cmd_alloc_query(cmd, num_cmds);
+	if (rc)
+		return rc;
+
+	rc = do_cmd(cmd, CXL_MEM_QUERY_COMMANDS);
+	if (rc < 0)
+		err(ctx, "%s: query commands failed: %s\n",
+			cxl_memdev_get_devname(cmd->memdev),
+			strerror(-rc));
+	return rc;
+}
+
+static int cxl_cmd_do_query(struct cxl_cmd *cmd)
+{
+	struct cxl_memdev *memdev = cmd->memdev;
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+	const char *devname = cxl_memdev_get_devname(memdev);
+	int rc, n_commands;
+
+	switch (cmd->query_status) {
+	case CXL_CMD_QUERY_OK:
+		return 0;
+	case CXL_CMD_QUERY_UNSUPPORTED:
+		return -EOPNOTSUPP;
+	case CXL_CMD_QUERY_NOT_RUN:
+		break;
+	default:
+		err(ctx, "%s: Unknown query_status %d\n",
+			devname, cmd->query_status);
+		return -EINVAL;
+	}
+
+	rc = alloc_do_query(cmd, 0);
+	if (rc)
+		return rc;
+
+	n_commands = cmd->query_cmd->n_commands;
+	dbg(ctx, "%s: supports %d commands\n", devname, n_commands);
+
+	return alloc_do_query(cmd, n_commands);
+}
+
+static int cxl_cmd_validate(struct cxl_cmd *cmd, u32 cmd_id)
+{
+	struct cxl_memdev *memdev = cmd->memdev;
+	struct cxl_mem_query_commands *query = cmd->query_cmd;
+	const char *devname = cxl_memdev_get_devname(memdev);
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+	u32 i;
+
+	for (i = 0; i < query->n_commands; i++) {
+		struct cxl_command_info *cinfo = &query->commands[i];
+		const char *cmd_name = cxl_command_names[cinfo->id].name;
+
+		if (cinfo->id != cmd_id)
+			continue;
+
+		dbg(ctx, "%s: %s: in: %d, out %d, flags: %#08x\n",
+			devname, cmd_name, cinfo->size_in,
+			cinfo->size_out, cinfo->flags);
+
+		cmd->query_idx = i;
+		cmd->query_status = CXL_CMD_QUERY_OK;
+		return 0;
+	}
+	cmd->query_status = CXL_CMD_QUERY_UNSUPPORTED;
+	return -EOPNOTSUPP;
+}
+
+CXL_EXPORT int cxl_cmd_set_input_payload(struct cxl_cmd *cmd, void *buf,
+		int size)
+{
+	struct cxl_memdev *memdev = cmd->memdev;
+
+	if (size > memdev->payload_max || size < 0)
+		return -EINVAL;
+
+	if (!buf) {
+
+		/* If the user didn't supply a buffer, allocate it */
+		cmd->input_payload = calloc(1, size);
+		if (!cmd->input_payload)
+			return -ENOMEM;
+		cmd->send_cmd->in.payload = (u64)cmd->input_payload;
+	} else {
+		/*
+		 * Use user-buffer as is. If an automatic allocation was
+		 * previously made (based on a fixed size from query),
+		 * it will get freed during unref.
+		 */
+		cmd->send_cmd->in.payload = (u64)buf;
+	}
+	cmd->send_cmd->in.size = size;
+
+	return 0;
+}
+
+CXL_EXPORT int cxl_cmd_set_output_payload(struct cxl_cmd *cmd, void *buf,
+		int size)
+{
+	struct cxl_memdev *memdev = cmd->memdev;
+
+	if (size > memdev->payload_max || size < 0)
+		return -EINVAL;
+
+	if (!buf) {
+
+		/* If the user didn't supply a buffer, allocate it */
+		cmd->output_payload = calloc(1, size);
+		if (!cmd->output_payload)
+			return -ENOMEM;
+		cmd->send_cmd->out.payload = (u64)cmd->output_payload;
+	} else {
+		/*
+		 * Use user-buffer as is. If an automatic allocation was
+		 * previously made (based on a fixed size from query),
+		 * it will get freed during unref.
+		 */
+		cmd->send_cmd->out.payload = (u64)buf;
+	}
+	cmd->send_cmd->out.size = size;
+
+	return 0;
+}
+
+static int cxl_cmd_alloc_send(struct cxl_cmd *cmd, u32 cmd_id)
+{
+	struct cxl_mem_query_commands *query = cmd->query_cmd;
+	struct cxl_command_info *cinfo = &query->commands[cmd->query_idx];
+	size_t size;
+
+	if (!query)
+		return -EINVAL;
+
+	size = sizeof(struct cxl_send_command);
+	cmd->send_cmd = calloc(1, size);
+	if (!cmd->send_cmd)
+		return -ENOMEM;
+
+	if (cinfo->id != cmd_id)
+		return -EINVAL;
+
+	cmd->send_cmd->id = cmd_id;
+
+	if (cinfo->size_in > 0) {
+		cmd->input_payload = calloc(1, cinfo->size_in);
+		if (!cmd->input_payload)
+			return -ENOMEM;
+		cmd->send_cmd->in.payload = (u64)cmd->input_payload;
+		cmd->send_cmd->in.size = cinfo->size_in;
+	}
+	if (cinfo->size_out > 0) {
+		cmd->output_payload = calloc(1, cinfo->size_out);
+		if (!cmd->output_payload)
+			return -ENOMEM;
+		cmd->send_cmd->out.payload = (u64)cmd->output_payload;
+		cmd->send_cmd->out.size = cinfo->size_out;
+	}
+
+	return 0;
+}
+
+static struct cxl_cmd *cxl_cmd_new_generic(struct cxl_memdev *memdev,
+		u32 cmd_id)
+{
+	const char *devname = cxl_memdev_get_devname(memdev);
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+	struct cxl_cmd *cmd;
+	int rc;
+
+	cmd = cxl_cmd_new(memdev);
+	if (!cmd)
+		return NULL;
+
+	rc = cxl_cmd_do_query(cmd);
+	if (rc) {
+		err(ctx, "%s: query returned: %s\n", devname, strerror(-rc));
+		goto fail;
+	}
+
+	rc = cxl_cmd_validate(cmd, cmd_id);
+	if (rc) {
+		errno = -rc;
+		goto fail;
+	}
+
+	rc = cxl_cmd_alloc_send(cmd, cmd_id);
+	if (rc) {
+		errno = -rc;
+		goto fail;
+	}
+
+	return cmd;
+
+fail:
+	cxl_cmd_unref(cmd);
+	return NULL;
+}
+
+CXL_EXPORT const char *cxl_cmd_get_devname(struct cxl_cmd *cmd)
+{
+	return cxl_memdev_get_devname(cmd->memdev);
+}
+
+CXL_EXPORT struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev,
+		int opcode)
+{
+	struct cxl_cmd *cmd;
+
+	/* opcode '0' is reserved */
+	if (opcode <= 0) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	cmd = cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_RAW);
+	if (!cmd)
+		return NULL;
+
+	cmd->send_cmd->raw.opcode = opcode;
+	return cmd;
+}
+
+CXL_EXPORT int cxl_cmd_submit(struct cxl_cmd *cmd)
+{
+	struct cxl_memdev *memdev = cmd->memdev;
+	const char *devname = cxl_memdev_get_devname(memdev);
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+	int rc;
+
+	switch (cmd->query_status) {
+	case CXL_CMD_QUERY_OK:
+		break;
+	case CXL_CMD_QUERY_UNSUPPORTED:
+		return -EOPNOTSUPP;
+	case CXL_CMD_QUERY_NOT_RUN:
+		return -EINVAL;
+	default:
+		err(ctx, "%s: Unknown query_status %d\n",
+			devname, cmd->query_status);
+		return -EINVAL;
+	}
+
+	dbg(ctx, "%s: submitting SEND cmd: in: %d, out: %d\n", devname,
+		cmd->send_cmd->in.size, cmd->send_cmd->out.size);
+	rc = do_cmd(cmd, CXL_MEM_SEND_COMMAND);
+	if (rc < 0)
+		err(ctx, "%s: send command failed: %s\n",
+			devname, strerror(-rc));
+	cmd->status = cmd->send_cmd->retval;
+	dbg(ctx, "%s: got SEND cmd: in: %d, out: %d, retval: %d\n", devname,
+		cmd->send_cmd->in.size, cmd->send_cmd->out.size, cmd->status);
+
+	return rc;
+}
+
+CXL_EXPORT int cxl_cmd_get_mbox_status(struct cxl_cmd *cmd)
+{
+	return cmd->status;
+}
+
+CXL_EXPORT int cxl_cmd_get_out_size(struct cxl_cmd *cmd)
+{
+	return cmd->send_cmd->out.size;
+}
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index fd06790..6e87b80 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -48,6 +48,17 @@ const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev);
              memdev != NULL; \
              memdev = cxl_memdev_get_next(memdev))
 
+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);
+int cxl_cmd_set_input_payload(struct cxl_cmd *cmd, void *in, int size);
+int cxl_cmd_set_output_payload(struct cxl_cmd *cmd, void *out, int size);
+void cxl_cmd_ref(struct cxl_cmd *cmd);
+void cxl_cmd_unref(struct cxl_cmd *cmd);
+int cxl_cmd_submit(struct cxl_cmd *cmd);
+int cxl_cmd_get_mbox_status(struct cxl_cmd *cmd);
+int cxl_cmd_get_out_size(struct cxl_cmd *cmd);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 0f6ecad..493429c 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -27,3 +27,16 @@ global:
 	cxl_memdev_get_ram_size;
 	cxl_memdev_get_firmware_verison;
 } LIBCXL_1;
+
+LIBCXL_3 {
+global:
+	cxl_cmd_get_devname;
+	cxl_cmd_new_raw;
+	cxl_cmd_set_input_payload;
+	cxl_cmd_set_output_payload;
+	cxl_cmd_ref;
+	cxl_cmd_unref;
+	cxl_cmd_submit;
+	cxl_cmd_get_mbox_status;
+	cxl_cmd_get_out_size;
+} LIBCXL_2;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 05/21] libcxl: add support for the 'Identify Device' command
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (3 preceding siblings ...)
  2021-07-01 20:09 ` [ndctl PATCH v3 04/21] libcxl: add support for command query and submission Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-15 23:50   ` Dan Williams
  2021-07-01 20:09 ` [ndctl PATCH v3 06/21] test: rename 'ndctl_test' to 'test_ctx' Vishal Verma
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Add APIs to allocate and send an 'Identify Device' command, and
accessors to retrieve some of the fields from the resulting data.

Only add a handful accessor functions; more can be added as the need
arises. The fields added are fw_revision, partition_align, and
lsa_size.

Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 cxl/lib/private.h  | 19 ++++++++++++++++++
 cxl/lib/libcxl.c   | 49 ++++++++++++++++++++++++++++++++++++++++++++++
 cxl/libcxl.h       |  4 ++++
 cxl/lib/libcxl.sym |  4 ++++
 4 files changed, 76 insertions(+)

diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index 87ca17e..3273f21 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -54,6 +54,25 @@ struct cxl_cmd {
 	int status;
 };
 
+#define CXL_CMD_IDENTIFY_FW_REV_LENGTH 0x10
+
+struct cxl_cmd_identify {
+	char fw_revision[CXL_CMD_IDENTIFY_FW_REV_LENGTH];
+	le64 total_capacity;
+	le64 volatile_capacity;
+	le64 persistent_capacity;
+	le64 partition_align;
+	le16 info_event_log_size;
+	le16 warning_event_log_size;
+	le16 failure_event_log_size;
+	le16 fatal_event_log_size;
+	le32 lsa_size;
+	u8 poison_list_max_mer[3];
+	le16 inject_poison_limit;
+	u8 poison_caps;
+	u8 qos_telemetry_caps;
+} __attribute__((packed));
+
 static inline int check_kmod(struct kmod_ctx *kmod_ctx)
 {
 	return kmod_ctx ? 0 : -ENXIO;
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 3be4f3d..06a6c20 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -13,7 +13,10 @@
 #include <sys/sysmacros.h>
 #include <uuid/uuid.h>
 #include <ccan/list/list.h>
+#include <ccan/endian/endian.h>
+#include <ccan/minmax/minmax.h>
 #include <ccan/array_size/array_size.h>
+#include <ccan/short_types/short_types.h>
 
 #include <util/log.h>
 #include <util/sysfs.h>
@@ -670,6 +673,52 @@ CXL_EXPORT const char *cxl_cmd_get_devname(struct cxl_cmd *cmd)
 	return cxl_memdev_get_devname(cmd->memdev);
 }
 
+CXL_EXPORT struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev)
+{
+	return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_IDENTIFY);
+}
+
+CXL_EXPORT int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev,
+		int fw_len)
+{
+	struct cxl_cmd_identify *id = (void *)cmd->send_cmd->out.payload;
+
+	if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_IDENTIFY)
+		return -EINVAL;
+	if (cmd->status < 0)
+		return cmd->status;
+
+	if (fw_len > 0)
+		memcpy(fw_rev, id->fw_revision,
+			min(fw_len, CXL_CMD_IDENTIFY_FW_REV_LENGTH));
+	return 0;
+}
+
+CXL_EXPORT unsigned long long cxl_cmd_identify_get_partition_align(
+		struct cxl_cmd *cmd)
+{
+	struct cxl_cmd_identify *id = (void *)cmd->send_cmd->out.payload;
+
+	if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_IDENTIFY)
+		return -EINVAL;
+	if (cmd->status < 0)
+		return cmd->status;
+
+	return le64_to_cpu(id->partition_align);
+}
+
+CXL_EXPORT unsigned int cxl_cmd_identify_get_lsa_size(struct cxl_cmd *cmd)
+{
+	struct cxl_cmd_identify *id = (void *)cmd->send_cmd->out.payload;
+
+	if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_IDENTIFY)
+		return -EINVAL;
+	if (cmd->status < 0)
+		return cmd->status;
+
+	return le32_to_cpu(id->lsa_size);
+}
+
 CXL_EXPORT struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev,
 		int opcode)
 {
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index 6e87b80..9ed8c83 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -58,6 +58,10 @@ void cxl_cmd_unref(struct cxl_cmd *cmd);
 int cxl_cmd_submit(struct cxl_cmd *cmd);
 int cxl_cmd_get_mbox_status(struct cxl_cmd *cmd);
 int cxl_cmd_get_out_size(struct cxl_cmd *cmd);
+struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev);
+int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev, int fw_len);
+unsigned long long cxl_cmd_identify_get_partition_align(struct cxl_cmd *cmd);
+unsigned int cxl_cmd_identify_get_lsa_size(struct cxl_cmd *cmd);
 
 #ifdef __cplusplus
 } /* extern "C" */
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 493429c..d6aa0b2 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -39,4 +39,8 @@ global:
 	cxl_cmd_submit;
 	cxl_cmd_get_mbox_status;
 	cxl_cmd_get_out_size;
+	cxl_cmd_new_identify;
+	cxl_cmd_identify_get_fw_rev;
+	cxl_cmd_identify_get_partition_align;
+	cxl_cmd_identify_get_lsa_size;
 } LIBCXL_2;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 06/21] test: rename 'ndctl_test' to 'test_ctx'
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (4 preceding siblings ...)
  2021-07-01 20:09 ` [ndctl PATCH v3 05/21] libcxl: add support for the 'Identify Device' command Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-15 23:51   ` Dan Williams
  2021-07-01 20:09 ` [ndctl PATCH v3 07/21] test: rename 'ndctl_test_*' helpers to 'test_*' Vishal Verma
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

In preparation for using the common test core for libcxl tests, rename
the 'ndctl_test' structure to 'test_ctx'

Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 test.h                        | 36 +++++++++++++++++------------------
 ndctl/bat.c                   |  2 +-
 ndctl/test.c                  |  2 +-
 test/ack-shutdown-count-set.c |  8 ++++----
 test/blk_namespaces.c         |  6 +++---
 test/core.c                   | 20 +++++++++----------
 test/dax-dev.c                |  4 ++--
 test/dax-pmd.c                |  9 +++++----
 test/dax-poison.c             |  4 ++--
 test/daxdev-errors.c          |  2 +-
 test/device-dax.c             | 10 +++++-----
 test/dpa-alloc.c              |  6 +++---
 test/dsm-fail.c               |  6 +++---
 test/libndctl.c               | 34 ++++++++++++++++-----------------
 test/multi-pmem.c             |  9 +++++----
 test/parent-uuid.c            |  5 +++--
 test/pmem_namespaces.c        |  6 +++---
 test/revoke-devmem.c          |  6 +++---
 18 files changed, 89 insertions(+), 86 deletions(-)

diff --git a/test.h b/test.h
index 7de13fe..c5b9d4a 100644
--- a/test.h
+++ b/test.h
@@ -4,16 +4,16 @@
 #define __TEST_H__
 #include <stdbool.h>
 
-struct ndctl_test;
+struct test_ctx;
 struct ndctl_ctx;
-struct ndctl_test *ndctl_test_new(unsigned int kver);
-int ndctl_test_result(struct ndctl_test *test, int rc);
-int ndctl_test_get_skipped(struct ndctl_test *test);
-int ndctl_test_get_attempted(struct ndctl_test *test);
-int __ndctl_test_attempt(struct ndctl_test *test, unsigned int kver,
+struct test_ctx *ndctl_test_new(unsigned int kver);
+int ndctl_test_result(struct test_ctx *test, int rc);
+int ndctl_test_get_skipped(struct test_ctx *test);
+int ndctl_test_get_attempted(struct test_ctx *test);
+int __ndctl_test_attempt(struct test_ctx *test, unsigned int kver,
 		const char *caller, int line);
 #define ndctl_test_attempt(t, v) __ndctl_test_attempt(t, v, __func__, __LINE__)
-void __ndctl_test_skip(struct ndctl_test *test, const char *caller, int line);
+void __ndctl_test_skip(struct test_ctx *test, const char *caller, int line);
 #define ndctl_test_skip(t) __ndctl_test_skip(t, __func__, __LINE__)
 struct ndctl_namespace *ndctl_get_test_dev(struct ndctl_ctx *ctx);
 void builtin_xaction_namespace_reset(void);
@@ -22,27 +22,27 @@ struct kmod_ctx;
 struct kmod_module;
 int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
 		struct ndctl_ctx *nd_ctx, int log_level,
-		struct ndctl_test *test);
+		struct test_ctx *test);
 
 struct ndctl_ctx;
-int test_parent_uuid(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
-int test_multi_pmem(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
+int test_parent_uuid(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx);
+int test_multi_pmem(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx);
 int test_dax_directio(int dax_fd, unsigned long align, void *dax_addr, off_t offset);
-int test_dax_remap(struct ndctl_test *test, int dax_fd, unsigned long align, void *dax_addr,
+int test_dax_remap(struct test_ctx *test, int dax_fd, unsigned long align, void *dax_addr,
 		off_t offset, bool fsdax);
 #ifdef ENABLE_POISON
-int test_dax_poison(struct ndctl_test *test, int dax_fd, unsigned long align,
+int test_dax_poison(struct test_ctx *test, int dax_fd, unsigned long align,
 		void *dax_addr, off_t offset, bool fsdax);
 #else
-static inline int test_dax_poison(struct ndctl_test *test, int dax_fd,
+static inline int test_dax_poison(struct test_ctx *test, int dax_fd,
 		unsigned long align, void *dax_addr, off_t offset, bool fsdax)
 {
 	return 0;
 }
 #endif
-int test_dpa_alloc(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
-int test_dsm_fail(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
-int test_libndctl(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
-int test_blk_namespaces(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
-int test_pmem_namespaces(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
+int test_dpa_alloc(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx);
+int test_dsm_fail(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx);
+int test_libndctl(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx);
+int test_blk_namespaces(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx);
+int test_pmem_namespaces(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx);
 #endif /* __TEST_H__ */
diff --git a/ndctl/bat.c b/ndctl/bat.c
index ef00a3b..18773fd 100644
--- a/ndctl/bat.c
+++ b/ndctl/bat.c
@@ -9,7 +9,7 @@
 int cmd_bat(int argc, const char **argv, struct ndctl_ctx *ctx)
 {
 	int loglevel = LOG_DEBUG, i, rc;
-	struct ndctl_test *test;
+	struct test_ctx *test;
 	bool force = false;
 	const char * const u[] = {
 		"ndctl bat [<options>]",
diff --git a/ndctl/test.c b/ndctl/test.c
index 6a05d8d..7af3681 100644
--- a/ndctl/test.c
+++ b/ndctl/test.c
@@ -18,7 +18,7 @@ static char *result(int rc)
 
 int cmd_test(int argc, const char **argv, struct ndctl_ctx *ctx)
 {
-	struct ndctl_test *test;
+	struct test_ctx *test;
 	int loglevel = LOG_DEBUG, i, rc;
 	const char * const u[] = {
 		"ndctl test [<options>]",
diff --git a/test/ack-shutdown-count-set.c b/test/ack-shutdown-count-set.c
index c561ff3..d5c7bcb 100644
--- a/test/ack-shutdown-count-set.c
+++ b/test/ack-shutdown-count-set.c
@@ -54,7 +54,7 @@ static void reset_bus(struct ndctl_bus *bus)
 		ndctl_dimm_zero_labels(dimm);
 }
 
-static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
+static int do_test(struct ndctl_ctx *ctx, struct test_ctx *test)
 {
 	struct ndctl_bus *bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0");
 	struct ndctl_dimm *dimm;
@@ -91,8 +91,8 @@ out:
 	return rc;
 }
 
-static int test_ack_shutdown_count_set(int loglevel, struct ndctl_test *test,
-		struct ndctl_ctx *ctx)
+static int test_ack_shutdown_count_set(int loglevel, struct test_ctx *test,
+				       struct ndctl_ctx *ctx)
 {
 	struct kmod_module *mod;
 	struct kmod_ctx *kmod_ctx;
@@ -117,7 +117,7 @@ static int test_ack_shutdown_count_set(int loglevel, struct ndctl_test *test,
 
 int main(int argc, char *argv[])
 {
-	struct ndctl_test *test = ndctl_test_new(0);
+	struct test_ctx *test = ndctl_test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
diff --git a/test/blk_namespaces.c b/test/blk_namespaces.c
index f076e85..4919890 100644
--- a/test/blk_namespaces.c
+++ b/test/blk_namespaces.c
@@ -198,8 +198,8 @@ static int ns_do_io(const char *bdev)
 
 static const char *comm = "test-blk-namespaces";
 
-int test_blk_namespaces(int log_level, struct ndctl_test *test,
-		struct ndctl_ctx *ctx)
+int test_blk_namespaces(int log_level, struct test_ctx *test,
+			struct ndctl_ctx *ctx)
 {
 	char bdev[50];
 	int rc = -ENXIO;
@@ -337,7 +337,7 @@ int test_blk_namespaces(int log_level, struct ndctl_test *test,
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct ndctl_test *test = ndctl_test_new(0);
+	struct test_ctx *test = ndctl_test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
diff --git a/test/core.c b/test/core.c
index 2b03aa9..1ef0ac4 100644
--- a/test/core.c
+++ b/test/core.c
@@ -16,7 +16,7 @@
 
 #define KVER_STRLEN 20
 
-struct ndctl_test {
+struct test_ctx {
 	unsigned int kver;
 	int attempt;
 	int skip;
@@ -39,9 +39,9 @@ static unsigned int get_system_kver(void)
 	return KERNEL_VERSION(a,b,c);
 }
 
-struct ndctl_test *ndctl_test_new(unsigned int kver)
+struct test_ctx *ndctl_test_new(unsigned int kver)
 {
-	struct ndctl_test *test = calloc(1, sizeof(*test));
+	struct test_ctx *test = calloc(1, sizeof(*test));
 
 	if (!test)
 		return NULL;
@@ -54,7 +54,7 @@ struct ndctl_test *ndctl_test_new(unsigned int kver)
 	return test;
 }
 
-int ndctl_test_result(struct ndctl_test *test, int rc)
+int ndctl_test_result(struct test_ctx *test, int rc)
 {
 	if (ndctl_test_get_skipped(test))
 		fprintf(stderr, "attempted: %d skipped: %d\n",
@@ -75,8 +75,8 @@ static char *kver_str(char *buf, unsigned int kver)
 	return buf;
 }
 
-int __ndctl_test_attempt(struct ndctl_test *test, unsigned int kver,
-		const char *caller, int line)
+int __ndctl_test_attempt(struct test_ctx *test, unsigned int kver,
+			 const char *caller, int line)
 {
 	char requires[KVER_STRLEN], current[KVER_STRLEN];
 
@@ -90,26 +90,26 @@ int __ndctl_test_attempt(struct ndctl_test *test, unsigned int kver,
 	return 0;
 }
 
-void __ndctl_test_skip(struct ndctl_test *test, const char *caller, int line)
+void __ndctl_test_skip(struct test_ctx *test, const char *caller, int line)
 {
 	test->skip++;
 	test->attempt = test->skip;
 	fprintf(stderr, "%s: explicit skip %s:%d\n", __func__, caller, line);
 }
 
-int ndctl_test_get_attempted(struct ndctl_test *test)
+int ndctl_test_get_attempted(struct test_ctx *test)
 {
 	return test->attempt;
 }
 
-int ndctl_test_get_skipped(struct ndctl_test *test)
+int ndctl_test_get_skipped(struct test_ctx *test)
 {
 	return test->skip;
 }
 
 int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
 		struct ndctl_ctx *nd_ctx, int log_level,
-		struct ndctl_test *test)
+		struct test_ctx *test)
 {
 	int rc, family = -1;
 	unsigned int i;
diff --git a/test/dax-dev.c b/test/dax-dev.c
index 6a1b76d..99eda26 100644
--- a/test/dax-dev.c
+++ b/test/dax-dev.c
@@ -87,7 +87,7 @@ struct ndctl_namespace *ndctl_get_test_dev(struct ndctl_ctx *ctx)
 	return rc ? NULL : ndns;
 }
 
-static int emit_e820_device(int loglevel, struct ndctl_test *test)
+static int emit_e820_device(int loglevel, struct test_ctx *test)
 {
 	int err;
 	struct ndctl_ctx *ctx;
@@ -118,7 +118,7 @@ static int emit_e820_device(int loglevel, struct ndctl_test *test)
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct ndctl_test *test = ndctl_test_new(0);
+	struct test_ctx *test = ndctl_test_new(0);
 	int rc;
 
 	if (!test) {
diff --git a/test/dax-pmd.c b/test/dax-pmd.c
index 7648e34..e9dedb9 100644
--- a/test/dax-pmd.c
+++ b/test/dax-pmd.c
@@ -37,8 +37,9 @@ static void sigbus(int sig, siginfo_t *siginfo, void *d)
 	siglongjmp(sj_env, 1);
 }
 
-int test_dax_remap(struct ndctl_test *test, int dax_fd, unsigned long align, void *dax_addr,
-		off_t offset, bool fsdax)
+int test_dax_remap(struct test_ctx *test, int dax_fd, unsigned long align,
+		   void *dax_addr,
+		   off_t offset, bool fsdax)
 {
 	void *anon, *remap, *addr;
 	struct sigaction act;
@@ -272,7 +273,7 @@ int test_dax_directio(int dax_fd, unsigned long align, void *dax_addr, off_t off
 }
 
 /* test_pmd assumes that fd references a pre-allocated + dax-capable file */
-static int test_pmd(struct ndctl_test *test, int fd)
+static int test_pmd(struct test_ctx *test, int fd)
 {
 	unsigned long long m_align, p_align, pmd_off;
 	static const bool fsdax = true;
@@ -351,7 +352,7 @@ err_mmap:
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct ndctl_test *test = ndctl_test_new(0);
+	struct test_ctx *test = ndctl_test_new(0);
 	int fd, rc;
 
 	if (!test) {
diff --git a/test/dax-poison.c b/test/dax-poison.c
index 4e09761..dc62742 100644
--- a/test/dax-poison.c
+++ b/test/dax-poison.c
@@ -44,8 +44,8 @@ static void sigbus_hdl(int sig, siginfo_t *si, void *ptr)
 	siglongjmp(sj_env, 1);
 }
 
-int test_dax_poison(struct ndctl_test *test, int dax_fd, unsigned long align,
-		void *dax_addr, off_t offset, bool fsdax)
+int test_dax_poison(struct test_ctx *test, int dax_fd, unsigned long align,
+		    void *dax_addr, off_t offset, bool fsdax)
 {
 	unsigned char *addr = MAP_FAILED;
 	struct sigaction act;
diff --git a/test/daxdev-errors.c b/test/daxdev-errors.c
index fbbea21..4cb6b4d 100644
--- a/test/daxdev-errors.c
+++ b/test/daxdev-errors.c
@@ -29,7 +29,7 @@
 
 struct check_cmd {
 	struct ndctl_cmd *cmd;
-	struct ndctl_test *test;
+	struct test_ctx *test;
 };
 
 static sigjmp_buf sj_env;
diff --git a/test/device-dax.c b/test/device-dax.c
index aad8fa5..1837b4d 100644
--- a/test/device-dax.c
+++ b/test/device-dax.c
@@ -90,7 +90,7 @@ static void sigbus(int sig, siginfo_t *siginfo, void *d)
 #define VERIFY_TIME(x) (suseconds_t) ((ALIGN(x, SZ_2M) / SZ_4K) * 60)
 
 static int verify_data(struct daxctl_dev *dev, char *dax_buf,
-		unsigned long align, int salt, struct ndctl_test *test)
+		unsigned long align, int salt, struct test_ctx *test)
 {
 	struct timeval tv1, tv2, tv_diff;
 	unsigned long i;
@@ -167,7 +167,7 @@ static int test_dax_soft_offline(struct ndctl_test *test, struct ndctl_namespace
 }
 
 static int __test_device_dax(unsigned long align, int loglevel,
-		struct ndctl_test *test, struct ndctl_ctx *ctx)
+		struct test_ctx *test, struct ndctl_ctx *ctx)
 {
 	unsigned long i;
 	struct sigaction act;
@@ -406,8 +406,8 @@ static int __test_device_dax(unsigned long align, int loglevel,
 	return rc;
 }
 
-static int test_device_dax(int loglevel, struct ndctl_test *test,
-		struct ndctl_ctx *ctx)
+static int test_device_dax(int loglevel, struct test_ctx *test,
+			   struct ndctl_ctx *ctx)
 {
 	unsigned long i, aligns[] = { SZ_4K, SZ_2M, SZ_1G };
 	int rc;
@@ -423,7 +423,7 @@ static int test_device_dax(int loglevel, struct ndctl_test *test,
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct ndctl_test *test = ndctl_test_new(0);
+	struct test_ctx *test = ndctl_test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
diff --git a/test/dpa-alloc.c b/test/dpa-alloc.c
index 59185cf..d0f5271 100644
--- a/test/dpa-alloc.c
+++ b/test/dpa-alloc.c
@@ -32,7 +32,7 @@ struct test_dpa_namespace {
 
 #define MIN_SIZE SZ_4M
 
-static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
+static int do_test(struct ndctl_ctx *ctx, struct test_ctx *test)
 {
 	unsigned int default_available_slots, available_slots, i;
 	struct ndctl_region *region, *blk_region = NULL;
@@ -280,7 +280,7 @@ static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
 	return 0;
 }
 
-int test_dpa_alloc(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
+int test_dpa_alloc(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
 {
 	struct kmod_module *mod;
 	struct kmod_ctx *kmod_ctx;
@@ -307,7 +307,7 @@ int test_dpa_alloc(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct ndctl_test *test = ndctl_test_new(0);
+	struct test_ctx *test = ndctl_test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
diff --git a/test/dsm-fail.c b/test/dsm-fail.c
index 0a6383d..74c56de 100644
--- a/test/dsm-fail.c
+++ b/test/dsm-fail.c
@@ -174,7 +174,7 @@ static int test_regions_enable(struct ndctl_bus *bus,
 	return 0;
 }
 
-static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
+static int do_test(struct ndctl_ctx *ctx, struct test_ctx *test)
 {
 	struct ndctl_bus *bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0");
 	struct ndctl_region *region, *victim_region = NULL;
@@ -339,7 +339,7 @@ static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
 	return err;
 }
 
-int test_dsm_fail(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
+int test_dsm_fail(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
 {
 	struct kmod_module *mod;
 	struct kmod_ctx *kmod_ctx;
@@ -364,7 +364,7 @@ int test_dsm_fail(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct ndctl_test *test = ndctl_test_new(0);
+	struct test_ctx *test = ndctl_test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
diff --git a/test/libndctl.c b/test/libndctl.c
index d9b50f4..30d19db 100644
--- a/test/libndctl.c
+++ b/test/libndctl.c
@@ -613,7 +613,7 @@ static int validate_dax(struct ndctl_dax *dax)
 	const char *devname = ndctl_namespace_get_devname(ndns);
 	struct ndctl_region *region = ndctl_dax_get_region(dax);
 	struct ndctl_ctx *ctx = ndctl_dax_get_ctx(dax);
-	struct ndctl_test *test = ndctl_get_private_data(ctx);
+	struct test_ctx *test = ndctl_get_private_data(ctx);
 	struct daxctl_region *dax_region = NULL, *found;
 	int rc = -ENXIO, fd, count, dax_expect;
 	struct daxctl_dev *dax_dev, *seed;
@@ -725,7 +725,7 @@ static int __check_dax_create(struct ndctl_region *region,
 {
 	struct ndctl_dax *dax_seed = ndctl_region_get_dax_seed(region);
 	struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
-	struct ndctl_test *test = ndctl_get_private_data(ctx);
+	struct test_ctx *test = ndctl_get_private_data(ctx);
 	enum ndctl_namespace_mode mode;
 	struct ndctl_dax *dax;
 	const char *devname;
@@ -835,7 +835,7 @@ static int __check_pfn_create(struct ndctl_region *region,
 {
 	struct ndctl_pfn *pfn_seed = ndctl_region_get_pfn_seed(region);
 	struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
-	struct ndctl_test *test = ndctl_get_private_data(ctx);
+	struct test_ctx *test = ndctl_get_private_data(ctx);
 	enum ndctl_namespace_mode mode;
 	struct ndctl_pfn *pfn;
 	const char *devname;
@@ -978,7 +978,7 @@ static int check_btt_size(struct ndctl_btt *btt)
 	unsigned long long actual, expect;
 	int size_select, sect_select;
 	struct ndctl_ctx *ctx = ndctl_btt_get_ctx(btt);
-	struct ndctl_test *test = ndctl_get_private_data(ctx);
+	struct test_ctx *test = ndctl_get_private_data(ctx);
 	struct ndctl_namespace *ndns = ndctl_btt_get_namespace(btt);
 	unsigned long long expect_table[][2] = {
 		[0] = {
@@ -1049,7 +1049,7 @@ static int check_btt_create(struct ndctl_region *region, struct ndctl_namespace
 		struct namespace *namespace)
 {
 	struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
-	struct ndctl_test *test = ndctl_get_private_data(ctx);
+	struct test_ctx *test = ndctl_get_private_data(ctx);
 	struct btt *btt_s = namespace->btt_settings;
 	int i, fd, retry = 10;
 	struct ndctl_btt *btt;
@@ -1257,7 +1257,7 @@ static int check_pfn_autodetect(struct ndctl_bus *bus,
 	struct ndctl_region *region = ndctl_namespace_get_region(ndns);
 	struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
 	const char *devname = ndctl_namespace_get_devname(ndns);
-	struct ndctl_test *test = ndctl_get_private_data(ctx);
+	struct test_ctx *test = ndctl_get_private_data(ctx);
 	struct pfn *auto_pfn = namespace->pfn_settings;
 	struct ndctl_pfn *pfn, *found = NULL;
 	enum ndctl_namespace_mode mode;
@@ -1354,7 +1354,7 @@ static int check_dax_autodetect(struct ndctl_bus *bus,
 	struct ndctl_region *region = ndctl_namespace_get_region(ndns);
 	struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
 	const char *devname = ndctl_namespace_get_devname(ndns);
-	struct ndctl_test *test = ndctl_get_private_data(ctx);
+	struct test_ctx *test = ndctl_get_private_data(ctx);
 	struct dax *auto_dax = namespace->dax_settings;
 	struct ndctl_dax *dax, *found = NULL;
 	enum ndctl_namespace_mode mode;
@@ -1439,7 +1439,7 @@ static int check_btt_autodetect(struct ndctl_bus *bus,
 	struct ndctl_region *region = ndctl_namespace_get_region(ndns);
 	struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
 	const char *devname = ndctl_namespace_get_devname(ndns);
-	struct ndctl_test *test = ndctl_get_private_data(ctx);
+	struct test_ctx *test = ndctl_get_private_data(ctx);
 	struct btt *auto_btt = namespace->btt_settings;
 	struct ndctl_btt *btt, *found = NULL;
 	enum ndctl_namespace_mode mode;
@@ -1681,7 +1681,7 @@ static int check_namespaces(struct ndctl_region *region,
 		struct namespace **namespaces, enum ns_mode mode)
 {
 	struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
-	struct ndctl_test *test = ndctl_get_private_data(ctx);
+	struct test_ctx *test = ndctl_get_private_data(ctx);
 	struct ndctl_bus *bus = ndctl_region_get_bus(region);
 	struct ndctl_namespace **ndns_save;
 	struct namespace *namespace;
@@ -2044,7 +2044,7 @@ static int check_btts(struct ndctl_region *region, struct btt **btts)
 struct check_cmd {
 	int (*check_fn)(struct ndctl_bus *bus, struct ndctl_dimm *dimm, struct check_cmd *check);
 	struct ndctl_cmd *cmd;
-	struct ndctl_test *test;
+	struct test_ctx *test;
 };
 
 static struct check_cmd *check_cmds;
@@ -2412,7 +2412,7 @@ static int check_smart_threshold(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
 #define BITS_PER_LONG 32
 static int check_commands(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
 		unsigned long bus_commands, unsigned long dimm_commands,
-		struct ndctl_test *test)
+		struct test_ctx *test)
 {
 	/*
 	 * For now, by coincidence, these are indexed in test execution
@@ -2483,7 +2483,7 @@ static int check_commands(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
 
 static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,
 		unsigned long bus_commands, unsigned long dimm_commands,
-		struct ndctl_test *test)
+		struct test_ctx *test)
 {
 	long long dsc;
 	int i, j, rc;
@@ -2604,7 +2604,7 @@ static void reset_bus(struct ndctl_bus *bus)
 		ndctl_region_enable(region);
 }
 
-static int do_test0(struct ndctl_ctx *ctx, struct ndctl_test *test)
+static int do_test0(struct ndctl_ctx *ctx, struct test_ctx *test)
 {
 	struct ndctl_bus *bus = ndctl_bus_get_by_provider(ctx, NFIT_PROVIDER0);
 	struct ndctl_region *region;
@@ -2662,7 +2662,7 @@ static int do_test0(struct ndctl_ctx *ctx, struct ndctl_test *test)
 	return check_regions(bus, regions0, ARRAY_SIZE(regions0), BTT);
 }
 
-static int do_test1(struct ndctl_ctx *ctx, struct ndctl_test *test)
+static int do_test1(struct ndctl_ctx *ctx, struct test_ctx *test)
 {
 	struct ndctl_bus *bus = ndctl_bus_get_by_provider(ctx, NFIT_PROVIDER1);
 	int rc;
@@ -2686,13 +2686,13 @@ static int do_test1(struct ndctl_ctx *ctx, struct ndctl_test *test)
 	return check_regions(bus, regions1, ARRAY_SIZE(regions1), BTT);
 }
 
-typedef int (*do_test_fn)(struct ndctl_ctx *ctx, struct ndctl_test *test);
+typedef int (*do_test_fn)(struct ndctl_ctx *ctx, struct test_ctx *test);
 static do_test_fn do_test[] = {
 	do_test0,
 	do_test1,
 };
 
-int test_libndctl(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
+int test_libndctl(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
 {
 	unsigned int i;
 	struct kmod_module *mod;
@@ -2732,7 +2732,7 @@ int test_libndctl(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct ndctl_test *test = ndctl_test_new(0);
+	struct test_ctx *test = ndctl_test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
diff --git a/test/multi-pmem.c b/test/multi-pmem.c
index 3ea08cc..e2f3bc5 100644
--- a/test/multi-pmem.c
+++ b/test/multi-pmem.c
@@ -53,7 +53,7 @@ static void destroy_namespace(struct ndctl_namespace *ndns)
 
 /* Check that the namespace device is gone (if it wasn't the seed) */
 static int check_deleted(struct ndctl_region *region, const char *devname,
-		struct ndctl_test *test)
+		struct test_ctx *test)
 {
 	struct ndctl_namespace *ndns;
 
@@ -73,7 +73,7 @@ static int check_deleted(struct ndctl_region *region, const char *devname,
 	return 0;
 }
 
-static int do_multi_pmem(struct ndctl_ctx *ctx, struct ndctl_test *test)
+static int do_multi_pmem(struct ndctl_ctx *ctx, struct test_ctx *test)
 {
 	int i;
 	char devname[100];
@@ -238,7 +238,8 @@ static int do_multi_pmem(struct ndctl_ctx *ctx, struct ndctl_test *test)
 	return 0;
 }
 
-int test_multi_pmem(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
+int test_multi_pmem(int loglevel, struct test_ctx *test,
+		    struct ndctl_ctx *ctx)
 {
 	struct kmod_module *mod;
 	struct kmod_ctx *kmod_ctx;
@@ -267,7 +268,7 @@ int test_multi_pmem(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct ndctl_test *test = ndctl_test_new(0);
+	struct test_ctx *test = ndctl_test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
diff --git a/test/parent-uuid.c b/test/parent-uuid.c
index bded33a..dd007c7 100644
--- a/test/parent-uuid.c
+++ b/test/parent-uuid.c
@@ -208,7 +208,8 @@ static int do_test(struct ndctl_ctx *ctx)
 	return 0;
 }
 
-int test_parent_uuid(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
+int test_parent_uuid(int loglevel, struct test_ctx *test,
+		     struct ndctl_ctx *ctx)
 {
 	struct kmod_module *mod;
 	struct kmod_ctx *kmod_ctx;
@@ -235,7 +236,7 @@ int test_parent_uuid(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ct
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct ndctl_test *test = ndctl_test_new(0);
+	struct test_ctx *test = ndctl_test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
diff --git a/test/pmem_namespaces.c b/test/pmem_namespaces.c
index a4db1ae..eddf32a 100644
--- a/test/pmem_namespaces.c
+++ b/test/pmem_namespaces.c
@@ -161,8 +161,8 @@ static int ns_do_io(const char *bdev)
 
 static const char *comm = "test-pmem-namespaces";
 
-int test_pmem_namespaces(int log_level, struct ndctl_test *test,
-		struct ndctl_ctx *ctx)
+int test_pmem_namespaces(int log_level, struct test_ctx *test,
+			 struct ndctl_ctx *ctx)
 {
 	struct ndctl_region *region, *pmem_region = NULL;
 	struct kmod_ctx *kmod_ctx = NULL;
@@ -262,7 +262,7 @@ int test_pmem_namespaces(int log_level, struct ndctl_test *test,
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct ndctl_test *test = ndctl_test_new(0);
+	struct test_ctx *test = ndctl_test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
diff --git a/test/revoke-devmem.c b/test/revoke-devmem.c
index bb8979e..0d67d93 100644
--- a/test/revoke-devmem.c
+++ b/test/revoke-devmem.c
@@ -32,8 +32,8 @@ static void sigbus(int sig, siginfo_t *siginfo, void *d)
 #define err(fmt, ...) \
 	fprintf(stderr, "%s: " fmt, __func__, ##__VA_ARGS__)
 
-static int test_devmem(int loglevel, struct ndctl_test *test,
-		struct ndctl_ctx *ctx)
+static int test_devmem(int loglevel, struct test_ctx *test,
+		       struct ndctl_ctx *ctx)
 {
 	void *buf;
 	int fd, rc;
@@ -124,7 +124,7 @@ out_devmem:
 
 int main(int argc, char *argv[])
 {
-	struct ndctl_test *test = ndctl_test_new(0);
+	struct test_ctx *test = ndctl_test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 07/21] test: rename 'ndctl_test_*' helpers to 'test_*'
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (5 preceding siblings ...)
  2021-07-01 20:09 ` [ndctl PATCH v3 06/21] test: rename 'ndctl_test' to 'test_ctx' Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-15 23:51   ` Dan Williams
  2021-07-01 20:09 ` [ndctl PATCH v3 08/21] test: introduce a libcxl unit test Vishal Verma
                   ` (14 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

In preparation for using the test harness for libcxl, rename
ndctl_test_* helpers to make them more generic.

Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 test.h                        | 16 +++++------
 ndctl/bat.c                   |  6 ++--
 ndctl/test.c                  |  6 ++--
 test/ack-shutdown-count-set.c | 10 +++----
 test/blk_namespaces.c         | 10 +++----
 test/core.c                   | 24 ++++++++--------
 test/dax-dev.c                |  8 +++---
 test/dax-pmd.c                |  6 ++--
 test/dax-poison.c             |  2 +-
 test/device-dax.c             | 18 ++++++------
 test/dpa-alloc.c              | 10 +++----
 test/dsm-fail.c               | 10 +++----
 test/libndctl.c               | 52 +++++++++++++++++------------------
 test/multi-pmem.c             | 16 +++++------
 test/parent-uuid.c            | 10 +++----
 test/pmem_namespaces.c        | 10 +++----
 test/revoke-devmem.c          |  8 +++---
 README.md                     |  2 +-
 18 files changed, 112 insertions(+), 112 deletions(-)

diff --git a/test.h b/test.h
index c5b9d4a..a25f6c9 100644
--- a/test.h
+++ b/test.h
@@ -6,15 +6,15 @@
 
 struct test_ctx;
 struct ndctl_ctx;
-struct test_ctx *ndctl_test_new(unsigned int kver);
-int ndctl_test_result(struct test_ctx *test, int rc);
-int ndctl_test_get_skipped(struct test_ctx *test);
-int ndctl_test_get_attempted(struct test_ctx *test);
-int __ndctl_test_attempt(struct test_ctx *test, unsigned int kver,
+struct test_ctx *test_new(unsigned int kver);
+int test_result(struct test_ctx *test, int rc);
+int test_get_skipped(struct test_ctx *test);
+int test_get_attempted(struct test_ctx *test);
+int __test_attempt(struct test_ctx *test, unsigned int kver,
 		const char *caller, int line);
-#define ndctl_test_attempt(t, v) __ndctl_test_attempt(t, v, __func__, __LINE__)
-void __ndctl_test_skip(struct test_ctx *test, const char *caller, int line);
-#define ndctl_test_skip(t) __ndctl_test_skip(t, __func__, __LINE__)
+#define test_attempt(t, v) __test_attempt(t, v, __func__, __LINE__)
+void __test_skip(struct test_ctx *test, const char *caller, int line);
+#define test_skip(t) __test_skip(t, __func__, __LINE__)
 struct ndctl_namespace *ndctl_get_test_dev(struct ndctl_ctx *ctx);
 void builtin_xaction_namespace_reset(void);
 
diff --git a/ndctl/bat.c b/ndctl/bat.c
index 18773fd..a3452fa 100644
--- a/ndctl/bat.c
+++ b/ndctl/bat.c
@@ -32,9 +32,9 @@ int cmd_bat(int argc, const char **argv, struct ndctl_ctx *ctx)
 		usage_with_options(u, options);
 
 	if (force)
-		test = ndctl_test_new(UINT_MAX);
+		test = test_new(UINT_MAX);
 	else
-		test = ndctl_test_new(0);
+		test = test_new(0);
 
 	if (!test) {
 		fprintf(stderr, "failed to initialize test\n");
@@ -48,5 +48,5 @@ int cmd_bat(int argc, const char **argv, struct ndctl_ctx *ctx)
 
 	rc = test_pmem_namespaces(loglevel, test, ctx);
 	fprintf(stderr, "test_pmem_namespaces: %s\n", rc ? "FAIL" : "PASS");
-	return ndctl_test_result(test, rc);
+	return test_result(test, rc);
 }
diff --git a/ndctl/test.c b/ndctl/test.c
index 7af3681..92713df 100644
--- a/ndctl/test.c
+++ b/ndctl/test.c
@@ -42,9 +42,9 @@ int cmd_test(int argc, const char **argv, struct ndctl_ctx *ctx)
 		usage_with_options(u, options);
 
 	if (force)
-		test = ndctl_test_new(UINT_MAX);
+		test = test_new(UINT_MAX);
 	else
-		test = ndctl_test_new(0);
+		test = test_new(0);
 	if (!test)
 		return EXIT_FAILURE;
 
@@ -69,5 +69,5 @@ int cmd_test(int argc, const char **argv, struct ndctl_ctx *ctx)
 	rc = test_multi_pmem(loglevel, test, ctx);
 	fprintf(stderr, "test-multi-pmem: %s\n", result(rc));
 
-	return ndctl_test_result(test, rc);
+	return test_result(test, rc);
 }
diff --git a/test/ack-shutdown-count-set.c b/test/ack-shutdown-count-set.c
index d5c7bcb..92690f4 100644
--- a/test/ack-shutdown-count-set.c
+++ b/test/ack-shutdown-count-set.c
@@ -62,7 +62,7 @@ static int do_test(struct ndctl_ctx *ctx, struct test_ctx *test)
 	struct log_ctx log_ctx;
 	int rc = 0;
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 15, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 15, 0)))
 		return 77;
 
 	if (!bus)
@@ -102,7 +102,7 @@ static int test_ack_shutdown_count_set(int loglevel, struct test_ctx *test,
 	err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
 	if (err < 0) {
 		result = 77;
-		ndctl_test_skip(test);
+		test_skip(test);
 		fprintf(stderr, "%s unavailable skipping tests\n",
 				"nfit_test");
 		return result;
@@ -117,7 +117,7 @@ static int test_ack_shutdown_count_set(int loglevel, struct test_ctx *test,
 
 int main(int argc, char *argv[])
 {
-	struct test_ctx *test = ndctl_test_new(0);
+	struct test_ctx *test = test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
@@ -128,9 +128,9 @@ int main(int argc, char *argv[])
 
 	rc = ndctl_new(&ctx);
 	if (rc)
-		return ndctl_test_result(test, rc);
+		return test_result(test, rc);
 	rc = test_ack_shutdown_count_set(LOG_DEBUG, test, ctx);
 	ndctl_unref(ctx);
 
-	return ndctl_test_result(test, rc);
+	return test_result(test, rc);
 }
diff --git a/test/blk_namespaces.c b/test/blk_namespaces.c
index 4919890..04eb600 100644
--- a/test/blk_namespaces.c
+++ b/test/blk_namespaces.c
@@ -210,7 +210,7 @@ int test_blk_namespaces(int log_level, struct test_ctx *test,
 	struct ndctl_namespace *ndns[2];
 	struct ndctl_region *region, *blk_region = NULL;
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 2, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 2, 0)))
 		return 77;
 
 	ndctl_set_log_priority(ctx, log_level);
@@ -232,7 +232,7 @@ int test_blk_namespaces(int log_level, struct test_ctx *test,
 		ndctl_invalidate(ctx);
 		bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0");
 		if (rc < 0 || !bus) {
-			ndctl_test_skip(test);
+			test_skip(test);
 			fprintf(stderr, "nfit_test unavailable skipping tests\n");
 			return 77;
 		}
@@ -337,7 +337,7 @@ int test_blk_namespaces(int log_level, struct test_ctx *test,
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct test_ctx *test = ndctl_test_new(0);
+	struct test_ctx *test = test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
@@ -349,9 +349,9 @@ int __attribute__((weak)) main(int argc, char *argv[])
 
 	rc = ndctl_new(&ctx);
 	if (rc)
-		return ndctl_test_result(test, rc);
+		return test_result(test, rc);
 
 	rc = test_blk_namespaces(LOG_DEBUG, test, ctx);
 	ndctl_unref(ctx);
-	return ndctl_test_result(test, rc);
+	return test_result(test, rc);
 }
diff --git a/test/core.c b/test/core.c
index 1ef0ac4..d143e89 100644
--- a/test/core.c
+++ b/test/core.c
@@ -39,7 +39,7 @@ static unsigned int get_system_kver(void)
 	return KERNEL_VERSION(a,b,c);
 }
 
-struct test_ctx *ndctl_test_new(unsigned int kver)
+struct test_ctx *test_new(unsigned int kver)
 {
 	struct test_ctx *test = calloc(1, sizeof(*test));
 
@@ -54,15 +54,15 @@ struct test_ctx *ndctl_test_new(unsigned int kver)
 	return test;
 }
 
-int ndctl_test_result(struct test_ctx *test, int rc)
+int test_result(struct test_ctx *test, int rc)
 {
-	if (ndctl_test_get_skipped(test))
+	if (test_get_skipped(test))
 		fprintf(stderr, "attempted: %d skipped: %d\n",
-				ndctl_test_get_attempted(test),
-				ndctl_test_get_skipped(test));
+				test_get_attempted(test),
+				test_get_skipped(test));
 	if (rc && rc != 77)
 		return rc;
-	if (ndctl_test_get_skipped(test) >= ndctl_test_get_attempted(test))
+	if (test_get_skipped(test) >= test_get_attempted(test))
 		return 77;
 	/* return success if no failures and at least one test not skipped */
 	return 0;
@@ -75,7 +75,7 @@ static char *kver_str(char *buf, unsigned int kver)
 	return buf;
 }
 
-int __ndctl_test_attempt(struct test_ctx *test, unsigned int kver,
+int __test_attempt(struct test_ctx *test, unsigned int kver,
 			 const char *caller, int line)
 {
 	char requires[KVER_STRLEN], current[KVER_STRLEN];
@@ -90,19 +90,19 @@ int __ndctl_test_attempt(struct test_ctx *test, unsigned int kver,
 	return 0;
 }
 
-void __ndctl_test_skip(struct test_ctx *test, const char *caller, int line)
+void __test_skip(struct test_ctx *test, const char *caller, int line)
 {
 	test->skip++;
 	test->attempt = test->skip;
 	fprintf(stderr, "%s: explicit skip %s:%d\n", __func__, caller, line);
 }
 
-int ndctl_test_get_attempted(struct test_ctx *test)
+int test_get_attempted(struct test_ctx *test)
 {
 	return test->attempt;
 }
 
-int ndctl_test_get_skipped(struct test_ctx *test)
+int test_get_skipped(struct test_ctx *test)
 {
 	return test->skip;
 }
@@ -174,7 +174,7 @@ int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
 		 * than 4.7.
 		 */
 		if (strcmp(name, "dax") == 0
-				&& !ndctl_test_attempt(test,
+				&& !test_attempt(test,
 					KERNEL_VERSION(4, 7, 0)))
 			continue;
 
@@ -183,7 +183,7 @@ int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
 		 */
 		if ((strcmp(name, "dax_pmem_core") == 0
 				|| strcmp(name, "dax_pmem_compat") == 0)
-				&& !ndctl_test_attempt(test,
+				&& !test_attempt(test,
 					KERNEL_VERSION(5, 1, 0)))
 			continue;
 
diff --git a/test/dax-dev.c b/test/dax-dev.c
index 99eda26..d61104f 100644
--- a/test/dax-dev.c
+++ b/test/dax-dev.c
@@ -93,7 +93,7 @@ static int emit_e820_device(int loglevel, struct test_ctx *test)
 	struct ndctl_ctx *ctx;
 	struct ndctl_namespace *ndns;
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 3, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 3, 0)))
 		return 77;
 
 	err = ndctl_new(&ctx);
@@ -106,7 +106,7 @@ static int emit_e820_device(int loglevel, struct test_ctx *test)
 	if (!ndns) {
 		fprintf(stderr, "%s: failed to find usable victim device\n",
 				__func__);
-		ndctl_test_skip(test);
+		test_skip(test);
 		err = 77;
 	} else {
 		fprintf(stdout, "%s\n", ndctl_namespace_get_devname(ndns));
@@ -118,7 +118,7 @@ static int emit_e820_device(int loglevel, struct test_ctx *test)
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct test_ctx *test = ndctl_test_new(0);
+	struct test_ctx *test = test_new(0);
 	int rc;
 
 	if (!test) {
@@ -127,5 +127,5 @@ int __attribute__((weak)) main(int argc, char *argv[])
 	}
 
 	rc = emit_e820_device(LOG_DEBUG, test);
-	return ndctl_test_result(test, rc);
+	return test_result(test, rc);
 }
diff --git a/test/dax-pmd.c b/test/dax-pmd.c
index e9dedb9..190a0fd 100644
--- a/test/dax-pmd.c
+++ b/test/dax-pmd.c
@@ -45,7 +45,7 @@ int test_dax_remap(struct test_ctx *test, int dax_fd, unsigned long align,
 	struct sigaction act;
 	int rc, val;
 
-	if ((fsdax || align == SZ_2M) && !ndctl_test_attempt(test, KERNEL_VERSION(5, 8, 0))) {
+	if ((fsdax || align == SZ_2M) && !test_attempt(test, KERNEL_VERSION(5, 8, 0))) {
 		/* kernel's prior to 5.8 may crash on this test */
 		fprintf(stderr, "%s: SKIP mremap() test\n", __func__);
 		return 0;
@@ -352,7 +352,7 @@ err_mmap:
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct test_ctx *test = ndctl_test_new(0);
+	struct test_ctx *test = test_new(0);
 	int fd, rc;
 
 	if (!test) {
@@ -367,5 +367,5 @@ int __attribute__((weak)) main(int argc, char *argv[])
 	rc = test_pmd(test, fd);
 	if (fd >= 0)
 		close(fd);
-	return ndctl_test_result(test, rc);
+	return test_result(test, rc);
 }
diff --git a/test/dax-poison.c b/test/dax-poison.c
index dc62742..e50ff8f 100644
--- a/test/dax-poison.c
+++ b/test/dax-poison.c
@@ -54,7 +54,7 @@ int test_dax_poison(struct test_ctx *test, int dax_fd, unsigned long align,
 	void *buf;
 	int rc;
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 19, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 19, 0)))
 		return 77;
 
 	/*
diff --git a/test/device-dax.c b/test/device-dax.c
index 1837b4d..80f0ef7 100644
--- a/test/device-dax.c
+++ b/test/device-dax.c
@@ -95,7 +95,7 @@ static int verify_data(struct daxctl_dev *dev, char *dax_buf,
 	struct timeval tv1, tv2, tv_diff;
 	unsigned long i;
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 9, 0)))
 		return 0;
 
 	/* verify data and cache mode */
@@ -128,7 +128,7 @@ static int verify_data(struct daxctl_dev *dev, char *dax_buf,
 	return 0;
 }
 
-static int test_dax_soft_offline(struct ndctl_test *test, struct ndctl_namespace *ndns)
+static int test_dax_soft_offline(struct test_ctx *test, struct ndctl_namespace *ndns)
 {
 	unsigned long long resource = ndctl_namespace_get_resource(ndns);
 	int fd, rc;
@@ -188,10 +188,10 @@ static int __test_device_dax(unsigned long align, int loglevel,
 		return 77;
 	}
 
-	if (align > SZ_2M && !ndctl_test_attempt(test, KERNEL_VERSION(4, 11, 0)))
+	if (align > SZ_2M && !test_attempt(test, KERNEL_VERSION(4, 11, 0)))
 		return 77;
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 7, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 7, 0)))
 		return 77;
 
 	/* setup up fsdax mode pmem device and seed with verification data */
@@ -279,7 +279,7 @@ static int __test_device_dax(unsigned long align, int loglevel,
 	 * Prior to 4.8-final these tests cause crashes, or are
 	 * otherwise not supported.
 	 */
-	if (ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0))) {
+	if (test_attempt(test, KERNEL_VERSION(4, 9, 0))) {
 		static const bool devdax = false;
 		int fd2;
 
@@ -394,7 +394,7 @@ static int __test_device_dax(unsigned long align, int loglevel,
 	rc = EXIT_SUCCESS;
 	p = (int *) (buf + align);
 	*p = 0xff;
-	if (ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0))) {
+	if (test_attempt(test, KERNEL_VERSION(4, 9, 0))) {
 		/* after 4.9 this test will properly get sigbus above */
 		rc = EXIT_FAILURE;
 		fprintf(stderr, "%s: failed to unmap after reset\n",
@@ -423,7 +423,7 @@ static int test_device_dax(int loglevel, struct test_ctx *test,
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct test_ctx *test = ndctl_test_new(0);
+	struct test_ctx *test = test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
@@ -434,9 +434,9 @@ int __attribute__((weak)) main(int argc, char *argv[])
 
 	rc = ndctl_new(&ctx);
 	if (rc < 0)
-		return ndctl_test_result(test, rc);
+		return test_result(test, rc);
 
 	rc = test_device_dax(LOG_DEBUG, test, ctx);
 	ndctl_unref(ctx);
-	return ndctl_test_result(test, rc);
+	return test_result(test, rc);
 }
diff --git a/test/dpa-alloc.c b/test/dpa-alloc.c
index d0f5271..e530ed4 100644
--- a/test/dpa-alloc.c
+++ b/test/dpa-alloc.c
@@ -286,13 +286,13 @@ int test_dpa_alloc(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
 	struct kmod_ctx *kmod_ctx;
 	int err, result = EXIT_FAILURE;
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 2, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 2, 0)))
 		return 77;
 
 	ndctl_set_log_priority(ctx, loglevel);
 	err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
 	if (err < 0) {
-		ndctl_test_skip(test);
+		test_skip(test);
 		fprintf(stderr, "nfit_test unavailable skipping tests\n");
 		return 77;
 	}
@@ -307,7 +307,7 @@ int test_dpa_alloc(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct test_ctx *test = ndctl_test_new(0);
+	struct test_ctx *test = test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
@@ -318,9 +318,9 @@ int __attribute__((weak)) main(int argc, char *argv[])
 
 	rc = ndctl_new(&ctx);
 	if (rc)
-		return ndctl_test_result(test, rc);
+		return test_result(test, rc);
 
 	rc = test_dpa_alloc(LOG_DEBUG, test, ctx);
 	ndctl_unref(ctx);
-	return ndctl_test_result(test, rc);
+	return test_result(test, rc);
 }
diff --git a/test/dsm-fail.c b/test/dsm-fail.c
index 74c56de..5559da2 100644
--- a/test/dsm-fail.c
+++ b/test/dsm-fail.c
@@ -184,7 +184,7 @@ static int do_test(struct ndctl_ctx *ctx, struct test_ctx *test)
 	unsigned int handle;
 	int rc, err = 0;
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 9, 0)))
 		return 77;
 
 	if (!bus)
@@ -349,7 +349,7 @@ int test_dsm_fail(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
 	err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
 	if (err < 0) {
 		result = 77;
-		ndctl_test_skip(test);
+		test_skip(test);
 		fprintf(stderr, "%s unavailable skipping tests\n",
 				"nfit_test");
 		return result;
@@ -364,7 +364,7 @@ int test_dsm_fail(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct test_ctx *test = ndctl_test_new(0);
+	struct test_ctx *test = test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
@@ -375,8 +375,8 @@ int __attribute__((weak)) main(int argc, char *argv[])
 
 	rc = ndctl_new(&ctx);
 	if (rc)
-		return ndctl_test_result(test, rc);
+		return test_result(test, rc);
 	rc = test_dsm_fail(LOG_DEBUG, test, ctx);
 	ndctl_unref(ctx);
-	return ndctl_test_result(test, rc);
+	return test_result(test, rc);
 }
diff --git a/test/libndctl.c b/test/libndctl.c
index 30d19db..8aeaded 100644
--- a/test/libndctl.c
+++ b/test/libndctl.c
@@ -639,7 +639,7 @@ static int validate_dax(struct ndctl_dax *dax)
 		return -ENXIO;
 	}
 
-	if (ndctl_test_attempt(test, KERNEL_VERSION(4, 10, 0))) {
+	if (test_attempt(test, KERNEL_VERSION(4, 10, 0))) {
 		if (daxctl_region_get_size(dax_region)
 				!= ndctl_dax_get_size(dax)) {
 			fprintf(stderr, "%s: expect size: %llu != %llu\n",
@@ -745,7 +745,7 @@ static int __check_dax_create(struct ndctl_region *region,
 	ndctl_dax_set_align(dax, SZ_4K);
 
 	rc = ndctl_namespace_set_enforce_mode(ndns, NDCTL_NS_MODE_DAX);
-	if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0)) && rc < 0) {
+	if (test_attempt(test, KERNEL_VERSION(4, 13, 0)) && rc < 0) {
 		fprintf(stderr, "%s: failed to enforce dax mode\n", devname);
 		return rc;
 	}
@@ -856,7 +856,7 @@ static int __check_pfn_create(struct ndctl_region *region,
 	 */
 	ndctl_pfn_set_align(pfn, SZ_4K);
 	rc = ndctl_namespace_set_enforce_mode(ndns, NDCTL_NS_MODE_MEMORY);
-	if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0)) && rc < 0) {
+	if (test_attempt(test, KERNEL_VERSION(4, 13, 0)) && rc < 0) {
 		fprintf(stderr, "%s: failed to enforce pfn mode\n", devname);
 		return rc;
 	}
@@ -1030,7 +1030,7 @@ static int check_btt_size(struct ndctl_btt *btt)
 	}
 
 	/* prior to 4.8 btt devices did not have a size attribute */
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 8, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 8, 0)))
 		return 0;
 
 	expect = expect_table[size_select][sect_select];
@@ -1077,7 +1077,7 @@ static int check_btt_create(struct ndctl_region *region, struct ndctl_namespace
 		ndctl_btt_set_uuid(btt, btt_s->uuid);
 		ndctl_btt_set_sector_size(btt, btt_s->sector_sizes[i]);
 		rc = ndctl_namespace_set_enforce_mode(ndns, NDCTL_NS_MODE_SECTOR);
-		if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0)) && rc < 0) {
+		if (test_attempt(test, KERNEL_VERSION(4, 13, 0)) && rc < 0) {
 			fprintf(stderr, "%s: failed to enforce btt mode\n", devname);
 			goto err;
 		}
@@ -1094,7 +1094,7 @@ static int check_btt_create(struct ndctl_region *region, struct ndctl_namespace
 		}
 
 		/* prior to v4.5 the mode attribute did not exist */
-		if (ndctl_test_attempt(test, KERNEL_VERSION(4, 5, 0))) {
+		if (test_attempt(test, KERNEL_VERSION(4, 5, 0))) {
 			mode = ndctl_namespace_get_mode(ndns);
 			if (mode >= 0 && mode != NDCTL_NS_MODE_SECTOR)
 				fprintf(stderr, "%s: expected safe mode got: %d\n",
@@ -1102,7 +1102,7 @@ static int check_btt_create(struct ndctl_region *region, struct ndctl_namespace
 		}
 
 		/* prior to v4.13 the expected sizes were different due to BTT1.1 */
-		if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0))) {
+		if (test_attempt(test, KERNEL_VERSION(4, 13, 0))) {
 			rc = check_btt_size(btt);
 			if (rc)
 				goto err;
@@ -1287,7 +1287,7 @@ static int check_pfn_autodetect(struct ndctl_bus *bus,
 		return -ENXIO;
 
 	mode = ndctl_namespace_get_enforce_mode(ndns);
-	if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0))
+	if (test_attempt(test, KERNEL_VERSION(4, 13, 0))
 			&& mode != NDCTL_NS_MODE_MEMORY) {
 		fprintf(stderr, "%s expected enforce_mode pfn\n", devname);
 		return -ENXIO;
@@ -1384,7 +1384,7 @@ static int check_dax_autodetect(struct ndctl_bus *bus,
 		return -ENXIO;
 
 	mode = ndctl_namespace_get_enforce_mode(ndns);
-	if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0))
+	if (test_attempt(test, KERNEL_VERSION(4, 13, 0))
 			&& mode != NDCTL_NS_MODE_DAX) {
 		fprintf(stderr, "%s expected enforce_mode dax\n", devname);
 		return -ENXIO;
@@ -1469,7 +1469,7 @@ static int check_btt_autodetect(struct ndctl_bus *bus,
 		return -ENXIO;
 
 	mode = ndctl_namespace_get_enforce_mode(ndns);
-	if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0))
+	if (test_attempt(test, KERNEL_VERSION(4, 13, 0))
 			&& mode != NDCTL_NS_MODE_SECTOR) {
 		fprintf(stderr, "%s expected enforce_mode btt\n", devname);
 		return -ENXIO;
@@ -1714,7 +1714,7 @@ static int check_namespaces(struct ndctl_region *region,
 		}
 
 		if (ndctl_region_get_type(region) == ND_DEVICE_REGION_PMEM
-				&& !ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0)))
+				&& !test_attempt(test, KERNEL_VERSION(4, 13, 0)))
 			/* pass, no sector_size support for pmem prior to 4.13 */;
 		else {
 			num_sector_sizes = namespace->num_sector_sizes;
@@ -2321,7 +2321,7 @@ static int check_smart_threshold(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
 	 * Starting with v4.9 smart threshold requests trigger the file
 	 * descriptor returned by ndctl_dimm_get_health_eventfd().
 	 */
-	if (ndctl_test_attempt(check->test, KERNEL_VERSION(4, 9, 0))) {
+	if (test_attempt(check->test, KERNEL_VERSION(4, 9, 0))) {
 		int pid = fork();
 
 		if (pid == 0) {
@@ -2396,7 +2396,7 @@ static int check_smart_threshold(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
 		ndctl_cmd_unref(cmd_set);
 	}
 
-	if (ndctl_test_attempt(check->test, KERNEL_VERSION(4, 9, 0))) {
+	if (test_attempt(check->test, KERNEL_VERSION(4, 9, 0))) {
 		wait(&rc);
 		if (WEXITSTATUS(rc) == EXIT_FAILURE) {
 			fprintf(stderr, "%s: expect health event trigger\n",
@@ -2439,7 +2439,7 @@ static int check_commands(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
 	 * The kernel did not start emulating v1.2 namespace spec smart data
 	 * until 4.9.
 	 */
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 9, 0)))
 		dimm_commands &= ~((1 << ND_CMD_SMART)
 				| (1 << ND_CMD_SMART_THRESHOLD));
 
@@ -2474,7 +2474,7 @@ static int check_commands(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
 	if (rc)
 		goto out;
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 6, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 6, 0)))
 		goto out;
 
  out:
@@ -2530,7 +2530,7 @@ static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,
 			return -ENXIO;
 		}
 
-		if (ndctl_test_attempt(test, KERNEL_VERSION(4, 7, 0))) {
+		if (test_attempt(test, KERNEL_VERSION(4, 7, 0))) {
 			if (ndctl_dimm_get_formats(dimm) != dimms[i].formats) {
 				fprintf(stderr, "dimm%d expected formats: %d got: %d\n",
 						i, dimms[i].formats,
@@ -2548,7 +2548,7 @@ static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,
 			}
 		}
 
-		if (ndctl_test_attempt(test, KERNEL_VERSION(4, 7, 0))) {
+		if (test_attempt(test, KERNEL_VERSION(4, 7, 0))) {
 			if (ndctl_dimm_get_subsystem_vendor(dimm)
 					!= dimms[i].subsystem_vendor) {
 				fprintf(stderr,
@@ -2559,7 +2559,7 @@ static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,
 			}
 		}
 
-		if (ndctl_test_attempt(test, KERNEL_VERSION(4, 8, 0))) {
+		if (test_attempt(test, KERNEL_VERSION(4, 8, 0))) {
 			if (ndctl_dimm_get_manufacturing_date(dimm)
 					!= dimms[i].manufacturing_date) {
 				fprintf(stderr,
@@ -2645,14 +2645,14 @@ static int do_test0(struct ndctl_ctx *ctx, struct test_ctx *test)
 	}
 
 	/* pfn and dax tests require vmalloc-enabled nfit_test */
-	if (ndctl_test_attempt(test, KERNEL_VERSION(4, 8, 0))) {
+	if (test_attempt(test, KERNEL_VERSION(4, 8, 0))) {
 		rc = check_regions(bus, regions0, ARRAY_SIZE(regions0), DAX);
 		if (rc)
 			return rc;
 		reset_bus(bus);
 	}
 
-	if (ndctl_test_attempt(test, KERNEL_VERSION(4, 8, 0))) {
+	if (test_attempt(test, KERNEL_VERSION(4, 8, 0))) {
 		rc = check_regions(bus, regions0, ARRAY_SIZE(regions0), PFN);
 		if (rc)
 			return rc;
@@ -2676,7 +2676,7 @@ static int do_test1(struct ndctl_ctx *ctx, struct test_ctx *test)
 	 * Starting with v4.10 the dimm on nfit_test.1 gets a unique
 	 * handle.
 	 */
-	if (ndctl_test_attempt(test, KERNEL_VERSION(4, 10, 0)))
+	if (test_attempt(test, KERNEL_VERSION(4, 10, 0)))
 		dimms1[0].handle = DIMM_HANDLE(1, 0, 0, 0, 0);
 
 	rc = check_dimms(bus, dimms1, ARRAY_SIZE(dimms1), 0, 0, test);
@@ -2700,7 +2700,7 @@ int test_libndctl(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
 	struct daxctl_ctx *daxctl_ctx;
 	int err, result = EXIT_FAILURE;
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 2, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 2, 0)))
 		return 77;
 
 	ndctl_set_log_priority(ctx, loglevel);
@@ -2710,7 +2710,7 @@ int test_libndctl(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
 
 	err = ndctl_test_init(&kmod_ctx, &mod, ctx, loglevel, test);
 	if (err < 0) {
-		ndctl_test_skip(test);
+		test_skip(test);
 		fprintf(stderr, "nfit_test unavailable skipping tests\n");
 		return 77;
 	}
@@ -2732,7 +2732,7 @@ int test_libndctl(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct test_ctx *test = ndctl_test_new(0);
+	struct test_ctx *test = test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
@@ -2743,8 +2743,8 @@ int __attribute__((weak)) main(int argc, char *argv[])
 
 	rc = ndctl_new(&ctx);
 	if (rc)
-		return ndctl_test_result(test, rc);
+		return test_result(test, rc);
 	rc = test_libndctl(LOG_DEBUG, test, ctx);
 	ndctl_unref(ctx);
-	return ndctl_test_result(test, rc);
+	return test_result(test, rc);
 }
diff --git a/test/multi-pmem.c b/test/multi-pmem.c
index e2f3bc5..f2eb381 100644
--- a/test/multi-pmem.c
+++ b/test/multi-pmem.c
@@ -57,7 +57,7 @@ static int check_deleted(struct ndctl_region *region, const char *devname,
 {
 	struct ndctl_namespace *ndns;
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 10, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 10, 0)))
 		return 0;
 
 	ndctl_namespace_foreach(region, ndns) {
@@ -85,8 +85,8 @@ static int do_multi_pmem(struct ndctl_ctx *ctx, struct test_ctx *test)
 	struct ndctl_namespace *namespaces[NUM_NAMESPACES];
 	unsigned long long blk_avail, blk_avail_orig, expect;
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0))) {
-		ndctl_test_skip(test);
+	if (!test_attempt(test, KERNEL_VERSION(4, 9, 0))) {
+		test_skip(test);
 		return 77;
 	}
 
@@ -245,7 +245,7 @@ int test_multi_pmem(int loglevel, struct test_ctx *test,
 	struct kmod_ctx *kmod_ctx;
 	int err, result = EXIT_FAILURE;
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 2, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 2, 0)))
 		return 77;
 
 	ndctl_set_log_priority(ctx, loglevel);
@@ -253,7 +253,7 @@ int test_multi_pmem(int loglevel, struct test_ctx *test,
 	err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
 	if (err < 0) {
 		result = 77;
-		ndctl_test_skip(test);
+		test_skip(test);
 		fprintf(stderr, "%s unavailable skipping tests\n",
 				"nfit_test");
 		return result;
@@ -268,7 +268,7 @@ int test_multi_pmem(int loglevel, struct test_ctx *test,
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct test_ctx *test = ndctl_test_new(0);
+	struct test_ctx *test = test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
@@ -279,8 +279,8 @@ int __attribute__((weak)) main(int argc, char *argv[])
 
 	rc = ndctl_new(&ctx);
 	if (rc)
-		return ndctl_test_result(test, rc);
+		return test_result(test, rc);
 	rc = test_multi_pmem(LOG_DEBUG, test, ctx);
 	ndctl_unref(ctx);
-	return ndctl_test_result(test, rc);
+	return test_result(test, rc);
 }
diff --git a/test/parent-uuid.c b/test/parent-uuid.c
index dd007c7..8da396f 100644
--- a/test/parent-uuid.c
+++ b/test/parent-uuid.c
@@ -215,13 +215,13 @@ int test_parent_uuid(int loglevel, struct test_ctx *test,
 	struct kmod_ctx *kmod_ctx;
 	int err, result = EXIT_FAILURE;
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 3, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 3, 0)))
 		return 77;
 
 	ndctl_set_log_priority(ctx, loglevel);
 	err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
 	if (err < 0) {
-		ndctl_test_skip(test);
+		test_skip(test);
 		fprintf(stderr, "nfit_test unavailable skipping tests\n");
 		return 77;
 	}
@@ -236,7 +236,7 @@ int test_parent_uuid(int loglevel, struct test_ctx *test,
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct test_ctx *test = ndctl_test_new(0);
+	struct test_ctx *test = test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
@@ -247,9 +247,9 @@ int __attribute__((weak)) main(int argc, char *argv[])
 
 	rc = ndctl_new(&ctx);
 	if (rc)
-		return ndctl_test_result(test, rc);
+		return test_result(test, rc);
 
 	rc = test_parent_uuid(LOG_DEBUG, test, ctx);
 	ndctl_unref(ctx);
-	return ndctl_test_result(test, rc);
+	return test_result(test, rc);
 }
diff --git a/test/pmem_namespaces.c b/test/pmem_namespaces.c
index eddf32a..20f41fe 100644
--- a/test/pmem_namespaces.c
+++ b/test/pmem_namespaces.c
@@ -173,7 +173,7 @@ int test_pmem_namespaces(int log_level, struct test_ctx *test,
 	int rc = -ENXIO;
 	char bdev[50];
 
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 2, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 2, 0)))
 		return 77;
 
 	ndctl_set_log_priority(ctx, log_level);
@@ -196,7 +196,7 @@ int test_pmem_namespaces(int log_level, struct test_ctx *test,
 		bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0");
 		if (rc < 0 || !bus) {
 			rc = 77;
-			ndctl_test_skip(test);
+			test_skip(test);
 			fprintf(stderr, "nfit_test unavailable skipping tests\n");
 			goto err_module;
 		}
@@ -262,7 +262,7 @@ int test_pmem_namespaces(int log_level, struct test_ctx *test,
 
 int __attribute__((weak)) main(int argc, char *argv[])
 {
-	struct test_ctx *test = ndctl_test_new(0);
+	struct test_ctx *test = test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
@@ -274,9 +274,9 @@ int __attribute__((weak)) main(int argc, char *argv[])
 
 	rc = ndctl_new(&ctx);
 	if (rc)
-		return ndctl_test_result(test, rc);
+		return test_result(test, rc);
 
 	rc = test_pmem_namespaces(LOG_DEBUG, test, ctx);
 	ndctl_unref(ctx);
-	return ndctl_test_result(test, rc);
+	return test_result(test, rc);
 }
diff --git a/test/revoke-devmem.c b/test/revoke-devmem.c
index 0d67d93..ac8d81c 100644
--- a/test/revoke-devmem.c
+++ b/test/revoke-devmem.c
@@ -44,7 +44,7 @@ static int test_devmem(int loglevel, struct test_ctx *test,
 	ndctl_set_log_priority(ctx, loglevel);
 
 	/* iostrict devmem started in kernel 4.5 */
-	if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 5, 0)))
+	if (!test_attempt(test, KERNEL_VERSION(4, 5, 0)))
 		return 77;
 
 	ndns = ndctl_get_test_dev(ctx);
@@ -124,7 +124,7 @@ out_devmem:
 
 int main(int argc, char *argv[])
 {
-	struct test_ctx *test = ndctl_test_new(0);
+	struct test_ctx *test = test_new(0);
 	struct ndctl_ctx *ctx;
 	int rc;
 
@@ -135,9 +135,9 @@ int main(int argc, char *argv[])
 
 	rc = ndctl_new(&ctx);
 	if (rc < 0)
-		return ndctl_test_result(test, rc);
+		return test_result(test, rc);
 
 	rc = test_devmem(LOG_DEBUG, test, ctx);
 	ndctl_unref(ctx);
-	return ndctl_test_result(test, rc);
+	return test_result(test, rc);
 }
diff --git a/README.md b/README.md
index 89dfc87..7a687ac 100644
--- a/README.md
+++ b/README.md
@@ -95,7 +95,7 @@ test/test-suite.log:
 SKIP: libndctl
 ==============
 test/init: nfit_test_init: nfit.ko: appears to be production version: /lib/modules/4.8.8-200.fc24.x86_64/kernel/drivers/acpi/nfit/nfit.ko.xz
-__ndctl_test_skip: explicit skip test_libndctl:2684
+__test_skip: explicit skip test_libndctl:2684
 nfit_test unavailable skipping tests
 ```
 
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 08/21] test: introduce a libcxl unit test
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (6 preceding siblings ...)
  2021-07-01 20:09 ` [ndctl PATCH v3 07/21] test: rename 'ndctl_test_*' helpers to 'test_*' Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-15 23:53   ` Dan Williams
  2021-07-01 20:09 ` [ndctl PATCH v3 09/21] libcxl: add GET_HEALTH_INFO mailbox command and accessors Vishal Verma
                   ` (13 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Add a new 'libcxl' test containing a basic harness for unit testing
libcxl APIs. Include sanity tests such as making sure the test is
running in an emulated environment, the ability to load and unload
modules. Submit an 'Identify Device' command, and verify that it
succeeds, and the identify data returned is as expected from an emulated
QEMU device.

Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 test/libcxl-expect.h |  13 +++
 test/libcxl.c        | 269 +++++++++++++++++++++++++++++++++++++++++++
 test/Makefile.am     |  12 +-
 3 files changed, 292 insertions(+), 2 deletions(-)
 create mode 100644 test/libcxl-expect.h
 create mode 100644 test/libcxl.c

diff --git a/test/libcxl-expect.h b/test/libcxl-expect.h
new file mode 100644
index 0000000..acb8db9
--- /dev/null
+++ b/test/libcxl-expect.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021 Intel Corporation. All rights reserved. */
+#ifndef __LIBCXL_EXPECT_H__
+#define __LIBCXL_EXPECT_H__
+#include <stdbool.h>
+
+#define EXPECT_FW_VER "BWFW VERSION 00"
+
+/* Identify command fields */
+#define EXPECT_CMD_IDENTIFY_PARTITION_ALIGN 0ULL
+#define EXPECT_CMD_IDENTIFY_LSA_SIZE 1024U
+
+#endif /* __LIBCXL_EXPECT_H__ */
diff --git a/test/libcxl.c b/test/libcxl.c
new file mode 100644
index 0000000..241a4bb
--- /dev/null
+++ b/test/libcxl.c
@@ -0,0 +1,269 @@
+// SPDX-License-Identifier: LGPL-2.1
+/* Copyright (C) 2021, Intel Corporation. All rights reserved. */
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <syslog.h>
+#include <libkmod.h>
+#include <sys/wait.h>
+#include <uuid/uuid.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <linux/version.h>
+
+#include <util/size.h>
+#include <ccan/short_types/short_types.h>
+#include <ccan/array_size/array_size.h>
+#include <ccan/endian/endian.h>
+#include <cxl/libcxl.h>
+#include <cxl/cxl_mem.h>
+#include <test.h>
+#include "libcxl-expect.h"
+
+#define TEST_SKIP 77
+
+const char *mod_list[] = {
+	"cxl_pci",
+	"cxl_acpi",
+	"cxl_core",
+};
+
+static int test_cxl_presence(struct cxl_ctx *ctx)
+{
+	struct cxl_memdev *memdev;
+	int count = 0;
+
+	cxl_memdev_foreach(ctx, memdev)
+		count++;
+
+	if (count == 0) {
+		fprintf(stderr, "%s: no cxl memdevs found\n", __func__);
+		return TEST_SKIP;
+	}
+
+	return 0;
+}
+
+/*
+ * Only continue with tests if all CXL devices in the system are qemu-emulated
+ * 'fake' devices. For now, use the firmware_version to check for this. Later,
+ * this might need to be changed to a vendor specific command.
+ *
+ * TODO: Change this to produce a list of devices that are safe to run tests
+ * against, and only run subsequent tests on this list. That will allow devices
+ * from other, non-emulated sources to be present in the system, and still run
+ * these unit tests safely.
+ */
+static int test_cxl_emulation_env(struct cxl_ctx *ctx)
+{
+	struct cxl_memdev *memdev;
+
+	cxl_memdev_foreach(ctx, memdev) {
+		const char *fw;
+
+		fw = cxl_memdev_get_firmware_verison(memdev);
+		if (!fw)
+			return -ENXIO;
+		if (strcmp(fw, EXPECT_FW_VER) != 0) {
+			fprintf(stderr,
+				"%s: found non-emulation device, aborting\n",
+				__func__);
+			return TEST_SKIP;
+		}
+	}
+	return 0;
+}
+
+static int test_cxl_modules(struct cxl_ctx *ctx)
+{
+	int rc;
+	unsigned int i;
+	const char *name;
+	struct kmod_module *mod;
+	struct kmod_ctx *kmod_ctx;
+
+	kmod_ctx = kmod_new(NULL, NULL);
+	if (!kmod_ctx)
+		return -ENXIO;
+	kmod_set_log_priority(kmod_ctx, LOG_DEBUG);
+
+	/* test module removal */
+	for (i = 0; i < ARRAY_SIZE(mod_list); i++) {
+		int state;
+
+		name = mod_list[i];
+
+		rc = kmod_module_new_from_name(kmod_ctx, name, &mod);
+		if (rc) {
+			fprintf(stderr, "%s: %s.ko: missing\n", __func__, name);
+			break;
+		}
+
+		state = kmod_module_get_initstate(mod);
+		if (state == KMOD_MODULE_LIVE) {
+			rc = kmod_module_remove_module(mod, 0);
+			if (rc) {
+				fprintf(stderr,
+					"%s: %s.ko: failed to remove: %d\n",
+					__func__, name, rc);
+				break;
+			}
+		} else if (state == KMOD_MODULE_BUILTIN) {
+			fprintf(stderr,
+				"%s: %s is builtin, skipping module removal test\n",
+				__func__, name);
+		} else {
+			fprintf(stderr,
+				"%s: warning: %s.ko: unexpected state (%d), trying to continue\n",
+				__func__, name, state);
+		}
+	}
+
+	if (rc)
+		goto out;
+
+	/* test module insertion */
+	for (i = 0; i < ARRAY_SIZE(mod_list); i++) {
+		name = mod_list[i];
+		rc = kmod_module_new_from_name(kmod_ctx, name, &mod);
+		if (rc) {
+			fprintf(stderr, "%s: %s.ko: missing\n", __func__, name);
+			break;
+		}
+
+		rc = kmod_module_probe_insert_module(mod,
+				KMOD_PROBE_APPLY_BLACKLIST,
+				NULL, NULL, NULL, NULL);
+	}
+
+out:
+	kmod_unref(kmod_ctx);
+	return rc;
+}
+
+#define expect(c, name, field, expect) \
+do { \
+	if (cxl_cmd_##name##_get_##field(c) != expect) { \
+		fprintf(stderr, \
+			"%s: %s: " #field " mismatch\n", \
+			__func__, cxl_cmd_get_devname(c)); \
+		cxl_cmd_unref(cmd); \
+		return -ENXIO; \
+	} \
+} while (0)
+
+static int test_cxl_cmd_identify(struct cxl_ctx *ctx)
+{
+	struct cxl_memdev *memdev;
+	struct cxl_cmd *cmd;
+	int rc;
+
+	cxl_memdev_foreach(ctx, memdev) {
+		char fw_rev[0x10];
+
+		cmd = cxl_cmd_new_identify(memdev);
+		if (!cmd)
+			return -ENOMEM;
+		rc = cxl_cmd_submit(cmd);
+		if (rc < 0) {
+			fprintf(stderr, "%s: %s: cmd submission failed: %s\n",
+				__func__, cxl_memdev_get_devname(memdev),
+				strerror(-rc));
+			goto out_fail;
+		}
+		rc = cxl_cmd_get_mbox_status(cmd);
+		if (rc) {
+			fprintf(stderr,
+				"%s: %s: cmd failed with firmware status: %d\n",
+				__func__, cxl_memdev_get_devname(memdev), rc);
+			rc = -ENXIO;
+			goto out_fail;
+		}
+
+		rc = cxl_cmd_identify_get_fw_rev(cmd, fw_rev, 0x10);
+		if (rc)
+			goto out_fail;
+		if (strncmp(fw_rev, EXPECT_FW_VER, 0x10) != 0) {
+			fprintf(stderr,
+				"%s: fw_rev mismatch. Expected %s, got %s\n",
+				__func__, EXPECT_FW_VER, fw_rev);
+			rc = -ENXIO;
+			goto out_fail;
+		}
+
+		expect(cmd, identify, lsa_size, EXPECT_CMD_IDENTIFY_LSA_SIZE);
+		expect(cmd, identify, partition_align,
+			EXPECT_CMD_IDENTIFY_PARTITION_ALIGN);
+		cxl_cmd_unref(cmd);
+	}
+	return 0;
+
+out_fail:
+	cxl_cmd_unref(cmd);
+	return rc;
+}
+
+typedef int (*do_test_fn)(struct cxl_ctx *ctx);
+
+static do_test_fn do_test[] = {
+	test_cxl_modules,
+	test_cxl_presence,
+	test_cxl_emulation_env,
+	test_cxl_cmd_identify,
+};
+
+static int test_libcxl(int loglevel, struct test_ctx *test, struct cxl_ctx *ctx)
+{
+	unsigned int i;
+	int err, result = EXIT_FAILURE;
+
+	if (!test_attempt(test, KERNEL_VERSION(5, 12, 0)))
+		return 77;
+
+	cxl_set_log_priority(ctx, loglevel);
+	cxl_set_private_data(ctx, test);
+
+	for (i = 0; i < ARRAY_SIZE(do_test); i++) {
+		err = do_test[i](ctx);
+		if (err < 0) {
+			fprintf(stderr, "test[%d] failed: %d\n", i, err);
+			break;
+		} else if (err == TEST_SKIP) {
+			fprintf(stderr, "test[%d]: SKIP\n", i);
+			test_skip(test);
+			result = TEST_SKIP;
+			break;
+		}
+		fprintf(stderr, "test[%d]: PASS\n", i);
+	}
+
+	if (i >= ARRAY_SIZE(do_test))
+		result = EXIT_SUCCESS;
+	return result;
+}
+
+int __attribute__((weak)) main(int argc, char *argv[])
+{
+	struct test_ctx *test = test_new(0);
+	struct cxl_ctx *ctx;
+	int rc;
+
+	if (!test) {
+		fprintf(stderr, "failed to initialize test\n");
+		return EXIT_FAILURE;
+	}
+
+	rc = cxl_new(&ctx);
+	if (rc)
+		return test_result(test, rc);
+	rc = test_libcxl(LOG_DEBUG, test, ctx);
+	cxl_unref(ctx);
+	return test_result(test, rc);
+}
diff --git a/test/Makefile.am b/test/Makefile.am
index c5b8764..ce492a4 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -44,7 +44,8 @@ check_PROGRAMS =\
 	hugetlb \
 	daxdev-errors \
 	ack-shutdown-count-set \
-	list-smart-dimm
+	list-smart-dimm \
+	libcxl
 
 if ENABLE_DESTRUCTIVE
 TESTS +=\
@@ -61,7 +62,8 @@ TESTS +=\
 	daxctl-devices.sh \
 	daxctl-create.sh \
 	dm.sh \
-	mmap.sh
+	mmap.sh \
+	libcxl
 
 if ENABLE_KEYUTILS
 TESTS += security.sh
@@ -190,3 +192,9 @@ list_smart_dimm_LDADD = \
 		$(JSON_LIBS) \
 		$(UUID_LIBS) \
 		../libutil.a
+
+LIBCXL_LIB =\
+	../cxl/lib/libcxl.la
+
+libcxl_SOURCES = libcxl.c $(testcore)
+libcxl_LDADD = $(LIBCXL_LIB) $(UUID_LIBS) $(KMOD_LIBS)
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 09/21] libcxl: add GET_HEALTH_INFO mailbox command and accessors
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (7 preceding siblings ...)
  2021-07-01 20:09 ` [ndctl PATCH v3 08/21] test: introduce a libcxl unit test Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-16  1:11   ` Dan Williams
  2021-07-01 20:09 ` [ndctl PATCH v3 10/21] libcxl: add support for the 'GET_LSA' command Vishal Verma
                   ` (12 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Add libcxl APIs to create a new GET_HEALTH_INFO mailbox command, the
command output data structure (privately), and accessor APIs to return
the different fields in the health info output.

Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 cxl/lib/private.h  | 11 +++++++++
 cxl/lib/libcxl.c   | 61 ++++++++++++++++++++++++++++++++++++++++++++++
 cxl/libcxl.h       |  9 +++++++
 cxl/lib/libcxl.sym |  9 +++++++
 4 files changed, 90 insertions(+)

diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index 3273f21..2232f4c 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -73,6 +73,17 @@ struct cxl_cmd_identify {
 	u8 qos_telemetry_caps;
 } __attribute__((packed));
 
+struct cxl_cmd_get_health_info {
+	u8 health_status;
+	u8 media_status;
+	u8 ext_status;
+	u8 life_used;
+	le16 temperature;
+	le32 dirty_shutdowns;
+	le32 volatile_errors;
+	le32 pmem_errors;
+} __attribute__((packed));
+
 static inline int check_kmod(struct kmod_ctx *kmod_ctx)
 {
 	return kmod_ctx ? 0 : -ENXIO;
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 06a6c20..2e33c5e 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -673,6 +673,67 @@ CXL_EXPORT const char *cxl_cmd_get_devname(struct cxl_cmd *cmd)
 	return cxl_memdev_get_devname(cmd->memdev);
 }
 
+#define cmd_get_int(cmd, n, N, field) \
+do { \
+	struct cxl_cmd_##n *c = (void *)cmd->send_cmd->out.payload; \
+	if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_##N) \
+		return EINVAL; \
+	if (cmd->status < 0) \
+		return cmd->status; \
+	return le32_to_cpu(c->field); \
+} while(0);
+
+CXL_EXPORT struct cxl_cmd *cxl_cmd_new_get_health_info(
+		struct cxl_memdev *memdev)
+{
+	return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_GET_HEALTH_INFO);
+}
+
+#define cmd_health_get_int(c, f) \
+do { \
+	cmd_get_int(c, get_health_info, GET_HEALTH_INFO, f); \
+} while (0);
+
+CXL_EXPORT int cxl_cmd_get_health_info_get_health_status(struct cxl_cmd *cmd)
+{
+	cmd_health_get_int(cmd, health_status);
+}
+
+CXL_EXPORT int cxl_cmd_get_health_info_get_media_status(struct cxl_cmd *cmd)
+{
+	cmd_health_get_int(cmd, media_status);
+}
+
+CXL_EXPORT int cxl_cmd_get_health_info_get_ext_status(struct cxl_cmd *cmd)
+{
+	cmd_health_get_int(cmd, ext_status);
+}
+
+CXL_EXPORT int cxl_cmd_get_health_info_get_life_used(struct cxl_cmd *cmd)
+{
+	cmd_health_get_int(cmd, life_used);
+}
+
+CXL_EXPORT int cxl_cmd_get_health_info_get_temperature(struct cxl_cmd *cmd)
+{
+	cmd_health_get_int(cmd, temperature);
+}
+
+CXL_EXPORT int cxl_cmd_get_health_info_get_dirty_shutdowns(struct cxl_cmd *cmd)
+{
+	cmd_health_get_int(cmd, dirty_shutdowns);
+}
+
+CXL_EXPORT int cxl_cmd_get_health_info_get_volatile_errors(struct cxl_cmd *cmd)
+{
+	cmd_health_get_int(cmd, volatile_errors);
+}
+
+CXL_EXPORT int cxl_cmd_get_health_info_get_pmem_errors(struct cxl_cmd *cmd)
+{
+	cmd_health_get_int(cmd, pmem_errors);
+}
+
 CXL_EXPORT struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev)
 {
 	return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_IDENTIFY);
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index 9ed8c83..56ae4af 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -62,6 +62,15 @@ struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev);
 int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev, int fw_len);
 unsigned long long cxl_cmd_identify_get_partition_align(struct cxl_cmd *cmd);
 unsigned int cxl_cmd_identify_get_lsa_size(struct cxl_cmd *cmd);
+struct cxl_cmd *cxl_cmd_new_get_health_info(struct cxl_memdev *memdev);
+int cxl_cmd_get_health_info_get_health_status(struct cxl_cmd *cmd);
+int cxl_cmd_get_health_info_get_media_status(struct cxl_cmd *cmd);
+int cxl_cmd_get_health_info_get_ext_status(struct cxl_cmd *cmd);
+int cxl_cmd_get_health_info_get_life_used(struct cxl_cmd *cmd);
+int cxl_cmd_get_health_info_get_temperature(struct cxl_cmd *cmd);
+int cxl_cmd_get_health_info_get_dirty_shutdowns(struct cxl_cmd *cmd);
+int cxl_cmd_get_health_info_get_volatile_errors(struct cxl_cmd *cmd);
+int cxl_cmd_get_health_info_get_pmem_errors(struct cxl_cmd *cmd);
 
 #ifdef __cplusplus
 } /* extern "C" */
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index d6aa0b2..e00443d 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -43,4 +43,13 @@ global:
 	cxl_cmd_identify_get_fw_rev;
 	cxl_cmd_identify_get_partition_align;
 	cxl_cmd_identify_get_lsa_size;
+	cxl_cmd_new_get_health_info;
+	cxl_cmd_get_health_info_get_health_status;
+	cxl_cmd_get_health_info_get_media_status;
+	cxl_cmd_get_health_info_get_ext_status;
+	cxl_cmd_get_health_info_get_life_used;
+	cxl_cmd_get_health_info_get_temperature;
+	cxl_cmd_get_health_info_get_dirty_shutdowns;
+	cxl_cmd_get_health_info_get_volatile_errors;
+	cxl_cmd_get_health_info_get_pmem_errors;
 } LIBCXL_2;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 10/21] libcxl: add support for the 'GET_LSA' command
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (8 preceding siblings ...)
  2021-07-01 20:09 ` [ndctl PATCH v3 09/21] libcxl: add GET_HEALTH_INFO mailbox command and accessors Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-16  2:24   ` Dan Williams
  2021-07-01 20:09 ` [ndctl PATCH v3 11/21] util/hexdump: Add a util helper to print a buffer in hex Vishal Verma
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Add a command allocator and accessor APIs for the 'GET_LSA' mailbox
command.

Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 cxl/lib/private.h  |  5 +++++
 cxl/lib/libcxl.c   | 31 +++++++++++++++++++++++++++++++
 cxl/libcxl.h       |  3 +++
 cxl/lib/libcxl.sym |  2 ++
 4 files changed, 41 insertions(+)

diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index 2232f4c..fb1dd8e 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -73,6 +73,11 @@ struct cxl_cmd_identify {
 	u8 qos_telemetry_caps;
 } __attribute__((packed));
 
+struct cxl_cmd_get_lsa_in {
+	le32 offset;
+	le32 length;
+} __attribute__((packed));
+
 struct cxl_cmd_get_health_info {
 	u8 health_status;
 	u8 media_status;
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 2e33c5e..d2c38c9 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -799,6 +799,37 @@ CXL_EXPORT struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev,
 	return cmd;
 }
 
+CXL_EXPORT struct cxl_cmd *cxl_cmd_new_get_lsa(struct cxl_memdev *memdev,
+		unsigned int offset, unsigned int length)
+{
+	struct cxl_cmd_get_lsa_in *get_lsa;
+	struct cxl_cmd *cmd;
+
+	cmd = cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_GET_LSA);
+	if (!cmd)
+		return NULL;
+
+	get_lsa = (void *)cmd->send_cmd->in.payload;
+	get_lsa->offset = cpu_to_le32(offset);
+	get_lsa->length = cpu_to_le32(length);
+	return cmd;
+}
+
+#define cmd_get_void(cmd, N) \
+do { \
+	void *p = (void *)cmd->send_cmd->out.payload; \
+	if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_##N) \
+		return NULL; \
+	if (cmd->status < 0) \
+		return NULL; \
+	return p; \
+} while(0);
+
+CXL_EXPORT void *cxl_cmd_get_lsa_get_payload(struct cxl_cmd *cmd)
+{
+	cmd_get_void(cmd, GET_LSA);
+}
+
 CXL_EXPORT int cxl_cmd_submit(struct cxl_cmd *cmd)
 {
 	struct cxl_memdev *memdev = cmd->memdev;
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index 56ae4af..6edbd8d 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -71,6 +71,9 @@ int cxl_cmd_get_health_info_get_temperature(struct cxl_cmd *cmd);
 int cxl_cmd_get_health_info_get_dirty_shutdowns(struct cxl_cmd *cmd);
 int cxl_cmd_get_health_info_get_volatile_errors(struct cxl_cmd *cmd);
 int cxl_cmd_get_health_info_get_pmem_errors(struct cxl_cmd *cmd);
+struct cxl_cmd *cxl_cmd_new_get_lsa(struct cxl_memdev *memdev,
+		unsigned int offset, unsigned int length);
+void *cxl_cmd_get_lsa_get_payload(struct cxl_cmd *cmd);
 
 #ifdef __cplusplus
 } /* extern "C" */
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index e00443d..2c6193b 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -52,4 +52,6 @@ global:
 	cxl_cmd_get_health_info_get_dirty_shutdowns;
 	cxl_cmd_get_health_info_get_volatile_errors;
 	cxl_cmd_get_health_info_get_pmem_errors;
+	cxl_cmd_new_get_lsa;
+	cxl_cmd_get_lsa_get_payload;
 } LIBCXL_2;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 11/21] util/hexdump: Add a util helper to print a buffer in hex
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (9 preceding siblings ...)
  2021-07-01 20:09 ` [ndctl PATCH v3 10/21] libcxl: add support for the 'GET_LSA' command Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-01 20:09 ` [ndctl PATCH v3 12/21] test/libcxl: add a test for {set, get}_lsa commands Vishal Verma
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

In preparation for tests that may need to set, retrieve, and display
opaque data, add a hexdump function in util/

Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 util/hexdump.h |  8 ++++++++
 util/hexdump.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+)
 create mode 100644 util/hexdump.h
 create mode 100644 util/hexdump.c

diff --git a/util/hexdump.h b/util/hexdump.h
new file mode 100644
index 0000000..d322b6a
--- /dev/null
+++ b/util/hexdump.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021 Intel Corporation. All rights reserved. */
+#ifndef _UTIL_HEXDUMP_H_
+#define _UTIL_HEXDUMP_H_
+
+void hex_dump_buf(unsigned char *buf, int size);
+
+#endif /* _UTIL_HEXDUMP_H_*/
diff --git a/util/hexdump.c b/util/hexdump.c
new file mode 100644
index 0000000..1ab0118
--- /dev/null
+++ b/util/hexdump.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2015-2021 Intel Corporation. All rights reserved. */
+#include <stdio.h>
+#include <util/hexdump.h>
+
+static void print_separator(int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		fprintf(stderr, "-");
+	fprintf(stderr, "\n");
+}
+
+void hex_dump_buf(unsigned char *buf, int size)
+{
+	int i;
+	const int grp = 4;  /* Number of bytes in a group */
+	const int wid = 16; /* Bytes per line. Should be a multiple of grp */
+	char ascii[wid + 1];
+
+	/* Generate header */
+	print_separator((wid * 4) + (wid / grp) + 12);
+
+	fprintf(stderr, "Offset    ");
+	for (i = 0; i < wid; i++) {
+		if (i % grp == 0) fprintf(stderr, " ");
+		fprintf(stderr, "%02x ", i);
+	}
+	fprintf(stderr, "  Ascii\n");
+
+	print_separator((wid * 4) + (wid / grp) + 12);
+
+	/* Generate hex dump */
+	for (i = 0; i < size; i++) {
+		if (i % wid == 0) fprintf(stderr, "%08x  ", i);
+		ascii[i % wid] =
+		    ((buf[i] >= ' ') && (buf[i] <= '~')) ? buf[i] : '.';
+		if (i % grp == 0) fprintf(stderr, " ");
+		fprintf(stderr, "%02x ", buf[i]);
+		if ((i == size - 1) && (size % wid != 0)) {
+			int j;
+			int done = size % wid;
+			int grps_done = (done / grp) + ((done % grp) ? 1 : 0);
+			int spaces = wid / grp - grps_done + ((wid - done) * 3);
+
+			for (j = 0; j < spaces; j++) fprintf(stderr, " ");
+		}
+		if ((i % wid == wid - 1) || (i == size - 1))
+			fprintf(stderr, "  %.*s\n", (i % wid) + 1, ascii);
+	}
+	print_separator((wid * 4) + (wid / grp) + 12);
+}
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 12/21] test/libcxl: add a test for {set, get}_lsa commands
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (10 preceding siblings ...)
  2021-07-01 20:09 ` [ndctl PATCH v3 11/21] util/hexdump: Add a util helper to print a buffer in hex Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-01 20:09 ` [ndctl PATCH v3 13/21] test/libcxl: introduce a command size fuzzing test Vishal Verma
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Add a test to store a static string in the label storage area using the
SET_LSA mailbox command, and retrieve it using the GET_LSA command.
Compare the strings sent and received and ensure they match.

Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 test/libcxl.c    | 134 +++++++++++++++++++++++++++++++++++++++++++++++
 test/Makefile.am |   3 +-
 2 files changed, 136 insertions(+), 1 deletion(-)

diff --git a/test/libcxl.c b/test/libcxl.c
index 241a4bb..437b1ba 100644
--- a/test/libcxl.c
+++ b/test/libcxl.c
@@ -19,6 +19,7 @@
 #include <linux/version.h>
 
 #include <util/size.h>
+#include <util/hexdump.h>
 #include <ccan/short_types/short_types.h>
 #include <ccan/array_size/array_size.h>
 #include <ccan/endian/endian.h>
@@ -210,6 +211,138 @@ out_fail:
 	return rc;
 }
 
+static int debugfs_write_raw_flag(char *str)
+{
+	char *path = "/sys/kernel/debug/cxl/mbox/raw_allow_all";
+	int fd = open(path, O_WRONLY|O_CLOEXEC);
+	int n, len = strlen(str) + 1, rc;
+
+	if (fd < 0)
+		return -errno;
+
+	n = write(fd, str, len);
+	rc = -errno;
+	close(fd);
+	if (n < len) {
+		fprintf(stderr, "failed to write %s to %s: %s\n", str, path,
+					strerror(errno));
+		return rc;
+	}
+	return 0;
+}
+
+static char *test_lsa_data = "LIBCXL_TEST LSA DATA 01";
+static int lsa_size = EXPECT_CMD_IDENTIFY_LSA_SIZE;
+
+static int test_set_lsa(struct cxl_memdev *memdev)
+{
+	int data_size = strlen(test_lsa_data) + 1;
+	struct cxl_cmd *cmd;
+	struct {
+		le32 offset;
+		le32 rsvd;
+		unsigned char data[lsa_size];
+	} __attribute__((packed)) set_lsa;
+	int rc;
+
+	set_lsa.offset = cpu_to_le32(0);
+	set_lsa.rsvd = cpu_to_le32(0);
+	memcpy(set_lsa.data, test_lsa_data, data_size);
+
+	cmd = cxl_cmd_new_raw(memdev, 0x4103);
+	if (!cmd)
+		return -ENOMEM;
+
+	rc = cxl_cmd_set_input_payload(cmd, &set_lsa, sizeof(set_lsa));
+	if (rc) {
+		fprintf(stderr, "%s: %s: cmd setup failed: %s\n",
+			__func__, cxl_memdev_get_devname(memdev),
+			strerror(-rc));
+		goto out_fail;
+	}
+
+	rc = debugfs_write_raw_flag("Y");
+	if (rc < 0)
+		return rc;
+
+	rc = cxl_cmd_submit(cmd);
+	if (rc < 0)
+		fprintf(stderr, "%s: %s: cmd submission failed: %s\n",
+			__func__, cxl_memdev_get_devname(memdev),
+			strerror(-rc));
+
+	rc = cxl_cmd_get_mbox_status(cmd);
+	if (rc != 0) {
+		fprintf(stderr, "%s: %s: firmware status: %d\n",
+			__func__, cxl_memdev_get_devname(memdev), rc);
+		return -ENXIO;
+	}
+
+	if(debugfs_write_raw_flag("N") < 0)
+		fprintf(stderr, "%s: %s: failed to restore raw flag\n",
+			__func__, cxl_memdev_get_devname(memdev));
+
+out_fail:
+	cxl_cmd_unref(cmd);
+	return rc;
+}
+
+static int test_cxl_cmd_lsa(struct cxl_ctx *ctx)
+{
+	int data_size = strlen(test_lsa_data) + 1;
+	struct cxl_memdev *memdev;
+	struct cxl_cmd *cmd;
+	unsigned char *buf;
+	int rc;
+
+	cxl_memdev_foreach(ctx, memdev) {
+		rc = test_set_lsa(memdev);
+		if (rc)
+			return rc;
+
+		cmd = cxl_cmd_new_get_lsa(memdev, 0, lsa_size);
+		if (!cmd)
+			return -ENOMEM;
+		rc = cxl_cmd_set_output_payload(cmd, NULL, lsa_size);
+		if (rc) {
+			fprintf(stderr, "%s: output buffer allocation: %s\n",
+				__func__, strerror(-rc));
+			return rc;
+		}
+		rc = cxl_cmd_submit(cmd);
+		if (rc < 0) {
+			fprintf(stderr, "%s: %s: cmd submission failed: %s\n",
+				__func__, cxl_memdev_get_devname(memdev),
+				strerror(-rc));
+			goto out_fail;
+		}
+
+		rc = cxl_cmd_get_mbox_status(cmd);
+		if (rc != 0) {
+			fprintf(stderr, "%s: %s: firmware status: %d\n",
+				__func__, cxl_memdev_get_devname(memdev), rc);
+			return -ENXIO;
+		}
+
+		buf = cxl_cmd_get_lsa_get_payload(cmd);
+		if (rc < 0)
+			goto out_fail;
+
+		if (memcmp(buf, test_lsa_data, data_size) != 0) {
+			fprintf(stderr, "%s: LSA data mismatch.\n", __func__);
+			hex_dump_buf(buf, data_size);
+			rc = -EIO;
+			goto out_fail;
+		}
+		cxl_cmd_unref(cmd);
+	}
+	return 0;
+
+out_fail:
+	cxl_cmd_unref(cmd);
+	return rc;
+}
+
 typedef int (*do_test_fn)(struct cxl_ctx *ctx);
 
 static do_test_fn do_test[] = {
@@ -217,6 +350,7 @@ static do_test_fn do_test[] = {
 	test_cxl_presence,
 	test_cxl_emulation_env,
 	test_cxl_cmd_identify,
+	test_cxl_cmd_lsa,
 };
 
 static int test_libcxl(int loglevel, struct test_ctx *test, struct cxl_ctx *ctx)
diff --git a/test/Makefile.am b/test/Makefile.am
index ce492a4..23f4860 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -86,7 +86,8 @@ LIBNDCTL_LIB =\
 testcore =\
 	core.c \
 	../util/log.c \
-	../util/sysfs.c
+	../util/sysfs.c \
+	../util/hexdump.c
 
 libndctl_SOURCES = libndctl.c $(testcore)
 libndctl_LDADD = $(LIBNDCTL_LIB) $(UUID_LIBS) $(KMOD_LIBS)
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 13/21] test/libcxl: introduce a command size fuzzing test
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (11 preceding siblings ...)
  2021-07-01 20:09 ` [ndctl PATCH v3 12/21] test/libcxl: add a test for {set, get}_lsa commands Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-01 20:09 ` [ndctl PATCH v3 14/21] libcxl: add lsa_size to cxl_memdev, and an API to retrieve it Vishal Verma
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Add a new test within test/libcxl which tries different combinations of
valid and invalid payload sizes, and ensures that the kernel responds as
expected by either succeeding, returning errors from the ioctl, adjusting
the out.size in the response, etc.

The fuzz set is a statically defined array which contains the different
combinations to test. Adding a new combination only needs appending to
this array.

Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 test/libcxl.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 112 insertions(+)

diff --git a/test/libcxl.c b/test/libcxl.c
index 437b1ba..10f96f2 100644
--- a/test/libcxl.c
+++ b/test/libcxl.c
@@ -211,6 +211,117 @@ out_fail:
 	return rc;
 }
 
+struct cmd_fuzzer {
+	struct cxl_cmd *(*new_fn)(struct cxl_memdev *memdev);
+	int in;		/* in size to set in cmd (INT_MAX = don't change) */
+	int out;	/* out size to set in cmd (INT_MAX = don't change) */
+	int e_out;	/* expected out size returned (INT_MAX = don't check) */
+	int e_rc;	/* expected ioctl return (INT_MAX = don't check) */
+	int e_hwrc;	/* expected 'mbox_status' (INT_MAX = don't check) */
+} fuzz_set[] = {
+	{ cxl_cmd_new_identify, INT_MAX, INT_MAX, 67, 0, 0 },
+	{ cxl_cmd_new_identify, 64, INT_MAX, INT_MAX, -ENOMEM, INT_MAX },
+	{ cxl_cmd_new_identify, INT_MAX, 1024, 67, 0, INT_MAX },
+	{ cxl_cmd_new_identify, INT_MAX, 16, INT_MAX, -ENOMEM, INT_MAX },
+};
+
+static int do_one_cmd_size_test(struct cxl_memdev *memdev,
+		struct cmd_fuzzer *test)
+{
+	const char *devname = cxl_memdev_get_devname(memdev);
+	struct cxl_cmd *cmd;
+	int rc;
+
+	cmd = test->new_fn(memdev);
+	if (!cmd)
+		return -ENOMEM;
+
+	if (test->in != INT_MAX) {
+		rc = cxl_cmd_set_input_payload(cmd, NULL, test->in);
+		if (rc) {
+			fprintf(stderr,
+				"%s: %s: failed to set in.size (%d): %s\n",
+				__func__, devname, test->in, strerror(-rc));
+			goto out_fail;
+		}
+	}
+	if (test->out != INT_MAX) {
+		rc = cxl_cmd_set_output_payload(cmd, NULL, test->out);
+		if (rc) {
+			fprintf(stderr,
+				"%s: %s: failed to set out.size (%d): %s\n",
+				__func__, devname, test->out, strerror(-rc));
+			goto out_fail;
+		}
+	}
+
+	rc = cxl_cmd_submit(cmd);
+	if (test->e_rc != INT_MAX && rc != test->e_rc) {
+		fprintf(stderr, "%s: %s: expected cmd rc %d, got %d\n",
+			__func__, devname, test->e_rc, rc);
+		rc = -ENXIO;
+		goto out_fail;
+	}
+
+	rc = cxl_cmd_get_out_size(cmd);
+	if (test->e_out != INT_MAX && rc != test->e_out) {
+		fprintf(stderr, "%s: %s: expected response out.size %d, got %d\n",
+			__func__, devname, test->e_out, rc);
+		rc = -ENXIO;
+		goto out_fail;
+	}
+
+	rc = cxl_cmd_get_mbox_status(cmd);
+	if (test->e_hwrc != INT_MAX && rc != test->e_hwrc) {
+		fprintf(stderr, "%s: %s: expected firmware status %d, got %d\n",
+			__func__, devname, test->e_hwrc, rc);
+		rc = -ENXIO;
+		goto out_fail;
+	}
+	return 0;
+
+out_fail:
+	cxl_cmd_unref(cmd);
+	return rc;
+
+}
+
+static void print_fuzz_test_status(struct cmd_fuzzer *t, const char *devname,
+		unsigned long idx, const char *msg)
+{
+	fprintf(stderr,
+		"%s: fuzz_set[%lu]: in: %d, out %d, e_out: %d, e_rc: %d, e_hwrc: %d, result: %s\n",
+		devname, idx,
+		(t->in == INT_MAX) ? -1 : t->in,
+		(t->out == INT_MAX) ? -1 : t->out,
+		(t->e_out == INT_MAX) ? -1 : t->e_out,
+		(t->e_rc == INT_MAX) ? -1 : t->e_rc,
+		(t->e_hwrc == INT_MAX) ? -1 : t->e_hwrc,
+		msg);
+}
+
+static int test_cxl_cmd_fuzz_sizes(struct cxl_ctx *ctx)
+{
+	struct cxl_memdev *memdev;
+	unsigned long i;
+	int rc;
+
+	cxl_memdev_foreach(ctx, memdev) {
+		const char *devname = cxl_memdev_get_devname(memdev);
+
+		for (i = 0; i < ARRAY_SIZE(fuzz_set); i++) {
+			rc = do_one_cmd_size_test(memdev, &fuzz_set[i]);
+			if (rc) {
+				print_fuzz_test_status(&fuzz_set[i], devname,
+					i, "FAIL");
+				return rc;
+			}
+			print_fuzz_test_status(&fuzz_set[i], devname, i, "OK");
+		}
+	}
+	return 0;
+}
+
 static int debugfs_write_raw_flag(char *str)
 {
 	char *path = "/sys/kernel/debug/cxl/mbox/raw_allow_all";
@@ -351,6 +462,7 @@ static do_test_fn do_test[] = {
 	test_cxl_emulation_env,
 	test_cxl_cmd_identify,
 	test_cxl_cmd_lsa,
+	test_cxl_cmd_fuzz_sizes,
 };
 
 static int test_libcxl(int loglevel, struct test_ctx *test, struct cxl_ctx *ctx)
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 14/21] libcxl: add lsa_size to cxl_memdev, and an API to retrieve it
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (12 preceding siblings ...)
  2021-07-01 20:09 ` [ndctl PATCH v3 13/21] test/libcxl: introduce a command size fuzzing test Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-01 20:09 ` [ndctl PATCH v3 15/21] libcxl: PLACEHOLDER: add an interface to determine whether a memdev is active Vishal Verma
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Size of the Label Storage Area (LSA) is available as a sysfs attribute
called 'lsa_size'. Add that to libcxl's memdev so that it is available
for label related commands.

Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 cxl/lib/private.h  |  1 +
 cxl/lib/libcxl.c   | 12 ++++++++++++
 cxl/libcxl.h       |  1 +
 cxl/lib/libcxl.sym |  5 +++++
 4 files changed, 19 insertions(+)

diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index fb1dd8e..1bce3b5 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -21,6 +21,7 @@ struct cxl_memdev {
 	unsigned long long pmem_size;
 	unsigned long long ram_size;
 	int payload_max;
+	size_t lsa_size;
 	struct kmod_module *module;
 };
 
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index d2c38c9..ae03e03 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -246,6 +246,13 @@ static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)
 	if (memdev->payload_max < 0)
 		goto err_read;
 
+	sprintf(path, "%s/label_storage_size", cxlmem_base);
+	if (sysfs_read_attr(ctx, path, buf) < 0)
+		goto err_read;
+	memdev->lsa_size = strtoull(buf, NULL, 0);
+	if (memdev->lsa_size == ULLONG_MAX)
+		goto err_read;
+
 	memdev->dev_path = strdup(cxlmem_base);
 	if (!memdev->dev_path)
 		goto err_read;
@@ -349,6 +356,11 @@ CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev
 	return memdev->firmware_version;
 }
 
+CXL_EXPORT size_t cxl_memdev_get_lsa_size(struct cxl_memdev *memdev)
+{
+	return memdev->lsa_size;
+}
+
 CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd)
 {
 	if (!cmd)
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index 6edbd8d..eeace11 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -42,6 +42,7 @@ struct cxl_ctx *cxl_memdev_get_ctx(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_lsa_size(struct cxl_memdev *memdev);
 
 #define cxl_memdev_foreach(ctx, memdev) \
         for (memdev = cxl_memdev_get_first(ctx); \
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index 2c6193b..a5a1371 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -55,3 +55,8 @@ global:
 	cxl_cmd_new_get_lsa;
 	cxl_cmd_get_lsa_get_payload;
 } LIBCXL_2;
+
+LIBCXL_4 {
+global:
+	cxl_memdev_get_lsa_size;
+} LIBCXL_3;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 15/21] libcxl: PLACEHOLDER: add an interface to determine whether a memdev is active
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (13 preceding siblings ...)
  2021-07-01 20:09 ` [ndctl PATCH v3 14/21] libcxl: add lsa_size to cxl_memdev, and an API to retrieve it Vishal Verma
@ 2021-07-01 20:09 ` Vishal Verma
  2021-07-01 20:10 ` [ndctl PATCH v3 16/21] libcxl: add interfaces for label operations Vishal Verma
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:09 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Add an interface to determine whether a memdev is bound to a region
driver and therefore is currently active.

For now, this just returns '0' all the time - i.e. devices are always
considered inactive. Flesh this out fully once the region driver is
available.

Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 cxl/lib/libcxl.c   | 10 ++++++++++
 cxl/libcxl.h       |  1 +
 cxl/lib/libcxl.sym |  1 +
 3 files changed, 12 insertions(+)

diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index ae03e03..246fa2a 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -361,6 +361,16 @@ CXL_EXPORT size_t cxl_memdev_get_lsa_size(struct cxl_memdev *memdev)
 	return memdev->lsa_size;
 }
 
+CXL_EXPORT int cxl_memdev_is_active(struct cxl_memdev *memdev)
+{
+	/*
+	 * TODO: Currently memdevs are always considered inactive. Once we have
+	 * cxl_bus drivers that are bound/unbound to memdevs, we'd use that to
+	 * determine the active/inactive state.
+	 */
+	return 0;
+}
+
 CXL_EXPORT void cxl_cmd_unref(struct cxl_cmd *cmd)
 {
 	if (!cmd)
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index eeace11..65f6c62 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -43,6 +43,7 @@ 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_lsa_size(struct cxl_memdev *memdev);
+int cxl_memdev_is_active(struct cxl_memdev *memdev);
 
 #define cxl_memdev_foreach(ctx, memdev) \
         for (memdev = cxl_memdev_get_first(ctx); \
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index a5a1371..d90502f 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -59,4 +59,5 @@ global:
 LIBCXL_4 {
 global:
 	cxl_memdev_get_lsa_size;
+	cxl_memdev_is_active;
 } LIBCXL_3;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 16/21] libcxl: add interfaces for label operations
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (14 preceding siblings ...)
  2021-07-01 20:09 ` [ndctl PATCH v3 15/21] libcxl: PLACEHOLDER: add an interface to determine whether a memdev is active Vishal Verma
@ 2021-07-01 20:10 ` Vishal Verma
  2021-07-01 20:10 ` [ndctl PATCH v3 17/21] test/libcxl: add a test for cxl_memdev_{get,set}_lsa Vishal Verma
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:10 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Add libcxl interfaces to allow performinfg label (LSA) manipulations.
Add a 'cxl_cmd_new_set_lsa' interface to create a 'Set LSA' mailbox
command payload, and interfaces to read, write, and zero the LSA area on
a memdev.

Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 cxl/lib/private.h  |   6 +++
 cxl/lib/libcxl.c   | 130 +++++++++++++++++++++++++++++++++++++++++++++
 cxl/libcxl.h       |   7 +++
 cxl/lib/libcxl.sym |   4 ++
 4 files changed, 147 insertions(+)

diff --git a/cxl/lib/private.h b/cxl/lib/private.h
index 1bce3b5..103429e 100644
--- a/cxl/lib/private.h
+++ b/cxl/lib/private.h
@@ -79,6 +79,12 @@ struct cxl_cmd_get_lsa_in {
 	le32 length;
 } __attribute__((packed));
 
+struct cxl_cmd_set_lsa {
+	le32 offset;
+	le32 rsvd;
+	unsigned char lsa_data[0];
+} __attribute__ ((packed));
+
 struct cxl_cmd_get_health_info {
 	u8 health_status;
 	u8 media_status;
diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
index 246fa2a..46d2c19 100644
--- a/cxl/lib/libcxl.c
+++ b/cxl/lib/libcxl.c
@@ -894,3 +894,133 @@ CXL_EXPORT int cxl_cmd_get_out_size(struct cxl_cmd *cmd)
 {
 	return cmd->send_cmd->out.size;
 }
+
+CXL_EXPORT struct cxl_cmd *cxl_cmd_new_set_lsa(struct cxl_memdev *memdev,
+		void *lsa_buf, unsigned int offset, unsigned int length)
+{
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+	struct cxl_cmd_set_lsa *set_lsa;
+	struct cxl_cmd *cmd;
+	int rc;
+
+	cmd = cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_SET_LSA);
+	if (!cmd)
+		return NULL;
+
+	/* this will allocate 'in.payload' */
+	rc = cxl_cmd_set_input_payload(cmd, NULL, sizeof(*set_lsa) + length);
+	if (rc) {
+		err(ctx, "%s: cmd setup failed: %s\n",
+			cxl_memdev_get_devname(memdev), strerror(-rc));
+		goto out_fail;
+	}
+	set_lsa = (void *)cmd->send_cmd->in.payload;
+	set_lsa->offset = cpu_to_le32(offset);
+	memcpy(set_lsa->lsa_data, lsa_buf, length);
+
+	return cmd;
+
+out_fail:
+	cxl_cmd_unref(cmd);
+	return NULL;
+}
+
+enum lsa_op {
+	LSA_OP_GET,
+	LSA_OP_SET,
+	LSA_OP_ZERO,
+};
+
+static int lsa_op(struct cxl_memdev *memdev, int op, void **buf,
+		size_t length, size_t offset)
+{
+	const char *devname = cxl_memdev_get_devname(memdev);
+	struct cxl_ctx *ctx = cxl_memdev_get_ctx(memdev);
+	struct cxl_cmd *cmd;
+	void *zero_buf = NULL;
+	int rc = 0;
+
+	if (op != LSA_OP_ZERO && (buf == NULL || *buf == NULL)) {
+		err(ctx, "%s: LSA buffer cannot be NULL\n", devname);
+		return -EINVAL;
+	}
+
+	/* TODO: handle the case for offset + len > mailbox payload size */
+	switch (op) {
+	case LSA_OP_GET:
+		if (length == 0)
+			length = memdev->lsa_size;
+		cmd = cxl_cmd_new_get_lsa(memdev, offset, length);
+		if (!cmd)
+			return -ENOMEM;
+		rc = cxl_cmd_set_output_payload(cmd, *buf, length);
+		if (rc) {
+			err(ctx, "%s: cmd setup failed: %s\n",
+			    cxl_memdev_get_devname(memdev), strerror(-rc));
+			goto out;
+		}
+		break;
+	case LSA_OP_ZERO:
+		if (length == 0)
+			length = memdev->lsa_size;
+		zero_buf = calloc(1, length);
+		if (!zero_buf)
+			return -ENOMEM;
+		buf = &zero_buf;
+		/* fall through */
+	case LSA_OP_SET:
+		cmd = cxl_cmd_new_set_lsa(memdev, *buf, offset, length);
+		if (!cmd) {
+			rc = -ENOMEM;
+			goto out_free;
+		}
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	rc = cxl_cmd_submit(cmd);
+	if (rc < 0) {
+		err(ctx, "%s: cmd submission failed: %s\n",
+			devname, strerror(-rc));
+		goto out;
+	}
+
+	rc = cxl_cmd_get_mbox_status(cmd);
+	if (rc != 0) {
+		err(ctx, "%s: firmware status: %d\n",
+			devname, rc);
+		rc = -ENXIO;
+		goto out;
+	}
+
+	if (op == LSA_OP_GET)
+		memcpy(*buf, cxl_cmd_get_lsa_get_payload(cmd), length);
+	/*
+	 * TODO: If writing, the memdev may need to be disabled/re-enabled to
+	 * refresh any cached LSA data in the kernel.
+	 */
+
+out:
+	cxl_cmd_unref(cmd);
+out_free:
+	free(zero_buf);
+	return rc;
+}
+
+CXL_EXPORT int cxl_memdev_zero_lsa(struct cxl_memdev *memdev)
+{
+	return lsa_op(memdev, LSA_OP_ZERO, NULL, 0, 0);
+}
+
+CXL_EXPORT int cxl_memdev_set_lsa(struct cxl_memdev *memdev, void *buf,
+		size_t length, size_t offset)
+{
+	return lsa_op(memdev, LSA_OP_SET, &buf, length, offset);
+}
+
+CXL_EXPORT int cxl_memdev_get_lsa(struct cxl_memdev *memdev, void *buf,
+		size_t length, size_t offset)
+{
+	return lsa_op(memdev, LSA_OP_GET, &buf, length, offset);
+}
diff --git a/cxl/libcxl.h b/cxl/libcxl.h
index 65f6c62..0ea2c8d 100644
--- a/cxl/libcxl.h
+++ b/cxl/libcxl.h
@@ -44,6 +44,11 @@ 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_lsa_size(struct cxl_memdev *memdev);
 int cxl_memdev_is_active(struct cxl_memdev *memdev);
+int cxl_memdev_zero_lsa(struct cxl_memdev *memdev);
+int cxl_memdev_get_lsa(struct cxl_memdev *memdev, void *buf, size_t length,
+		size_t offset);
+int cxl_memdev_set_lsa(struct cxl_memdev *memdev, void *buf, size_t length,
+		size_t offset);
 
 #define cxl_memdev_foreach(ctx, memdev) \
         for (memdev = cxl_memdev_get_first(ctx); \
@@ -76,6 +81,8 @@ int cxl_cmd_get_health_info_get_pmem_errors(struct cxl_cmd *cmd);
 struct cxl_cmd *cxl_cmd_new_get_lsa(struct cxl_memdev *memdev,
 		unsigned int offset, unsigned int length);
 void *cxl_cmd_get_lsa_get_payload(struct cxl_cmd *cmd);
+struct cxl_cmd *cxl_cmd_new_set_lsa(struct cxl_memdev *memdev,
+		void *buf, unsigned int offset, unsigned int length);
 
 #ifdef __cplusplus
 } /* extern "C" */
diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
index d90502f..ba8fa4b 100644
--- a/cxl/lib/libcxl.sym
+++ b/cxl/lib/libcxl.sym
@@ -60,4 +60,8 @@ LIBCXL_4 {
 global:
 	cxl_memdev_get_lsa_size;
 	cxl_memdev_is_active;
+	cxl_cmd_new_set_lsa;
+	cxl_memdev_zero_lsa;
+	cxl_memdev_set_lsa;
+	cxl_memdev_get_lsa;
 } LIBCXL_3;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 17/21] test/libcxl: add a test for cxl_memdev_{get,set}_lsa
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (15 preceding siblings ...)
  2021-07-01 20:10 ` [ndctl PATCH v3 16/21] libcxl: add interfaces for label operations Vishal Verma
@ 2021-07-01 20:10 ` Vishal Verma
  2021-07-01 20:10 ` [ndctl PATCH v3 18/21] cxl: add commands to read, write, and zero labels Vishal Verma
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:10 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Add a unit test to test the new get/set LSA APIs in libcxl.

Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 test/libcxl.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/test/libcxl.c b/test/libcxl.c
index 10f96f2..e3da19c 100644
--- a/test/libcxl.c
+++ b/test/libcxl.c
@@ -454,6 +454,43 @@ out_fail:
 	return rc;
 }
 
+static char *test_lsa_api_data = "LIBCXL_TEST READ/WRITE LSA DATA 2";
+static int test_cxl_read_write_lsa(struct cxl_ctx *ctx)
+{
+	int data_size = strlen(test_lsa_api_data) + 1;
+	struct cxl_memdev *memdev;
+	unsigned char *buf;
+	int rc = 0;
+
+	buf = calloc(1, data_size);
+	if (!buf)
+		return -ENOMEM;
+
+	cxl_memdev_foreach(ctx, memdev) {
+		rc = cxl_memdev_set_lsa(memdev, test_lsa_api_data, data_size, 0);
+		if (rc)
+			goto out_fail;
+
+		rc = cxl_memdev_get_lsa(memdev, buf, data_size, 0);
+		if (rc < 0)
+			goto out_fail;
+
+		if (memcmp(buf, test_lsa_api_data, data_size) != 0) {
+			fprintf(stderr, "%s: LSA data mismatch.\n", __func__);
+			fprintf(stderr, "%s: Get LSA returned:\n", __func__);
+			hex_dump_buf(buf, data_size);
+			fprintf(stderr, "%s: Set LSA had set:\n", __func__);
+			hex_dump_buf((unsigned char *)test_lsa_api_data, data_size);
+			rc = -EIO;
+			goto out_fail;
+		}
+	}
+
+out_fail:
+	free(buf);
+	return rc;
+}
+
 typedef int (*do_test_fn)(struct cxl_ctx *ctx);
 
 static do_test_fn do_test[] = {
@@ -463,6 +500,7 @@ static do_test_fn do_test[] = {
 	test_cxl_cmd_identify,
 	test_cxl_cmd_lsa,
 	test_cxl_cmd_fuzz_sizes,
+	test_cxl_read_write_lsa,
 };
 
 static int test_libcxl(int loglevel, struct test_ctx *test, struct cxl_ctx *ctx)
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 18/21] cxl: add commands to read, write, and zero labels
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (16 preceding siblings ...)
  2021-07-01 20:10 ` [ndctl PATCH v3 17/21] test/libcxl: add a test for cxl_memdev_{get,set}_lsa Vishal Verma
@ 2021-07-01 20:10 ` Vishal Verma
  2021-07-01 20:10 ` [ndctl PATCH v3 19/21] Documentation/cxl: add library API documentation Vishal Verma
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:10 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Add the following cxl-cli commands: read-labels, write-labels,
zero-labels. They operate on a CXL memdev, or a set of memdevs, and
allow interacting with the label storage area (LSA) on the device.

Add man pages for the above cxl-cli commands.

Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 Documentation/cxl/cxl-read-labels.txt    |  33 +++
 Documentation/cxl/cxl-write-labels.txt   |  32 +++
 Documentation/cxl/cxl-zero-labels.txt    |  29 +++
 Documentation/cxl/labels-description.txt |   8 +
 Documentation/cxl/labels-options.txt     |  17 ++
 Documentation/cxl/memdev-option.txt      |   4 +
 cxl/builtin.h                            |   5 +
 cxl/cxl.c                                |   3 +
 cxl/memdev.c                             | 314 +++++++++++++++++++++++
 Documentation/cxl/Makefile.am            |   5 +-
 cxl/Makefile.am                          |   1 +
 11 files changed, 450 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/cxl/cxl-read-labels.txt
 create mode 100644 Documentation/cxl/cxl-write-labels.txt
 create mode 100644 Documentation/cxl/cxl-zero-labels.txt
 create mode 100644 Documentation/cxl/labels-description.txt
 create mode 100644 Documentation/cxl/labels-options.txt
 create mode 100644 Documentation/cxl/memdev-option.txt
 create mode 100644 cxl/memdev.c

diff --git a/Documentation/cxl/cxl-read-labels.txt b/Documentation/cxl/cxl-read-labels.txt
new file mode 100644
index 0000000..143f296
--- /dev/null
+++ b/Documentation/cxl/cxl-read-labels.txt
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0
+
+cxl-read-labels(1)
+==================
+
+NAME
+----
+cxl-read-labels - read out the label area on a CXL memdev
+
+SYNOPSIS
+--------
+[verse]
+'cxl read-labels' <mem0> [<mem1>..<memN>] [<options>]
+
+include::labels-description.txt[]
+This command dumps the raw binary data in a memdev's label area to stdout or a
+file.  In the multi-memdev case the data is concatenated.
+
+OPTIONS
+-------
+include::labels-options.txt[]
+
+-o::
+--output::
+	output file
+
+include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkcxl:cxl-write-labels[1],
+linkcxl:cxl-zero-labels[1],
+CXL-2.0 9.13.2
diff --git a/Documentation/cxl/cxl-write-labels.txt b/Documentation/cxl/cxl-write-labels.txt
new file mode 100644
index 0000000..c4592b3
--- /dev/null
+++ b/Documentation/cxl/cxl-write-labels.txt
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+
+cxl-write-labels(1)
+===================
+
+NAME
+----
+cxl-write-labels - write data to the label area on a memdev
+
+SYNOPSIS
+--------
+[verse]
+'cxl write-labels <mem> [-i <filename>]'
+
+include::labels-description.txt[]
+Read data from the input filename, or stdin, and write it to the given
+<mem> device. Note that the device must not be active in any region,
+otherwise the kernel will not allow write access to the device's label
+data area.
+
+OPTIONS
+-------
+include::labels-options.txt[]
+-i::
+--input::
+	input file
+
+SEE ALSO
+--------
+linkcxl:cxl-read-labels[1],
+linkcxl:cxl-zero-labels[1],
+CXL-2.0 9.13.2
diff --git a/Documentation/cxl/cxl-zero-labels.txt b/Documentation/cxl/cxl-zero-labels.txt
new file mode 100644
index 0000000..bf95b24
--- /dev/null
+++ b/Documentation/cxl/cxl-zero-labels.txt
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+
+cxl-zero-labels(1)
+==================
+
+NAME
+----
+cxl-zero-labels - zero out the label area on a set of memdevs
+
+SYNOPSIS
+--------
+[verse]
+'cxl zero-labels' <mem0> [<mem1>..<memN>] [<options>]
+
+include::labels-description.txt[]
+This command resets the device to its default state by
+deleting all labels.
+
+OPTIONS
+-------
+include::labels-options.txt[]
+
+include::../copyright.txt[]
+
+SEE ALSO
+--------
+linkcxl:cxl-read-labels[1],
+linkcxl:cxl-write-labels[1],
+CXL-2.0 9.13.2
diff --git a/Documentation/cxl/labels-description.txt b/Documentation/cxl/labels-description.txt
new file mode 100644
index 0000000..f60bd5d
--- /dev/null
+++ b/Documentation/cxl/labels-description.txt
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+
+DESCRIPTION
+-----------
+The region label area is a small persistent partition of capacity
+available on some CXL memory devices. The label area is used to
+and configure or determine the set of memory devices participating
+in different interleave sets.
diff --git a/Documentation/cxl/labels-options.txt b/Documentation/cxl/labels-options.txt
new file mode 100644
index 0000000..06fbac3
--- /dev/null
+++ b/Documentation/cxl/labels-options.txt
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
+
+<memory device(s)>::
+include::memdev-option.txt[]
+
+-s::
+--size=::
+	Limit the operation to the given number of bytes. A size of 0
+	indicates to operate over the entire label capacity.
+
+-O::
+--offset=::
+	Begin the operation at the given offset into the label area.
+
+-v::
+	Turn on verbose debug messages in the library (if libcxl was built with
+	logging and debug enabled).
diff --git a/Documentation/cxl/memdev-option.txt b/Documentation/cxl/memdev-option.txt
new file mode 100644
index 0000000..e778582
--- /dev/null
+++ b/Documentation/cxl/memdev-option.txt
@@ -0,0 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
+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.
diff --git a/cxl/builtin.h b/cxl/builtin.h
index 3797f98..78eca6e 100644
--- a/cxl/builtin.h
+++ b/cxl/builtin.h
@@ -5,4 +5,9 @@
 
 struct cxl_ctx;
 int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx);
+int cmd_write_labels(int argc, const char **argv, struct cxl_ctx *ctx);
+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);
 #endif /* _CXL_BUILTIN_H_ */
diff --git a/cxl/cxl.c b/cxl/cxl.c
index a7725f8..4b1661d 100644
--- a/cxl/cxl.c
+++ b/cxl/cxl.c
@@ -61,6 +61,9 @@ static struct cmd_struct commands[] = {
 	{ "version", .c_fn = cmd_version },
 	{ "list", .c_fn = cmd_list },
 	{ "help", .c_fn = cmd_help },
+	{ "zero-labels", .c_fn = cmd_zero_labels },
+	{ "read-labels", .c_fn = cmd_read_labels },
+	{ "write-labels", .c_fn = cmd_write_labels },
 };
 
 int main(int argc, const char **argv)
diff --git a/cxl/memdev.c b/cxl/memdev.c
new file mode 100644
index 0000000..c80fe29
--- /dev/null
+++ b/cxl/memdev.c
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2020-2021 Intel Corporation. All rights reserved. */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <util/log.h>
+#include <util/filter.h>
+#include <cxl/libcxl.h>
+#include <util/parse-options.h>
+#include <ccan/minmax/minmax.h>
+#include <ccan/array_size/array_size.h>
+
+struct action_context {
+	FILE *f_out;
+	FILE *f_in;
+};
+
+static struct parameters {
+	const char *outfile;
+	const char *infile;
+	unsigned len;
+	unsigned offset;
+	bool verbose;
+} param;
+
+#define fail(fmt, ...) \
+do { \
+	fprintf(stderr, "cxl-%s:%s:%d: " fmt, \
+			VERSION, __func__, __LINE__, ##__VA_ARGS__); \
+} while (0)
+
+#define BASE_OPTIONS() \
+OPT_BOOLEAN('v',"verbose", &param.verbose, "turn on debug")
+
+#define READ_OPTIONS() \
+OPT_STRING('o', "output", &param.outfile, "output-file", \
+	"filename to write label area contents")
+
+#define WRITE_OPTIONS() \
+OPT_STRING('i', "input", &param.infile, "input-file", \
+	"filename to read label area data")
+
+#define LABEL_OPTIONS() \
+OPT_UINTEGER('s', "size", &param.len, "number of label bytes to operate"), \
+OPT_UINTEGER('O', "offset", &param.offset, \
+	"offset into the label area to start operation")
+
+static const struct option read_options[] = {
+	BASE_OPTIONS(),
+	LABEL_OPTIONS(),
+	READ_OPTIONS(),
+	OPT_END(),
+};
+
+static const struct option write_options[] = {
+	BASE_OPTIONS(),
+	LABEL_OPTIONS(),
+	WRITE_OPTIONS(),
+	OPT_END(),
+};
+
+static const struct option zero_options[] = {
+	BASE_OPTIONS(),
+	LABEL_OPTIONS(),
+	OPT_END(),
+};
+
+static int action_zero(struct cxl_memdev *memdev, struct action_context *actx)
+{
+	int rc;
+
+	if (cxl_memdev_is_active(memdev)) {
+		fprintf(stderr, "%s: memdev active, abort label write\n",
+			cxl_memdev_get_devname(memdev));
+		return -EBUSY;
+	}
+
+	rc = cxl_memdev_zero_lsa(memdev);
+	if (rc < 0)
+		fprintf(stderr, "%s: label zeroing failed: %s\n",
+			cxl_memdev_get_devname(memdev), strerror(-rc));
+
+	return rc;
+}
+
+static int action_write(struct cxl_memdev *memdev, struct action_context *actx)
+{
+	size_t size = param.len, read_len;
+	unsigned char *buf;
+	int rc;
+
+	if (cxl_memdev_is_active(memdev)) {
+		fprintf(stderr, "%s is active, abort label write\n",
+			cxl_memdev_get_devname(memdev));
+		return -EBUSY;
+	}
+
+	if (!size) {
+		size_t lsa_size = cxl_memdev_get_lsa_size(memdev);
+
+		fseek(actx->f_in, 0L, SEEK_END);
+		size = ftell(actx->f_in);
+		fseek(actx->f_in, 0L, SEEK_SET);
+
+		if (size > lsa_size) {
+			fprintf(stderr,
+				"File size (%zu) greater than LSA size (%zu), aborting\n",
+				size, lsa_size);
+			return -EINVAL;
+		}
+	}
+
+	buf = calloc(1, size);
+	if (!buf)
+		return -ENOMEM;
+
+	read_len = fread(buf, 1, size, actx->f_in);
+	if (read_len != size) {
+		rc = -ENXIO;
+		goto out;
+	}
+
+	rc = cxl_memdev_set_lsa(memdev, buf, size, param.offset);
+	if (rc < 0)
+		fprintf(stderr, "%s: label write failed: %s\n",
+			cxl_memdev_get_devname(memdev), strerror(-rc));
+
+out:
+	free(buf);
+	return rc;
+}
+
+static int action_read(struct cxl_memdev *memdev, struct action_context *actx)
+{
+	size_t size = param.len, write_len;
+	char *buf;
+	int rc;
+
+	if (!size)
+		size = cxl_memdev_get_lsa_size(memdev);
+
+	buf = calloc(1, size);
+	if (!buf)
+		return -ENOMEM;
+
+	rc = cxl_memdev_get_lsa(memdev, buf, size, param.offset);
+	if (rc < 0) {
+		fprintf(stderr, "%s: label read failed: %s\n",
+			cxl_memdev_get_devname(memdev), strerror(-rc));
+		goto out;
+	}
+
+	write_len = fwrite(buf, 1, size, actx->f_out);
+	if (write_len != size) {
+		rc = -ENXIO;
+		goto out;
+	}
+	fflush(actx->f_out);
+
+out:
+	free(buf);
+	return rc;
+}
+
+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)
+{
+	struct cxl_memdev *memdev, *single = NULL;
+	struct action_context actx = { 0 };
+	int i, rc = 0, count = 0, err = 0;
+	const char * const u[] = {
+		usage,
+		NULL
+	};
+	unsigned long id;
+
+	argc = parse_options(argc, argv, options, u, 0);
+
+	if (argc == 0)
+		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) {
+			fprintf(stderr, "'%s' is not a valid memdev name\n",
+					argv[i]);
+			err++;
+		}
+	}
+
+	if (err == argc) {
+		usage_with_options(u, options);
+		return -EINVAL;
+	}
+
+	if (!param.outfile)
+		actx.f_out = stdout;
+	else {
+		actx.f_out = fopen(param.outfile, "w+");
+		if (!actx.f_out) {
+			fprintf(stderr, "failed to open: %s: (%s)\n",
+					param.outfile, strerror(errno));
+			rc = -errno;
+			goto out;
+		}
+	}
+
+	if (!param.infile) {
+		actx.f_in = stdin;
+	} else {
+		actx.f_in = fopen(param.infile, "r");
+		if (!actx.f_in) {
+			fprintf(stderr, "failed to open: %s: (%s)\n",
+					param.infile, strerror(errno));
+			rc = -errno;
+			goto out_close_fout;
+		}
+	}
+
+	if (param.verbose)
+		cxl_set_log_priority(ctx, LOG_DEBUG);
+
+	rc = 0;
+	err = 0;
+	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) {
+			if (!util_cxl_memdev_filter(memdev, argv[i]))
+				continue;
+
+			if (action == action_write) {
+				single = memdev;
+				rc = 0;
+			} else
+				rc = action(memdev, &actx);
+
+			if (rc == 0)
+				count++;
+			else if (rc && !err)
+				err = rc;
+		}
+	}
+	rc = err;
+
+	if (action == action_write) {
+		if (count > 1) {
+			error("write-labels only supports writing a single memdev\n");
+			usage_with_options(u, options);
+			return -EINVAL;
+		} else if (single) {
+			rc = action(single, &actx);
+			if (rc)
+				count = 0;
+		}
+	}
+
+	if (actx.f_in != stdin)
+		fclose(actx.f_in);
+
+ out_close_fout:
+	if (actx.f_out != stdout)
+		fclose(actx.f_out);
+
+ out:
+	/*
+	 * count if some actions succeeded, 0 if none were attempted,
+	 * negative error code otherwise.
+	 */
+	if (count > 0)
+		return count;
+	return rc;
+}
+
+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 <memdev> [-i <filename>]");
+
+	fprintf(stderr, "wrote %d mem%s\n", count >= 0 ? count : 0,
+			count > 1 ? "s" : "");
+	return count >= 0 ? 0 : EXIT_FAILURE;
+}
+
+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 <mem0> [<mem1>..<memN>] [-o <filename>]");
+
+	fprintf(stderr, "read %d mem%s\n", count >= 0 ? count : 0,
+			count > 1 ? "s" : "");
+	return count >= 0 ? 0 : EXIT_FAILURE;
+}
+
+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 <mem0> [<mem1>..<memN>] [<options>]");
+
+	fprintf(stderr, "zeroed %d mem%s\n", count >= 0 ? count : 0,
+			count > 1 ? "s" : "");
+	return count >= 0 ? 0 : EXIT_FAILURE;
+}
diff --git a/Documentation/cxl/Makefile.am b/Documentation/cxl/Makefile.am
index db98dd7..efabaa3 100644
--- a/Documentation/cxl/Makefile.am
+++ b/Documentation/cxl/Makefile.am
@@ -19,7 +19,10 @@ endif
 
 man1_MANS = \
 	cxl.1 \
-	cxl-list.1
+	cxl-list.1 \
+	cxl-read-labels.1 \
+	cxl-write-labels.1 \
+	cxl-zero-labels.1
 
 EXTRA_DIST = $(man1_MANS)
 
diff --git a/cxl/Makefile.am b/cxl/Makefile.am
index 98606b9..da9f91d 100644
--- a/cxl/Makefile.am
+++ b/cxl/Makefile.am
@@ -10,6 +10,7 @@ config.h: $(srcdir)/Makefile.am
 cxl_SOURCES =\
 		cxl.c \
 		list.c \
+		memdev.c \
 		../util/json.c \
 		builtin.h
 
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 19/21] Documentation/cxl: add library API documentation
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (17 preceding siblings ...)
  2021-07-01 20:10 ` [ndctl PATCH v3 18/21] cxl: add commands to read, write, and zero labels Vishal Verma
@ 2021-07-01 20:10 ` Vishal Verma
  2021-07-01 20:10 ` [ndctl PATCH v3 20/21] ndctl: Add CXL packages to the RPM spec Vishal Verma
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:10 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Add library API documentation for libcxl(3) using the existing
asciidoc(tor) build system. Add a section 3 man page for 'libcxl' that
provides an overview of the library and its usage, and a man page for
the 'cxl_new()' API.

Cc: Ben Widawsky <ben.widawsky@intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 Documentation/cxl/lib/cxl_new.txt | 43 +++++++++++++++++++++++
 Documentation/cxl/lib/libcxl.txt  | 56 +++++++++++++++++++++++++++++
 configure.ac                      |  1 +
 Makefile.am                       |  1 +
 .gitignore                        |  3 ++
 Documentation/cxl/lib/Makefile.am | 58 +++++++++++++++++++++++++++++++
 6 files changed, 162 insertions(+)
 create mode 100644 Documentation/cxl/lib/cxl_new.txt
 create mode 100644 Documentation/cxl/lib/libcxl.txt
 create mode 100644 Documentation/cxl/lib/Makefile.am

diff --git a/Documentation/cxl/lib/cxl_new.txt b/Documentation/cxl/lib/cxl_new.txt
new file mode 100644
index 0000000..d4d5bcb
--- /dev/null
+++ b/Documentation/cxl/lib/cxl_new.txt
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0
+
+cxl_new(3)
+==========
+
+NAME
+----
+cxl_new - Create a new library context object that acts as a handle for all
+library operations
+
+SYNOPSIS
+--------
+[verse]
+----
+#include <cxl/libcxl.h>
+
+int cxl_new(struct cxl_ctx **ctx);
+----
+
+DESCRIPTION
+-----------
+Instantiates a new library context, and stores an opaque pointer in ctx. The
+context is freed by linklibcxl:cxl_unref[3], i.e. cxl_new(3) implies an
+internal linklibcxl:cxl_ref[3].
+
+
+RETURN VALUE
+------------
+Returns 0 on success, and a negative errno on failure.
+Possible error codes are:
+
+ * -ENOMEM
+ * -ENXIO
+
+EXAMPLE
+-------
+See example usage in test/libcxl.c
+
+include::../../copyright.txt[]
+
+SEE ALSO
+--------
+linklibcxl:cxl_ref[3], linklibcxl:cxl_unref[3]
diff --git a/Documentation/cxl/lib/libcxl.txt b/Documentation/cxl/lib/libcxl.txt
new file mode 100644
index 0000000..47f4cc3
--- /dev/null
+++ b/Documentation/cxl/lib/libcxl.txt
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+
+libcxl(3)
+=========
+
+NAME
+----
+libcxl - A library to interact with CXL devices through sysfs(5)
+and ioctl(2) interfaces
+
+SYNOPSIS
+--------
+[verse]
+#include <cxl/libcxl.h>
+cc ... -lcxl
+
+DESCRIPTION
+-----------
+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.
+
+Library level interfaces that are agnostic to any device, or a specific
+subclass of operations have the prefix 'cxl_'
+
+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.
+
+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_submit' which submits the command via ioctl()
+
+ * 'cxl_cmd_<name>_get_<field>' interfaces that get specific fields out of the
+   command response
+
+ * 'cxl_cmd_get_*' interfaces to get general command related information.
+
+include::../../copyright.txt[]
+
+SEE ALSO
+--------
+linklibcxl:cxl[1]
diff --git a/configure.ac b/configure.ac
index dadae0a..00497ae 100644
--- a/configure.ac
+++ b/configure.ac
@@ -231,6 +231,7 @@ AC_CONFIG_FILES([
         Documentation/ndctl/Makefile
         Documentation/daxctl/Makefile
         Documentation/cxl/Makefile
+        Documentation/cxl/lib/Makefile
 ])
 
 AC_OUTPUT
diff --git a/Makefile.am b/Makefile.am
index 4904ee7..e2f6bef 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,6 +4,7 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
 SUBDIRS = . cxl/lib daxctl/lib ndctl/lib cxl ndctl daxctl
 if ENABLE_DOCS
 SUBDIRS += Documentation/ndctl Documentation/daxctl Documentation/cxl
+SUBDIRS += Documentation/cxl/lib
 endif
 SUBDIRS += test
 
diff --git a/.gitignore b/.gitignore
index 6a97b92..6468c7a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,12 +14,15 @@ Makefile.in
 /libtool
 /stamp-h1
 *.1
+*.3
 Documentation/daxctl/asciidoc.conf
 Documentation/ndctl/asciidoc.conf
 Documentation/cxl/asciidoc.conf
+Documentation/cxl/lib/asciidoc.conf
 Documentation/daxctl/asciidoctor-extensions.rb
 Documentation/ndctl/asciidoctor-extensions.rb
 Documentation/cxl/asciidoctor-extensions.rb
+Documentation/cxl/lib/asciidoctor-extensions.rb
 Documentation/ndctl/attrs.adoc
 .dirstamp
 daxctl/config.h
diff --git a/Documentation/cxl/lib/Makefile.am b/Documentation/cxl/lib/Makefile.am
new file mode 100644
index 0000000..41e3a5f
--- /dev/null
+++ b/Documentation/cxl/lib/Makefile.am
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2020-2021 Intel Corporation. All rights reserved.
+
+if USE_ASCIIDOCTOR
+
+do_subst = sed -e 's,@Utility@,Libcxl,g' -e's,@utility@,libcxl,g'
+CONFFILE = asciidoctor-extensions.rb
+asciidoctor-extensions.rb: ../../asciidoctor-extensions.rb.in
+	$(AM_V_GEN) $(do_subst) < $< > $@
+
+else
+
+do_subst = sed -e 's,UTILITY,libcxl,g'
+CONFFILE = asciidoc.conf
+asciidoc.conf: ../../asciidoc.conf.in
+	$(AM_V_GEN) $(do_subst) < $< > $@
+
+endif
+
+man3_MANS = \
+	libcxl.3 \
+	cxl_new.3
+
+EXTRA_DIST = $(man3_MANS)
+
+CLEANFILES = $(man3_MANS)
+
+XML_DEPS = \
+	../../../version.m4 \
+	../../copyright.txt \
+	Makefile \
+	$(CONFFILE)
+
+RM ?= rm -f
+
+if USE_ASCIIDOCTOR
+
+%.3: %.txt $(XML_DEPS)
+	$(AM_V_GEN)$(RM) $@+ $@ && \
+		$(ASCIIDOC) -b manpage -d manpage -acompat-mode \
+		-I. -rasciidoctor-extensions \
+		-amansource=libcxl -amanmanual="libcxl Manual" \
+		-andctl_version=$(VERSION) -o $@+ $< && \
+		mv $@+ $@
+
+else
+
+%.xml: %.txt $(XML_DEPS)
+	$(AM_V_GEN)$(RM) $@+ $@ && \
+		$(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
+		--unsafe -alibcxl_version=$(VERSION) -o $@+ $< && \
+		mv $@+ $@
+
+%.3: %.xml $(XML_DEPS)
+	$(AM_V_GEN)$(RM) $@ && \
+		$(XMLTO) -o . -m ../../manpage-normal.xsl man $<
+
+endif
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 20/21] ndctl: Add CXL packages to the RPM spec
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (18 preceding siblings ...)
  2021-07-01 20:10 ` [ndctl PATCH v3 19/21] Documentation/cxl: add library API documentation Vishal Verma
@ 2021-07-01 20:10 ` Vishal Verma
  2021-07-01 20:10 ` [ndctl PATCH v3 21/21] cxl-cli: add bash completion Vishal Verma
  2021-07-01 20:13 ` [ndctl PATCH v3 00/21] Initial CXL support Verma, Vishal L
  21 siblings, 0 replies; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:10 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

From: Ira Weiny <ira.weiny@intel.com>

Add CXL related packages - the cxl-cli utility, the libcxl library, and
development headers to respective RPM packages in the main spec file.

Signed-off-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 Makefile.am   |  4 ++++
 ndctl.spec.in | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index e2f6bef..fa2010a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -23,17 +23,21 @@ CLEANFILES += $(noinst_SCRIPTS)
 
 do_rhel_subst = sed -e 's,VERSION,$(VERSION),g' \
             -e 's,DAX_DNAME,daxctl-devel,g' \
+            -e 's,CXL_DNAME,cxl-devel,g' \
             -e 's,DNAME,ndctl-devel,g' \
             -e '/^%defattr.*/d' \
 	    -e 's,DAX_LNAME,daxctl-libs,g' \
+	    -e 's,CXL_LNAME,cxl-libs,g' \
 	    -e 's,LNAME,ndctl-libs,g'
 
 do_sles_subst = sed -e 's,VERSION,$(VERSION),g' \
             -e 's,DAX_DNAME,libdaxctl-devel,g' \
+            -e 's,CXL_DNAME,libcxl-devel,g' \
             -e 's,DNAME,libndctl-devel,g' \
             -e 's,%license,%doc,g' \
             -e 's,\(^License:.*GPL\)v2,\1-2.0,g' \
             -e "s,DAX_LNAME,libdaxctl$$(($(LIBDAXCTL_CURRENT) - $(LIBDAXCTL_AGE))),g" \
+            -e "s,CXL_LNAME,libcxl$$(($(LIBCXL_CURRENT) - $(LIBCXL_AGE))),g" \
             -e "s,LNAME,libndctl$$(($(LIBNDCTL_CURRENT) - $(LIBNDCTL_AGE))),g"
 
 rhel/ndctl.spec: ndctl.spec.in Makefile.am version.m4
diff --git a/ndctl.spec.in b/ndctl.spec.in
index 0563b2d..4b08c05 100644
--- a/ndctl.spec.in
+++ b/ndctl.spec.in
@@ -8,6 +8,7 @@ Source0:	https://github.com/pmem/%{name}/archive/v%{version}.tar.gz#/%{name}-%{v
 
 Requires:	LNAME%{?_isa} = %{version}-%{release}
 Requires:	DAX_LNAME%{?_isa} = %{version}-%{release}
+Requires:	CXL_LNAME%{?_isa} = %{version}-%{release}
 BuildRequires:	autoconf
 %if 0%{?rhel} < 9
 BuildRequires:	asciidoc
@@ -54,6 +55,24 @@ the Linux kernel Device-DAX facility. This facility enables DAX mappings
 of performance / feature differentiated memory without need of a
 filesystem.
 
+%package -n cxl-cli
+Summary:	Manage CXL devices
+License:	GPLv2
+Requires:	CXL_LNAME%{?_isa} = %{version}-%{release}
+
+%description -n cxl-cli
+The cxl utility provides enumeration and provisioning commands for
+the Linux kernel CXL devices.
+
+%package -n CXL_DNAME
+Summary:	Development files for libcxl
+License:	LGPLv2
+Requires:	CXL_LNAME%{?_isa} = %{version}-%{release}
+
+%description -n CXL_DNAME
+This package contains libraries and header files for developing applications
+that use libcxl, a library for enumerating and communicating with CXL devices.
+
 %package -n DAX_DNAME
 Summary:	Development files for libdaxctl
 License:	LGPLv2
@@ -84,6 +103,13 @@ Device DAX is a facility for establishing DAX mappings of performance /
 feature-differentiated memory. DAX_LNAME provides an enumeration /
 control API for these devices.
 
+%package -n CXL_LNAME
+Summary:	Management library for CXL devices
+License:	LGPLv2
+
+%description -n CXL_LNAME
+libcxl is a library for enumerating and communicating with CXL devices.
+
 
 %prep
 %setup -q ndctl-%{version}
@@ -105,6 +131,8 @@ make check
 
 %ldconfig_scriptlets -n DAX_LNAME
 
+%ldconfig_scriptlets -n CXL_LNAME
+
 %define bashcompdir %(pkg-config --variable=completionsdir bash-completion)
 
 %files
@@ -126,6 +154,12 @@ make check
 %{_mandir}/man1/daxctl*
 %{_datadir}/daxctl/daxctl.conf
 
+%files -n cxl-cli
+%defattr(-,root,root)
+%license LICENSES/preferred/GPL-2.0 LICENSES/other/MIT LICENSES/other/CC0-1.0
+%{_bindir}/cxl
+%{_mandir}/man1/cxl*
+
 %files -n LNAME
 %defattr(-,root,root)
 %doc README.md
@@ -138,6 +172,12 @@ make check
 %license LICENSES/preferred/LGPL-2.1 LICENSES/other/MIT LICENSES/other/CC0-1.0
 %{_libdir}/libdaxctl.so.*
 
+%files -n CXL_LNAME
+%defattr(-,root,root)
+%doc README.md
+%license LICENSES/preferred/LGPL-2.1 LICENSES/other/MIT LICENSES/other/CC0-1.0
+%{_libdir}/libcxl.so.*
+
 %files -n DNAME
 %defattr(-,root,root)
 %license LICENSES/preferred/LGPL-2.1
@@ -152,6 +192,15 @@ make check
 %{_libdir}/libdaxctl.so
 %{_libdir}/pkgconfig/libdaxctl.pc
 
+%files -n CXL_DNAME
+%defattr(-,root,root)
+%license LICENSES/preferred/LGPL-2.1
+%{_includedir}/cxl/
+%{_libdir}/libcxl.so
+%{_libdir}/pkgconfig/libcxl.pc
+%{_mandir}/man3/cxl*
+%{_mandir}/man3/libcxl.3.gz
+
 
 %changelog
 * Fri May 27 2016 Dan Williams <dan.j.williams@intel.com> - 53-1
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [ndctl PATCH v3 21/21] cxl-cli: add bash completion
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (19 preceding siblings ...)
  2021-07-01 20:10 ` [ndctl PATCH v3 20/21] ndctl: Add CXL packages to the RPM spec Vishal Verma
@ 2021-07-01 20:10 ` Vishal Verma
  2021-07-01 20:13 ` [ndctl PATCH v3 00/21] Initial CXL support Verma, Vishal L
  21 siblings, 0 replies; 36+ messages in thread
From: Vishal Verma @ 2021-07-01 20:10 UTC (permalink / raw)
  To: nvdimm, linux-cxl
  Cc: Dan Williams, Ben Widawsky, Alison Schofield, Ira Weiny, Vishal Verma

Add bash completion for the cxl-cli commands implemented so far:
  cxl-list
  cxl-read-labels
  cxl-write-labels
  cxl-zero-labels

Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 contrib/ndctl | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 109 insertions(+)

diff --git a/contrib/ndctl b/contrib/ndctl
index 680fe6a..cae4b1b 100755
--- a/contrib/ndctl
+++ b/contrib/ndctl
@@ -647,5 +647,114 @@ _daxctl()
 	__daxctl_main
 }
 
+### cxl-cli ###
+
+__cxl_get_devs()
+{
+	local opts=("--memdevs" "$*")
+	cxl list "${opts[@]}" | grep -E "^\s*\"memdev\":" | cut -d'"' -f4
+}
+
+__cxlcomp()
+{
+	local i=0
+
+	COMPREPLY=( $( compgen -W "$1" -- "$2" ) )
+	for cword in "${COMPREPLY[@]}"; do
+		if [[ "$cword" == @(--memdev|--offset|--size|--input|--output) ]]; then
+			COMPREPLY[$i]="${cword}="
+		else
+			COMPREPLY[$i]="${cword} "
+		fi
+		((i++))
+	done
+}
+
+__cxl_comp_options()
+{
+
+	local cur=$1
+	local opts
+
+	if [[ "$cur" == *=* ]]; then
+		local cur_subopt=${cur%%=*}
+		local cur_arg=${cur##*=}
+		case $cur_subopt in
+		--memdev)
+			opts="$(__cxl_get_devs -i)"
+			;;
+		*)
+			return
+			;;
+		esac
+		__cxlcomp "$opts" "$cur_arg"
+	fi
+}
+
+__cxl_comp_non_option_args()
+{
+	local subcmd=$1
+	local cur=$2
+	local opts
+
+	case $subcmd in
+	read-labels)
+		;&
+	write-labels)
+		;&
+	zero-labels)
+		opts="$(__cxl_get_devs -i) all"
+		;;
+	*)
+		return
+		;;
+	esac
+	__cxlcomp "$opts" "$cur"
+}
+
+__cxl_main()
+{
+	local cmd subcmd
+
+	cmd=${words[0]}
+	COMPREPLY=()
+
+	# Skip options backward and find the last cxl command
+	__nd_common_prev_skip_opts
+	subcmd=$prev_skip_opts
+	# List cxl subcommands or long options
+	if [ -z $subcmd ]; then
+		if [[ $cur == --* ]]; then
+			cmds="--version --help --list-cmds"
+		else
+			cmds=$($cmd --list-cmds)
+		fi
+		__cxlcomp "$cmds" "$cur"
+	else
+		# List long option names
+		if [[ $cur == --* ]];  then
+			opts=$($cmd $subcmd --list-opts)
+			__cxlcomp "$opts" "$cur"
+			__cxl_comp_options "$cur"
+		else
+			[ -z "$subcmd" ] && return
+			__cxl_comp_non_option_args "$subcmd" "$cur"
+		fi
+	fi
+}
+
+type cxl &>/dev/null &&
+_cxl()
+{
+	local cur words cword prev
+	if [ $preload_get_comp_words_by_ref = "true" ]; then
+		_get_comp_words_by_ref -n =: cur words cword prev
+	else
+		__nd_common_get_comp_words_by_ref -n =: cur words cword prev
+	fi
+	__cxl_main
+}
+
 complete -o nospace -F _ndctl ndctl
 complete -o nospace -F _daxctl daxctl
+complete -o nospace -F _cxl cxl
-- 
2.31.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [ndctl PATCH v3 00/21] Initial CXL support
  2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
                   ` (20 preceding siblings ...)
  2021-07-01 20:10 ` [ndctl PATCH v3 21/21] cxl-cli: add bash completion Vishal Verma
@ 2021-07-01 20:13 ` Verma, Vishal L
  21 siblings, 0 replies; 36+ messages in thread
From: Verma, Vishal L @ 2021-07-01 20:13 UTC (permalink / raw)
  To: linux-cxl, nvdimm
  Cc: Williams, Dan J, Widawsky, Ben, Schofield, Alison, Weiny, Ira

On Thu, 2021-07-01 at 14:09 -0600, Vishal Verma wrote:
> Changes since v2[1]:
> 
> - Some minor cleanups and formatting (Ben)
> - Update cxl_mem.h to the latest kernel version (Ben)
> - Add .clang-format (Ben)
> - Add label commands to cxl-clu - {read,write,zero}-labels
> - Add libcxl and cxl-cli to the RPM spec
> - Add bash-completion for cxl-cli
> - 
> 
> [1]: https://lore.kernel.org/linux-cxl/20210219020331.725687-1-vishal.l.verma@intel.com/
> 
> ---
> 
> These patches add a new utility and library to support CXL devices.
> This comprehends the kernel's sysfs layout for CXL devices, and
> implements a command submission harness for CXL mailbox commands via
> ioctl()s definied by the cxl_mem driver. 
> 
> These patches include:
> - libcxl representation of cxl_mem devices
> - A command submission harness through libcxl
> - A 'cxl-list' command which displays information about a device
> - cxl-{read,write,zero}-labels commands for Label Storage Area
>   manipulation
> - Unit tests to exercise several libcxl APIs and perform mailbox
>   commands.
> 
> Patch 15 is an RFC - maybe this should just be dropped entirely for now
> until there is a concept of active/disabled memdevs. It is useful as a
> placeholder as it allows for a way to pre-insert checks in places
> we expect the device to be active or disabled.
> 
> An ndctl branch with these patches is also available at [2]
> 
> [2]: https://github.com/pmem/ndctl/tree/cxl-2.0v2

Sorry, this should be:
https://github.com/pmem/ndctl/tree/cxl-2.0v3

> 
> Ira Weiny (1):
>   ndctl: Add CXL packages to the RPM spec
> 
> Vishal Verma (20):
>   ndctl: add .clang-format
>   cxl: add a cxl utility and libcxl library
>   cxl: add a local copy of the cxl_mem UAPI header
>   libcxl: add support for command query and submission
>   libcxl: add support for the 'Identify Device' command
>   test: rename 'ndctl_test' to 'test_ctx'
>   test: rename 'ndctl_test_*' helpers to 'test_*'
>   test: introduce a libcxl unit test
>   libcxl: add GET_HEALTH_INFO mailbox command and accessors
>   libcxl: add support for the 'GET_LSA' command
>   util/hexdump: Add a util helper to print a buffer in hex
>   test/libcxl: add a test for {set, get}_lsa commands
>   test/libcxl: introduce a command size fuzzing test
>   libcxl: add lsa_size to cxl_memdev, and an API to retrieve it
>   libcxl: PLACEHOLDER: add an interface to determine whether a memdev is
>     active
>   libcxl: add interfaces for label operations
>   test/libcxl: add a test for cxl_memdev_{get,set}_lsa
>   cxl: add commands to read, write, and zero labels
>   Documentation/cxl: add library API documentation
>   cxl-cli: add bash completion
> 
>  Documentation/cxl/cxl-list.txt           |   64 ++
>  Documentation/cxl/cxl-read-labels.txt    |   33 +
>  Documentation/cxl/cxl-write-labels.txt   |   32 +
>  Documentation/cxl/cxl-zero-labels.txt    |   29 +
>  Documentation/cxl/cxl.txt                |   34 +
>  Documentation/cxl/human-option.txt       |    8 +
>  Documentation/cxl/labels-description.txt |    8 +
>  Documentation/cxl/labels-options.txt     |   17 +
>  Documentation/cxl/lib/cxl_new.txt        |   43 +
>  Documentation/cxl/lib/libcxl.txt         |   56 ++
>  Documentation/cxl/memdev-option.txt      |    4 +
>  Documentation/cxl/verbose-option.txt     |    5 +
>  configure.ac                             |    4 +
>  Makefile.am                              |   14 +-
>  Makefile.am.in                           |    5 +
>  cxl/lib/private.h                        |  104 +++
>  cxl/lib/libcxl.c                         | 1026 ++++++++++++++++++++++
>  cxl/builtin.h                            |   13 +
>  cxl/cxl_mem.h                            |  189 ++++
>  cxl/libcxl.h                             |   91 ++
>  test.h                                   |   40 +-
>  test/libcxl-expect.h                     |   13 +
>  util/filter.h                            |    2 +
>  util/hexdump.h                           |    8 +
>  util/json.h                              |    3 +
>  util/main.h                              |    3 +
>  cxl/cxl.c                                |   99 +++
>  cxl/list.c                               |  113 +++
>  cxl/memdev.c                             |  314 +++++++
>  ndctl/bat.c                              |    8 +-
>  ndctl/test.c                             |    8 +-
>  test/ack-shutdown-count-set.c            |   16 +-
>  test/blk_namespaces.c                    |   14 +-
>  test/core.c                              |   32 +-
>  test/dax-dev.c                           |   10 +-
>  test/dax-pmd.c                           |   13 +-
>  test/dax-poison.c                        |    6 +-
>  test/daxdev-errors.c                     |    2 +-
>  test/device-dax.c                        |   26 +-
>  test/dpa-alloc.c                         |   14 +-
>  test/dsm-fail.c                          |   14 +-
>  test/libcxl.c                            |  553 ++++++++++++
>  test/libndctl.c                          |   84 +-
>  test/multi-pmem.c                        |   23 +-
>  test/parent-uuid.c                       |   13 +-
>  test/pmem_namespaces.c                   |   14 +-
>  test/revoke-devmem.c                     |   12 +-
>  util/filter.c                            |   20 +
>  util/hexdump.c                           |   53 ++
>  util/json.c                              |   26 +
>  .clang-format                            |  162 ++++
>  .gitignore                               |    7 +-
>  Documentation/cxl/Makefile.am            |   61 ++
>  Documentation/cxl/lib/Makefile.am        |   58 ++
>  README.md                                |    2 +-
>  contrib/ndctl                            |  109 +++
>  cxl/Makefile.am                          |   22 +
>  cxl/lib/Makefile.am                      |   32 +
>  cxl/lib/libcxl.pc.in                     |   11 +
>  cxl/lib/libcxl.sym                       |   67 ++
>  ndctl.spec.in                            |   49 ++
>  test/Makefile.am                         |   15 +-
>  62 files changed, 3749 insertions(+), 181 deletions(-)
>  create mode 100644 Documentation/cxl/cxl-list.txt
>  create mode 100644 Documentation/cxl/cxl-read-labels.txt
>  create mode 100644 Documentation/cxl/cxl-write-labels.txt
>  create mode 100644 Documentation/cxl/cxl-zero-labels.txt
>  create mode 100644 Documentation/cxl/cxl.txt
>  create mode 100644 Documentation/cxl/human-option.txt
>  create mode 100644 Documentation/cxl/labels-description.txt
>  create mode 100644 Documentation/cxl/labels-options.txt
>  create mode 100644 Documentation/cxl/lib/cxl_new.txt
>  create mode 100644 Documentation/cxl/lib/libcxl.txt
>  create mode 100644 Documentation/cxl/memdev-option.txt
>  create mode 100644 Documentation/cxl/verbose-option.txt
>  create mode 100644 cxl/lib/private.h
>  create mode 100644 cxl/lib/libcxl.c
>  create mode 100644 cxl/builtin.h
>  create mode 100644 cxl/cxl_mem.h
>  create mode 100644 cxl/libcxl.h
>  create mode 100644 test/libcxl-expect.h
>  create mode 100644 util/hexdump.h
>  create mode 100644 cxl/cxl.c
>  create mode 100644 cxl/list.c
>  create mode 100644 cxl/memdev.c
>  create mode 100644 test/libcxl.c
>  create mode 100644 util/hexdump.c
>  create mode 100644 .clang-format
>  create mode 100644 Documentation/cxl/Makefile.am
>  create mode 100644 Documentation/cxl/lib/Makefile.am
>  create mode 100644 cxl/Makefile.am
>  create mode 100644 cxl/lib/Makefile.am
>  create mode 100644 cxl/lib/libcxl.pc.in
>  create mode 100644 cxl/lib/libcxl.sym
> 
> 
> base-commit: 4e646fa490ba4b782afa188dd8818b94c419924e


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [ndctl PATCH v3 02/21] cxl: add a cxl utility and libcxl library
  2021-07-01 20:09 ` [ndctl PATCH v3 02/21] cxl: add a cxl utility and libcxl library Vishal Verma
@ 2021-07-10  1:12   ` Dan Williams
  2021-07-13 21:14     ` Verma, Vishal L
  0 siblings, 1 reply; 36+ messages in thread
From: Dan Williams @ 2021-07-10  1:12 UTC (permalink / raw)
  To: Vishal Verma
  Cc: Linux NVDIMM, linux-cxl, Ben Widawsky, Alison Schofield, Ira Weiny

On Thu, Jul 1, 2021 at 1:10 PM Vishal Verma <vishal.l.verma@intel.com> wrote:
>
> CXL - or Compute eXpress Link - is a new interconnect that extends PCIe
> to support a wide range of devices, including cache coherent memory
> expanders. As such, these devices can be new sources of 'persistent
> memory', and the 'ndctl' umbrella of tools and libraries needs to be able
> to interact with them.
>
> Add a new utility and library for managing these CXL memory devices. This
> is an initial bring-up for interacting with CXL devices, and only includes
> adding the utility and library infrastructure, parsing device information
> from sysfs for CXL devices, and providing a 'cxl-list' command to
> display this information in JSON formatted output.
>
> Cc: Ben Widawsky <ben.widawsky@intel.com>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

Looks good, just a couple minor quibbles below:

Reviewed-by: Dan Williams <dan.j.williams@intel.com>

> ---
>  Documentation/cxl/cxl-list.txt       |  64 +++++
>  Documentation/cxl/cxl.txt            |  34 +++
>  Documentation/cxl/human-option.txt   |   8 +
>  Documentation/cxl/verbose-option.txt |   5 +
>  configure.ac                         |   3 +
>  Makefile.am                          |   8 +-
>  Makefile.am.in                       |   4 +
>  cxl/lib/private.h                    |  29 +++
>  cxl/lib/libcxl.c                     | 345 +++++++++++++++++++++++++++
>  cxl/builtin.h                        |   8 +
>  cxl/libcxl.h                         |  55 +++++
>  util/filter.h                        |   2 +
>  util/json.h                          |   3 +
>  util/main.h                          |   3 +
>  cxl/cxl.c                            |  96 ++++++++
>  cxl/list.c                           | 113 +++++++++
>  util/filter.c                        |  20 ++
>  util/json.c                          |  26 ++
>  .clang-format                        |   1 +
>  .gitignore                           |   4 +-
>  Documentation/cxl/Makefile.am        |  58 +++++
>  cxl/Makefile.am                      |  21 ++
>  cxl/lib/Makefile.am                  |  32 +++
>  cxl/lib/libcxl.pc.in                 |  11 +
>  cxl/lib/libcxl.sym                   |  29 +++
>  25 files changed, 978 insertions(+), 4 deletions(-)
>  create mode 100644 Documentation/cxl/cxl-list.txt
>  create mode 100644 Documentation/cxl/cxl.txt
>  create mode 100644 Documentation/cxl/human-option.txt
>  create mode 100644 Documentation/cxl/verbose-option.txt
>  create mode 100644 cxl/lib/private.h
>  create mode 100644 cxl/lib/libcxl.c
>  create mode 100644 cxl/builtin.h
>  create mode 100644 cxl/libcxl.h
>  create mode 100644 cxl/cxl.c
>  create mode 100644 cxl/list.c
>  create mode 100644 Documentation/cxl/Makefile.am
>  create mode 100644 cxl/Makefile.am
>  create mode 100644 cxl/lib/Makefile.am
>  create mode 100644 cxl/lib/libcxl.pc.in
>  create mode 100644 cxl/lib/libcxl.sym
>
> diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
> new file mode 100644
> index 0000000..4e2be87
> --- /dev/null
> +++ b/Documentation/cxl/cxl-list.txt
> @@ -0,0 +1,64 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +cxl-list(1)
> +===========
> +
> +NAME
> +----
> +cxl-list - List CXL capable memory devices, and their attributes in json.

This will also show CXL port topology in the future. I'm fine to fix
that up later when that support arrives.

> +
> +SYNOPSIS
> +--------
> +[verse]
> +'cxl list' [<options>]
> +
> +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 devices.
> +By default, 'cxl list' with no options is equivalent to:
> +[verse]
> +cxl list --devices
> +
> +EXAMPLE
> +-------
> +----
> +# cxl list --devices

Is this from an earlier version, should it be --memdevs?

> +{
> +  "memdev":"mem0",
> +  "pmem_size":268435456,
> +  "ram_size":0,
> +}
> +----
> +
> +OPTIONS
> +-------
> +-d::
> +--memdev=::
> +       Specify a cxl memory device name to filter the listing. For example:
> +----
> +# cxl list --memdev=mem0
> +{
> +  "memdev":"mem0",
> +  "pmem_size":268435456,
> +  "ram_size":0,
> +}
> +----
> +
> +-D::
> +--memdevs::
> +       Include all CXL memory devices in the listing
> +
> +-i::
> +--idle::
> +       Include idle (not enabled / zero-sized) devices in the listing
> +
> +include::human-option.txt[]
> +
> +include::verbose-option.txt[]
> +
> +include::../copyright.txt[]
> +
> +SEE ALSO
> +--------
> +linkcxl:ndctl-list[1]
> diff --git a/Documentation/cxl/cxl.txt b/Documentation/cxl/cxl.txt
> new file mode 100644
> index 0000000..e99e61b
> --- /dev/null
> +++ b/Documentation/cxl/cxl.txt
> @@ -0,0 +1,34 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +cxl(1)
> +======
> +
> +NAME
> +----
> +cxl - Provides enumeration and provisioning commands for CXL devices

s/device/platforms/ since it should enumerate an entire topology.

> +
> +SYNOPSIS
> +--------
> +[verse]
> +'cxl' [--version] [--help] COMMAND [ARGS]
> +
> +OPTIONS
> +-------
> +-v::
> +--version::
> +  Display the version of the 'cxl' utility.
> +
> +-h::
> +--help::
> +  Run the 'cxl help' command.
> +
> +DESCRIPTION
> +-----------
> +The cxl utility provides enumeration and provisioning commands for
> +the CXL devices managed by the Linux kernel.
> +
> +include::../copyright.txt[]
> +
> +SEE ALSO
> +--------
> +linkcxl:ndctl[1]
> diff --git a/Documentation/cxl/human-option.txt b/Documentation/cxl/human-option.txt
> new file mode 100644
> index 0000000..2f4de7a
> --- /dev/null
> +++ b/Documentation/cxl/human-option.txt
> @@ -0,0 +1,8 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +-u::
> +--human::
> +       By default the command will output machine-friendly raw-integer
> +       data. Instead, with this flag, numbers representing storage size
> +       will be formatted as human readable strings with units, other
> +       fields are converted to hexadecimal strings.
> diff --git a/Documentation/cxl/verbose-option.txt b/Documentation/cxl/verbose-option.txt
> new file mode 100644
> index 0000000..cb62c8e
> --- /dev/null
> +++ b/Documentation/cxl/verbose-option.txt
> @@ -0,0 +1,5 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +-v::
> +--verbose::
> +       Emit more debug messages
> diff --git a/configure.ac b/configure.ac
> index dc39dbe..dadae0a 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -222,12 +222,15 @@ AC_CONFIG_HEADERS(config.h)
>  AC_CONFIG_FILES([
>          Makefile
>          daxctl/lib/Makefile
> +        cxl/lib/Makefile
>          ndctl/lib/Makefile
>          ndctl/Makefile
>          daxctl/Makefile
> +        cxl/Makefile
>          test/Makefile
>          Documentation/ndctl/Makefile
>          Documentation/daxctl/Makefile
> +        Documentation/cxl/Makefile
>  ])
>
>  AC_OUTPUT
> diff --git a/Makefile.am b/Makefile.am
> index 60a1998..428fd40 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -1,9 +1,9 @@
>  include Makefile.am.in
>
>  ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
> -SUBDIRS = . daxctl/lib ndctl/lib ndctl daxctl
> +SUBDIRS = . cxl/lib daxctl/lib ndctl/lib cxl ndctl daxctl
>  if ENABLE_DOCS
> -SUBDIRS += Documentation/ndctl Documentation/daxctl
> +SUBDIRS += Documentation/ndctl Documentation/daxctl Documentation/cxl
>  endif
>  SUBDIRS += test
>
> @@ -87,4 +87,6 @@ libutil_a_SOURCES = \
>         util/filter.h \
>         util/bitmap.h
>
> -nobase_include_HEADERS = daxctl/libdaxctl.h
> +nobase_include_HEADERS = \
> +       daxctl/libdaxctl.h \
> +       cxl/libcxl.h
> diff --git a/Makefile.am.in b/Makefile.am.in
> index bdceda9..aaeee53 100644
> --- a/Makefile.am.in
> +++ b/Makefile.am.in
> @@ -42,3 +42,7 @@ LIBNDCTL_AGE=19
>  LIBDAXCTL_CURRENT=6
>  LIBDAXCTL_REVISION=0
>  LIBDAXCTL_AGE=5
> +
> +LIBCXL_CURRENT=1
> +LIBCXL_REVISION=0
> +LIBCXL_AGE=0
> diff --git a/cxl/lib/private.h b/cxl/lib/private.h
> new file mode 100644
> index 0000000..fc88fa1
> --- /dev/null
> +++ b/cxl/lib/private.h
> @@ -0,0 +1,29 @@
> +/* SPDX-License-Identifier: LGPL-2.1 */
> +/* Copyright (C) 2020-2021, Intel Corporation. All rights reserved. */
> +#ifndef _LIBCXL_PRIVATE_H_
> +#define _LIBCXL_PRIVATE_H_
> +
> +#include <libkmod.h>
> +
> +#define CXL_EXPORT __attribute__ ((visibility("default")))
> +
> +struct cxl_memdev {
> +       int id, major, minor;
> +       void *dev_buf;
> +       size_t buf_len;
> +       char *dev_path;
> +       char *firmware_version;
> +       struct cxl_ctx *ctx;
> +       struct list_node list;
> +       unsigned long long pmem_size;
> +       unsigned long long ram_size;
> +       int payload_max;
> +       struct kmod_module *module;
> +};
> +
> +static inline int check_kmod(struct kmod_ctx *kmod_ctx)
> +{
> +       return kmod_ctx ? 0 : -ENXIO;
> +}
> +
> +#endif /* _LIBCXL_PRIVATE_H_ */
> diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
> new file mode 100644
> index 0000000..d34e7d0
> --- /dev/null
> +++ b/cxl/lib/libcxl.c
> @@ -0,0 +1,345 @@
> +// SPDX-License-Identifier: LGPL-2.1
> +// Copyright (C) 2020-2021, Intel Corporation. All rights reserved.
> +#include <stdio.h>
> +#include <errno.h>
> +#include <limits.h>
> +#include <libgen.h>
> +#include <stdlib.h>
> +#include <dirent.h>
> +#include <unistd.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <sys/sysmacros.h>
> +#include <uuid/uuid.h>
> +#include <ccan/list/list.h>
> +#include <ccan/array_size/array_size.h>
> +
> +#include <util/log.h>
> +#include <util/sysfs.h>
> +#include <util/bitmap.h>
> +#include <cxl/libcxl.h>
> +#include "private.h"
> +
> +/**
> + * struct cxl_ctx - library user context to find "nd" instances
> + *
> + * Instantiate with cxl_new(), which takes an initial reference.  Free
> + * the context by dropping the reference count to zero with
> + * cxl_unref(), or take additional references with cxl_ref()
> + * @timeout: default library timeout in milliseconds
> + */
> +struct cxl_ctx {
> +       /* log_ctx must be first member for cxl_set_log_fn compat */
> +       struct log_ctx ctx;
> +       int refcount;
> +       void *userdata;
> +       int memdevs_init;
> +       struct list_head memdevs;
> +       struct kmod_ctx *kmod_ctx;
> +       void *private_data;
> +};
> +
> +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(memdev->firmware_version);
> +       free(memdev->dev_buf);
> +       free(memdev->dev_path);
> +       free(memdev);
> +}
> +
> +/**
> + * cxl_get_userdata - retrieve stored data pointer from library context
> + * @ctx: cxl library context
> + *
> + * This might be useful to access from callbacks like a custom logging
> + * function.
> + */
> +CXL_EXPORT void *cxl_get_userdata(struct cxl_ctx *ctx)
> +{
> +       if (ctx == NULL)
> +               return NULL;
> +       return ctx->userdata;
> +}
> +
> +/**
> + * cxl_set_userdata - store custom @userdata in the library context
> + * @ctx: cxl library context
> + * @userdata: data pointer
> + */
> +CXL_EXPORT void cxl_set_userdata(struct cxl_ctx *ctx, void *userdata)
> +{
> +       if (ctx == NULL)
> +               return;
> +       ctx->userdata = userdata;
> +}
> +
> +CXL_EXPORT void cxl_set_private_data(struct cxl_ctx *ctx, void *data)
> +{
> +       ctx->private_data = data;
> +}
> +
> +CXL_EXPORT void *cxl_get_private_data(struct cxl_ctx *ctx)
> +{
> +       return ctx->private_data;
> +}
> +
> +/**
> + * cxl_new - instantiate a new library context
> + * @ctx: context to establish
> + *
> + * Returns zero on success and stores an opaque pointer in ctx.  The
> + * context is freed by cxl_unref(), i.e. cxl_new() implies an
> + * internal cxl_ref().
> + */
> +CXL_EXPORT int cxl_new(struct cxl_ctx **ctx)
> +{
> +       struct kmod_ctx *kmod_ctx;
> +       struct cxl_ctx *c;
> +       int rc = 0;
> +
> +       c = calloc(1, sizeof(struct cxl_ctx));
> +       if (!c)
> +               return -ENOMEM;
> +
> +       kmod_ctx = kmod_new(NULL, NULL);
> +       if (check_kmod(kmod_ctx) != 0) {
> +               rc = -ENXIO;
> +               goto out;
> +       }
> +
> +       c->refcount = 1;
> +       log_init(&c->ctx, "libcxl", "CXL_LOG");
> +       info(c, "ctx %p created\n", c);
> +       dbg(c, "log_priority=%d\n", c->ctx.log_priority);
> +       *ctx = c;
> +       list_head_init(&c->memdevs);
> +       c->kmod_ctx = kmod_ctx;
> +
> +       return 0;
> +out:
> +       free(c);
> +       return rc;
> +}
> +
> +/**
> + * cxl_ref - take an additional reference on the context
> + * @ctx: context established by cxl_new()
> + */
> +CXL_EXPORT struct cxl_ctx *cxl_ref(struct cxl_ctx *ctx)
> +{
> +       if (ctx == NULL)
> +               return NULL;
> +       ctx->refcount++;
> +       return ctx;
> +}
> +
> +/**
> + * cxl_unref - drop a context reference count
> + * @ctx: context established by cxl_new()
> + *
> + * Drop a reference and if the resulting reference count is 0 destroy
> + * the context.
> + */
> +CXL_EXPORT void cxl_unref(struct cxl_ctx *ctx)
> +{
> +       struct cxl_memdev *memdev, *_d;
> +
> +       if (ctx == NULL)
> +               return;
> +       ctx->refcount--;
> +       if (ctx->refcount > 0)
> +               return;
> +
> +       list_for_each_safe(&ctx->memdevs, memdev, _d, list)
> +               free_memdev(memdev, &ctx->memdevs);
> +
> +       kmod_unref(ctx->kmod_ctx);
> +       info(ctx, "context %p released\n", ctx);
> +       free(ctx);
> +}
> +
> +/**
> + * cxl_set_log_fn - override default log routine
> + * @ctx: cxl library context
> + * @log_fn: function to be called for logging messages
> + *
> + * The built-in logging writes to stderr. It can be overridden by a
> + * custom function, to plug log messages into the user's logging
> + * functionality.
> + */
> +CXL_EXPORT void cxl_set_log_fn(struct cxl_ctx *ctx,
> +               void (*cxl_log_fn)(struct cxl_ctx *ctx, int priority,
> +                       const char *file, int line, const char *fn,
> +                       const char *format, va_list args))
> +{
> +       ctx->ctx.log_fn = (log_fn) cxl_log_fn;
> +       info(ctx, "custom logging function %p registered\n", cxl_log_fn);
> +}
> +
> +/**
> + * cxl_get_log_priority - retrieve current library loglevel (syslog)
> + * @ctx: cxl library context
> + */
> +CXL_EXPORT int cxl_get_log_priority(struct cxl_ctx *ctx)
> +{
> +       return ctx->ctx.log_priority;
> +}
> +
> +/**
> + * cxl_set_log_priority - set log verbosity
> + * @priority: from syslog.h, LOG_ERR, LOG_INFO, LOG_DEBUG
> + *
> + * Note: LOG_DEBUG requires library be built with "configure --enable-debug"
> + */
> +CXL_EXPORT void cxl_set_log_priority(struct cxl_ctx *ctx, int priority)
> +{
> +       ctx->ctx.log_priority = priority;
> +}
> +
> +static void *add_cxl_memdev(void *parent, int id, const char *cxlmem_base)
> +{
> +       const char *devname = devpath_to_devname(cxlmem_base);
> +       char *path = calloc(1, strlen(cxlmem_base) + 100);
> +       struct cxl_ctx *ctx = parent;
> +       struct cxl_memdev *memdev, *memdev_dup;
> +       char buf[SYSFS_ATTR_SIZE];
> +       struct stat st;
> +
> +       if (!path)
> +               return NULL;
> +       dbg(ctx, "%s: base: \'%s\'\n", __func__, cxlmem_base);
> +
> +       memdev = calloc(1, sizeof(*memdev));
> +       if (!memdev)
> +               goto err_dev;
> +       memdev->id = id;
> +       memdev->ctx = ctx;
> +
> +       sprintf(path, "/dev/cxl/%s", devname);
> +       if (stat(path, &st) < 0)
> +               goto err_read;
> +       memdev->major = major(st.st_rdev);
> +       memdev->minor = minor(st.st_rdev);
> +
> +       sprintf(path, "%s/pmem/size", cxlmem_base);
> +       if (sysfs_read_attr(ctx, path, buf) < 0)
> +               goto err_read;
> +       memdev->pmem_size = strtoull(buf, NULL, 0);
> +
> +       sprintf(path, "%s/ram/size", cxlmem_base);
> +       if (sysfs_read_attr(ctx, path, buf) < 0)
> +               goto err_read;
> +       memdev->ram_size = strtoull(buf, NULL, 0);
> +
> +       sprintf(path, "%s/payload_max", cxlmem_base);
> +       if (sysfs_read_attr(ctx, path, buf) < 0)
> +               goto err_read;
> +       memdev->payload_max = strtoull(buf, NULL, 0);
> +       if (memdev->payload_max < 0)
> +               goto err_read;
> +
> +       memdev->dev_path = strdup(cxlmem_base);
> +       if (!memdev->dev_path)
> +               goto err_read;
> +
> +       sprintf(path, "%s/firmware_version", cxlmem_base);
> +       if (sysfs_read_attr(ctx, path, buf) < 0)
> +               goto err_read;
> +
> +       memdev->firmware_version = strdup(buf);
> +       if (!memdev->firmware_version)
> +               goto err_read;
> +
> +       memdev->dev_buf = calloc(1, strlen(cxlmem_base) + 50);
> +       if (!memdev->dev_buf)
> +               goto err_read;
> +       memdev->buf_len = strlen(cxlmem_base) + 50;
> +
> +       cxl_memdev_foreach(ctx, memdev_dup)
> +               if (memdev_dup->id == memdev->id) {
> +                       free_memdev(memdev, NULL);
> +                       free(path);
> +                       return memdev_dup;
> +               }
> +
> +       list_add(&ctx->memdevs, &memdev->list);
> +       free(path);
> +       return memdev;
> +
> + err_read:
> +       free(memdev->firmware_version);
> +       free(memdev->dev_buf);
> +       free(memdev->dev_path);
> +       free(memdev);
> + err_dev:
> +       free(path);
> +       return NULL;
> +}
> +
> +static void cxl_memdevs_init(struct cxl_ctx *ctx)
> +{
> +       if (ctx->memdevs_init)
> +               return;
> +
> +       ctx->memdevs_init = 1;
> +
> +       sysfs_device_parse(ctx, "/sys/bus/cxl/devices", "mem", ctx,
> +                          add_cxl_memdev);
> +}
> +
> +CXL_EXPORT struct cxl_ctx *cxl_memdev_get_ctx(struct cxl_memdev *memdev)
> +{
> +       return memdev->ctx;
> +}
> +
> +CXL_EXPORT struct cxl_memdev *cxl_memdev_get_first(struct cxl_ctx *ctx)
> +{
> +       cxl_memdevs_init(ctx);
> +
> +       return list_top(&ctx->memdevs, struct cxl_memdev, list);
> +}
> +
> +CXL_EXPORT struct cxl_memdev *cxl_memdev_get_next(struct cxl_memdev *memdev)
> +{
> +       struct cxl_ctx *ctx = memdev->ctx;
> +
> +       return list_next(&ctx->memdevs, memdev, list);
> +}
> +
> +CXL_EXPORT int cxl_memdev_get_id(struct cxl_memdev *memdev)
> +{
> +       return memdev->id;
> +}
> +
> +CXL_EXPORT const char *cxl_memdev_get_devname(struct cxl_memdev *memdev)
> +{
> +       return devpath_to_devname(memdev->dev_path);
> +}
> +
> +CXL_EXPORT int cxl_memdev_get_major(struct cxl_memdev *memdev)
> +{
> +       return memdev->major;
> +}
> +
> +CXL_EXPORT int cxl_memdev_get_minor(struct cxl_memdev *memdev)
> +{
> +       return memdev->minor;
> +}
> +
> +CXL_EXPORT unsigned long long cxl_memdev_get_pmem_size(struct cxl_memdev *memdev)
> +{
> +       return memdev->pmem_size;
> +}
> +
> +CXL_EXPORT unsigned long long cxl_memdev_get_ram_size(struct cxl_memdev *memdev)
> +{
> +       return memdev->ram_size;
> +}
> +
> +CXL_EXPORT const char *cxl_memdev_get_firmware_verison(struct cxl_memdev *memdev)
> +{
> +       return memdev->firmware_version;
> +}
> diff --git a/cxl/builtin.h b/cxl/builtin.h
> new file mode 100644
> index 0000000..3797f98
> --- /dev/null
> +++ b/cxl/builtin.h
> @@ -0,0 +1,8 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2020-2021 Intel Corporation. All rights reserved. */
> +#ifndef _CXL_BUILTIN_H_
> +#define _CXL_BUILTIN_H_
> +
> +struct cxl_ctx;
> +int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx);
> +#endif /* _CXL_BUILTIN_H_ */
> diff --git a/cxl/libcxl.h b/cxl/libcxl.h
> new file mode 100644
> index 0000000..fd06790
> --- /dev/null
> +++ b/cxl/libcxl.h
> @@ -0,0 +1,55 @@
> +/* SPDX-License-Identifier: LGPL-2.1 */
> +/* Copyright (C) 2020-2021, Intel Corporation. All rights reserved. */
> +#ifndef _LIBCXL_H_
> +#define _LIBCXL_H_
> +
> +#include <stdarg.h>
> +#include <unistd.h>
> +
> +#ifdef HAVE_UUID
> +#include <uuid/uuid.h>
> +#else
> +typedef unsigned char uuid_t[16];
> +#endif
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +struct cxl_ctx;
> +struct cxl_ctx *cxl_ref(struct cxl_ctx *ctx);
> +void cxl_unref(struct cxl_ctx *ctx);
> +int cxl_new(struct cxl_ctx **ctx);
> +void cxl_set_log_fn(struct cxl_ctx *ctx,
> +               void (*log_fn)(struct cxl_ctx *ctx, int priority,
> +                       const char *file, int line, const char *fn,
> +                       const char *format, va_list args));
> +int cxl_get_log_priority(struct cxl_ctx *ctx);
> +void cxl_set_log_priority(struct cxl_ctx *ctx, int priority);
> +void cxl_set_userdata(struct cxl_ctx *ctx, void *userdata);
> +void *cxl_get_userdata(struct cxl_ctx *ctx);
> +void cxl_set_private_data(struct cxl_ctx *ctx, void *data);
> +void *cxl_get_private_data(struct cxl_ctx *ctx);
> +
> +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);
> +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);
> +struct cxl_ctx *cxl_memdev_get_ctx(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);
> +
> +#define cxl_memdev_foreach(ctx, memdev) \
> +        for (memdev = cxl_memdev_get_first(ctx); \
> +             memdev != NULL; \
> +             memdev = cxl_memdev_get_next(memdev))
> +
> +#ifdef __cplusplus
> +} /* extern "C" */
> +#endif
> +
> +#endif
> diff --git a/util/filter.h b/util/filter.h
> index 1e1a41c..9a80d65 100644
> --- a/util/filter.h
> +++ b/util/filter.h
> @@ -29,6 +29,8 @@ struct daxctl_dev *util_daxctl_dev_filter(struct daxctl_dev *dev,
>                 const char *ident);
>  struct daxctl_region *util_daxctl_region_filter(struct daxctl_region *region,
>                 const char *ident);
> +struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
> +               const char *ident);
>
>  enum ndctl_namespace_mode util_nsmode(const char *mode);
>  const char *util_nsmode_name(enum ndctl_namespace_mode mode);
> diff --git a/util/json.h b/util/json.h
> index 0f09e36..91918c8 100644
> --- a/util/json.h
> +++ b/util/json.h
> @@ -55,4 +55,7 @@ struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm);
>  struct json_object *util_dimm_firmware_to_json(struct ndctl_dimm *dimm,
>                 unsigned long flags);
>  struct json_object *util_region_capabilities_to_json(struct ndctl_region *region);
> +struct cxl_memdev;
> +struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
> +               unsigned long flags);
>  #endif /* __NDCTL_JSON_H__ */
> diff --git a/util/main.h b/util/main.h
> index c89a843..80b55c4 100644
> --- a/util/main.h
> +++ b/util/main.h
> @@ -10,16 +10,19 @@
>  enum program {
>         PROG_NDCTL,
>         PROG_DAXCTL,
> +       PROG_CXL,
>  };
>
>  struct ndctl_ctx;
>  struct daxctl_ctx;
> +struct cxl_ctx;
>
>  struct cmd_struct {
>         const char *cmd;
>         union {
>                 int (*n_fn)(int, const char **, struct ndctl_ctx *ctx);
>                 int (*d_fn)(int, const char **, struct daxctl_ctx *ctx);
> +               int (*c_fn)(int, const char **, struct cxl_ctx *ctx);
>         };
>  };
>
> diff --git a/cxl/cxl.c b/cxl/cxl.c
> new file mode 100644
> index 0000000..a7725f8
> --- /dev/null
> +++ b/cxl/cxl.c
> @@ -0,0 +1,96 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (C) 2020-2021 Intel Corporation. All rights reserved. */
> +/* Copyright (C) 2005 Andreas Ericsson. All rights reserved. */
> +
> +/* originally copied from perf and git */
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <cxl/libcxl.h>
> +#include <util/parse-options.h>
> +#include <ccan/array_size/array_size.h>
> +
> +#include <util/strbuf.h>
> +#include <util/util.h>
> +#include <util/main.h>
> +#include <cxl/builtin.h>
> +
> +const char cxl_usage_string[] = "cxl [--version] [--help] COMMAND [ARGS]";
> +const char cxl_more_info_string[] =
> +       "See 'cxl help COMMAND' for more information on a specific command.\n"
> +       " cxl --list-cmds to see all available commands";
> +
> +static int cmd_version(int argc, const char **argv, struct cxl_ctx *ctx)
> +{
> +       printf("%s\n", VERSION);
> +       return 0;
> +}
> +
> +static int cmd_help(int argc, const char **argv, struct cxl_ctx *ctx)
> +{
> +       const char * const builtin_help_subcommands[] = {
> +               "list",
> +               NULL,
> +       };
> +       struct option builtin_help_options[] = {
> +               OPT_END(),
> +       };
> +       const char *builtin_help_usage[] = {
> +               "cxl help [command]",
> +               NULL
> +       };
> +
> +       argc = parse_options_subcommand(argc, argv, builtin_help_options,
> +                       builtin_help_subcommands, builtin_help_usage, 0);
> +
> +       if (!argv[0]) {
> +               printf("\n usage: %s\n\n", cxl_usage_string);
> +               printf("\n %s\n\n", cxl_more_info_string);
> +               return 0;
> +       }
> +
> +       return help_show_man_page(argv[0], "cxl", "CXL_MAN_VIEWER");
> +}
> +
> +static struct cmd_struct commands[] = {
> +       { "version", .c_fn = cmd_version },
> +       { "list", .c_fn = cmd_list },
> +       { "help", .c_fn = cmd_help },
> +};
> +
> +int main(int argc, const char **argv)
> +{
> +       struct cxl_ctx *ctx;
> +       int rc;
> +
> +       /* Look for flags.. */
> +       argv++;
> +       argc--;
> +       main_handle_options(&argv, &argc, cxl_usage_string, commands,
> +                       ARRAY_SIZE(commands));
> +
> +       if (argc > 0) {
> +               if (!prefixcmp(argv[0], "--"))
> +                       argv[0] += 2;
> +       } else {
> +               /* The user didn't specify a command; give them help */
> +               printf("\n usage: %s\n\n", cxl_usage_string);
> +               printf("\n %s\n\n", cxl_more_info_string);
> +               goto out;
> +       }
> +
> +       rc = cxl_new(&ctx);
> +       if (rc)
> +               goto out;
> +       main_handle_internal_command(argc, argv, ctx, commands,
> +                       ARRAY_SIZE(commands), PROG_CXL);
> +       cxl_unref(ctx);
> +       fprintf(stderr, "Unknown command: '%s'\n", argv[0]);
> +out:
> +       return 1;
> +}
> diff --git a/cxl/list.c b/cxl/list.c
> new file mode 100644
> index 0000000..3dea73f
> --- /dev/null
> +++ b/cxl/list.c
> @@ -0,0 +1,113 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (C) 2020-2021 Intel Corporation. All rights reserved. */
> +#include <stdio.h>
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <limits.h>
> +#include <util/json.h>
> +#include <util/filter.h>
> +#include <json-c/json.h>
> +#include <cxl/libcxl.h>
> +#include <util/parse-options.h>
> +#include <ccan/array_size/array_size.h>
> +
> +static struct {
> +       bool memdevs;
> +       bool idle;
> +       bool human;
> +} 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;
> +       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 int num_list_flags(void)
> +{
> +       return list.memdevs;
> +}
> +
> +int cmd_list(int argc, const char **argv, struct cxl_ctx *ctx)
> +{
> +       const struct option options[] = {
> +               OPT_STRING('d', "memdev", &param.memdev, "memory device name",
> +                          "filter by CXL memory device name"),
> +               OPT_BOOLEAN('D', "memdevs", &list.memdevs,
> +                           "include CXL memory device info"),
> +               OPT_BOOLEAN('i', "idle", &list.idle, "include idle devices"),
> +               OPT_BOOLEAN('u', "human", &list.human,
> +                               "use human friendly number formats "),
> +               OPT_END(),
> +       };
> +       const char * const u[] = {
> +               "cxl list [<options>]",
> +               NULL
> +       };
> +       struct json_object *jdevs = NULL;
> +       unsigned long list_flags;
> +       struct cxl_memdev *memdev;
> +       int i;
> +
> +       argc = parse_options(argc, argv, options, u, 0);
> +       for (i = 0; i < argc; i++)
> +               error("unknown parameter \"%s\"\n", argv[i]);
> +
> +       if (argc)
> +               usage_with_options(u, options);
> +
> +       if (num_list_flags() == 0)
> +               list.memdevs = true;
> +
> +       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 (jdevs)
> +               util_display_json_array(stdout, jdevs, list_flags);
> +
> +       if (did_fail)
> +               return -ENOMEM;
> +       return 0;
> +}
> diff --git a/util/filter.c b/util/filter.c
> index 8b4aad3..d81dade 100644
> --- a/util/filter.c
> +++ b/util/filter.c
> @@ -12,6 +12,7 @@
>  #include <util/filter.h>
>  #include <ndctl/libndctl.h>
>  #include <daxctl/libdaxctl.h>
> +#include <cxl/libcxl.h>
>
>  struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *__ident)
>  {
> @@ -339,6 +340,25 @@ struct daxctl_region *util_daxctl_region_filter(struct daxctl_region *region,
>         return NULL;
>  }
>
> +struct cxl_memdev *util_cxl_memdev_filter(struct cxl_memdev *memdev,
> +                                         const char *ident)
> +{
> +       int memdev_id;
> +
> +       if (!ident || strcmp(ident, "all") == 0)
> +               return memdev;
> +
> +       if (strcmp(ident, cxl_memdev_get_devname(memdev)) == 0)
> +               return memdev;
> +
> +       if ((sscanf(ident, "%d", &memdev_id) == 1
> +                       || sscanf(ident, "mem%d", &memdev_id) == 1)
> +                       && cxl_memdev_get_id(memdev) == memdev_id)
> +               return memdev;
> +
> +       return NULL;
> +}
> +
>  enum ndctl_namespace_mode util_nsmode(const char *mode)
>  {
>         if (!mode)
> diff --git a/util/json.c b/util/json.c
> index a8d2412..3be3a92 100644
> --- a/util/json.c
> +++ b/util/json.c
> @@ -9,6 +9,7 @@
>  #include <json-c/printbuf.h>
>  #include <ndctl/libndctl.h>
>  #include <daxctl/libdaxctl.h>
> +#include <cxl/libcxl.h>
>  #include <ccan/array_size/array_size.h>
>  #include <ccan/short_types/short_types.h>
>  #include <ndctl.h>
> @@ -1440,3 +1441,28 @@ struct json_object *util_badblock_rec_to_json(u64 block, u64 count,
>         json_object_put(jerr);
>         return NULL;
>  }
> +
> +struct json_object *util_cxl_memdev_to_json(struct cxl_memdev *memdev,
> +               unsigned long flags)
> +{
> +       const char *devname = cxl_memdev_get_devname(memdev);
> +       struct json_object *jdev, *jobj;
> +
> +       jdev = json_object_new_object();
> +       if (!devname || !jdev)
> +               return NULL;
> +
> +       jobj = json_object_new_string(devname);
> +       if (jobj)
> +               json_object_object_add(jdev, "memdev", jobj);
> +
> +       jobj = util_json_object_size(cxl_memdev_get_pmem_size(memdev), flags);
> +       if (jobj)
> +               json_object_object_add(jdev, "pmem_size", jobj);
> +
> +       jobj = util_json_object_size(cxl_memdev_get_ram_size(memdev), flags);
> +       if (jobj)
> +               json_object_object_add(jdev, "ram_size", jobj);
> +
> +       return jdev;
> +}
> diff --git a/.clang-format b/.clang-format
> index 4e00fff..d2e77d0 100644
> --- a/.clang-format
> +++ b/.clang-format
> @@ -77,6 +77,7 @@ ExperimentalAutoDetectBinPacking: false
>  #              -e 's/\(.*foreach.*\)(.*/\1/' \
>  #      | sort -u)
>  ForEachMacros:
> +  - 'cxl_memdev_foreach'
>    - 'daxctl_dev_foreach'
>    - 'daxctl_mapping_foreach'
>    - 'daxctl_region_foreach'
> diff --git a/.gitignore b/.gitignore
> index 53512b2..6a97b92 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -16,9 +16,11 @@ Makefile.in
>  *.1
>  Documentation/daxctl/asciidoc.conf
>  Documentation/ndctl/asciidoc.conf
> -Documentation/ndctl/attrs.adoc
> +Documentation/cxl/asciidoc.conf
>  Documentation/daxctl/asciidoctor-extensions.rb
>  Documentation/ndctl/asciidoctor-extensions.rb
> +Documentation/cxl/asciidoctor-extensions.rb
> +Documentation/ndctl/attrs.adoc
>  .dirstamp
>  daxctl/config.h
>  daxctl/daxctl
> diff --git a/Documentation/cxl/Makefile.am b/Documentation/cxl/Makefile.am
> new file mode 100644
> index 0000000..db98dd7
> --- /dev/null
> +++ b/Documentation/cxl/Makefile.am
> @@ -0,0 +1,58 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2020-2021 Intel Corporation. All rights reserved.
> +
> +if USE_ASCIIDOCTOR
> +
> +do_subst = sed -e 's,@Utility@,Cxl,g' -e's,@utility@,cxl,g'
> +CONFFILE = asciidoctor-extensions.rb
> +asciidoctor-extensions.rb: ../asciidoctor-extensions.rb.in
> +       $(AM_V_GEN) $(do_subst) < $< > $@
> +
> +else
> +
> +do_subst = sed -e 's,UTILITY,cxl,g'
> +CONFFILE = asciidoc.conf
> +asciidoc.conf: ../asciidoc.conf.in
> +       $(AM_V_GEN) $(do_subst) < $< > $@
> +
> +endif
> +
> +man1_MANS = \
> +       cxl.1 \
> +       cxl-list.1
> +
> +EXTRA_DIST = $(man1_MANS)
> +
> +CLEANFILES = $(man1_MANS)
> +
> +XML_DEPS = \
> +       ../../version.m4 \
> +       ../copyright.txt \
> +       Makefile \
> +       $(CONFFILE)
> +
> +RM ?= rm -f
> +
> +if USE_ASCIIDOCTOR
> +
> +%.1: %.txt $(XML_DEPS)
> +       $(AM_V_GEN)$(RM) $@+ $@ && \
> +               $(ASCIIDOC) -b manpage -d manpage -acompat-mode \
> +               -I. -rasciidoctor-extensions \
> +               -amansource=cxl -amanmanual="cxl Manual" \
> +               -andctl_version=$(VERSION) -o $@+ $< && \
> +               mv $@+ $@
> +
> +else
> +
> +%.xml: %.txt $(XML_DEPS)
> +       $(AM_V_GEN)$(RM) $@+ $@ && \
> +               $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
> +               --unsafe -acxl_version=$(VERSION) -o $@+ $< && \
> +               mv $@+ $@
> +
> +%.1: %.xml $(XML_DEPS)
> +       $(AM_V_GEN)$(RM) $@ && \
> +               $(XMLTO) -o . -m ../manpage-normal.xsl man $<
> +
> +endif
> diff --git a/cxl/Makefile.am b/cxl/Makefile.am
> new file mode 100644
> index 0000000..98606b9
> --- /dev/null
> +++ b/cxl/Makefile.am
> @@ -0,0 +1,21 @@
> +include $(top_srcdir)/Makefile.am.in
> +
> +bin_PROGRAMS = cxl
> +
> +DISTCLEANFILES = config.h
> +BUILT_SOURCES = config.h
> +config.h: $(srcdir)/Makefile.am
> +       $(AM_V_GEN) echo "/* Autogenerated by cxl/Makefile.am */" >$@
> +
> +cxl_SOURCES =\
> +               cxl.c \
> +               list.c \
> +               ../util/json.c \
> +               builtin.h
> +
> +cxl_LDADD =\
> +       lib/libcxl.la \
> +       ../libutil.a \
> +       $(UUID_LIBS) \
> +       $(KMOD_LIBS) \
> +       $(JSON_LIBS)
> diff --git a/cxl/lib/Makefile.am b/cxl/lib/Makefile.am
> new file mode 100644
> index 0000000..277f0cd
> --- /dev/null
> +++ b/cxl/lib/Makefile.am
> @@ -0,0 +1,32 @@
> +include $(top_srcdir)/Makefile.am.in
> +
> +%.pc: %.pc.in Makefile
> +       $(SED_PROCESS)
> +
> +pkginclude_HEADERS = ../libcxl.h
> +lib_LTLIBRARIES = libcxl.la
> +
> +libcxl_la_SOURCES =\
> +       ../libcxl.h \
> +       private.h \
> +       ../../util/sysfs.c \
> +       ../../util/sysfs.h \
> +       ../../util/log.c \
> +       ../../util/log.h \
> +       libcxl.c
> +
> +libcxl_la_LIBADD =\
> +       $(UUID_LIBS) \
> +       $(KMOD_LIBS)
> +
> +EXTRA_DIST += libcxl.sym
> +
> +libcxl_la_LDFLAGS = $(AM_LDFLAGS) \
> +       -version-info $(LIBCXL_CURRENT):$(LIBCXL_REVISION):$(LIBCXL_AGE) \
> +       -Wl,--version-script=$(top_srcdir)/cxl/lib/libcxl.sym
> +libcxl_la_DEPENDENCIES = libcxl.sym
> +
> +pkgconfigdir = $(libdir)/pkgconfig
> +pkgconfig_DATA = libcxl.pc
> +EXTRA_DIST += libcxl.pc.in
> +CLEANFILES += libcxl.pc
> diff --git a/cxl/lib/libcxl.pc.in b/cxl/lib/libcxl.pc.in
> new file mode 100644
> index 0000000..949fcdc
> --- /dev/null
> +++ b/cxl/lib/libcxl.pc.in
> @@ -0,0 +1,11 @@
> +prefix=@prefix@
> +exec_prefix=@exec_prefix@
> +libdir=@libdir@
> +includedir=@includedir@
> +
> +Name: libcxl
> +Description: Manage CXL devices
> +Version: @VERSION@
> +Libs: -L${libdir} -lcxl
> +Libs.private:
> +Cflags: -I${includedir}
> diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
> new file mode 100644
> index 0000000..0f6ecad
> --- /dev/null
> +++ b/cxl/lib/libcxl.sym
> @@ -0,0 +1,29 @@
> +LIBCXL_1 {
> +global:
> +       cxl_get_userdata;
> +       cxl_set_userdata;
> +       cxl_get_private_data;
> +       cxl_set_private_data;
> +       cxl_ref;
> +       cxl_get_log_priority;
> +       cxl_set_log_fn;
> +       cxl_unref;
> +       cxl_set_log_priority;
> +       cxl_new;
> +local:
> +        *;
> +};
> +
> +LIBCXL_2 {
> +global:
> +       cxl_memdev_get_first;
> +       cxl_memdev_get_next;
> +       cxl_memdev_get_id;
> +       cxl_memdev_get_devname;
> +       cxl_memdev_get_major;
> +       cxl_memdev_get_minor;
> +       cxl_memdev_get_ctx;
> +       cxl_memdev_get_pmem_size;
> +       cxl_memdev_get_ram_size;
> +       cxl_memdev_get_firmware_verison;
> +} LIBCXL_1;
> --
> 2.31.1
>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [ndctl PATCH v3 01/21] ndctl: add .clang-format
  2021-07-01 20:09 ` [ndctl PATCH v3 01/21] ndctl: add .clang-format Vishal Verma
@ 2021-07-10  1:12   ` Dan Williams
  0 siblings, 0 replies; 36+ messages in thread
From: Dan Williams @ 2021-07-10  1:12 UTC (permalink / raw)
  To: Vishal Verma
  Cc: Linux NVDIMM, linux-cxl, Ben Widawsky, Alison Schofield, Ira Weiny

On Thu, Jul 1, 2021 at 1:10 PM Vishal Verma <vishal.l.verma@intel.com> wrote:
>
> Copy the Linux kernel's .clang-format and modify it for ndctl. Only the
> 'ForEachMacros' section has been modified from the original kernel copy.
>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Reported-by: Ben Widawsky <ben.widawsky@intel.com>
> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

Nice!

Reviewed-by: Dan Williams <dan.j.williams@intel.com>


> ---
>  .clang-format | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 161 insertions(+)
>  create mode 100644 .clang-format
>
> diff --git a/.clang-format b/.clang-format
> new file mode 100644
> index 0000000..4e00fff
> --- /dev/null
> +++ b/.clang-format
> @@ -0,0 +1,161 @@
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# clang-format configuration file. Intended for clang-format >= 4.
> +# Copied from Linux's .clang-format
> +#
> +# For more information, see:
> +#
> +#   https://clang.llvm.org/docs/ClangFormat.html
> +#   https://clang.llvm.org/docs/ClangFormatStyleOptions.html
> +#
> +---
> +AccessModifierOffset: -4
> +AlignAfterOpenBracket: Align
> +AlignConsecutiveAssignments: false
> +AlignConsecutiveDeclarations: false
> +#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
> +AlignOperands: true
> +AlignTrailingComments: false
> +AllowAllParametersOfDeclarationOnNextLine: false
> +AllowShortBlocksOnASingleLine: false
> +AllowShortCaseLabelsOnASingleLine: false
> +AllowShortFunctionsOnASingleLine: None
> +AllowShortIfStatementsOnASingleLine: false
> +AllowShortLoopsOnASingleLine: false
> +AlwaysBreakAfterDefinitionReturnType: None
> +AlwaysBreakAfterReturnType: None
> +AlwaysBreakBeforeMultilineStrings: false
> +AlwaysBreakTemplateDeclarations: false
> +BinPackArguments: true
> +BinPackParameters: true
> +BraceWrapping:
> +  AfterClass: false
> +  AfterControlStatement: false
> +  AfterEnum: false
> +  AfterFunction: true
> +  AfterNamespace: true
> +  AfterObjCDeclaration: false
> +  AfterStruct: false
> +  AfterUnion: false
> +  #AfterExternBlock: false # Unknown to clang-format-5.0
> +  BeforeCatch: false
> +  BeforeElse: false
> +  IndentBraces: false
> +  #SplitEmptyFunction: true # Unknown to clang-format-4.0
> +  #SplitEmptyRecord: true # Unknown to clang-format-4.0
> +  #SplitEmptyNamespace: true # Unknown to clang-format-4.0
> +BreakBeforeBinaryOperators: None
> +BreakBeforeBraces: Custom
> +#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
> +BreakBeforeTernaryOperators: false
> +BreakConstructorInitializersBeforeComma: false
> +#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
> +BreakAfterJavaFieldAnnotations: false
> +BreakStringLiterals: false
> +ColumnLimit: 80
> +CommentPragmas: '^ IWYU pragma:'
> +#CompactNamespaces: false # Unknown to clang-format-4.0
> +ConstructorInitializerAllOnOneLineOrOnePerLine: false
> +ConstructorInitializerIndentWidth: 8
> +ContinuationIndentWidth: 8
> +Cpp11BracedListStyle: false
> +DerivePointerAlignment: false
> +DisableFormat: false
> +ExperimentalAutoDetectBinPacking: false
> +#FixNamespaceComments: false # Unknown to clang-format-4.0
> +
> +# Taken from:
> +# while read -r sym; do
> +#      printf "  - '%s'\n" "$sym";
> +# done < \
> +#      <(cscope -dL6 "foreach|for_each" \
> +#      | awk '{ print $4 $5 }' | grep -E 'foreach|for_each' \
> +#      | sed -e 's/#define//' \
> +#              -e 's/*//' \
> +#              -e 's/://' \
> +#              -e 's/\(.*for_each.*\)(.*/\1/' \
> +#              -e 's/\(.*foreach.*\)(.*/\1/' \
> +#      | sort -u)
> +ForEachMacros:
> +  - 'daxctl_dev_foreach'
> +  - 'daxctl_mapping_foreach'
> +  - 'daxctl_region_foreach'
> +  - 'kmod_list_foreach'
> +  - 'kmod_list_foreach_reverse'
> +  - 'list_for_each'
> +  - 'list_for_each_off'
> +  - 'list_for_each_rev'
> +  - 'list_for_each_safe'
> +  - 'list_for_each_safe_off'
> +  - 'ndctl_btt_foreach'
> +  - 'ndctl_btt_foreach_safe'
> +  - 'ndctl_bus_foreach'
> +  - 'ndctl_dax_foreach'
> +  - 'ndctl_dax_foreach_safe'
> +  - 'ndctl_dimm_foreach'
> +  - 'ndctl_dimm_foreach_in_interleave_set'
> +  - 'ndctl_dimm_foreach_in_region'
> +  - 'ndctl_interleave_set_foreach'
> +  - 'ndctl_mapping_foreach'
> +  - 'ndctl_namespace_badblock_foreach'
> +  - 'ndctl_namespace_bb_foreach'
> +  - 'ndctl_namespace_foreach'
> +  - 'ndctl_namespace_foreach_safe'
> +  - 'ndctl_pfn_foreach'
> +  - 'ndctl_pfn_foreach_safe'
> +  - 'ndctl_region_badblock_foreach'
> +  - 'ndctl_region_foreach'
> +  - 'udev_list_entry_foreach'
> +
> +#IncludeBlocks: Preserve # Unknown to clang-format-5.0
> +IncludeCategories:
> +  - Regex: '.*'
> +    Priority: 1
> +IncludeIsMainRegex: '(Test)?$'
> +IndentCaseLabels: false
> +#IndentPPDirectives: None # Unknown to clang-format-5.0
> +IndentWidth: 8
> +IndentWrappedFunctionNames: false
> +JavaScriptQuotes: Leave
> +JavaScriptWrapImports: true
> +KeepEmptyLinesAtTheStartOfBlocks: false
> +MacroBlockBegin: ''
> +MacroBlockEnd: ''
> +MaxEmptyLinesToKeep: 1
> +NamespaceIndentation: None
> +#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
> +ObjCBlockIndentWidth: 8
> +ObjCSpaceAfterProperty: true
> +ObjCSpaceBeforeProtocolList: true
> +
> +# Taken from git's rules
> +#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
> +PenaltyBreakBeforeFirstCallParameter: 30
> +PenaltyBreakComment: 10
> +PenaltyBreakFirstLessLess: 0
> +PenaltyBreakString: 10
> +PenaltyExcessCharacter: 100
> +PenaltyReturnTypeOnItsOwnLine: 60
> +
> +PointerAlignment: Right
> +ReflowComments: false
> +SortIncludes: false
> +#SortUsingDeclarations: false # Unknown to clang-format-4.0
> +SpaceAfterCStyleCast: false
> +SpaceAfterTemplateKeyword: true
> +SpaceBeforeAssignmentOperators: true
> +#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
> +#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
> +SpaceBeforeParens: ControlStatements
> +#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
> +SpaceInEmptyParentheses: false
> +SpacesBeforeTrailingComments: 1
> +SpacesInAngles: false
> +SpacesInContainerLiterals: false
> +SpacesInCStyleCastParentheses: false
> +SpacesInParentheses: false
> +SpacesInSquareBrackets: false
> +Standard: Cpp03
> +TabWidth: 8
> +UseTab: Always
> +...
> --
> 2.31.1
>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [ndctl PATCH v3 03/21] cxl: add a local copy of the cxl_mem UAPI header
  2021-07-01 20:09 ` [ndctl PATCH v3 03/21] cxl: add a local copy of the cxl_mem UAPI header Vishal Verma
@ 2021-07-10  1:13   ` Dan Williams
  0 siblings, 0 replies; 36+ messages in thread
From: Dan Williams @ 2021-07-10  1:13 UTC (permalink / raw)
  To: Vishal Verma
  Cc: Linux NVDIMM, linux-cxl, Ben Widawsky, Alison Schofield, Ira Weiny

On Thu, Jul 1, 2021 at 1:10 PM Vishal Verma <vishal.l.verma@intel.com> wrote:
>
> While CXL functionality is under development, it is useful to have a
> local copy of the UAPI header for cxl_mem definitions. This allows
> building cxl and libcxl on systems where the appropriate kernel headers
> are not installed in the usual locations.
>
> Cc: Ben Widawsky <ben.widawsky@intel.com>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>

Looks good,

Reviewed-by: Dan Williams <dan.j.williams@intel.com>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [ndctl PATCH v3 04/21] libcxl: add support for command query and submission
  2021-07-01 20:09 ` [ndctl PATCH v3 04/21] libcxl: add support for command query and submission Vishal Verma
@ 2021-07-13  5:12   ` Dan Williams
  2021-07-13 21:17     ` Verma, Vishal L
  0 siblings, 1 reply; 36+ messages in thread
From: Dan Williams @ 2021-07-13  5:12 UTC (permalink / raw)
  To: Vishal Verma
  Cc: Linux NVDIMM, linux-cxl, Ben Widawsky, Alison Schofield, Ira Weiny

On Thu, Jul 1, 2021 at 1:10 PM Vishal Verma <vishal.l.verma@intel.com> wrote:
>
> Add a set of APIs around 'cxl_cmd' for querying the kernel for supported
> commands, allocating and validating command structures against the
> supported set, and submitting the commands.
>
> 'Query Commands' and 'Send Command' are implemented as IOCTLs in the
> kernel. 'Query Commands' returns information about each supported
> command, such as flags governing its use, or input and output payload
> sizes. This information is used to validate command support, as well as
> set up input and output buffers for command submission.

It strikes me after reading the above that it would be useful to have
a cxl list option that enumerates the command support on a given
memdev. Basically a "query-to-json" helper.

>
> Cc: Ben Widawsky <ben.widawsky@intel.com>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
> ---
>  cxl/lib/private.h  |  33 ++++
>  cxl/lib/libcxl.c   | 388 +++++++++++++++++++++++++++++++++++++++++++++
>  cxl/libcxl.h       |  11 ++
>  cxl/lib/libcxl.sym |  13 ++
>  4 files changed, 445 insertions(+)
>
[..]
> +static int cxl_cmd_alloc_query(struct cxl_cmd *cmd, int num_cmds)
> +{
> +       size_t size;
> +
> +       if (!cmd)
> +               return -EINVAL;
> +
> +       if (cmd->query_cmd != NULL)
> +               free(cmd->query_cmd);
> +
> +       size = sizeof(struct cxl_mem_query_commands) +
> +                       (num_cmds * sizeof(struct cxl_command_info));

This is asking for the kernel's include/linux/overflow.h to be
imported into ndctl so that struct_size() could be used here. The file
is MIT licensed, just the small matter of factoring out only the MIT
licensed bits.

Other than that, looks good to me.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [ndctl PATCH v3 02/21] cxl: add a cxl utility and libcxl library
  2021-07-10  1:12   ` Dan Williams
@ 2021-07-13 21:14     ` Verma, Vishal L
  0 siblings, 0 replies; 36+ messages in thread
From: Verma, Vishal L @ 2021-07-13 21:14 UTC (permalink / raw)
  To: Williams, Dan J
  Cc: Widawsky, Ben, linux-cxl, nvdimm, Schofield, Alison, Weiny, Ira

On Fri, 2021-07-09 at 18:12 -0700, Dan Williams wrote:
> On Thu, Jul 1, 2021 at 1:10 PM Vishal Verma <vishal.l.verma@intel.com> wrote:
> > 
> > CXL - or Compute eXpress Link - is a new interconnect that extends PCIe
> > to support a wide range of devices, including cache coherent memory
> > expanders. As such, these devices can be new sources of 'persistent
> > memory', and the 'ndctl' umbrella of tools and libraries needs to be able
> > to interact with them.
> > 
> > Add a new utility and library for managing these CXL memory devices. This
> > is an initial bring-up for interacting with CXL devices, and only includes
> > adding the utility and library infrastructure, parsing device information
> > from sysfs for CXL devices, and providing a 'cxl-list' command to
> > display this information in JSON formatted output.
> > 
> > Cc: Ben Widawsky <ben.widawsky@intel.com>
> > Cc: Dan Williams <dan.j.williams@intel.com>
> > Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
> 
> Looks good, just a couple minor quibbles below:
> 
> Reviewed-by: Dan Williams <dan.j.williams@intel.com>

Thanks Dan - addressed as below.

> 
> > ---
> >  Documentation/cxl/cxl-list.txt       |  64 +++++
> >  Documentation/cxl/cxl.txt            |  34 +++
> >  Documentation/cxl/human-option.txt   |   8 +
> >  Documentation/cxl/verbose-option.txt |   5 +
> >  configure.ac                         |   3 +
> >  Makefile.am                          |   8 +-
> >  Makefile.am.in                       |   4 +
> >  cxl/lib/private.h                    |  29 +++
> >  cxl/lib/libcxl.c                     | 345 +++++++++++++++++++++++++++
> >  cxl/builtin.h                        |   8 +
> >  cxl/libcxl.h                         |  55 +++++
> >  util/filter.h                        |   2 +
> >  util/json.h                          |   3 +
> >  util/main.h                          |   3 +
> >  cxl/cxl.c                            |  96 ++++++++
> >  cxl/list.c                           | 113 +++++++++
> >  util/filter.c                        |  20 ++
> >  util/json.c                          |  26 ++
> >  .clang-format                        |   1 +
> >  .gitignore                           |   4 +-
> >  Documentation/cxl/Makefile.am        |  58 +++++
> >  cxl/Makefile.am                      |  21 ++
> >  cxl/lib/Makefile.am                  |  32 +++
> >  cxl/lib/libcxl.pc.in                 |  11 +
> >  cxl/lib/libcxl.sym                   |  29 +++
> >  25 files changed, 978 insertions(+), 4 deletions(-)
> >  create mode 100644 Documentation/cxl/cxl-list.txt
> >  create mode 100644 Documentation/cxl/cxl.txt
> >  create mode 100644 Documentation/cxl/human-option.txt
> >  create mode 100644 Documentation/cxl/verbose-option.txt
> >  create mode 100644 cxl/lib/private.h
> >  create mode 100644 cxl/lib/libcxl.c
> >  create mode 100644 cxl/builtin.h
> >  create mode 100644 cxl/libcxl.h
> >  create mode 100644 cxl/cxl.c
> >  create mode 100644 cxl/list.c
> >  create mode 100644 Documentation/cxl/Makefile.am
> >  create mode 100644 cxl/Makefile.am
> >  create mode 100644 cxl/lib/Makefile.am
> >  create mode 100644 cxl/lib/libcxl.pc.in
> >  create mode 100644 cxl/lib/libcxl.sym
> > 
> > diff --git a/Documentation/cxl/cxl-list.txt b/Documentation/cxl/cxl-list.txt
> > new file mode 100644
> > index 0000000..4e2be87
> > --- /dev/null
> > +++ b/Documentation/cxl/cxl-list.txt
> > @@ -0,0 +1,64 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +cxl-list(1)
> > +===========
> > +
> > +NAME
> > +----
> > +cxl-list - List CXL capable memory devices, and their attributes in json.
> 
> This will also show CXL port topology in the future. I'm fine to fix
> that up later when that support arrives.

Yep I actually removed it based on feedback from Ben saying we should
add those when the actual support for those is added.

> 
> > +
> > +SYNOPSIS
> > +--------
> > +[verse]
> > +'cxl list' [<options>]
> > +
> > +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 devices.
> > +By default, 'cxl list' with no options is equivalent to:
> > +[verse]
> > +cxl list --devices
> > +
> > +EXAMPLE
> > +-------
> > +----
> > +# cxl list --devices
> 
> Is this from an earlier version, should it be --memdevs?

Yep stale, fixed for v4.

> 
> > +{
> > +  "memdev":"mem0",
> > +  "pmem_size":268435456,
> > +  "ram_size":0,
> > +}
> > +----
> > +
> > +OPTIONS
> > +-------
> > +-d::
> > +--memdev=::
> > +       Specify a cxl memory device name to filter the listing. For example:
> > +----
> > +# cxl list --memdev=mem0
> > +{
> > +  "memdev":"mem0",
> > +  "pmem_size":268435456,
> > +  "ram_size":0,
> > +}
> > +----
> > +
> > +-D::
> > +--memdevs::
> > +       Include all CXL memory devices in the listing
> > +
> > +-i::
> > +--idle::
> > +       Include idle (not enabled / zero-sized) devices in the listing
> > +
> > +include::human-option.txt[]
> > +
> > +include::verbose-option.txt[]
> > +
> > +include::../copyright.txt[]
> > +
> > +SEE ALSO
> > +--------
> > +linkcxl:ndctl-list[1]
> > diff --git a/Documentation/cxl/cxl.txt b/Documentation/cxl/cxl.txt
> > new file mode 100644
> > index 0000000..e99e61b
> > --- /dev/null
> > +++ b/Documentation/cxl/cxl.txt
> > @@ -0,0 +1,34 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +cxl(1)
> > +======
> > +
> > +NAME
> > +----
> > +cxl - Provides enumeration and provisioning commands for CXL devices
> 
> s/device/platforms/ since it should enumerate an entire topology.

Good catch, fixed.


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [ndctl PATCH v3 04/21] libcxl: add support for command query and submission
  2021-07-13  5:12   ` Dan Williams
@ 2021-07-13 21:17     ` Verma, Vishal L
  2021-07-13 21:39       ` Dan Williams
  0 siblings, 1 reply; 36+ messages in thread
From: Verma, Vishal L @ 2021-07-13 21:17 UTC (permalink / raw)
  To: Williams, Dan J
  Cc: Widawsky, Ben, linux-cxl, nvdimm, Schofield, Alison, Weiny, Ira

On Mon, 2021-07-12 at 22:12 -0700, Dan Williams wrote:
> On Thu, Jul 1, 2021 at 1:10 PM Vishal Verma <vishal.l.verma@intel.com> wrote:
> > 
> > Add a set of APIs around 'cxl_cmd' for querying the kernel for supported
> > commands, allocating and validating command structures against the
> > supported set, and submitting the commands.
> > 
> > 'Query Commands' and 'Send Command' are implemented as IOCTLs in the
> > kernel. 'Query Commands' returns information about each supported
> > command, such as flags governing its use, or input and output payload
> > sizes. This information is used to validate command support, as well as
> > set up input and output buffers for command submission.
> 
> It strikes me after reading the above that it would be useful to have
> a cxl list option that enumerates the command support on a given
> memdev. Basically a "query-to-json" helper.

Hm, yes that makes sense..  There may not always be a 1:1 correlation
between the commands returned by query and the actual cxl-cli command
corresponding with that - and for some commands, there may not even be
a cxl-cli equivalent. Do we want to create a json representation of the
raw query data, or cxl-cli equivalents?

> > 
> > Cc: Ben Widawsky <ben.widawsky@intel.com>
> > Cc: Dan Williams <dan.j.williams@intel.com>
> > Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
> > ---
> >  cxl/lib/private.h  |  33 ++++
> >  cxl/lib/libcxl.c   | 388 +++++++++++++++++++++++++++++++++++++++++++++
> >  cxl/libcxl.h       |  11 ++
> >  cxl/lib/libcxl.sym |  13 ++
> >  4 files changed, 445 insertions(+)
> > 
> [..]
> > +static int cxl_cmd_alloc_query(struct cxl_cmd *cmd, int num_cmds)
> > +{
> > +       size_t size;
> > +
> > +       if (!cmd)
> > +               return -EINVAL;
> > +
> > +       if (cmd->query_cmd != NULL)
> > +               free(cmd->query_cmd);
> > +
> > +       size = sizeof(struct cxl_mem_query_commands) +
> > +                       (num_cmds * sizeof(struct cxl_command_info));
> 
> This is asking for the kernel's include/linux/overflow.h to be
> imported into ndctl so that struct_size() could be used here. The file
> is MIT licensed, just the small matter of factoring out only the MIT
> licensed bits.

Ah ok let me take a look.

> Other than that, looks good to me.


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [ndctl PATCH v3 04/21] libcxl: add support for command query and submission
  2021-07-13 21:17     ` Verma, Vishal L
@ 2021-07-13 21:39       ` Dan Williams
  0 siblings, 0 replies; 36+ messages in thread
From: Dan Williams @ 2021-07-13 21:39 UTC (permalink / raw)
  To: Verma, Vishal L
  Cc: Widawsky, Ben, linux-cxl, nvdimm, Schofield, Alison, Weiny, Ira

On Tue, Jul 13, 2021 at 2:17 PM Verma, Vishal L
<vishal.l.verma@intel.com> wrote:
>
> On Mon, 2021-07-12 at 22:12 -0700, Dan Williams wrote:
> > On Thu, Jul 1, 2021 at 1:10 PM Vishal Verma <vishal.l.verma@intel.com> wrote:
> > >
> > > Add a set of APIs around 'cxl_cmd' for querying the kernel for supported
> > > commands, allocating and validating command structures against the
> > > supported set, and submitting the commands.
> > >
> > > 'Query Commands' and 'Send Command' are implemented as IOCTLs in the
> > > kernel. 'Query Commands' returns information about each supported
> > > command, such as flags governing its use, or input and output payload
> > > sizes. This information is used to validate command support, as well as
> > > set up input and output buffers for command submission.
> >
> > It strikes me after reading the above that it would be useful to have
> > a cxl list option that enumerates the command support on a given
> > memdev. Basically a "query-to-json" helper.
>
> Hm, yes that makes sense..  There may not always be a 1:1 correlation
> between the commands returned by query and the actual cxl-cli command
> corresponding with that - and for some commands, there may not even be
> a cxl-cli equivalent. Do we want to create a json representation of the
> raw query data, or cxl-cli equivalents?

I was thinking it would purely be a list and association of that to
whether there is a cxl-cli helper for it is left as an exercise for
the reader. Especially when there may be commands that are upgraded
versions of existing commands and cxl-cli handles that difference in
the background.

>
> > >
> > > Cc: Ben Widawsky <ben.widawsky@intel.com>
> > > Cc: Dan Williams <dan.j.williams@intel.com>
> > > Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
> > > ---
> > >  cxl/lib/private.h  |  33 ++++
> > >  cxl/lib/libcxl.c   | 388 +++++++++++++++++++++++++++++++++++++++++++++
> > >  cxl/libcxl.h       |  11 ++
> > >  cxl/lib/libcxl.sym |  13 ++
> > >  4 files changed, 445 insertions(+)
> > >
> > [..]
> > > +static int cxl_cmd_alloc_query(struct cxl_cmd *cmd, int num_cmds)
> > > +{
> > > +       size_t size;
> > > +
> > > +       if (!cmd)
> > > +               return -EINVAL;
> > > +
> > > +       if (cmd->query_cmd != NULL)
> > > +               free(cmd->query_cmd);
> > > +
> > > +       size = sizeof(struct cxl_mem_query_commands) +
> > > +                       (num_cmds * sizeof(struct cxl_command_info));
> >
> > This is asking for the kernel's include/linux/overflow.h to be
> > imported into ndctl so that struct_size() could be used here. The file
> > is MIT licensed, just the small matter of factoring out only the MIT
> > licensed bits.
>
> Ah ok let me take a look.

I would certainly limit to just copying struct_size() for now and not
try to pull the whole header. If it turns into a larger ordeal and not
a quick copy feel free to table it for later.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [ndctl PATCH v3 05/21] libcxl: add support for the 'Identify Device' command
  2021-07-01 20:09 ` [ndctl PATCH v3 05/21] libcxl: add support for the 'Identify Device' command Vishal Verma
@ 2021-07-15 23:50   ` Dan Williams
  0 siblings, 0 replies; 36+ messages in thread
From: Dan Williams @ 2021-07-15 23:50 UTC (permalink / raw)
  To: Vishal Verma
  Cc: Linux NVDIMM, linux-cxl, Ben Widawsky, Alison Schofield, Ira Weiny

On Thu, Jul 1, 2021 at 1:10 PM Vishal Verma <vishal.l.verma@intel.com> wrote:
>
> Add APIs to allocate and send an 'Identify Device' command, and
> accessors to retrieve some of the fields from the resulting data.
>
> Only add a handful accessor functions; more can be added as the need
> arises. The fields added are fw_revision, partition_align, and
> lsa_size.

Looks good,

Reviewed-by: Dan Williams <dan.j.williams@intel.com>

>
> Cc: Ben Widawsky <ben.widawsky@intel.com>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
> ---
>  cxl/lib/private.h  | 19 ++++++++++++++++++
>  cxl/lib/libcxl.c   | 49 ++++++++++++++++++++++++++++++++++++++++++++++
>  cxl/libcxl.h       |  4 ++++
>  cxl/lib/libcxl.sym |  4 ++++
>  4 files changed, 76 insertions(+)
>
> diff --git a/cxl/lib/private.h b/cxl/lib/private.h
> index 87ca17e..3273f21 100644
> --- a/cxl/lib/private.h
> +++ b/cxl/lib/private.h
> @@ -54,6 +54,25 @@ struct cxl_cmd {
>         int status;
>  };
>
> +#define CXL_CMD_IDENTIFY_FW_REV_LENGTH 0x10
> +
> +struct cxl_cmd_identify {
> +       char fw_revision[CXL_CMD_IDENTIFY_FW_REV_LENGTH];
> +       le64 total_capacity;
> +       le64 volatile_capacity;
> +       le64 persistent_capacity;
> +       le64 partition_align;
> +       le16 info_event_log_size;
> +       le16 warning_event_log_size;
> +       le16 failure_event_log_size;
> +       le16 fatal_event_log_size;
> +       le32 lsa_size;
> +       u8 poison_list_max_mer[3];
> +       le16 inject_poison_limit;
> +       u8 poison_caps;
> +       u8 qos_telemetry_caps;
> +} __attribute__((packed));
> +
>  static inline int check_kmod(struct kmod_ctx *kmod_ctx)
>  {
>         return kmod_ctx ? 0 : -ENXIO;
> diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
> index 3be4f3d..06a6c20 100644
> --- a/cxl/lib/libcxl.c
> +++ b/cxl/lib/libcxl.c
> @@ -13,7 +13,10 @@
>  #include <sys/sysmacros.h>
>  #include <uuid/uuid.h>
>  #include <ccan/list/list.h>
> +#include <ccan/endian/endian.h>
> +#include <ccan/minmax/minmax.h>
>  #include <ccan/array_size/array_size.h>
> +#include <ccan/short_types/short_types.h>
>
>  #include <util/log.h>
>  #include <util/sysfs.h>
> @@ -670,6 +673,52 @@ CXL_EXPORT const char *cxl_cmd_get_devname(struct cxl_cmd *cmd)
>         return cxl_memdev_get_devname(cmd->memdev);
>  }
>
> +CXL_EXPORT struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev)
> +{
> +       return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_IDENTIFY);
> +}
> +
> +CXL_EXPORT int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev,
> +               int fw_len)
> +{
> +       struct cxl_cmd_identify *id = (void *)cmd->send_cmd->out.payload;
> +
> +       if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_IDENTIFY)
> +               return -EINVAL;
> +       if (cmd->status < 0)
> +               return cmd->status;
> +
> +       if (fw_len > 0)
> +               memcpy(fw_rev, id->fw_revision,
> +                       min(fw_len, CXL_CMD_IDENTIFY_FW_REV_LENGTH));
> +       return 0;
> +}
> +
> +CXL_EXPORT unsigned long long cxl_cmd_identify_get_partition_align(
> +               struct cxl_cmd *cmd)
> +{
> +       struct cxl_cmd_identify *id = (void *)cmd->send_cmd->out.payload;
> +
> +       if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_IDENTIFY)
> +               return -EINVAL;
> +       if (cmd->status < 0)
> +               return cmd->status;
> +
> +       return le64_to_cpu(id->partition_align);
> +}
> +
> +CXL_EXPORT unsigned int cxl_cmd_identify_get_lsa_size(struct cxl_cmd *cmd)
> +{
> +       struct cxl_cmd_identify *id = (void *)cmd->send_cmd->out.payload;
> +
> +       if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_IDENTIFY)
> +               return -EINVAL;
> +       if (cmd->status < 0)
> +               return cmd->status;
> +
> +       return le32_to_cpu(id->lsa_size);
> +}
> +
>  CXL_EXPORT struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev,
>                 int opcode)
>  {
> diff --git a/cxl/libcxl.h b/cxl/libcxl.h
> index 6e87b80..9ed8c83 100644
> --- a/cxl/libcxl.h
> +++ b/cxl/libcxl.h
> @@ -58,6 +58,10 @@ void cxl_cmd_unref(struct cxl_cmd *cmd);
>  int cxl_cmd_submit(struct cxl_cmd *cmd);
>  int cxl_cmd_get_mbox_status(struct cxl_cmd *cmd);
>  int cxl_cmd_get_out_size(struct cxl_cmd *cmd);
> +struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev);
> +int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev, int fw_len);
> +unsigned long long cxl_cmd_identify_get_partition_align(struct cxl_cmd *cmd);
> +unsigned int cxl_cmd_identify_get_lsa_size(struct cxl_cmd *cmd);
>
>  #ifdef __cplusplus
>  } /* extern "C" */
> diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
> index 493429c..d6aa0b2 100644
> --- a/cxl/lib/libcxl.sym
> +++ b/cxl/lib/libcxl.sym
> @@ -39,4 +39,8 @@ global:
>         cxl_cmd_submit;
>         cxl_cmd_get_mbox_status;
>         cxl_cmd_get_out_size;
> +       cxl_cmd_new_identify;
> +       cxl_cmd_identify_get_fw_rev;
> +       cxl_cmd_identify_get_partition_align;
> +       cxl_cmd_identify_get_lsa_size;
>  } LIBCXL_2;
> --
> 2.31.1
>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [ndctl PATCH v3 06/21] test: rename 'ndctl_test' to 'test_ctx'
  2021-07-01 20:09 ` [ndctl PATCH v3 06/21] test: rename 'ndctl_test' to 'test_ctx' Vishal Verma
@ 2021-07-15 23:51   ` Dan Williams
  0 siblings, 0 replies; 36+ messages in thread
From: Dan Williams @ 2021-07-15 23:51 UTC (permalink / raw)
  To: Vishal Verma
  Cc: Linux NVDIMM, linux-cxl, Ben Widawsky, Alison Schofield, Ira Weiny

On Thu, Jul 1, 2021 at 1:10 PM Vishal Verma <vishal.l.verma@intel.com> wrote:
>
> In preparation for using the common test core for libcxl tests, rename
> the 'ndctl_test' structure to 'test_ctx'
>

Looks good,

Reviewed-by: Dan Williams <dan.j.williams@intel.com>


> Cc: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
> ---
>  test.h                        | 36 +++++++++++++++++------------------
>  ndctl/bat.c                   |  2 +-
>  ndctl/test.c                  |  2 +-
>  test/ack-shutdown-count-set.c |  8 ++++----
>  test/blk_namespaces.c         |  6 +++---
>  test/core.c                   | 20 +++++++++----------
>  test/dax-dev.c                |  4 ++--
>  test/dax-pmd.c                |  9 +++++----
>  test/dax-poison.c             |  4 ++--
>  test/daxdev-errors.c          |  2 +-
>  test/device-dax.c             | 10 +++++-----
>  test/dpa-alloc.c              |  6 +++---
>  test/dsm-fail.c               |  6 +++---
>  test/libndctl.c               | 34 ++++++++++++++++-----------------
>  test/multi-pmem.c             |  9 +++++----
>  test/parent-uuid.c            |  5 +++--
>  test/pmem_namespaces.c        |  6 +++---
>  test/revoke-devmem.c          |  6 +++---
>  18 files changed, 89 insertions(+), 86 deletions(-)
>
> diff --git a/test.h b/test.h
> index 7de13fe..c5b9d4a 100644
> --- a/test.h
> +++ b/test.h
> @@ -4,16 +4,16 @@
>  #define __TEST_H__
>  #include <stdbool.h>
>
> -struct ndctl_test;
> +struct test_ctx;
>  struct ndctl_ctx;
> -struct ndctl_test *ndctl_test_new(unsigned int kver);
> -int ndctl_test_result(struct ndctl_test *test, int rc);
> -int ndctl_test_get_skipped(struct ndctl_test *test);
> -int ndctl_test_get_attempted(struct ndctl_test *test);
> -int __ndctl_test_attempt(struct ndctl_test *test, unsigned int kver,
> +struct test_ctx *ndctl_test_new(unsigned int kver);
> +int ndctl_test_result(struct test_ctx *test, int rc);
> +int ndctl_test_get_skipped(struct test_ctx *test);
> +int ndctl_test_get_attempted(struct test_ctx *test);
> +int __ndctl_test_attempt(struct test_ctx *test, unsigned int kver,
>                 const char *caller, int line);
>  #define ndctl_test_attempt(t, v) __ndctl_test_attempt(t, v, __func__, __LINE__)
> -void __ndctl_test_skip(struct ndctl_test *test, const char *caller, int line);
> +void __ndctl_test_skip(struct test_ctx *test, const char *caller, int line);
>  #define ndctl_test_skip(t) __ndctl_test_skip(t, __func__, __LINE__)
>  struct ndctl_namespace *ndctl_get_test_dev(struct ndctl_ctx *ctx);
>  void builtin_xaction_namespace_reset(void);
> @@ -22,27 +22,27 @@ struct kmod_ctx;
>  struct kmod_module;
>  int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
>                 struct ndctl_ctx *nd_ctx, int log_level,
> -               struct ndctl_test *test);
> +               struct test_ctx *test);
>
>  struct ndctl_ctx;
> -int test_parent_uuid(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
> -int test_multi_pmem(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
> +int test_parent_uuid(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx);
> +int test_multi_pmem(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx);
>  int test_dax_directio(int dax_fd, unsigned long align, void *dax_addr, off_t offset);
> -int test_dax_remap(struct ndctl_test *test, int dax_fd, unsigned long align, void *dax_addr,
> +int test_dax_remap(struct test_ctx *test, int dax_fd, unsigned long align, void *dax_addr,
>                 off_t offset, bool fsdax);
>  #ifdef ENABLE_POISON
> -int test_dax_poison(struct ndctl_test *test, int dax_fd, unsigned long align,
> +int test_dax_poison(struct test_ctx *test, int dax_fd, unsigned long align,
>                 void *dax_addr, off_t offset, bool fsdax);
>  #else
> -static inline int test_dax_poison(struct ndctl_test *test, int dax_fd,
> +static inline int test_dax_poison(struct test_ctx *test, int dax_fd,
>                 unsigned long align, void *dax_addr, off_t offset, bool fsdax)
>  {
>         return 0;
>  }
>  #endif
> -int test_dpa_alloc(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
> -int test_dsm_fail(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
> -int test_libndctl(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
> -int test_blk_namespaces(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
> -int test_pmem_namespaces(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx);
> +int test_dpa_alloc(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx);
> +int test_dsm_fail(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx);
> +int test_libndctl(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx);
> +int test_blk_namespaces(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx);
> +int test_pmem_namespaces(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx);
>  #endif /* __TEST_H__ */
> diff --git a/ndctl/bat.c b/ndctl/bat.c
> index ef00a3b..18773fd 100644
> --- a/ndctl/bat.c
> +++ b/ndctl/bat.c
> @@ -9,7 +9,7 @@
>  int cmd_bat(int argc, const char **argv, struct ndctl_ctx *ctx)
>  {
>         int loglevel = LOG_DEBUG, i, rc;
> -       struct ndctl_test *test;
> +       struct test_ctx *test;
>         bool force = false;
>         const char * const u[] = {
>                 "ndctl bat [<options>]",
> diff --git a/ndctl/test.c b/ndctl/test.c
> index 6a05d8d..7af3681 100644
> --- a/ndctl/test.c
> +++ b/ndctl/test.c
> @@ -18,7 +18,7 @@ static char *result(int rc)
>
>  int cmd_test(int argc, const char **argv, struct ndctl_ctx *ctx)
>  {
> -       struct ndctl_test *test;
> +       struct test_ctx *test;
>         int loglevel = LOG_DEBUG, i, rc;
>         const char * const u[] = {
>                 "ndctl test [<options>]",
> diff --git a/test/ack-shutdown-count-set.c b/test/ack-shutdown-count-set.c
> index c561ff3..d5c7bcb 100644
> --- a/test/ack-shutdown-count-set.c
> +++ b/test/ack-shutdown-count-set.c
> @@ -54,7 +54,7 @@ static void reset_bus(struct ndctl_bus *bus)
>                 ndctl_dimm_zero_labels(dimm);
>  }
>
> -static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
> +static int do_test(struct ndctl_ctx *ctx, struct test_ctx *test)
>  {
>         struct ndctl_bus *bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0");
>         struct ndctl_dimm *dimm;
> @@ -91,8 +91,8 @@ out:
>         return rc;
>  }
>
> -static int test_ack_shutdown_count_set(int loglevel, struct ndctl_test *test,
> -               struct ndctl_ctx *ctx)
> +static int test_ack_shutdown_count_set(int loglevel, struct test_ctx *test,
> +                                      struct ndctl_ctx *ctx)
>  {
>         struct kmod_module *mod;
>         struct kmod_ctx *kmod_ctx;
> @@ -117,7 +117,7 @@ static int test_ack_shutdown_count_set(int loglevel, struct ndctl_test *test,
>
>  int main(int argc, char *argv[])
>  {
> -       struct ndctl_test *test = ndctl_test_new(0);
> +       struct test_ctx *test = ndctl_test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> diff --git a/test/blk_namespaces.c b/test/blk_namespaces.c
> index f076e85..4919890 100644
> --- a/test/blk_namespaces.c
> +++ b/test/blk_namespaces.c
> @@ -198,8 +198,8 @@ static int ns_do_io(const char *bdev)
>
>  static const char *comm = "test-blk-namespaces";
>
> -int test_blk_namespaces(int log_level, struct ndctl_test *test,
> -               struct ndctl_ctx *ctx)
> +int test_blk_namespaces(int log_level, struct test_ctx *test,
> +                       struct ndctl_ctx *ctx)
>  {
>         char bdev[50];
>         int rc = -ENXIO;
> @@ -337,7 +337,7 @@ int test_blk_namespaces(int log_level, struct ndctl_test *test,
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct ndctl_test *test = ndctl_test_new(0);
> +       struct test_ctx *test = ndctl_test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> diff --git a/test/core.c b/test/core.c
> index 2b03aa9..1ef0ac4 100644
> --- a/test/core.c
> +++ b/test/core.c
> @@ -16,7 +16,7 @@
>
>  #define KVER_STRLEN 20
>
> -struct ndctl_test {
> +struct test_ctx {
>         unsigned int kver;
>         int attempt;
>         int skip;
> @@ -39,9 +39,9 @@ static unsigned int get_system_kver(void)
>         return KERNEL_VERSION(a,b,c);
>  }
>
> -struct ndctl_test *ndctl_test_new(unsigned int kver)
> +struct test_ctx *ndctl_test_new(unsigned int kver)
>  {
> -       struct ndctl_test *test = calloc(1, sizeof(*test));
> +       struct test_ctx *test = calloc(1, sizeof(*test));
>
>         if (!test)
>                 return NULL;
> @@ -54,7 +54,7 @@ struct ndctl_test *ndctl_test_new(unsigned int kver)
>         return test;
>  }
>
> -int ndctl_test_result(struct ndctl_test *test, int rc)
> +int ndctl_test_result(struct test_ctx *test, int rc)
>  {
>         if (ndctl_test_get_skipped(test))
>                 fprintf(stderr, "attempted: %d skipped: %d\n",
> @@ -75,8 +75,8 @@ static char *kver_str(char *buf, unsigned int kver)
>         return buf;
>  }
>
> -int __ndctl_test_attempt(struct ndctl_test *test, unsigned int kver,
> -               const char *caller, int line)
> +int __ndctl_test_attempt(struct test_ctx *test, unsigned int kver,
> +                        const char *caller, int line)
>  {
>         char requires[KVER_STRLEN], current[KVER_STRLEN];
>
> @@ -90,26 +90,26 @@ int __ndctl_test_attempt(struct ndctl_test *test, unsigned int kver,
>         return 0;
>  }
>
> -void __ndctl_test_skip(struct ndctl_test *test, const char *caller, int line)
> +void __ndctl_test_skip(struct test_ctx *test, const char *caller, int line)
>  {
>         test->skip++;
>         test->attempt = test->skip;
>         fprintf(stderr, "%s: explicit skip %s:%d\n", __func__, caller, line);
>  }
>
> -int ndctl_test_get_attempted(struct ndctl_test *test)
> +int ndctl_test_get_attempted(struct test_ctx *test)
>  {
>         return test->attempt;
>  }
>
> -int ndctl_test_get_skipped(struct ndctl_test *test)
> +int ndctl_test_get_skipped(struct test_ctx *test)
>  {
>         return test->skip;
>  }
>
>  int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
>                 struct ndctl_ctx *nd_ctx, int log_level,
> -               struct ndctl_test *test)
> +               struct test_ctx *test)
>  {
>         int rc, family = -1;
>         unsigned int i;
> diff --git a/test/dax-dev.c b/test/dax-dev.c
> index 6a1b76d..99eda26 100644
> --- a/test/dax-dev.c
> +++ b/test/dax-dev.c
> @@ -87,7 +87,7 @@ struct ndctl_namespace *ndctl_get_test_dev(struct ndctl_ctx *ctx)
>         return rc ? NULL : ndns;
>  }
>
> -static int emit_e820_device(int loglevel, struct ndctl_test *test)
> +static int emit_e820_device(int loglevel, struct test_ctx *test)
>  {
>         int err;
>         struct ndctl_ctx *ctx;
> @@ -118,7 +118,7 @@ static int emit_e820_device(int loglevel, struct ndctl_test *test)
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct ndctl_test *test = ndctl_test_new(0);
> +       struct test_ctx *test = ndctl_test_new(0);
>         int rc;
>
>         if (!test) {
> diff --git a/test/dax-pmd.c b/test/dax-pmd.c
> index 7648e34..e9dedb9 100644
> --- a/test/dax-pmd.c
> +++ b/test/dax-pmd.c
> @@ -37,8 +37,9 @@ static void sigbus(int sig, siginfo_t *siginfo, void *d)
>         siglongjmp(sj_env, 1);
>  }
>
> -int test_dax_remap(struct ndctl_test *test, int dax_fd, unsigned long align, void *dax_addr,
> -               off_t offset, bool fsdax)
> +int test_dax_remap(struct test_ctx *test, int dax_fd, unsigned long align,
> +                  void *dax_addr,
> +                  off_t offset, bool fsdax)
>  {
>         void *anon, *remap, *addr;
>         struct sigaction act;
> @@ -272,7 +273,7 @@ int test_dax_directio(int dax_fd, unsigned long align, void *dax_addr, off_t off
>  }
>
>  /* test_pmd assumes that fd references a pre-allocated + dax-capable file */
> -static int test_pmd(struct ndctl_test *test, int fd)
> +static int test_pmd(struct test_ctx *test, int fd)
>  {
>         unsigned long long m_align, p_align, pmd_off;
>         static const bool fsdax = true;
> @@ -351,7 +352,7 @@ err_mmap:
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct ndctl_test *test = ndctl_test_new(0);
> +       struct test_ctx *test = ndctl_test_new(0);
>         int fd, rc;
>
>         if (!test) {
> diff --git a/test/dax-poison.c b/test/dax-poison.c
> index 4e09761..dc62742 100644
> --- a/test/dax-poison.c
> +++ b/test/dax-poison.c
> @@ -44,8 +44,8 @@ static void sigbus_hdl(int sig, siginfo_t *si, void *ptr)
>         siglongjmp(sj_env, 1);
>  }
>
> -int test_dax_poison(struct ndctl_test *test, int dax_fd, unsigned long align,
> -               void *dax_addr, off_t offset, bool fsdax)
> +int test_dax_poison(struct test_ctx *test, int dax_fd, unsigned long align,
> +                   void *dax_addr, off_t offset, bool fsdax)
>  {
>         unsigned char *addr = MAP_FAILED;
>         struct sigaction act;
> diff --git a/test/daxdev-errors.c b/test/daxdev-errors.c
> index fbbea21..4cb6b4d 100644
> --- a/test/daxdev-errors.c
> +++ b/test/daxdev-errors.c
> @@ -29,7 +29,7 @@
>
>  struct check_cmd {
>         struct ndctl_cmd *cmd;
> -       struct ndctl_test *test;
> +       struct test_ctx *test;
>  };
>
>  static sigjmp_buf sj_env;
> diff --git a/test/device-dax.c b/test/device-dax.c
> index aad8fa5..1837b4d 100644
> --- a/test/device-dax.c
> +++ b/test/device-dax.c
> @@ -90,7 +90,7 @@ static void sigbus(int sig, siginfo_t *siginfo, void *d)
>  #define VERIFY_TIME(x) (suseconds_t) ((ALIGN(x, SZ_2M) / SZ_4K) * 60)
>
>  static int verify_data(struct daxctl_dev *dev, char *dax_buf,
> -               unsigned long align, int salt, struct ndctl_test *test)
> +               unsigned long align, int salt, struct test_ctx *test)
>  {
>         struct timeval tv1, tv2, tv_diff;
>         unsigned long i;
> @@ -167,7 +167,7 @@ static int test_dax_soft_offline(struct ndctl_test *test, struct ndctl_namespace
>  }
>
>  static int __test_device_dax(unsigned long align, int loglevel,
> -               struct ndctl_test *test, struct ndctl_ctx *ctx)
> +               struct test_ctx *test, struct ndctl_ctx *ctx)
>  {
>         unsigned long i;
>         struct sigaction act;
> @@ -406,8 +406,8 @@ static int __test_device_dax(unsigned long align, int loglevel,
>         return rc;
>  }
>
> -static int test_device_dax(int loglevel, struct ndctl_test *test,
> -               struct ndctl_ctx *ctx)
> +static int test_device_dax(int loglevel, struct test_ctx *test,
> +                          struct ndctl_ctx *ctx)
>  {
>         unsigned long i, aligns[] = { SZ_4K, SZ_2M, SZ_1G };
>         int rc;
> @@ -423,7 +423,7 @@ static int test_device_dax(int loglevel, struct ndctl_test *test,
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct ndctl_test *test = ndctl_test_new(0);
> +       struct test_ctx *test = ndctl_test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> diff --git a/test/dpa-alloc.c b/test/dpa-alloc.c
> index 59185cf..d0f5271 100644
> --- a/test/dpa-alloc.c
> +++ b/test/dpa-alloc.c
> @@ -32,7 +32,7 @@ struct test_dpa_namespace {
>
>  #define MIN_SIZE SZ_4M
>
> -static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
> +static int do_test(struct ndctl_ctx *ctx, struct test_ctx *test)
>  {
>         unsigned int default_available_slots, available_slots, i;
>         struct ndctl_region *region, *blk_region = NULL;
> @@ -280,7 +280,7 @@ static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
>         return 0;
>  }
>
> -int test_dpa_alloc(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
> +int test_dpa_alloc(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
>  {
>         struct kmod_module *mod;
>         struct kmod_ctx *kmod_ctx;
> @@ -307,7 +307,7 @@ int test_dpa_alloc(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct ndctl_test *test = ndctl_test_new(0);
> +       struct test_ctx *test = ndctl_test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> diff --git a/test/dsm-fail.c b/test/dsm-fail.c
> index 0a6383d..74c56de 100644
> --- a/test/dsm-fail.c
> +++ b/test/dsm-fail.c
> @@ -174,7 +174,7 @@ static int test_regions_enable(struct ndctl_bus *bus,
>         return 0;
>  }
>
> -static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
> +static int do_test(struct ndctl_ctx *ctx, struct test_ctx *test)
>  {
>         struct ndctl_bus *bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0");
>         struct ndctl_region *region, *victim_region = NULL;
> @@ -339,7 +339,7 @@ static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test)
>         return err;
>  }
>
> -int test_dsm_fail(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
> +int test_dsm_fail(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
>  {
>         struct kmod_module *mod;
>         struct kmod_ctx *kmod_ctx;
> @@ -364,7 +364,7 @@ int test_dsm_fail(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct ndctl_test *test = ndctl_test_new(0);
> +       struct test_ctx *test = ndctl_test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> diff --git a/test/libndctl.c b/test/libndctl.c
> index d9b50f4..30d19db 100644
> --- a/test/libndctl.c
> +++ b/test/libndctl.c
> @@ -613,7 +613,7 @@ static int validate_dax(struct ndctl_dax *dax)
>         const char *devname = ndctl_namespace_get_devname(ndns);
>         struct ndctl_region *region = ndctl_dax_get_region(dax);
>         struct ndctl_ctx *ctx = ndctl_dax_get_ctx(dax);
> -       struct ndctl_test *test = ndctl_get_private_data(ctx);
> +       struct test_ctx *test = ndctl_get_private_data(ctx);
>         struct daxctl_region *dax_region = NULL, *found;
>         int rc = -ENXIO, fd, count, dax_expect;
>         struct daxctl_dev *dax_dev, *seed;
> @@ -725,7 +725,7 @@ static int __check_dax_create(struct ndctl_region *region,
>  {
>         struct ndctl_dax *dax_seed = ndctl_region_get_dax_seed(region);
>         struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
> -       struct ndctl_test *test = ndctl_get_private_data(ctx);
> +       struct test_ctx *test = ndctl_get_private_data(ctx);
>         enum ndctl_namespace_mode mode;
>         struct ndctl_dax *dax;
>         const char *devname;
> @@ -835,7 +835,7 @@ static int __check_pfn_create(struct ndctl_region *region,
>  {
>         struct ndctl_pfn *pfn_seed = ndctl_region_get_pfn_seed(region);
>         struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
> -       struct ndctl_test *test = ndctl_get_private_data(ctx);
> +       struct test_ctx *test = ndctl_get_private_data(ctx);
>         enum ndctl_namespace_mode mode;
>         struct ndctl_pfn *pfn;
>         const char *devname;
> @@ -978,7 +978,7 @@ static int check_btt_size(struct ndctl_btt *btt)
>         unsigned long long actual, expect;
>         int size_select, sect_select;
>         struct ndctl_ctx *ctx = ndctl_btt_get_ctx(btt);
> -       struct ndctl_test *test = ndctl_get_private_data(ctx);
> +       struct test_ctx *test = ndctl_get_private_data(ctx);
>         struct ndctl_namespace *ndns = ndctl_btt_get_namespace(btt);
>         unsigned long long expect_table[][2] = {
>                 [0] = {
> @@ -1049,7 +1049,7 @@ static int check_btt_create(struct ndctl_region *region, struct ndctl_namespace
>                 struct namespace *namespace)
>  {
>         struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
> -       struct ndctl_test *test = ndctl_get_private_data(ctx);
> +       struct test_ctx *test = ndctl_get_private_data(ctx);
>         struct btt *btt_s = namespace->btt_settings;
>         int i, fd, retry = 10;
>         struct ndctl_btt *btt;
> @@ -1257,7 +1257,7 @@ static int check_pfn_autodetect(struct ndctl_bus *bus,
>         struct ndctl_region *region = ndctl_namespace_get_region(ndns);
>         struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
>         const char *devname = ndctl_namespace_get_devname(ndns);
> -       struct ndctl_test *test = ndctl_get_private_data(ctx);
> +       struct test_ctx *test = ndctl_get_private_data(ctx);
>         struct pfn *auto_pfn = namespace->pfn_settings;
>         struct ndctl_pfn *pfn, *found = NULL;
>         enum ndctl_namespace_mode mode;
> @@ -1354,7 +1354,7 @@ static int check_dax_autodetect(struct ndctl_bus *bus,
>         struct ndctl_region *region = ndctl_namespace_get_region(ndns);
>         struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
>         const char *devname = ndctl_namespace_get_devname(ndns);
> -       struct ndctl_test *test = ndctl_get_private_data(ctx);
> +       struct test_ctx *test = ndctl_get_private_data(ctx);
>         struct dax *auto_dax = namespace->dax_settings;
>         struct ndctl_dax *dax, *found = NULL;
>         enum ndctl_namespace_mode mode;
> @@ -1439,7 +1439,7 @@ static int check_btt_autodetect(struct ndctl_bus *bus,
>         struct ndctl_region *region = ndctl_namespace_get_region(ndns);
>         struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
>         const char *devname = ndctl_namespace_get_devname(ndns);
> -       struct ndctl_test *test = ndctl_get_private_data(ctx);
> +       struct test_ctx *test = ndctl_get_private_data(ctx);
>         struct btt *auto_btt = namespace->btt_settings;
>         struct ndctl_btt *btt, *found = NULL;
>         enum ndctl_namespace_mode mode;
> @@ -1681,7 +1681,7 @@ static int check_namespaces(struct ndctl_region *region,
>                 struct namespace **namespaces, enum ns_mode mode)
>  {
>         struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
> -       struct ndctl_test *test = ndctl_get_private_data(ctx);
> +       struct test_ctx *test = ndctl_get_private_data(ctx);
>         struct ndctl_bus *bus = ndctl_region_get_bus(region);
>         struct ndctl_namespace **ndns_save;
>         struct namespace *namespace;
> @@ -2044,7 +2044,7 @@ static int check_btts(struct ndctl_region *region, struct btt **btts)
>  struct check_cmd {
>         int (*check_fn)(struct ndctl_bus *bus, struct ndctl_dimm *dimm, struct check_cmd *check);
>         struct ndctl_cmd *cmd;
> -       struct ndctl_test *test;
> +       struct test_ctx *test;
>  };
>
>  static struct check_cmd *check_cmds;
> @@ -2412,7 +2412,7 @@ static int check_smart_threshold(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
>  #define BITS_PER_LONG 32
>  static int check_commands(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
>                 unsigned long bus_commands, unsigned long dimm_commands,
> -               struct ndctl_test *test)
> +               struct test_ctx *test)
>  {
>         /*
>          * For now, by coincidence, these are indexed in test execution
> @@ -2483,7 +2483,7 @@ static int check_commands(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
>
>  static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,
>                 unsigned long bus_commands, unsigned long dimm_commands,
> -               struct ndctl_test *test)
> +               struct test_ctx *test)
>  {
>         long long dsc;
>         int i, j, rc;
> @@ -2604,7 +2604,7 @@ static void reset_bus(struct ndctl_bus *bus)
>                 ndctl_region_enable(region);
>  }
>
> -static int do_test0(struct ndctl_ctx *ctx, struct ndctl_test *test)
> +static int do_test0(struct ndctl_ctx *ctx, struct test_ctx *test)
>  {
>         struct ndctl_bus *bus = ndctl_bus_get_by_provider(ctx, NFIT_PROVIDER0);
>         struct ndctl_region *region;
> @@ -2662,7 +2662,7 @@ static int do_test0(struct ndctl_ctx *ctx, struct ndctl_test *test)
>         return check_regions(bus, regions0, ARRAY_SIZE(regions0), BTT);
>  }
>
> -static int do_test1(struct ndctl_ctx *ctx, struct ndctl_test *test)
> +static int do_test1(struct ndctl_ctx *ctx, struct test_ctx *test)
>  {
>         struct ndctl_bus *bus = ndctl_bus_get_by_provider(ctx, NFIT_PROVIDER1);
>         int rc;
> @@ -2686,13 +2686,13 @@ static int do_test1(struct ndctl_ctx *ctx, struct ndctl_test *test)
>         return check_regions(bus, regions1, ARRAY_SIZE(regions1), BTT);
>  }
>
> -typedef int (*do_test_fn)(struct ndctl_ctx *ctx, struct ndctl_test *test);
> +typedef int (*do_test_fn)(struct ndctl_ctx *ctx, struct test_ctx *test);
>  static do_test_fn do_test[] = {
>         do_test0,
>         do_test1,
>  };
>
> -int test_libndctl(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
> +int test_libndctl(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
>  {
>         unsigned int i;
>         struct kmod_module *mod;
> @@ -2732,7 +2732,7 @@ int test_libndctl(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct ndctl_test *test = ndctl_test_new(0);
> +       struct test_ctx *test = ndctl_test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> diff --git a/test/multi-pmem.c b/test/multi-pmem.c
> index 3ea08cc..e2f3bc5 100644
> --- a/test/multi-pmem.c
> +++ b/test/multi-pmem.c
> @@ -53,7 +53,7 @@ static void destroy_namespace(struct ndctl_namespace *ndns)
>
>  /* Check that the namespace device is gone (if it wasn't the seed) */
>  static int check_deleted(struct ndctl_region *region, const char *devname,
> -               struct ndctl_test *test)
> +               struct test_ctx *test)
>  {
>         struct ndctl_namespace *ndns;
>
> @@ -73,7 +73,7 @@ static int check_deleted(struct ndctl_region *region, const char *devname,
>         return 0;
>  }
>
> -static int do_multi_pmem(struct ndctl_ctx *ctx, struct ndctl_test *test)
> +static int do_multi_pmem(struct ndctl_ctx *ctx, struct test_ctx *test)
>  {
>         int i;
>         char devname[100];
> @@ -238,7 +238,8 @@ static int do_multi_pmem(struct ndctl_ctx *ctx, struct ndctl_test *test)
>         return 0;
>  }
>
> -int test_multi_pmem(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
> +int test_multi_pmem(int loglevel, struct test_ctx *test,
> +                   struct ndctl_ctx *ctx)
>  {
>         struct kmod_module *mod;
>         struct kmod_ctx *kmod_ctx;
> @@ -267,7 +268,7 @@ int test_multi_pmem(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct ndctl_test *test = ndctl_test_new(0);
> +       struct test_ctx *test = ndctl_test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> diff --git a/test/parent-uuid.c b/test/parent-uuid.c
> index bded33a..dd007c7 100644
> --- a/test/parent-uuid.c
> +++ b/test/parent-uuid.c
> @@ -208,7 +208,8 @@ static int do_test(struct ndctl_ctx *ctx)
>         return 0;
>  }
>
> -int test_parent_uuid(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx)
> +int test_parent_uuid(int loglevel, struct test_ctx *test,
> +                    struct ndctl_ctx *ctx)
>  {
>         struct kmod_module *mod;
>         struct kmod_ctx *kmod_ctx;
> @@ -235,7 +236,7 @@ int test_parent_uuid(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ct
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct ndctl_test *test = ndctl_test_new(0);
> +       struct test_ctx *test = ndctl_test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> diff --git a/test/pmem_namespaces.c b/test/pmem_namespaces.c
> index a4db1ae..eddf32a 100644
> --- a/test/pmem_namespaces.c
> +++ b/test/pmem_namespaces.c
> @@ -161,8 +161,8 @@ static int ns_do_io(const char *bdev)
>
>  static const char *comm = "test-pmem-namespaces";
>
> -int test_pmem_namespaces(int log_level, struct ndctl_test *test,
> -               struct ndctl_ctx *ctx)
> +int test_pmem_namespaces(int log_level, struct test_ctx *test,
> +                        struct ndctl_ctx *ctx)
>  {
>         struct ndctl_region *region, *pmem_region = NULL;
>         struct kmod_ctx *kmod_ctx = NULL;
> @@ -262,7 +262,7 @@ int test_pmem_namespaces(int log_level, struct ndctl_test *test,
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct ndctl_test *test = ndctl_test_new(0);
> +       struct test_ctx *test = ndctl_test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> diff --git a/test/revoke-devmem.c b/test/revoke-devmem.c
> index bb8979e..0d67d93 100644
> --- a/test/revoke-devmem.c
> +++ b/test/revoke-devmem.c
> @@ -32,8 +32,8 @@ static void sigbus(int sig, siginfo_t *siginfo, void *d)
>  #define err(fmt, ...) \
>         fprintf(stderr, "%s: " fmt, __func__, ##__VA_ARGS__)
>
> -static int test_devmem(int loglevel, struct ndctl_test *test,
> -               struct ndctl_ctx *ctx)
> +static int test_devmem(int loglevel, struct test_ctx *test,
> +                      struct ndctl_ctx *ctx)
>  {
>         void *buf;
>         int fd, rc;
> @@ -124,7 +124,7 @@ out_devmem:
>
>  int main(int argc, char *argv[])
>  {
> -       struct ndctl_test *test = ndctl_test_new(0);
> +       struct test_ctx *test = ndctl_test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> --
> 2.31.1
>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [ndctl PATCH v3 07/21] test: rename 'ndctl_test_*' helpers to 'test_*'
  2021-07-01 20:09 ` [ndctl PATCH v3 07/21] test: rename 'ndctl_test_*' helpers to 'test_*' Vishal Verma
@ 2021-07-15 23:51   ` Dan Williams
  0 siblings, 0 replies; 36+ messages in thread
From: Dan Williams @ 2021-07-15 23:51 UTC (permalink / raw)
  To: Vishal Verma
  Cc: Linux NVDIMM, linux-cxl, Ben Widawsky, Alison Schofield, Ira Weiny

On Thu, Jul 1, 2021 at 1:10 PM Vishal Verma <vishal.l.verma@intel.com> wrote:
>
> In preparation for using the test harness for libcxl, rename
> ndctl_test_* helpers to make them more generic.

Looks good,

Reviewed-by: Dan Williams <dan.j.williams@intel.com>

>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
> ---
>  test.h                        | 16 +++++------
>  ndctl/bat.c                   |  6 ++--
>  ndctl/test.c                  |  6 ++--
>  test/ack-shutdown-count-set.c | 10 +++----
>  test/blk_namespaces.c         | 10 +++----
>  test/core.c                   | 24 ++++++++--------
>  test/dax-dev.c                |  8 +++---
>  test/dax-pmd.c                |  6 ++--
>  test/dax-poison.c             |  2 +-
>  test/device-dax.c             | 18 ++++++------
>  test/dpa-alloc.c              | 10 +++----
>  test/dsm-fail.c               | 10 +++----
>  test/libndctl.c               | 52 +++++++++++++++++------------------
>  test/multi-pmem.c             | 16 +++++------
>  test/parent-uuid.c            | 10 +++----
>  test/pmem_namespaces.c        | 10 +++----
>  test/revoke-devmem.c          |  8 +++---
>  README.md                     |  2 +-
>  18 files changed, 112 insertions(+), 112 deletions(-)
>
> diff --git a/test.h b/test.h
> index c5b9d4a..a25f6c9 100644
> --- a/test.h
> +++ b/test.h
> @@ -6,15 +6,15 @@
>
>  struct test_ctx;
>  struct ndctl_ctx;
> -struct test_ctx *ndctl_test_new(unsigned int kver);
> -int ndctl_test_result(struct test_ctx *test, int rc);
> -int ndctl_test_get_skipped(struct test_ctx *test);
> -int ndctl_test_get_attempted(struct test_ctx *test);
> -int __ndctl_test_attempt(struct test_ctx *test, unsigned int kver,
> +struct test_ctx *test_new(unsigned int kver);
> +int test_result(struct test_ctx *test, int rc);
> +int test_get_skipped(struct test_ctx *test);
> +int test_get_attempted(struct test_ctx *test);
> +int __test_attempt(struct test_ctx *test, unsigned int kver,
>                 const char *caller, int line);
> -#define ndctl_test_attempt(t, v) __ndctl_test_attempt(t, v, __func__, __LINE__)
> -void __ndctl_test_skip(struct test_ctx *test, const char *caller, int line);
> -#define ndctl_test_skip(t) __ndctl_test_skip(t, __func__, __LINE__)
> +#define test_attempt(t, v) __test_attempt(t, v, __func__, __LINE__)
> +void __test_skip(struct test_ctx *test, const char *caller, int line);
> +#define test_skip(t) __test_skip(t, __func__, __LINE__)
>  struct ndctl_namespace *ndctl_get_test_dev(struct ndctl_ctx *ctx);
>  void builtin_xaction_namespace_reset(void);
>
> diff --git a/ndctl/bat.c b/ndctl/bat.c
> index 18773fd..a3452fa 100644
> --- a/ndctl/bat.c
> +++ b/ndctl/bat.c
> @@ -32,9 +32,9 @@ int cmd_bat(int argc, const char **argv, struct ndctl_ctx *ctx)
>                 usage_with_options(u, options);
>
>         if (force)
> -               test = ndctl_test_new(UINT_MAX);
> +               test = test_new(UINT_MAX);
>         else
> -               test = ndctl_test_new(0);
> +               test = test_new(0);
>
>         if (!test) {
>                 fprintf(stderr, "failed to initialize test\n");
> @@ -48,5 +48,5 @@ int cmd_bat(int argc, const char **argv, struct ndctl_ctx *ctx)
>
>         rc = test_pmem_namespaces(loglevel, test, ctx);
>         fprintf(stderr, "test_pmem_namespaces: %s\n", rc ? "FAIL" : "PASS");
> -       return ndctl_test_result(test, rc);
> +       return test_result(test, rc);
>  }
> diff --git a/ndctl/test.c b/ndctl/test.c
> index 7af3681..92713df 100644
> --- a/ndctl/test.c
> +++ b/ndctl/test.c
> @@ -42,9 +42,9 @@ int cmd_test(int argc, const char **argv, struct ndctl_ctx *ctx)
>                 usage_with_options(u, options);
>
>         if (force)
> -               test = ndctl_test_new(UINT_MAX);
> +               test = test_new(UINT_MAX);
>         else
> -               test = ndctl_test_new(0);
> +               test = test_new(0);
>         if (!test)
>                 return EXIT_FAILURE;
>
> @@ -69,5 +69,5 @@ int cmd_test(int argc, const char **argv, struct ndctl_ctx *ctx)
>         rc = test_multi_pmem(loglevel, test, ctx);
>         fprintf(stderr, "test-multi-pmem: %s\n", result(rc));
>
> -       return ndctl_test_result(test, rc);
> +       return test_result(test, rc);
>  }
> diff --git a/test/ack-shutdown-count-set.c b/test/ack-shutdown-count-set.c
> index d5c7bcb..92690f4 100644
> --- a/test/ack-shutdown-count-set.c
> +++ b/test/ack-shutdown-count-set.c
> @@ -62,7 +62,7 @@ static int do_test(struct ndctl_ctx *ctx, struct test_ctx *test)
>         struct log_ctx log_ctx;
>         int rc = 0;
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 15, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 15, 0)))
>                 return 77;
>
>         if (!bus)
> @@ -102,7 +102,7 @@ static int test_ack_shutdown_count_set(int loglevel, struct test_ctx *test,
>         err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
>         if (err < 0) {
>                 result = 77;
> -               ndctl_test_skip(test);
> +               test_skip(test);
>                 fprintf(stderr, "%s unavailable skipping tests\n",
>                                 "nfit_test");
>                 return result;
> @@ -117,7 +117,7 @@ static int test_ack_shutdown_count_set(int loglevel, struct test_ctx *test,
>
>  int main(int argc, char *argv[])
>  {
> -       struct test_ctx *test = ndctl_test_new(0);
> +       struct test_ctx *test = test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> @@ -128,9 +128,9 @@ int main(int argc, char *argv[])
>
>         rc = ndctl_new(&ctx);
>         if (rc)
> -               return ndctl_test_result(test, rc);
> +               return test_result(test, rc);
>         rc = test_ack_shutdown_count_set(LOG_DEBUG, test, ctx);
>         ndctl_unref(ctx);
>
> -       return ndctl_test_result(test, rc);
> +       return test_result(test, rc);
>  }
> diff --git a/test/blk_namespaces.c b/test/blk_namespaces.c
> index 4919890..04eb600 100644
> --- a/test/blk_namespaces.c
> +++ b/test/blk_namespaces.c
> @@ -210,7 +210,7 @@ int test_blk_namespaces(int log_level, struct test_ctx *test,
>         struct ndctl_namespace *ndns[2];
>         struct ndctl_region *region, *blk_region = NULL;
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 2, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 2, 0)))
>                 return 77;
>
>         ndctl_set_log_priority(ctx, log_level);
> @@ -232,7 +232,7 @@ int test_blk_namespaces(int log_level, struct test_ctx *test,
>                 ndctl_invalidate(ctx);
>                 bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0");
>                 if (rc < 0 || !bus) {
> -                       ndctl_test_skip(test);
> +                       test_skip(test);
>                         fprintf(stderr, "nfit_test unavailable skipping tests\n");
>                         return 77;
>                 }
> @@ -337,7 +337,7 @@ int test_blk_namespaces(int log_level, struct test_ctx *test,
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct test_ctx *test = ndctl_test_new(0);
> +       struct test_ctx *test = test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> @@ -349,9 +349,9 @@ int __attribute__((weak)) main(int argc, char *argv[])
>
>         rc = ndctl_new(&ctx);
>         if (rc)
> -               return ndctl_test_result(test, rc);
> +               return test_result(test, rc);
>
>         rc = test_blk_namespaces(LOG_DEBUG, test, ctx);
>         ndctl_unref(ctx);
> -       return ndctl_test_result(test, rc);
> +       return test_result(test, rc);
>  }
> diff --git a/test/core.c b/test/core.c
> index 1ef0ac4..d143e89 100644
> --- a/test/core.c
> +++ b/test/core.c
> @@ -39,7 +39,7 @@ static unsigned int get_system_kver(void)
>         return KERNEL_VERSION(a,b,c);
>  }
>
> -struct test_ctx *ndctl_test_new(unsigned int kver)
> +struct test_ctx *test_new(unsigned int kver)
>  {
>         struct test_ctx *test = calloc(1, sizeof(*test));
>
> @@ -54,15 +54,15 @@ struct test_ctx *ndctl_test_new(unsigned int kver)
>         return test;
>  }
>
> -int ndctl_test_result(struct test_ctx *test, int rc)
> +int test_result(struct test_ctx *test, int rc)
>  {
> -       if (ndctl_test_get_skipped(test))
> +       if (test_get_skipped(test))
>                 fprintf(stderr, "attempted: %d skipped: %d\n",
> -                               ndctl_test_get_attempted(test),
> -                               ndctl_test_get_skipped(test));
> +                               test_get_attempted(test),
> +                               test_get_skipped(test));
>         if (rc && rc != 77)
>                 return rc;
> -       if (ndctl_test_get_skipped(test) >= ndctl_test_get_attempted(test))
> +       if (test_get_skipped(test) >= test_get_attempted(test))
>                 return 77;
>         /* return success if no failures and at least one test not skipped */
>         return 0;
> @@ -75,7 +75,7 @@ static char *kver_str(char *buf, unsigned int kver)
>         return buf;
>  }
>
> -int __ndctl_test_attempt(struct test_ctx *test, unsigned int kver,
> +int __test_attempt(struct test_ctx *test, unsigned int kver,
>                          const char *caller, int line)
>  {
>         char requires[KVER_STRLEN], current[KVER_STRLEN];
> @@ -90,19 +90,19 @@ int __ndctl_test_attempt(struct test_ctx *test, unsigned int kver,
>         return 0;
>  }
>
> -void __ndctl_test_skip(struct test_ctx *test, const char *caller, int line)
> +void __test_skip(struct test_ctx *test, const char *caller, int line)
>  {
>         test->skip++;
>         test->attempt = test->skip;
>         fprintf(stderr, "%s: explicit skip %s:%d\n", __func__, caller, line);
>  }
>
> -int ndctl_test_get_attempted(struct test_ctx *test)
> +int test_get_attempted(struct test_ctx *test)
>  {
>         return test->attempt;
>  }
>
> -int ndctl_test_get_skipped(struct test_ctx *test)
> +int test_get_skipped(struct test_ctx *test)
>  {
>         return test->skip;
>  }
> @@ -174,7 +174,7 @@ int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
>                  * than 4.7.
>                  */
>                 if (strcmp(name, "dax") == 0
> -                               && !ndctl_test_attempt(test,
> +                               && !test_attempt(test,
>                                         KERNEL_VERSION(4, 7, 0)))
>                         continue;
>
> @@ -183,7 +183,7 @@ int ndctl_test_init(struct kmod_ctx **ctx, struct kmod_module **mod,
>                  */
>                 if ((strcmp(name, "dax_pmem_core") == 0
>                                 || strcmp(name, "dax_pmem_compat") == 0)
> -                               && !ndctl_test_attempt(test,
> +                               && !test_attempt(test,
>                                         KERNEL_VERSION(5, 1, 0)))
>                         continue;
>
> diff --git a/test/dax-dev.c b/test/dax-dev.c
> index 99eda26..d61104f 100644
> --- a/test/dax-dev.c
> +++ b/test/dax-dev.c
> @@ -93,7 +93,7 @@ static int emit_e820_device(int loglevel, struct test_ctx *test)
>         struct ndctl_ctx *ctx;
>         struct ndctl_namespace *ndns;
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 3, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 3, 0)))
>                 return 77;
>
>         err = ndctl_new(&ctx);
> @@ -106,7 +106,7 @@ static int emit_e820_device(int loglevel, struct test_ctx *test)
>         if (!ndns) {
>                 fprintf(stderr, "%s: failed to find usable victim device\n",
>                                 __func__);
> -               ndctl_test_skip(test);
> +               test_skip(test);
>                 err = 77;
>         } else {
>                 fprintf(stdout, "%s\n", ndctl_namespace_get_devname(ndns));
> @@ -118,7 +118,7 @@ static int emit_e820_device(int loglevel, struct test_ctx *test)
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct test_ctx *test = ndctl_test_new(0);
> +       struct test_ctx *test = test_new(0);
>         int rc;
>
>         if (!test) {
> @@ -127,5 +127,5 @@ int __attribute__((weak)) main(int argc, char *argv[])
>         }
>
>         rc = emit_e820_device(LOG_DEBUG, test);
> -       return ndctl_test_result(test, rc);
> +       return test_result(test, rc);
>  }
> diff --git a/test/dax-pmd.c b/test/dax-pmd.c
> index e9dedb9..190a0fd 100644
> --- a/test/dax-pmd.c
> +++ b/test/dax-pmd.c
> @@ -45,7 +45,7 @@ int test_dax_remap(struct test_ctx *test, int dax_fd, unsigned long align,
>         struct sigaction act;
>         int rc, val;
>
> -       if ((fsdax || align == SZ_2M) && !ndctl_test_attempt(test, KERNEL_VERSION(5, 8, 0))) {
> +       if ((fsdax || align == SZ_2M) && !test_attempt(test, KERNEL_VERSION(5, 8, 0))) {
>                 /* kernel's prior to 5.8 may crash on this test */
>                 fprintf(stderr, "%s: SKIP mremap() test\n", __func__);
>                 return 0;
> @@ -352,7 +352,7 @@ err_mmap:
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct test_ctx *test = ndctl_test_new(0);
> +       struct test_ctx *test = test_new(0);
>         int fd, rc;
>
>         if (!test) {
> @@ -367,5 +367,5 @@ int __attribute__((weak)) main(int argc, char *argv[])
>         rc = test_pmd(test, fd);
>         if (fd >= 0)
>                 close(fd);
> -       return ndctl_test_result(test, rc);
> +       return test_result(test, rc);
>  }
> diff --git a/test/dax-poison.c b/test/dax-poison.c
> index dc62742..e50ff8f 100644
> --- a/test/dax-poison.c
> +++ b/test/dax-poison.c
> @@ -54,7 +54,7 @@ int test_dax_poison(struct test_ctx *test, int dax_fd, unsigned long align,
>         void *buf;
>         int rc;
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 19, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 19, 0)))
>                 return 77;
>
>         /*
> diff --git a/test/device-dax.c b/test/device-dax.c
> index 1837b4d..80f0ef7 100644
> --- a/test/device-dax.c
> +++ b/test/device-dax.c
> @@ -95,7 +95,7 @@ static int verify_data(struct daxctl_dev *dev, char *dax_buf,
>         struct timeval tv1, tv2, tv_diff;
>         unsigned long i;
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 9, 0)))
>                 return 0;
>
>         /* verify data and cache mode */
> @@ -128,7 +128,7 @@ static int verify_data(struct daxctl_dev *dev, char *dax_buf,
>         return 0;
>  }
>
> -static int test_dax_soft_offline(struct ndctl_test *test, struct ndctl_namespace *ndns)
> +static int test_dax_soft_offline(struct test_ctx *test, struct ndctl_namespace *ndns)
>  {
>         unsigned long long resource = ndctl_namespace_get_resource(ndns);
>         int fd, rc;
> @@ -188,10 +188,10 @@ static int __test_device_dax(unsigned long align, int loglevel,
>                 return 77;
>         }
>
> -       if (align > SZ_2M && !ndctl_test_attempt(test, KERNEL_VERSION(4, 11, 0)))
> +       if (align > SZ_2M && !test_attempt(test, KERNEL_VERSION(4, 11, 0)))
>                 return 77;
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 7, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 7, 0)))
>                 return 77;
>
>         /* setup up fsdax mode pmem device and seed with verification data */
> @@ -279,7 +279,7 @@ static int __test_device_dax(unsigned long align, int loglevel,
>          * Prior to 4.8-final these tests cause crashes, or are
>          * otherwise not supported.
>          */
> -       if (ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0))) {
> +       if (test_attempt(test, KERNEL_VERSION(4, 9, 0))) {
>                 static const bool devdax = false;
>                 int fd2;
>
> @@ -394,7 +394,7 @@ static int __test_device_dax(unsigned long align, int loglevel,
>         rc = EXIT_SUCCESS;
>         p = (int *) (buf + align);
>         *p = 0xff;
> -       if (ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0))) {
> +       if (test_attempt(test, KERNEL_VERSION(4, 9, 0))) {
>                 /* after 4.9 this test will properly get sigbus above */
>                 rc = EXIT_FAILURE;
>                 fprintf(stderr, "%s: failed to unmap after reset\n",
> @@ -423,7 +423,7 @@ static int test_device_dax(int loglevel, struct test_ctx *test,
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct test_ctx *test = ndctl_test_new(0);
> +       struct test_ctx *test = test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> @@ -434,9 +434,9 @@ int __attribute__((weak)) main(int argc, char *argv[])
>
>         rc = ndctl_new(&ctx);
>         if (rc < 0)
> -               return ndctl_test_result(test, rc);
> +               return test_result(test, rc);
>
>         rc = test_device_dax(LOG_DEBUG, test, ctx);
>         ndctl_unref(ctx);
> -       return ndctl_test_result(test, rc);
> +       return test_result(test, rc);
>  }
> diff --git a/test/dpa-alloc.c b/test/dpa-alloc.c
> index d0f5271..e530ed4 100644
> --- a/test/dpa-alloc.c
> +++ b/test/dpa-alloc.c
> @@ -286,13 +286,13 @@ int test_dpa_alloc(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
>         struct kmod_ctx *kmod_ctx;
>         int err, result = EXIT_FAILURE;
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 2, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 2, 0)))
>                 return 77;
>
>         ndctl_set_log_priority(ctx, loglevel);
>         err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
>         if (err < 0) {
> -               ndctl_test_skip(test);
> +               test_skip(test);
>                 fprintf(stderr, "nfit_test unavailable skipping tests\n");
>                 return 77;
>         }
> @@ -307,7 +307,7 @@ int test_dpa_alloc(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct test_ctx *test = ndctl_test_new(0);
> +       struct test_ctx *test = test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> @@ -318,9 +318,9 @@ int __attribute__((weak)) main(int argc, char *argv[])
>
>         rc = ndctl_new(&ctx);
>         if (rc)
> -               return ndctl_test_result(test, rc);
> +               return test_result(test, rc);
>
>         rc = test_dpa_alloc(LOG_DEBUG, test, ctx);
>         ndctl_unref(ctx);
> -       return ndctl_test_result(test, rc);
> +       return test_result(test, rc);
>  }
> diff --git a/test/dsm-fail.c b/test/dsm-fail.c
> index 74c56de..5559da2 100644
> --- a/test/dsm-fail.c
> +++ b/test/dsm-fail.c
> @@ -184,7 +184,7 @@ static int do_test(struct ndctl_ctx *ctx, struct test_ctx *test)
>         unsigned int handle;
>         int rc, err = 0;
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 9, 0)))
>                 return 77;
>
>         if (!bus)
> @@ -349,7 +349,7 @@ int test_dsm_fail(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
>         err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
>         if (err < 0) {
>                 result = 77;
> -               ndctl_test_skip(test);
> +               test_skip(test);
>                 fprintf(stderr, "%s unavailable skipping tests\n",
>                                 "nfit_test");
>                 return result;
> @@ -364,7 +364,7 @@ int test_dsm_fail(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct test_ctx *test = ndctl_test_new(0);
> +       struct test_ctx *test = test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> @@ -375,8 +375,8 @@ int __attribute__((weak)) main(int argc, char *argv[])
>
>         rc = ndctl_new(&ctx);
>         if (rc)
> -               return ndctl_test_result(test, rc);
> +               return test_result(test, rc);
>         rc = test_dsm_fail(LOG_DEBUG, test, ctx);
>         ndctl_unref(ctx);
> -       return ndctl_test_result(test, rc);
> +       return test_result(test, rc);
>  }
> diff --git a/test/libndctl.c b/test/libndctl.c
> index 30d19db..8aeaded 100644
> --- a/test/libndctl.c
> +++ b/test/libndctl.c
> @@ -639,7 +639,7 @@ static int validate_dax(struct ndctl_dax *dax)
>                 return -ENXIO;
>         }
>
> -       if (ndctl_test_attempt(test, KERNEL_VERSION(4, 10, 0))) {
> +       if (test_attempt(test, KERNEL_VERSION(4, 10, 0))) {
>                 if (daxctl_region_get_size(dax_region)
>                                 != ndctl_dax_get_size(dax)) {
>                         fprintf(stderr, "%s: expect size: %llu != %llu\n",
> @@ -745,7 +745,7 @@ static int __check_dax_create(struct ndctl_region *region,
>         ndctl_dax_set_align(dax, SZ_4K);
>
>         rc = ndctl_namespace_set_enforce_mode(ndns, NDCTL_NS_MODE_DAX);
> -       if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0)) && rc < 0) {
> +       if (test_attempt(test, KERNEL_VERSION(4, 13, 0)) && rc < 0) {
>                 fprintf(stderr, "%s: failed to enforce dax mode\n", devname);
>                 return rc;
>         }
> @@ -856,7 +856,7 @@ static int __check_pfn_create(struct ndctl_region *region,
>          */
>         ndctl_pfn_set_align(pfn, SZ_4K);
>         rc = ndctl_namespace_set_enforce_mode(ndns, NDCTL_NS_MODE_MEMORY);
> -       if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0)) && rc < 0) {
> +       if (test_attempt(test, KERNEL_VERSION(4, 13, 0)) && rc < 0) {
>                 fprintf(stderr, "%s: failed to enforce pfn mode\n", devname);
>                 return rc;
>         }
> @@ -1030,7 +1030,7 @@ static int check_btt_size(struct ndctl_btt *btt)
>         }
>
>         /* prior to 4.8 btt devices did not have a size attribute */
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 8, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 8, 0)))
>                 return 0;
>
>         expect = expect_table[size_select][sect_select];
> @@ -1077,7 +1077,7 @@ static int check_btt_create(struct ndctl_region *region, struct ndctl_namespace
>                 ndctl_btt_set_uuid(btt, btt_s->uuid);
>                 ndctl_btt_set_sector_size(btt, btt_s->sector_sizes[i]);
>                 rc = ndctl_namespace_set_enforce_mode(ndns, NDCTL_NS_MODE_SECTOR);
> -               if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0)) && rc < 0) {
> +               if (test_attempt(test, KERNEL_VERSION(4, 13, 0)) && rc < 0) {
>                         fprintf(stderr, "%s: failed to enforce btt mode\n", devname);
>                         goto err;
>                 }
> @@ -1094,7 +1094,7 @@ static int check_btt_create(struct ndctl_region *region, struct ndctl_namespace
>                 }
>
>                 /* prior to v4.5 the mode attribute did not exist */
> -               if (ndctl_test_attempt(test, KERNEL_VERSION(4, 5, 0))) {
> +               if (test_attempt(test, KERNEL_VERSION(4, 5, 0))) {
>                         mode = ndctl_namespace_get_mode(ndns);
>                         if (mode >= 0 && mode != NDCTL_NS_MODE_SECTOR)
>                                 fprintf(stderr, "%s: expected safe mode got: %d\n",
> @@ -1102,7 +1102,7 @@ static int check_btt_create(struct ndctl_region *region, struct ndctl_namespace
>                 }
>
>                 /* prior to v4.13 the expected sizes were different due to BTT1.1 */
> -               if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0))) {
> +               if (test_attempt(test, KERNEL_VERSION(4, 13, 0))) {
>                         rc = check_btt_size(btt);
>                         if (rc)
>                                 goto err;
> @@ -1287,7 +1287,7 @@ static int check_pfn_autodetect(struct ndctl_bus *bus,
>                 return -ENXIO;
>
>         mode = ndctl_namespace_get_enforce_mode(ndns);
> -       if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0))
> +       if (test_attempt(test, KERNEL_VERSION(4, 13, 0))
>                         && mode != NDCTL_NS_MODE_MEMORY) {
>                 fprintf(stderr, "%s expected enforce_mode pfn\n", devname);
>                 return -ENXIO;
> @@ -1384,7 +1384,7 @@ static int check_dax_autodetect(struct ndctl_bus *bus,
>                 return -ENXIO;
>
>         mode = ndctl_namespace_get_enforce_mode(ndns);
> -       if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0))
> +       if (test_attempt(test, KERNEL_VERSION(4, 13, 0))
>                         && mode != NDCTL_NS_MODE_DAX) {
>                 fprintf(stderr, "%s expected enforce_mode dax\n", devname);
>                 return -ENXIO;
> @@ -1469,7 +1469,7 @@ static int check_btt_autodetect(struct ndctl_bus *bus,
>                 return -ENXIO;
>
>         mode = ndctl_namespace_get_enforce_mode(ndns);
> -       if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0))
> +       if (test_attempt(test, KERNEL_VERSION(4, 13, 0))
>                         && mode != NDCTL_NS_MODE_SECTOR) {
>                 fprintf(stderr, "%s expected enforce_mode btt\n", devname);
>                 return -ENXIO;
> @@ -1714,7 +1714,7 @@ static int check_namespaces(struct ndctl_region *region,
>                 }
>
>                 if (ndctl_region_get_type(region) == ND_DEVICE_REGION_PMEM
> -                               && !ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0)))
> +                               && !test_attempt(test, KERNEL_VERSION(4, 13, 0)))
>                         /* pass, no sector_size support for pmem prior to 4.13 */;
>                 else {
>                         num_sector_sizes = namespace->num_sector_sizes;
> @@ -2321,7 +2321,7 @@ static int check_smart_threshold(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
>          * Starting with v4.9 smart threshold requests trigger the file
>          * descriptor returned by ndctl_dimm_get_health_eventfd().
>          */
> -       if (ndctl_test_attempt(check->test, KERNEL_VERSION(4, 9, 0))) {
> +       if (test_attempt(check->test, KERNEL_VERSION(4, 9, 0))) {
>                 int pid = fork();
>
>                 if (pid == 0) {
> @@ -2396,7 +2396,7 @@ static int check_smart_threshold(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
>                 ndctl_cmd_unref(cmd_set);
>         }
>
> -       if (ndctl_test_attempt(check->test, KERNEL_VERSION(4, 9, 0))) {
> +       if (test_attempt(check->test, KERNEL_VERSION(4, 9, 0))) {
>                 wait(&rc);
>                 if (WEXITSTATUS(rc) == EXIT_FAILURE) {
>                         fprintf(stderr, "%s: expect health event trigger\n",
> @@ -2439,7 +2439,7 @@ static int check_commands(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
>          * The kernel did not start emulating v1.2 namespace spec smart data
>          * until 4.9.
>          */
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 9, 0)))
>                 dimm_commands &= ~((1 << ND_CMD_SMART)
>                                 | (1 << ND_CMD_SMART_THRESHOLD));
>
> @@ -2474,7 +2474,7 @@ static int check_commands(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
>         if (rc)
>                 goto out;
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 6, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 6, 0)))
>                 goto out;
>
>   out:
> @@ -2530,7 +2530,7 @@ static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,
>                         return -ENXIO;
>                 }
>
> -               if (ndctl_test_attempt(test, KERNEL_VERSION(4, 7, 0))) {
> +               if (test_attempt(test, KERNEL_VERSION(4, 7, 0))) {
>                         if (ndctl_dimm_get_formats(dimm) != dimms[i].formats) {
>                                 fprintf(stderr, "dimm%d expected formats: %d got: %d\n",
>                                                 i, dimms[i].formats,
> @@ -2548,7 +2548,7 @@ static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,
>                         }
>                 }
>
> -               if (ndctl_test_attempt(test, KERNEL_VERSION(4, 7, 0))) {
> +               if (test_attempt(test, KERNEL_VERSION(4, 7, 0))) {
>                         if (ndctl_dimm_get_subsystem_vendor(dimm)
>                                         != dimms[i].subsystem_vendor) {
>                                 fprintf(stderr,
> @@ -2559,7 +2559,7 @@ static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,
>                         }
>                 }
>
> -               if (ndctl_test_attempt(test, KERNEL_VERSION(4, 8, 0))) {
> +               if (test_attempt(test, KERNEL_VERSION(4, 8, 0))) {
>                         if (ndctl_dimm_get_manufacturing_date(dimm)
>                                         != dimms[i].manufacturing_date) {
>                                 fprintf(stderr,
> @@ -2645,14 +2645,14 @@ static int do_test0(struct ndctl_ctx *ctx, struct test_ctx *test)
>         }
>
>         /* pfn and dax tests require vmalloc-enabled nfit_test */
> -       if (ndctl_test_attempt(test, KERNEL_VERSION(4, 8, 0))) {
> +       if (test_attempt(test, KERNEL_VERSION(4, 8, 0))) {
>                 rc = check_regions(bus, regions0, ARRAY_SIZE(regions0), DAX);
>                 if (rc)
>                         return rc;
>                 reset_bus(bus);
>         }
>
> -       if (ndctl_test_attempt(test, KERNEL_VERSION(4, 8, 0))) {
> +       if (test_attempt(test, KERNEL_VERSION(4, 8, 0))) {
>                 rc = check_regions(bus, regions0, ARRAY_SIZE(regions0), PFN);
>                 if (rc)
>                         return rc;
> @@ -2676,7 +2676,7 @@ static int do_test1(struct ndctl_ctx *ctx, struct test_ctx *test)
>          * Starting with v4.10 the dimm on nfit_test.1 gets a unique
>          * handle.
>          */
> -       if (ndctl_test_attempt(test, KERNEL_VERSION(4, 10, 0)))
> +       if (test_attempt(test, KERNEL_VERSION(4, 10, 0)))
>                 dimms1[0].handle = DIMM_HANDLE(1, 0, 0, 0, 0);
>
>         rc = check_dimms(bus, dimms1, ARRAY_SIZE(dimms1), 0, 0, test);
> @@ -2700,7 +2700,7 @@ int test_libndctl(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
>         struct daxctl_ctx *daxctl_ctx;
>         int err, result = EXIT_FAILURE;
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 2, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 2, 0)))
>                 return 77;
>
>         ndctl_set_log_priority(ctx, loglevel);
> @@ -2710,7 +2710,7 @@ int test_libndctl(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
>
>         err = ndctl_test_init(&kmod_ctx, &mod, ctx, loglevel, test);
>         if (err < 0) {
> -               ndctl_test_skip(test);
> +               test_skip(test);
>                 fprintf(stderr, "nfit_test unavailable skipping tests\n");
>                 return 77;
>         }
> @@ -2732,7 +2732,7 @@ int test_libndctl(int loglevel, struct test_ctx *test, struct ndctl_ctx *ctx)
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct test_ctx *test = ndctl_test_new(0);
> +       struct test_ctx *test = test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> @@ -2743,8 +2743,8 @@ int __attribute__((weak)) main(int argc, char *argv[])
>
>         rc = ndctl_new(&ctx);
>         if (rc)
> -               return ndctl_test_result(test, rc);
> +               return test_result(test, rc);
>         rc = test_libndctl(LOG_DEBUG, test, ctx);
>         ndctl_unref(ctx);
> -       return ndctl_test_result(test, rc);
> +       return test_result(test, rc);
>  }
> diff --git a/test/multi-pmem.c b/test/multi-pmem.c
> index e2f3bc5..f2eb381 100644
> --- a/test/multi-pmem.c
> +++ b/test/multi-pmem.c
> @@ -57,7 +57,7 @@ static int check_deleted(struct ndctl_region *region, const char *devname,
>  {
>         struct ndctl_namespace *ndns;
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 10, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 10, 0)))
>                 return 0;
>
>         ndctl_namespace_foreach(region, ndns) {
> @@ -85,8 +85,8 @@ static int do_multi_pmem(struct ndctl_ctx *ctx, struct test_ctx *test)
>         struct ndctl_namespace *namespaces[NUM_NAMESPACES];
>         unsigned long long blk_avail, blk_avail_orig, expect;
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0))) {
> -               ndctl_test_skip(test);
> +       if (!test_attempt(test, KERNEL_VERSION(4, 9, 0))) {
> +               test_skip(test);
>                 return 77;
>         }
>
> @@ -245,7 +245,7 @@ int test_multi_pmem(int loglevel, struct test_ctx *test,
>         struct kmod_ctx *kmod_ctx;
>         int err, result = EXIT_FAILURE;
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 2, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 2, 0)))
>                 return 77;
>
>         ndctl_set_log_priority(ctx, loglevel);
> @@ -253,7 +253,7 @@ int test_multi_pmem(int loglevel, struct test_ctx *test,
>         err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
>         if (err < 0) {
>                 result = 77;
> -               ndctl_test_skip(test);
> +               test_skip(test);
>                 fprintf(stderr, "%s unavailable skipping tests\n",
>                                 "nfit_test");
>                 return result;
> @@ -268,7 +268,7 @@ int test_multi_pmem(int loglevel, struct test_ctx *test,
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct test_ctx *test = ndctl_test_new(0);
> +       struct test_ctx *test = test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> @@ -279,8 +279,8 @@ int __attribute__((weak)) main(int argc, char *argv[])
>
>         rc = ndctl_new(&ctx);
>         if (rc)
> -               return ndctl_test_result(test, rc);
> +               return test_result(test, rc);
>         rc = test_multi_pmem(LOG_DEBUG, test, ctx);
>         ndctl_unref(ctx);
> -       return ndctl_test_result(test, rc);
> +       return test_result(test, rc);
>  }
> diff --git a/test/parent-uuid.c b/test/parent-uuid.c
> index dd007c7..8da396f 100644
> --- a/test/parent-uuid.c
> +++ b/test/parent-uuid.c
> @@ -215,13 +215,13 @@ int test_parent_uuid(int loglevel, struct test_ctx *test,
>         struct kmod_ctx *kmod_ctx;
>         int err, result = EXIT_FAILURE;
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 3, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 3, 0)))
>                 return 77;
>
>         ndctl_set_log_priority(ctx, loglevel);
>         err = ndctl_test_init(&kmod_ctx, &mod, NULL, loglevel, test);
>         if (err < 0) {
> -               ndctl_test_skip(test);
> +               test_skip(test);
>                 fprintf(stderr, "nfit_test unavailable skipping tests\n");
>                 return 77;
>         }
> @@ -236,7 +236,7 @@ int test_parent_uuid(int loglevel, struct test_ctx *test,
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct test_ctx *test = ndctl_test_new(0);
> +       struct test_ctx *test = test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> @@ -247,9 +247,9 @@ int __attribute__((weak)) main(int argc, char *argv[])
>
>         rc = ndctl_new(&ctx);
>         if (rc)
> -               return ndctl_test_result(test, rc);
> +               return test_result(test, rc);
>
>         rc = test_parent_uuid(LOG_DEBUG, test, ctx);
>         ndctl_unref(ctx);
> -       return ndctl_test_result(test, rc);
> +       return test_result(test, rc);
>  }
> diff --git a/test/pmem_namespaces.c b/test/pmem_namespaces.c
> index eddf32a..20f41fe 100644
> --- a/test/pmem_namespaces.c
> +++ b/test/pmem_namespaces.c
> @@ -173,7 +173,7 @@ int test_pmem_namespaces(int log_level, struct test_ctx *test,
>         int rc = -ENXIO;
>         char bdev[50];
>
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 2, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 2, 0)))
>                 return 77;
>
>         ndctl_set_log_priority(ctx, log_level);
> @@ -196,7 +196,7 @@ int test_pmem_namespaces(int log_level, struct test_ctx *test,
>                 bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0");
>                 if (rc < 0 || !bus) {
>                         rc = 77;
> -                       ndctl_test_skip(test);
> +                       test_skip(test);
>                         fprintf(stderr, "nfit_test unavailable skipping tests\n");
>                         goto err_module;
>                 }
> @@ -262,7 +262,7 @@ int test_pmem_namespaces(int log_level, struct test_ctx *test,
>
>  int __attribute__((weak)) main(int argc, char *argv[])
>  {
> -       struct test_ctx *test = ndctl_test_new(0);
> +       struct test_ctx *test = test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> @@ -274,9 +274,9 @@ int __attribute__((weak)) main(int argc, char *argv[])
>
>         rc = ndctl_new(&ctx);
>         if (rc)
> -               return ndctl_test_result(test, rc);
> +               return test_result(test, rc);
>
>         rc = test_pmem_namespaces(LOG_DEBUG, test, ctx);
>         ndctl_unref(ctx);
> -       return ndctl_test_result(test, rc);
> +       return test_result(test, rc);
>  }
> diff --git a/test/revoke-devmem.c b/test/revoke-devmem.c
> index 0d67d93..ac8d81c 100644
> --- a/test/revoke-devmem.c
> +++ b/test/revoke-devmem.c
> @@ -44,7 +44,7 @@ static int test_devmem(int loglevel, struct test_ctx *test,
>         ndctl_set_log_priority(ctx, loglevel);
>
>         /* iostrict devmem started in kernel 4.5 */
> -       if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 5, 0)))
> +       if (!test_attempt(test, KERNEL_VERSION(4, 5, 0)))
>                 return 77;
>
>         ndns = ndctl_get_test_dev(ctx);
> @@ -124,7 +124,7 @@ out_devmem:
>
>  int main(int argc, char *argv[])
>  {
> -       struct test_ctx *test = ndctl_test_new(0);
> +       struct test_ctx *test = test_new(0);
>         struct ndctl_ctx *ctx;
>         int rc;
>
> @@ -135,9 +135,9 @@ int main(int argc, char *argv[])
>
>         rc = ndctl_new(&ctx);
>         if (rc < 0)
> -               return ndctl_test_result(test, rc);
> +               return test_result(test, rc);
>
>         rc = test_devmem(LOG_DEBUG, test, ctx);
>         ndctl_unref(ctx);
> -       return ndctl_test_result(test, rc);
> +       return test_result(test, rc);
>  }
> diff --git a/README.md b/README.md
> index 89dfc87..7a687ac 100644
> --- a/README.md
> +++ b/README.md
> @@ -95,7 +95,7 @@ test/test-suite.log:
>  SKIP: libndctl
>  ==============
>  test/init: nfit_test_init: nfit.ko: appears to be production version: /lib/modules/4.8.8-200.fc24.x86_64/kernel/drivers/acpi/nfit/nfit.ko.xz
> -__ndctl_test_skip: explicit skip test_libndctl:2684
> +__test_skip: explicit skip test_libndctl:2684
>  nfit_test unavailable skipping tests
>  ```
>
> --
> 2.31.1
>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [ndctl PATCH v3 08/21] test: introduce a libcxl unit test
  2021-07-01 20:09 ` [ndctl PATCH v3 08/21] test: introduce a libcxl unit test Vishal Verma
@ 2021-07-15 23:53   ` Dan Williams
  0 siblings, 0 replies; 36+ messages in thread
From: Dan Williams @ 2021-07-15 23:53 UTC (permalink / raw)
  To: Vishal Verma
  Cc: Linux NVDIMM, linux-cxl, Ben Widawsky, Alison Schofield, Ira Weiny

On Thu, Jul 1, 2021 at 1:10 PM Vishal Verma <vishal.l.verma@intel.com> wrote:
>
> Add a new 'libcxl' test containing a basic harness for unit testing
> libcxl APIs. Include sanity tests such as making sure the test is
> running in an emulated environment, the ability to load and unload
> modules. Submit an 'Identify Device' command, and verify that it
> succeeds, and the identify data returned is as expected from an emulated
> QEMU device.

Maybe hold off on this one until we can replace QEMU with a kernel
provided emulation environment. I.e. our tests need to be reproducible
upstream and this far QEMU community has not shown any interest in
taking the CXL emulation upstream.

>
> Cc: Ben Widawsky <ben.widawsky@intel.com>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
> ---
>  test/libcxl-expect.h |  13 +++
>  test/libcxl.c        | 269 +++++++++++++++++++++++++++++++++++++++++++
>  test/Makefile.am     |  12 +-
>  3 files changed, 292 insertions(+), 2 deletions(-)
>  create mode 100644 test/libcxl-expect.h
>  create mode 100644 test/libcxl.c
>
> diff --git a/test/libcxl-expect.h b/test/libcxl-expect.h
> new file mode 100644
> index 0000000..acb8db9
> --- /dev/null
> +++ b/test/libcxl-expect.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2021 Intel Corporation. All rights reserved. */
> +#ifndef __LIBCXL_EXPECT_H__
> +#define __LIBCXL_EXPECT_H__
> +#include <stdbool.h>
> +
> +#define EXPECT_FW_VER "BWFW VERSION 00"
> +
> +/* Identify command fields */
> +#define EXPECT_CMD_IDENTIFY_PARTITION_ALIGN 0ULL
> +#define EXPECT_CMD_IDENTIFY_LSA_SIZE 1024U
> +
> +#endif /* __LIBCXL_EXPECT_H__ */
> diff --git a/test/libcxl.c b/test/libcxl.c
> new file mode 100644
> index 0000000..241a4bb
> --- /dev/null
> +++ b/test/libcxl.c
> @@ -0,0 +1,269 @@
> +// SPDX-License-Identifier: LGPL-2.1
> +/* Copyright (C) 2021, Intel Corporation. All rights reserved. */
> +#include <stdio.h>
> +#include <stddef.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <ctype.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <limits.h>
> +#include <syslog.h>
> +#include <libkmod.h>
> +#include <sys/wait.h>
> +#include <uuid/uuid.h>
> +#include <sys/types.h>
> +#include <sys/ioctl.h>
> +#include <sys/select.h>
> +#include <linux/version.h>
> +
> +#include <util/size.h>
> +#include <ccan/short_types/short_types.h>
> +#include <ccan/array_size/array_size.h>
> +#include <ccan/endian/endian.h>
> +#include <cxl/libcxl.h>
> +#include <cxl/cxl_mem.h>
> +#include <test.h>
> +#include "libcxl-expect.h"
> +
> +#define TEST_SKIP 77
> +
> +const char *mod_list[] = {
> +       "cxl_pci",
> +       "cxl_acpi",
> +       "cxl_core",
> +};
> +
> +static int test_cxl_presence(struct cxl_ctx *ctx)
> +{
> +       struct cxl_memdev *memdev;
> +       int count = 0;
> +
> +       cxl_memdev_foreach(ctx, memdev)
> +               count++;
> +
> +       if (count == 0) {
> +               fprintf(stderr, "%s: no cxl memdevs found\n", __func__);
> +               return TEST_SKIP;
> +       }
> +
> +       return 0;
> +}
> +
> +/*
> + * Only continue with tests if all CXL devices in the system are qemu-emulated
> + * 'fake' devices. For now, use the firmware_version to check for this. Later,
> + * this might need to be changed to a vendor specific command.
> + *
> + * TODO: Change this to produce a list of devices that are safe to run tests
> + * against, and only run subsequent tests on this list. That will allow devices
> + * from other, non-emulated sources to be present in the system, and still run
> + * these unit tests safely.
> + */
> +static int test_cxl_emulation_env(struct cxl_ctx *ctx)
> +{
> +       struct cxl_memdev *memdev;
> +
> +       cxl_memdev_foreach(ctx, memdev) {
> +               const char *fw;
> +
> +               fw = cxl_memdev_get_firmware_verison(memdev);
> +               if (!fw)
> +                       return -ENXIO;
> +               if (strcmp(fw, EXPECT_FW_VER) != 0) {
> +                       fprintf(stderr,
> +                               "%s: found non-emulation device, aborting\n",
> +                               __func__);
> +                       return TEST_SKIP;
> +               }
> +       }
> +       return 0;
> +}
> +
> +static int test_cxl_modules(struct cxl_ctx *ctx)
> +{
> +       int rc;
> +       unsigned int i;
> +       const char *name;
> +       struct kmod_module *mod;
> +       struct kmod_ctx *kmod_ctx;
> +
> +       kmod_ctx = kmod_new(NULL, NULL);
> +       if (!kmod_ctx)
> +               return -ENXIO;
> +       kmod_set_log_priority(kmod_ctx, LOG_DEBUG);
> +
> +       /* test module removal */
> +       for (i = 0; i < ARRAY_SIZE(mod_list); i++) {
> +               int state;
> +
> +               name = mod_list[i];
> +
> +               rc = kmod_module_new_from_name(kmod_ctx, name, &mod);
> +               if (rc) {
> +                       fprintf(stderr, "%s: %s.ko: missing\n", __func__, name);
> +                       break;
> +               }
> +
> +               state = kmod_module_get_initstate(mod);
> +               if (state == KMOD_MODULE_LIVE) {
> +                       rc = kmod_module_remove_module(mod, 0);
> +                       if (rc) {
> +                               fprintf(stderr,
> +                                       "%s: %s.ko: failed to remove: %d\n",
> +                                       __func__, name, rc);
> +                               break;
> +                       }
> +               } else if (state == KMOD_MODULE_BUILTIN) {
> +                       fprintf(stderr,
> +                               "%s: %s is builtin, skipping module removal test\n",
> +                               __func__, name);
> +               } else {
> +                       fprintf(stderr,
> +                               "%s: warning: %s.ko: unexpected state (%d), trying to continue\n",
> +                               __func__, name, state);
> +               }
> +       }
> +
> +       if (rc)
> +               goto out;
> +
> +       /* test module insertion */
> +       for (i = 0; i < ARRAY_SIZE(mod_list); i++) {
> +               name = mod_list[i];
> +               rc = kmod_module_new_from_name(kmod_ctx, name, &mod);
> +               if (rc) {
> +                       fprintf(stderr, "%s: %s.ko: missing\n", __func__, name);
> +                       break;
> +               }
> +
> +               rc = kmod_module_probe_insert_module(mod,
> +                               KMOD_PROBE_APPLY_BLACKLIST,
> +                               NULL, NULL, NULL, NULL);
> +       }
> +
> +out:
> +       kmod_unref(kmod_ctx);
> +       return rc;
> +}
> +
> +#define expect(c, name, field, expect) \
> +do { \
> +       if (cxl_cmd_##name##_get_##field(c) != expect) { \
> +               fprintf(stderr, \
> +                       "%s: %s: " #field " mismatch\n", \
> +                       __func__, cxl_cmd_get_devname(c)); \
> +               cxl_cmd_unref(cmd); \
> +               return -ENXIO; \
> +       } \
> +} while (0)
> +
> +static int test_cxl_cmd_identify(struct cxl_ctx *ctx)
> +{
> +       struct cxl_memdev *memdev;
> +       struct cxl_cmd *cmd;
> +       int rc;
> +
> +       cxl_memdev_foreach(ctx, memdev) {
> +               char fw_rev[0x10];
> +
> +               cmd = cxl_cmd_new_identify(memdev);
> +               if (!cmd)
> +                       return -ENOMEM;
> +               rc = cxl_cmd_submit(cmd);
> +               if (rc < 0) {
> +                       fprintf(stderr, "%s: %s: cmd submission failed: %s\n",
> +                               __func__, cxl_memdev_get_devname(memdev),
> +                               strerror(-rc));
> +                       goto out_fail;
> +               }
> +               rc = cxl_cmd_get_mbox_status(cmd);
> +               if (rc) {
> +                       fprintf(stderr,
> +                               "%s: %s: cmd failed with firmware status: %d\n",
> +                               __func__, cxl_memdev_get_devname(memdev), rc);
> +                       rc = -ENXIO;
> +                       goto out_fail;
> +               }
> +
> +               rc = cxl_cmd_identify_get_fw_rev(cmd, fw_rev, 0x10);
> +               if (rc)
> +                       goto out_fail;
> +               if (strncmp(fw_rev, EXPECT_FW_VER, 0x10) != 0) {
> +                       fprintf(stderr,
> +                               "%s: fw_rev mismatch. Expected %s, got %s\n",
> +                               __func__, EXPECT_FW_VER, fw_rev);
> +                       rc = -ENXIO;
> +                       goto out_fail;
> +               }
> +
> +               expect(cmd, identify, lsa_size, EXPECT_CMD_IDENTIFY_LSA_SIZE);
> +               expect(cmd, identify, partition_align,
> +                       EXPECT_CMD_IDENTIFY_PARTITION_ALIGN);
> +               cxl_cmd_unref(cmd);
> +       }
> +       return 0;
> +
> +out_fail:
> +       cxl_cmd_unref(cmd);
> +       return rc;
> +}
> +
> +typedef int (*do_test_fn)(struct cxl_ctx *ctx);
> +
> +static do_test_fn do_test[] = {
> +       test_cxl_modules,
> +       test_cxl_presence,
> +       test_cxl_emulation_env,
> +       test_cxl_cmd_identify,
> +};
> +
> +static int test_libcxl(int loglevel, struct test_ctx *test, struct cxl_ctx *ctx)
> +{
> +       unsigned int i;
> +       int err, result = EXIT_FAILURE;
> +
> +       if (!test_attempt(test, KERNEL_VERSION(5, 12, 0)))
> +               return 77;
> +
> +       cxl_set_log_priority(ctx, loglevel);
> +       cxl_set_private_data(ctx, test);
> +
> +       for (i = 0; i < ARRAY_SIZE(do_test); i++) {
> +               err = do_test[i](ctx);
> +               if (err < 0) {
> +                       fprintf(stderr, "test[%d] failed: %d\n", i, err);
> +                       break;
> +               } else if (err == TEST_SKIP) {
> +                       fprintf(stderr, "test[%d]: SKIP\n", i);
> +                       test_skip(test);
> +                       result = TEST_SKIP;
> +                       break;
> +               }
> +               fprintf(stderr, "test[%d]: PASS\n", i);
> +       }
> +
> +       if (i >= ARRAY_SIZE(do_test))
> +               result = EXIT_SUCCESS;
> +       return result;
> +}
> +
> +int __attribute__((weak)) main(int argc, char *argv[])
> +{
> +       struct test_ctx *test = test_new(0);
> +       struct cxl_ctx *ctx;
> +       int rc;
> +
> +       if (!test) {
> +               fprintf(stderr, "failed to initialize test\n");
> +               return EXIT_FAILURE;
> +       }
> +
> +       rc = cxl_new(&ctx);
> +       if (rc)
> +               return test_result(test, rc);
> +       rc = test_libcxl(LOG_DEBUG, test, ctx);
> +       cxl_unref(ctx);
> +       return test_result(test, rc);
> +}
> diff --git a/test/Makefile.am b/test/Makefile.am
> index c5b8764..ce492a4 100644
> --- a/test/Makefile.am
> +++ b/test/Makefile.am
> @@ -44,7 +44,8 @@ check_PROGRAMS =\
>         hugetlb \
>         daxdev-errors \
>         ack-shutdown-count-set \
> -       list-smart-dimm
> +       list-smart-dimm \
> +       libcxl
>
>  if ENABLE_DESTRUCTIVE
>  TESTS +=\
> @@ -61,7 +62,8 @@ TESTS +=\
>         daxctl-devices.sh \
>         daxctl-create.sh \
>         dm.sh \
> -       mmap.sh
> +       mmap.sh \
> +       libcxl
>
>  if ENABLE_KEYUTILS
>  TESTS += security.sh
> @@ -190,3 +192,9 @@ list_smart_dimm_LDADD = \
>                 $(JSON_LIBS) \
>                 $(UUID_LIBS) \
>                 ../libutil.a
> +
> +LIBCXL_LIB =\
> +       ../cxl/lib/libcxl.la
> +
> +libcxl_SOURCES = libcxl.c $(testcore)
> +libcxl_LDADD = $(LIBCXL_LIB) $(UUID_LIBS) $(KMOD_LIBS)
> --
> 2.31.1
>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [ndctl PATCH v3 09/21] libcxl: add GET_HEALTH_INFO mailbox command and accessors
  2021-07-01 20:09 ` [ndctl PATCH v3 09/21] libcxl: add GET_HEALTH_INFO mailbox command and accessors Vishal Verma
@ 2021-07-16  1:11   ` Dan Williams
  0 siblings, 0 replies; 36+ messages in thread
From: Dan Williams @ 2021-07-16  1:11 UTC (permalink / raw)
  To: Vishal Verma
  Cc: Linux NVDIMM, linux-cxl, Ben Widawsky, Alison Schofield, Ira Weiny

On Thu, Jul 1, 2021 at 1:11 PM Vishal Verma <vishal.l.verma@intel.com> wrote:
>
> Add libcxl APIs to create a new GET_HEALTH_INFO mailbox command, the
> command output data structure (privately), and accessor APIs to return
> the different fields in the health info output.
>
> Cc: Ben Widawsky <ben.widawsky@intel.com>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
> ---
>  cxl/lib/private.h  | 11 +++++++++
>  cxl/lib/libcxl.c   | 61 ++++++++++++++++++++++++++++++++++++++++++++++
>  cxl/libcxl.h       |  9 +++++++
>  cxl/lib/libcxl.sym |  9 +++++++
>  4 files changed, 90 insertions(+)
>
> diff --git a/cxl/lib/private.h b/cxl/lib/private.h
> index 3273f21..2232f4c 100644
> --- a/cxl/lib/private.h
> +++ b/cxl/lib/private.h
> @@ -73,6 +73,17 @@ struct cxl_cmd_identify {
>         u8 qos_telemetry_caps;
>  } __attribute__((packed));
>
> +struct cxl_cmd_get_health_info {
> +       u8 health_status;
> +       u8 media_status;
> +       u8 ext_status;
> +       u8 life_used;
> +       le16 temperature;
> +       le32 dirty_shutdowns;
> +       le32 volatile_errors;
> +       le32 pmem_errors;
> +} __attribute__((packed));
> +
>  static inline int check_kmod(struct kmod_ctx *kmod_ctx)
>  {
>         return kmod_ctx ? 0 : -ENXIO;
> diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
> index 06a6c20..2e33c5e 100644
> --- a/cxl/lib/libcxl.c
> +++ b/cxl/lib/libcxl.c
> @@ -673,6 +673,67 @@ CXL_EXPORT const char *cxl_cmd_get_devname(struct cxl_cmd *cmd)
>         return cxl_memdev_get_devname(cmd->memdev);
>  }
>
> +#define cmd_get_int(cmd, n, N, field) \
> +do { \
> +       struct cxl_cmd_##n *c = (void *)cmd->send_cmd->out.payload; \
> +       if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_##N) \
> +               return EINVAL; \
> +       if (cmd->status < 0) \
> +               return cmd->status; \
> +       return le32_to_cpu(c->field); \
> +} while(0);
> +
> +CXL_EXPORT struct cxl_cmd *cxl_cmd_new_get_health_info(
> +               struct cxl_memdev *memdev)
> +{
> +       return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_GET_HEALTH_INFO);
> +}
> +
> +#define cmd_health_get_int(c, f) \
> +do { \
> +       cmd_get_int(c, get_health_info, GET_HEALTH_INFO, f); \
> +} while (0);
> +
> +CXL_EXPORT int cxl_cmd_get_health_info_get_health_status(struct cxl_cmd *cmd)
> +{
> +       cmd_health_get_int(cmd, health_status);
> +}

I would expect this to broken up into a helper per flag like:

bool cxl_cmd_health_info_get_maintenance_needed(struct cxl_cmd *cmd)
bool cxl_cmd_health_info_get_performance_degraded(struct cxl_cmd *cmd)
bool cxl_cmd_health_info_get_replacement_needed(struct cxl_cmd *cmd)

i.e. the payload helpers should try to hide reserved fields from being
inadvertently communicated, otherwise software that's starts reserved
values being set may break. Rather than masking reserved adding
explicit helpers makes the library usage more readable... but yeah it
makes the library definition a bit more tedious.

I also think it's ok to drop verbs out of command names especially
when the collide with library verb names, i.e.
s/get_health_info_get/s/health_info_get/


> +CXL_EXPORT int cxl_cmd_get_health_info_get_media_status(struct cxl_cmd *cmd)
> +{
> +       cmd_health_get_int(cmd, media_status);
> +}

Similar feedback here, i.e. unless the payload field is literally an
integer it should have a scheme to prevent reserved values from being
passed through, and ideally have formal retrieval methods for each
defined value. In this case I think a library defined enum to mirror
the status values is warranted. No need to make the enum values match
up with payload values.

> +
> +CXL_EXPORT int cxl_cmd_get_health_info_get_ext_status(struct cxl_cmd *cmd)
> +{
> +       cmd_health_get_int(cmd, ext_status);
> +}
> +

This one is fun with enums and flags to parse...

> +CXL_EXPORT int cxl_cmd_get_health_info_get_life_used(struct cxl_cmd *cmd)
> +{
> +       cmd_health_get_int(cmd, life_used);
> +}
> +

This should probably return a positive number from 0-100 or a negative
error code.

> +CXL_EXPORT int cxl_cmd_get_health_info_get_temperature(struct cxl_cmd *cmd)
> +{
> +       cmd_health_get_int(cmd, temperature);
> +}

This is a two's complement value that needs to be cast into a positive
or negative number of degrees.

> +
> +CXL_EXPORT int cxl_cmd_get_health_info_get_dirty_shutdowns(struct cxl_cmd *cmd)
> +{
> +       cmd_health_get_int(cmd, dirty_shutdowns);
> +}
> +
> +CXL_EXPORT int cxl_cmd_get_health_info_get_volatile_errors(struct cxl_cmd *cmd)
> +{
> +       cmd_health_get_int(cmd, volatile_errors);
> +}
> +
> +CXL_EXPORT int cxl_cmd_get_health_info_get_pmem_errors(struct cxl_cmd *cmd)
> +{
> +       cmd_health_get_int(cmd, pmem_errors);
> +}
> +

These 3 seem ok to not need translation helpers, but only as unsigned integers.

>  CXL_EXPORT struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev)
>  {
>         return cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_IDENTIFY);
> diff --git a/cxl/libcxl.h b/cxl/libcxl.h
> index 9ed8c83..56ae4af 100644
> --- a/cxl/libcxl.h
> +++ b/cxl/libcxl.h
> @@ -62,6 +62,15 @@ struct cxl_cmd *cxl_cmd_new_identify(struct cxl_memdev *memdev);
>  int cxl_cmd_identify_get_fw_rev(struct cxl_cmd *cmd, char *fw_rev, int fw_len);
>  unsigned long long cxl_cmd_identify_get_partition_align(struct cxl_cmd *cmd);
>  unsigned int cxl_cmd_identify_get_lsa_size(struct cxl_cmd *cmd);
> +struct cxl_cmd *cxl_cmd_new_get_health_info(struct cxl_memdev *memdev);
> +int cxl_cmd_get_health_info_get_health_status(struct cxl_cmd *cmd);
> +int cxl_cmd_get_health_info_get_media_status(struct cxl_cmd *cmd);
> +int cxl_cmd_get_health_info_get_ext_status(struct cxl_cmd *cmd);
> +int cxl_cmd_get_health_info_get_life_used(struct cxl_cmd *cmd);
> +int cxl_cmd_get_health_info_get_temperature(struct cxl_cmd *cmd);
> +int cxl_cmd_get_health_info_get_dirty_shutdowns(struct cxl_cmd *cmd);
> +int cxl_cmd_get_health_info_get_volatile_errors(struct cxl_cmd *cmd);
> +int cxl_cmd_get_health_info_get_pmem_errors(struct cxl_cmd *cmd);
>
>  #ifdef __cplusplus
>  } /* extern "C" */
> diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
> index d6aa0b2..e00443d 100644
> --- a/cxl/lib/libcxl.sym
> +++ b/cxl/lib/libcxl.sym
> @@ -43,4 +43,13 @@ global:
>         cxl_cmd_identify_get_fw_rev;
>         cxl_cmd_identify_get_partition_align;
>         cxl_cmd_identify_get_lsa_size;
> +       cxl_cmd_new_get_health_info;
> +       cxl_cmd_get_health_info_get_health_status;
> +       cxl_cmd_get_health_info_get_media_status;
> +       cxl_cmd_get_health_info_get_ext_status;
> +       cxl_cmd_get_health_info_get_life_used;
> +       cxl_cmd_get_health_info_get_temperature;
> +       cxl_cmd_get_health_info_get_dirty_shutdowns;
> +       cxl_cmd_get_health_info_get_volatile_errors;
> +       cxl_cmd_get_health_info_get_pmem_errors;
>  } LIBCXL_2;
> --
> 2.31.1
>

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [ndctl PATCH v3 10/21] libcxl: add support for the 'GET_LSA' command
  2021-07-01 20:09 ` [ndctl PATCH v3 10/21] libcxl: add support for the 'GET_LSA' command Vishal Verma
@ 2021-07-16  2:24   ` Dan Williams
  0 siblings, 0 replies; 36+ messages in thread
From: Dan Williams @ 2021-07-16  2:24 UTC (permalink / raw)
  To: Vishal Verma
  Cc: Linux NVDIMM, linux-cxl, Ben Widawsky, Alison Schofield, Ira Weiny

On Thu, Jul 1, 2021 at 1:10 PM Vishal Verma <vishal.l.verma@intel.com> wrote:
>
> Add a command allocator and accessor APIs for the 'GET_LSA' mailbox
> command.
>
> Cc: Ben Widawsky <ben.widawsky@intel.com>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
> ---
>  cxl/lib/private.h  |  5 +++++
>  cxl/lib/libcxl.c   | 31 +++++++++++++++++++++++++++++++
>  cxl/libcxl.h       |  3 +++
>  cxl/lib/libcxl.sym |  2 ++
>  4 files changed, 41 insertions(+)
>
> diff --git a/cxl/lib/private.h b/cxl/lib/private.h
> index 2232f4c..fb1dd8e 100644
> --- a/cxl/lib/private.h
> +++ b/cxl/lib/private.h
> @@ -73,6 +73,11 @@ struct cxl_cmd_identify {
>         u8 qos_telemetry_caps;
>  } __attribute__((packed));
>
> +struct cxl_cmd_get_lsa_in {
> +       le32 offset;
> +       le32 length;
> +} __attribute__((packed));
> +
>  struct cxl_cmd_get_health_info {
>         u8 health_status;
>         u8 media_status;
> diff --git a/cxl/lib/libcxl.c b/cxl/lib/libcxl.c
> index 2e33c5e..d2c38c9 100644
> --- a/cxl/lib/libcxl.c
> +++ b/cxl/lib/libcxl.c
> @@ -799,6 +799,37 @@ CXL_EXPORT struct cxl_cmd *cxl_cmd_new_raw(struct cxl_memdev *memdev,
>         return cmd;
>  }
>
> +CXL_EXPORT struct cxl_cmd *cxl_cmd_new_get_lsa(struct cxl_memdev *memdev,
> +               unsigned int offset, unsigned int length)

What about a rename here to cxl_cmd_new_read_label? Because, like
before, 'get' is overloaded in lib{cxl,ndctl,daxctl} land, and 'lsa'
is a spec acronym that we don't need to be matchy-matchy with if
there's a better name for libcxl users.

That said, that's only a mild preference if you like the symmetry with the spec.

> +{
> +       struct cxl_cmd_get_lsa_in *get_lsa;
> +       struct cxl_cmd *cmd;
> +
> +       cmd = cxl_cmd_new_generic(memdev, CXL_MEM_COMMAND_ID_GET_LSA);
> +       if (!cmd)
> +               return NULL;
> +
> +       get_lsa = (void *)cmd->send_cmd->in.payload;
> +       get_lsa->offset = cpu_to_le32(offset);
> +       get_lsa->length = cpu_to_le32(length);
> +       return cmd;
> +}
> +
> +#define cmd_get_void(cmd, N) \
> +do { \
> +       void *p = (void *)cmd->send_cmd->out.payload; \
> +       if (cmd->send_cmd->id != CXL_MEM_COMMAND_ID_##N) \
> +               return NULL; \
> +       if (cmd->status < 0) \
> +               return NULL; \
> +       return p; \
> +} while(0);
> +
> +CXL_EXPORT void *cxl_cmd_get_lsa_get_payload(struct cxl_cmd *cmd)

Here's another get_X_get that might be better as cxl_cmd_read_label_get_payload.

I also liked the ndctl behavior where it was made difficult to do out
of bounds access to this buffer because the user had to go through
ndctl_cmd_cfg_read_get_data() which did error checking if they tried
to access more of the payload than was initially requested.

> +{
> +       cmd_get_void(cmd, GET_LSA);
> +}
> +
>  CXL_EXPORT int cxl_cmd_submit(struct cxl_cmd *cmd)
>  {
>         struct cxl_memdev *memdev = cmd->memdev;
> diff --git a/cxl/libcxl.h b/cxl/libcxl.h
> index 56ae4af..6edbd8d 100644
> --- a/cxl/libcxl.h
> +++ b/cxl/libcxl.h
> @@ -71,6 +71,9 @@ int cxl_cmd_get_health_info_get_temperature(struct cxl_cmd *cmd);
>  int cxl_cmd_get_health_info_get_dirty_shutdowns(struct cxl_cmd *cmd);
>  int cxl_cmd_get_health_info_get_volatile_errors(struct cxl_cmd *cmd);
>  int cxl_cmd_get_health_info_get_pmem_errors(struct cxl_cmd *cmd);
> +struct cxl_cmd *cxl_cmd_new_get_lsa(struct cxl_memdev *memdev,
> +               unsigned int offset, unsigned int length);
> +void *cxl_cmd_get_lsa_get_payload(struct cxl_cmd *cmd);
>
>  #ifdef __cplusplus
>  } /* extern "C" */
> diff --git a/cxl/lib/libcxl.sym b/cxl/lib/libcxl.sym
> index e00443d..2c6193b 100644
> --- a/cxl/lib/libcxl.sym
> +++ b/cxl/lib/libcxl.sym
> @@ -52,4 +52,6 @@ global:
>         cxl_cmd_get_health_info_get_dirty_shutdowns;
>         cxl_cmd_get_health_info_get_volatile_errors;
>         cxl_cmd_get_health_info_get_pmem_errors;
> +       cxl_cmd_new_get_lsa;
> +       cxl_cmd_get_lsa_get_payload;
>  } LIBCXL_2;
> --
> 2.31.1
>

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2021-07-16  2:25 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-01 20:09 [ndctl PATCH v3 00/21] Initial CXL support Vishal Verma
2021-07-01 20:09 ` [ndctl PATCH v3 01/21] ndctl: add .clang-format Vishal Verma
2021-07-10  1:12   ` Dan Williams
2021-07-01 20:09 ` [ndctl PATCH v3 02/21] cxl: add a cxl utility and libcxl library Vishal Verma
2021-07-10  1:12   ` Dan Williams
2021-07-13 21:14     ` Verma, Vishal L
2021-07-01 20:09 ` [ndctl PATCH v3 03/21] cxl: add a local copy of the cxl_mem UAPI header Vishal Verma
2021-07-10  1:13   ` Dan Williams
2021-07-01 20:09 ` [ndctl PATCH v3 04/21] libcxl: add support for command query and submission Vishal Verma
2021-07-13  5:12   ` Dan Williams
2021-07-13 21:17     ` Verma, Vishal L
2021-07-13 21:39       ` Dan Williams
2021-07-01 20:09 ` [ndctl PATCH v3 05/21] libcxl: add support for the 'Identify Device' command Vishal Verma
2021-07-15 23:50   ` Dan Williams
2021-07-01 20:09 ` [ndctl PATCH v3 06/21] test: rename 'ndctl_test' to 'test_ctx' Vishal Verma
2021-07-15 23:51   ` Dan Williams
2021-07-01 20:09 ` [ndctl PATCH v3 07/21] test: rename 'ndctl_test_*' helpers to 'test_*' Vishal Verma
2021-07-15 23:51   ` Dan Williams
2021-07-01 20:09 ` [ndctl PATCH v3 08/21] test: introduce a libcxl unit test Vishal Verma
2021-07-15 23:53   ` Dan Williams
2021-07-01 20:09 ` [ndctl PATCH v3 09/21] libcxl: add GET_HEALTH_INFO mailbox command and accessors Vishal Verma
2021-07-16  1:11   ` Dan Williams
2021-07-01 20:09 ` [ndctl PATCH v3 10/21] libcxl: add support for the 'GET_LSA' command Vishal Verma
2021-07-16  2:24   ` Dan Williams
2021-07-01 20:09 ` [ndctl PATCH v3 11/21] util/hexdump: Add a util helper to print a buffer in hex Vishal Verma
2021-07-01 20:09 ` [ndctl PATCH v3 12/21] test/libcxl: add a test for {set, get}_lsa commands Vishal Verma
2021-07-01 20:09 ` [ndctl PATCH v3 13/21] test/libcxl: introduce a command size fuzzing test Vishal Verma
2021-07-01 20:09 ` [ndctl PATCH v3 14/21] libcxl: add lsa_size to cxl_memdev, and an API to retrieve it Vishal Verma
2021-07-01 20:09 ` [ndctl PATCH v3 15/21] libcxl: PLACEHOLDER: add an interface to determine whether a memdev is active Vishal Verma
2021-07-01 20:10 ` [ndctl PATCH v3 16/21] libcxl: add interfaces for label operations Vishal Verma
2021-07-01 20:10 ` [ndctl PATCH v3 17/21] test/libcxl: add a test for cxl_memdev_{get,set}_lsa Vishal Verma
2021-07-01 20:10 ` [ndctl PATCH v3 18/21] cxl: add commands to read, write, and zero labels Vishal Verma
2021-07-01 20:10 ` [ndctl PATCH v3 19/21] Documentation/cxl: add library API documentation Vishal Verma
2021-07-01 20:10 ` [ndctl PATCH v3 20/21] ndctl: Add CXL packages to the RPM spec Vishal Verma
2021-07-01 20:10 ` [ndctl PATCH v3 21/21] cxl-cli: add bash completion Vishal Verma
2021-07-01 20:13 ` [ndctl PATCH v3 00/21] Initial CXL support Verma, Vishal L

This is a public inbox, see mirroring instructions
on how to clone and mirror all data and code used for this inbox