diff mbox series

[v4,5/5] DONOTMERGE: PCI/DOE: Add userspace example program to tools/pci

Message ID 20210524133938.2815206-6-Jonathan.Cameron@huawei.com
State New, archived
Headers show
Series PCI Data Object Exchange support + CXL CDAT | expand

Commit Message

Jonathan Cameron May 24, 2021, 1:39 p.m. UTC
The example uses the Discovery Protocol to illustrate the
use of the IOCTL interface to access the DOE mailboxes form
userspace.

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 tools/pci/Build     |   1 +
 tools/pci/Makefile  |   9 ++-
 tools/pci/doetest.c | 131 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 140 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/tools/pci/Build b/tools/pci/Build
index c375aea21790..af4521bebf93 100644
--- a/tools/pci/Build
+++ b/tools/pci/Build
@@ -1 +1,2 @@ 
 pcitest-y += pcitest.o
+doetest-y += doetest.o
diff --git a/tools/pci/Makefile b/tools/pci/Makefile
index 4b95a5176355..b2e54afe583c 100644
--- a/tools/pci/Makefile
+++ b/tools/pci/Makefile
@@ -14,7 +14,7 @@  MAKEFLAGS += -r
 
 CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
 
-ALL_TARGETS := pcitest
+ALL_TARGETS := pcitest doetest
 ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
 
 SCRIPTS := pcitest.sh
@@ -30,6 +30,7 @@  include $(srctree)/tools/build/Makefile.include
 $(OUTPUT)include/linux/: ../../include/uapi/linux/
 	mkdir -p $(OUTPUT)include/linux/ 2>&1 || true
 	ln -sf $(CURDIR)/../../include/uapi/linux/pcitest.h $@
+	ln -sf $(CURDIR)/../../include/uapi/linux/pci_doe.h $@
 
 prepare: $(OUTPUT)include/linux/
 
@@ -39,6 +40,12 @@  $(PCITEST_IN): prepare FORCE
 $(OUTPUT)pcitest: $(PCITEST_IN)
 	$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
 
+DOETEST_IN := $(OUTPUT)doetest-in.o
+$(DOETEST_IN): prepare FORCE
+	$(Q)$(MAKE) $(build)=doetest
+$(OUTPUT)doetest: $(DOETEST_IN)
+	$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
+
 clean:
 	rm -f $(ALL_PROGRAMS)
 	rm -rf $(OUTPUT)include/
diff --git a/tools/pci/doetest.c b/tools/pci/doetest.c
new file mode 100644
index 000000000000..b2db847b1503
--- /dev/null
+++ b/tools/pci/doetest.c
@@ -0,0 +1,131 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Example user of the DOE userspace interface.
+ *
+ * Jonathan Cameron <Jonathan.Cameron@huawei.com>
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <linux/types.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <getopt.h>
+#include <string.h>
+
+struct pci_doe_uexchange {
+	__u16 vid;
+	__u8 protocol;
+	__u8 rsvd;
+	__u32 retval;
+	struct {
+		__s32 size;
+		__u32 rsvd;
+		__u64 payload;
+	} in;
+	struct {
+		__s32 size;
+		__u32 rsvd;
+		__u64 payload;
+	} out;
+};
+
+#define PCI_DOE_EXCHANGE _IOWR(0xDA, 1, struct pci_doe_uexchange)
+
+int doe_list_protocols(int fd)
+{
+	__u32 outbuf = 0;
+	__u32 inbuf; /* Start with index 0 */
+	struct pci_doe_uexchange ex = {
+		.vid = 33,
+		.protocol = 1,
+		.in.size = sizeof(inbuf),
+		.in.payload = (__u64)&inbuf,
+		.out.size = sizeof(outbuf),
+		.out.payload = (__u64)&outbuf,
+		.vid = 0x01, /* PCI SIG */
+		.protocol = 0x00,
+	};
+	int rc;
+	uint8_t index = 0;
+
+	do {
+		inbuf = index;
+		rc = ioctl(fd, PCI_DOE_EXCHANGE, &ex);
+		if (rc) {
+			printf("IOCTL error: %d\n", rc);
+			return rc;
+		}
+		if (ex.retval) {
+			printf("DOE return value indicates failure: %d\n", ex.retval);
+			return ex.retval;
+		}
+		index = outbuf >> 24;
+
+		printf("VID: %#x, Protocol: %#x\n", outbuf & 0xffff, (outbuf >> 16) & 0xff);
+	} while (index);
+
+	return 0;
+}
+
+static const struct option longopts[] = {
+	{ "filename",		1, 0, 'f' },
+	{ }
+};
+
+static void print_usage(void)
+{
+	fprintf(stderr, "Usage: doe [options]...\n"
+		"Example userspace access to a PCI DOE mailbox\n"
+		"  -f <filename>	Path to chardev /dev/pcidoe/...\n"
+		"  -l			List supported protocols\n");
+}
+
+int main(int argc, char **argv)
+{
+	char *filename = NULL;
+	bool run_discovery = false;
+	int fd, c;
+	int rc = 0;
+
+	while ((c = getopt_long(argc, argv, "?f:l", longopts, NULL)) != -1) {
+		switch (c) {
+		case 'f':
+			filename = strdup(optarg);
+			break;
+		case 'l':
+			run_discovery = true;
+			break;
+		case '?':
+			print_usage();
+			goto free_filename;
+		}
+	}
+	if (!filename) {
+		fprintf(stderr, "Filename must be supplied using -f FILENAME\n");
+		rc = -1;
+		/* No need to actually free the filename, but keep exit path simple */
+		goto free_filename;
+	}
+
+	fd = open(filename, 0);
+	if (fd == -1) {
+		fprintf(stderr, "Could not open file %s\n", filename);
+		rc = -1;
+		goto free_filename;
+	}
+	if (run_discovery) {
+		rc = doe_list_protocols(fd);
+		if (rc)
+			goto close_fd;
+	}
+close_fd:
+	close(fd);
+free_filename:
+	free(filename);
+
+	return rc;
+}