New upstream version 18.08
[deb_dpdk.git] / drivers / net / nfp / nfpcore / nfp_resource.c
diff --git a/drivers/net/nfp/nfpcore/nfp_resource.c b/drivers/net/nfp/nfpcore/nfp_resource.c
new file mode 100644 (file)
index 0000000..dd41fa4
--- /dev/null
@@ -0,0 +1,266 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Netronome Systems, Inc.
+ * All rights reserved.
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <endian.h>
+
+#include <rte_string_fns.h>
+
+#include "nfp_cpp.h"
+#include "nfp6000/nfp6000.h"
+#include "nfp_resource.h"
+#include "nfp_crc.h"
+
+#define NFP_RESOURCE_TBL_TARGET                NFP_CPP_TARGET_MU
+#define NFP_RESOURCE_TBL_BASE          0x8100000000ULL
+
+/* NFP Resource Table self-identifier */
+#define NFP_RESOURCE_TBL_NAME          "nfp.res"
+#define NFP_RESOURCE_TBL_KEY           0x00000000 /* Special key for entry 0 */
+
+#define NFP_RESOURCE_ENTRY_NAME_SZ     8
+
+/*
+ * struct nfp_resource_entry - Resource table entry
+ * @owner:             NFP CPP Lock, interface owner
+ * @key:               NFP CPP Lock, posix_crc32(name, 8)
+ * @region:            Memory region descriptor
+ * @name:              ASCII, zero padded name
+ * @reserved
+ * @cpp_action:                CPP Action
+ * @cpp_token:         CPP Token
+ * @cpp_target:                CPP Target ID
+ * @page_offset:       256-byte page offset into target's CPP address
+ * @page_size:         size, in 256-byte pages
+ */
+struct nfp_resource_entry {
+       struct nfp_resource_entry_mutex {
+               uint32_t owner;
+               uint32_t key;
+       } mutex;
+       struct nfp_resource_entry_region {
+               uint8_t  name[NFP_RESOURCE_ENTRY_NAME_SZ];
+               uint8_t  reserved[5];
+               uint8_t  cpp_action;
+               uint8_t  cpp_token;
+               uint8_t  cpp_target;
+               uint32_t page_offset;
+               uint32_t page_size;
+       } region;
+};
+
+#define NFP_RESOURCE_TBL_SIZE          4096
+#define NFP_RESOURCE_TBL_ENTRIES       (int)(NFP_RESOURCE_TBL_SIZE /   \
+                                        sizeof(struct nfp_resource_entry))
+
+struct nfp_resource {
+       char name[NFP_RESOURCE_ENTRY_NAME_SZ + 1];
+       uint32_t cpp_id;
+       uint64_t addr;
+       uint64_t size;
+       struct nfp_cpp_mutex *mutex;
+};
+
+static int
+nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
+{
+       char name_pad[NFP_RESOURCE_ENTRY_NAME_SZ + 2];
+       struct nfp_resource_entry entry;
+       uint32_t cpp_id, key;
+       int ret, i;
+
+       cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0);  /* Atomic read */
+
+       memset(name_pad, 0, sizeof(name_pad));
+       strlcpy(name_pad, res->name, sizeof(name_pad));
+
+       /* Search for a matching entry */
+       if (!memcmp(name_pad, NFP_RESOURCE_TBL_NAME "\0\0\0\0\0\0\0\0", 8)) {
+               printf("Grabbing device lock not supported\n");
+               return -EOPNOTSUPP;
+       }
+       key = nfp_crc32_posix(name_pad, NFP_RESOURCE_ENTRY_NAME_SZ);
+
+       for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
+               uint64_t addr = NFP_RESOURCE_TBL_BASE +
+                       sizeof(struct nfp_resource_entry) * i;
+
+               ret = nfp_cpp_read(cpp, cpp_id, addr, &entry, sizeof(entry));
+               if (ret != sizeof(entry))
+                       return -EIO;
+
+               if (entry.mutex.key != key)
+                       continue;
+
+               /* Found key! */
+               res->mutex =
+                       nfp_cpp_mutex_alloc(cpp,
+                                           NFP_RESOURCE_TBL_TARGET, addr, key);
+               res->cpp_id = NFP_CPP_ID(entry.region.cpp_target,
+                                        entry.region.cpp_action,
+                                        entry.region.cpp_token);
+               res->addr = ((uint64_t)entry.region.page_offset) << 8;
+               res->size = (uint64_t)entry.region.page_size << 8;
+               return 0;
+       }
+
+       return -ENOENT;
+}
+
+static int
+nfp_resource_try_acquire(struct nfp_cpp *cpp, struct nfp_resource *res,
+                        struct nfp_cpp_mutex *dev_mutex)
+{
+       int err;
+
+       if (nfp_cpp_mutex_lock(dev_mutex))
+               return -EINVAL;
+
+       err = nfp_cpp_resource_find(cpp, res);
+       if (err)
+               goto err_unlock_dev;
+
+       err = nfp_cpp_mutex_trylock(res->mutex);
+       if (err)
+               goto err_res_mutex_free;
+
+       nfp_cpp_mutex_unlock(dev_mutex);
+
+       return 0;
+
+err_res_mutex_free:
+       nfp_cpp_mutex_free(res->mutex);
+err_unlock_dev:
+       nfp_cpp_mutex_unlock(dev_mutex);
+
+       return err;
+}
+
+/*
+ * nfp_resource_acquire() - Acquire a resource handle
+ * @cpp:       NFP CPP handle
+ * @name:      Name of the resource
+ *
+ * NOTE: This function locks the acquired resource
+ *
+ * Return: NFP Resource handle, or ERR_PTR()
+ */
+struct nfp_resource *
+nfp_resource_acquire(struct nfp_cpp *cpp, const char *name)
+{
+       struct nfp_cpp_mutex *dev_mutex;
+       struct nfp_resource *res;
+       int err;
+       struct timespec wait;
+       int count;
+
+       res = malloc(sizeof(*res));
+       if (!res)
+               return NULL;
+
+       memset(res, 0, sizeof(*res));
+
+       strncpy(res->name, name, NFP_RESOURCE_ENTRY_NAME_SZ);
+
+       dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
+                                       NFP_RESOURCE_TBL_BASE,
+                                       NFP_RESOURCE_TBL_KEY);
+       if (!dev_mutex) {
+               free(res);
+               return NULL;
+       }
+
+       wait.tv_sec = 0;
+       wait.tv_nsec = 1000000;
+       count = 0;
+
+       for (;;) {
+               err = nfp_resource_try_acquire(cpp, res, dev_mutex);
+               if (!err)
+                       break;
+               if (err != -EBUSY)
+                       goto err_free;
+
+               if (count++ > 1000) {
+                       printf("Error: resource %s timed out\n", name);
+                       err = -EBUSY;
+                       goto err_free;
+               }
+
+               nanosleep(&wait, NULL);
+       }
+
+       nfp_cpp_mutex_free(dev_mutex);
+
+       return res;
+
+err_free:
+       nfp_cpp_mutex_free(dev_mutex);
+       free(res);
+       return NULL;
+}
+
+/*
+ * nfp_resource_release() - Release a NFP Resource handle
+ * @res:       NFP Resource handle
+ *
+ * NOTE: This function implictly unlocks the resource handle
+ */
+void
+nfp_resource_release(struct nfp_resource *res)
+{
+       nfp_cpp_mutex_unlock(res->mutex);
+       nfp_cpp_mutex_free(res->mutex);
+       free(res);
+}
+
+/*
+ * nfp_resource_cpp_id() - Return the cpp_id of a resource handle
+ * @res:        NFP Resource handle
+ *
+ * Return: NFP CPP ID
+ */
+uint32_t
+nfp_resource_cpp_id(const struct nfp_resource *res)
+{
+       return res->cpp_id;
+}
+
+/*
+ * nfp_resource_name() - Return the name of a resource handle
+ * @res:        NFP Resource handle
+ *
+ * Return: const char pointer to the name of the resource
+ */
+const char
+*nfp_resource_name(const struct nfp_resource *res)
+{
+       return res->name;
+}
+
+/*
+ * nfp_resource_address() - Return the address of a resource handle
+ * @res:        NFP Resource handle
+ *
+ * Return: Address of the resource
+ */
+uint64_t
+nfp_resource_address(const struct nfp_resource *res)
+{
+       return res->addr;
+}
+
+/*
+ * nfp_resource_size() - Return the size in bytes of a resource handle
+ * @res:        NFP Resource handle
+ *
+ * Return: Size of the resource in bytes
+ */
+uint64_t
+nfp_resource_size(const struct nfp_resource *res)
+{
+       return res->size;
+}