New upstream version 18.05
[deb_dpdk.git] / drivers / crypto / ccp / ccp_pci.c
diff --git a/drivers/crypto/ccp/ccp_pci.c b/drivers/crypto/ccp/ccp_pci.c
new file mode 100644 (file)
index 0000000..59152ca
--- /dev/null
@@ -0,0 +1,236 @@
+/*   SPDX-License-Identifier: BSD-3-Clause
+ *   Copyright(c) 2018 Advanced Micro Devices, Inc. All rights reserved.
+ */
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <rte_string_fns.h>
+
+#include "ccp_pci.h"
+
+static const char * const uio_module_names[] = {
+       "igb_uio",
+       "uio_pci_generic",
+};
+
+int
+ccp_check_pci_uio_module(void)
+{
+       FILE *fp;
+       int i;
+       char buf[BUFSIZ];
+
+       fp = fopen(PROC_MODULES, "r");
+       if (fp == NULL)
+               return -1;
+       i = 0;
+       while (uio_module_names[i] != NULL) {
+               while (fgets(buf, sizeof(buf), fp) != NULL) {
+                       if (!strncmp(buf, uio_module_names[i],
+                                    strlen(uio_module_names[i])))
+                               return i;
+               }
+               i++;
+               rewind(fp);
+       }
+       printf("Insert igb_uio or uio_pci_generic kernel module(s)");
+       return -1;/* uio not inserted */
+}
+
+/*
+ * split up a pci address into its constituent parts.
+ */
+int
+ccp_parse_pci_addr_format(const char *buf, int bufsize, uint16_t *domain,
+                         uint8_t *bus, uint8_t *devid, uint8_t *function)
+{
+       /* first split on ':' */
+       union splitaddr {
+               struct {
+                       char *domain;
+                       char *bus;
+                       char *devid;
+                       char *function;
+               };
+               char *str[PCI_FMT_NVAL];
+               /* last element-separator is "." not ":" */
+       } splitaddr;
+
+       char *buf_copy = strndup(buf, bufsize);
+
+       if (buf_copy == NULL)
+               return -1;
+
+       if (rte_strsplit(buf_copy, bufsize, splitaddr.str, PCI_FMT_NVAL, ':')
+                       != PCI_FMT_NVAL - 1)
+               goto error;
+       /* final split is on '.' between devid and function */
+       splitaddr.function = strchr(splitaddr.devid, '.');
+       if (splitaddr.function == NULL)
+               goto error;
+       *splitaddr.function++ = '\0';
+
+       /* now convert to int values */
+       errno = 0;
+       *domain = (uint8_t)strtoul(splitaddr.domain, NULL, 16);
+       *bus = (uint8_t)strtoul(splitaddr.bus, NULL, 16);
+       *devid = (uint8_t)strtoul(splitaddr.devid, NULL, 16);
+       *function = (uint8_t)strtoul(splitaddr.function, NULL, 10);
+       if (errno != 0)
+               goto error;
+
+       free(buf_copy); /* free the copy made with strdup */
+       return 0;
+error:
+       free(buf_copy);
+       return -1;
+}
+
+int
+ccp_pci_parse_sysfs_value(const char *filename, unsigned long *val)
+{
+       FILE *f;
+       char buf[BUFSIZ];
+       char *end = NULL;
+
+       f = fopen(filename, "r");
+       if (f == NULL)
+               return -1;
+       if (fgets(buf, sizeof(buf), f) == NULL) {
+               fclose(f);
+               return -1;
+       }
+       *val = strtoul(buf, &end, 0);
+       if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) {
+               fclose(f);
+               return -1;
+       }
+       fclose(f);
+       return 0;
+}
+
+/** IO resource type: */
+#define IORESOURCE_IO         0x00000100
+#define IORESOURCE_MEM        0x00000200
+
+/* parse one line of the "resource" sysfs file (note that the 'line'
+ * string is modified)
+ */
+static int
+ccp_pci_parse_one_sysfs_resource(char *line, size_t len, uint64_t *phys_addr,
+                                uint64_t *end_addr, uint64_t *flags)
+{
+       union pci_resource_info {
+               struct {
+                       char *phys_addr;
+                       char *end_addr;
+                       char *flags;
+               };
+               char *ptrs[PCI_RESOURCE_FMT_NVAL];
+       } res_info;
+
+       if (rte_strsplit(line, len, res_info.ptrs, 3, ' ') != 3)
+               return -1;
+       errno = 0;
+       *phys_addr = strtoull(res_info.phys_addr, NULL, 16);
+       *end_addr = strtoull(res_info.end_addr, NULL, 16);
+       *flags = strtoull(res_info.flags, NULL, 16);
+       if (errno != 0)
+               return -1;
+
+       return 0;
+}
+
+/* parse the "resource" sysfs file */
+int
+ccp_pci_parse_sysfs_resource(const char *filename, struct rte_pci_device *dev)
+{
+       FILE *fp;
+       char buf[BUFSIZ];
+       int i;
+       uint64_t phys_addr, end_addr, flags;
+
+       fp = fopen(filename, "r");
+       if (fp == NULL)
+               return -1;
+
+       for (i = 0; i < PCI_MAX_RESOURCE; i++) {
+               if (fgets(buf, sizeof(buf), fp) == NULL)
+                       goto error;
+               if (ccp_pci_parse_one_sysfs_resource(buf, sizeof(buf),
+                               &phys_addr, &end_addr, &flags) < 0)
+                       goto error;
+
+               if (flags & IORESOURCE_MEM) {
+                       dev->mem_resource[i].phys_addr = phys_addr;
+                       dev->mem_resource[i].len = end_addr - phys_addr + 1;
+                       /* not mapped for now */
+                       dev->mem_resource[i].addr = NULL;
+               }
+       }
+       fclose(fp);
+       return 0;
+
+error:
+       fclose(fp);
+       return -1;
+}
+
+int
+ccp_find_uio_devname(const char *dirname)
+{
+
+       DIR *dir;
+       struct dirent *e;
+       char dirname_uio[PATH_MAX];
+       unsigned int uio_num;
+       int ret = -1;
+
+       /* depending on kernel version, uio can be located in uio/uioX
+        * or uio:uioX
+        */
+       snprintf(dirname_uio, sizeof(dirname_uio), "%s/uio", dirname);
+       dir = opendir(dirname_uio);
+       if (dir == NULL) {
+       /* retry with the parent directory might be different kernel version*/
+               dir = opendir(dirname);
+               if (dir == NULL)
+                       return -1;
+       }
+
+       /* take the first file starting with "uio" */
+       while ((e = readdir(dir)) != NULL) {
+               /* format could be uio%d ...*/
+               int shortprefix_len = sizeof("uio") - 1;
+               /* ... or uio:uio%d */
+               int longprefix_len = sizeof("uio:uio") - 1;
+               char *endptr;
+
+               if (strncmp(e->d_name, "uio", 3) != 0)
+                       continue;
+
+               /* first try uio%d */
+               errno = 0;
+               uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10);
+               if (errno == 0 && endptr != (e->d_name + shortprefix_len)) {
+                       ret = uio_num;
+                       break;
+               }
+
+               /* then try uio:uio%d */
+               errno = 0;
+               uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10);
+               if (errno == 0 && endptr != (e->d_name + longprefix_len)) {
+                       ret = uio_num;
+                       break;
+               }
+       }
+       closedir(dir);
+       return ret;
+
+
+}