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@xxxxxxxxxx> --- tools/pci/Build | 1 + tools/pci/Makefile | 9 ++- tools/pci/doetest.c | 131 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 1 deletion(-) 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@xxxxxxxxxx> + */ + +#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; +} -- 2.19.1