static int __nfp_resource_entry_init(struct nfp_cpp *cpp, int entry, const struct nfp_resource_entry_region *region, struct nfp_cpp_mutex **resource_mutex) { struct nfp_cpp_mutex *mutex; int target, entries; size_t size; u32 cpp_id; u32 key; int err; u64 base; entries = nfp_cpp_resource_table(cpp, &target, &base, &size); if (entries < 0) return entries; if (entry >= entries) return -EINVAL; base += sizeof(struct nfp_resource_entry) * entry; if (entry == 0) key = NFP_RESOURCE_TABLE_KEY; else key = crc32_posix(region->name, 8); err = nfp_cpp_mutex_init(cpp, target, base, key); if (err < 0) return err; /* We already own the initialized lock */ mutex = nfp_cpp_mutex_alloc(cpp, target, base, key); if (!mutex) return -ENOMEM; /* Mutex Owner and Key are already set */ cpp_id = NFP_CPP_ID(target, 4, 0); /* Atomic write */ err = nfp_cpp_write(cpp, cpp_id, base + offsetof(struct nfp_resource_entry, region), region, sizeof(*region)); if (err < 0) { /* Try to unlock in the face of adversity */ nfp_cpp_mutex_unlock(mutex); nfp_cpp_mutex_free(mutex); return err; } if (resource_mutex) { *resource_mutex = mutex; } else { nfp_cpp_mutex_unlock(mutex); nfp_cpp_mutex_free(mutex); } return 0; }
/** * 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) { unsigned long warn_at = jiffies + 15 * HZ; struct nfp_cpp_mutex *dev_mutex; struct nfp_resource *res; int err; res = kzalloc(sizeof(*res), GFP_KERNEL); if (!res) return ERR_PTR(-ENOMEM); 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) { kfree(res); return ERR_PTR(-ENOMEM); } for (;;) { err = nfp_resource_try_acquire(cpp, res, dev_mutex); if (!err) break; if (err != -EBUSY) goto err_free; err = msleep_interruptible(1); if (err != 0) { err = -ERESTARTSYS; goto err_free; } if (time_is_before_eq_jiffies(warn_at)) { warn_at = jiffies + 60 * HZ; nfp_warn(cpp, "Warning: waiting for NFP resource %s\n", name); } } nfp_cpp_mutex_free(dev_mutex); return res; err_free: nfp_cpp_mutex_free(dev_mutex); kfree(res); return ERR_PTR(err); }
static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res) { char name_pad[NFP_RESOURCE_ENTRY_NAME_SZ] = {}; struct nfp_resource_entry entry; u32 cpp_id, key; int ret, i; cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0); /* Atomic read */ strncpy(name_pad, res->name, sizeof(name_pad)); /* Search for a matching entry */ key = NFP_RESOURCE_TBL_KEY; if (memcmp(name_pad, NFP_RESOURCE_TBL_NAME "\0\0\0\0\0\0\0\0", 8)) key = crc32_posix(name_pad, sizeof(name_pad)); for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) { u64 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 = (u64)entry.region.page_offset << 8; res->size = (u64)entry.region.page_size << 8; return 0; } return -ENOENT; }
static int nfp_cpp_resource_acquire(struct nfp_cpp *cpp, const char *name, u32 *r_cpp, u64 *r_addr, u64 *r_size, struct nfp_cpp_mutex **resource_mutex) { struct nfp_resource_entry_region region; struct nfp_resource_entry tmp; struct nfp_cpp_mutex *mutex; int target, err, i, entries; u64 base; u32 key; u32 cpp_id; for (i = 0; i < sizeof(region.name); i++) { if (*name != 0) region.name[i] = *(name++); else region.name[i] = 0; } entries = nfp_cpp_resource_table(cpp, &target, &base, NULL); if (entries < 0) return entries; cpp_id = NFP_CPP_ID(target, 3, 0); /* Atomic read */ key = NFP_RESOURCE_TABLE_KEY; mutex = nfp_cpp_mutex_alloc(cpp, target, base, key); if (!mutex) return -ENOMEM; /* Wait for the lock.. */ err = nfp_cpp_mutex_lock(mutex); if (err < 0) { nfp_cpp_mutex_free(mutex); return err; } /* Search for a matching entry */ if (memcmp(region.name, NFP_RESOURCE_TABLE_NAME "\0\0\0\0\0\0\0\0", 8) != 0) key = crc32_posix(®ion.name[0], sizeof(region.name)); for (i = 0; i < entries; i++) { u64 addr = base + sizeof(struct nfp_resource_entry) * i; err = nfp_cpp_read(cpp, cpp_id, addr, &tmp, sizeof(tmp)); if (err < 0) { /* Unlikely to work if the read failed, * but we should at least try... */ nfp_cpp_mutex_unlock(mutex); nfp_cpp_mutex_free(mutex); return err; } if (tmp.mutex.key == key) { /* Found key! */ if (resource_mutex) *resource_mutex = nfp_cpp_mutex_alloc(cpp, target, addr, key); if (r_cpp) *r_cpp = NFP_CPP_ID(tmp.region.cpp_target, tmp.region.cpp_action, tmp.region.cpp_token); if (r_addr) *r_addr = (u64)tmp.region.page_offset << 8; if (r_size) *r_size = (u64)tmp.region.page_size << 8; nfp_cpp_mutex_unlock(mutex); nfp_cpp_mutex_free(mutex); return 0; } } nfp_cpp_mutex_unlock(mutex); nfp_cpp_mutex_free(mutex); return -ENOENT; }
/** * nfp_cpp_resource_add() - Construct a new NFP Resource entry * @cpp: NFP CPP handle * @name: Name of the resource * @cpp_id: NFP CPP ID of the resource * @address: NFP CPP address of the resource * @size: Size, in bytes, of the resource area * @resource_mutex: Location to place the resource's mutex * * NOTE: If resource_mutex is NULL, the mutex of the resource is * implictly unlocked. * * Return: 0, or -ERRNO */ int nfp_cpp_resource_add(struct nfp_cpp *cpp, const char *name, u32 cpp_id, u64 address, u64 size, struct nfp_cpp_mutex **resource_mutex) { int target, err, i, entries, minfree; u64 base; u32 key; struct nfp_resource_entry_region region = { .cpp_action = NFP_CPP_ID_ACTION_of(cpp_id), .cpp_token = NFP_CPP_ID_TOKEN_of(cpp_id), .cpp_target = NFP_CPP_ID_TARGET_of(cpp_id), .page_offset = (u32)(address >> 8), .page_size = (u32)(size >> 8), }; struct nfp_cpp_mutex *mutex; u32 tmp; for (i = 0; i < sizeof(region.name); i++) { if (*name != 0) region.name[i] = *(name++); else region.name[i] = 0; } entries = nfp_cpp_resource_table(cpp, &target, &base, NULL); if (entries < 0) return entries; cpp_id = NFP_CPP_ID(target, 3, 0); /* Atomic read */ key = NFP_RESOURCE_TABLE_KEY; mutex = nfp_cpp_mutex_alloc(cpp, target, base, key); if (!mutex) return -ENOMEM; /* Wait for the lock.. */ err = nfp_cpp_mutex_lock(mutex); if (err < 0) { nfp_cpp_mutex_free(mutex); return err; } /* Search for a free entry, or a duplicate */ minfree = 0; key = crc32_posix(name, 8); for (i = 1; i < entries; i++) { u64 addr = base + sizeof(struct nfp_resource_entry) * i; err = nfp_cpp_readl(cpp, cpp_id, addr + offsetof(struct nfp_resource_entry, mutex.key), &tmp); if (err < 0) { /* Unlikely to work if the read failed, * but we should at least try... */ nfp_cpp_mutex_unlock(mutex); nfp_cpp_mutex_free(mutex); return err; } if (tmp == key) { /* Duplicate key! */ nfp_cpp_mutex_unlock(mutex); nfp_cpp_mutex_free(mutex); return -EEXIST; } if (tmp == 0 && minfree == 0) minfree = i; } /* No available space in the table! */ if (minfree == 0) return -ENOSPC; err = __nfp_resource_entry_init(cpp, minfree, ®ion, resource_mutex); nfp_cpp_mutex_unlock(mutex); nfp_cpp_mutex_free(mutex); return err; }