// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
/*
* nfp_resource . c
* Author : Jakub Kicinski < jakub . kicinski @ netronome . com >
* Jason McMullan < jason . mcmullan @ netronome . com >
*/
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include "crc32.h"
#include "nfp.h"
#include "nfp_cpp.h"
#include "nfp6000/nfp6000.h"
#define NFP_RESOURCE_TBL_TARGET NFP_CPP_TARGET_MU
#define NFP_RESOURCE_TBL_BASE 0 x8100000000ULL
/* NFP Resource Table self-identifier */
#define NFP_RESOURCE_TBL_NAME "nfp.res"
#define NFP_RESOURCE_TBL_KEY 0 x00000000 /* Special key for entry 0 */
#define NFP_RESOURCE_ENTRY_NAME_SZ 8
/**
* struct nfp_resource_entry - Resource table entry
* @ mutex : NFP CPP Lock
* @ mutex . owner : NFP CPP Lock , interface owner
* @ mutex . key : NFP CPP Lock , posix_crc32 ( name , 8 )
* @ region : Memory region descriptor
* @ region . name : ASCII , zero padded name
* @ region . reserved : padding
* @ region . cpp_action : CPP Action
* @ region . cpp_token : CPP Token
* @ region . cpp_target : CPP Target ID
* @ region . page_offset : 256 - byte page offset into target ' s CPP address
* @ region . page_size : size , in 256 - byte pages
*/
struct nfp_resource_entry {
struct nfp_resource_entry_mutex {
u32 owner;
u32 key;
} mutex;
struct nfp_resource_entry_region {
u8 name[NFP_RESOURCE_ENTRY_NAME_SZ];
u8 reserved[5 ];
u8 cpp_action;
u8 cpp_token;
u8 cpp_target;
u32 page_offset;
u32 page_size;
} region;
};
#define NFP_RESOURCE_TBL_SIZE 4096
#define NFP_RESOURCE_TBL_ENTRIES (NFP_RESOURCE_TBL_SIZE / \
sizeof (struct nfp_resource_entry))
struct nfp_resource {
char name[NFP_RESOURCE_ENTRY_NAME_SZ + 1 ];
u32 cpp_id;
u64 addr;
u64 size;
struct nfp_cpp_mutex *mutex;
};
static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
{
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 */
/* Search for a matching entry */
if (!strcmp(res->name, NFP_RESOURCE_TBL_NAME)) {
nfp_err(cpp, "Grabbing device lock not supported\n" );
return -EOPNOTSUPP;
}
key = crc32_posix(res->name, NFP_RESOURCE_ENTRY_NAME_SZ);
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_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)
{
unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
unsigned long err_at = jiffies + NFP_MUTEX_WAIT_ERROR * 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);
strscpy(res->name, name, sizeof (res->name));
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 + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
nfp_warn(cpp, "Warning: waiting for NFP resource %s\n" ,
name);
}
if (time_is_before_eq_jiffies(err_at)) {
nfp_err(cpp, "Error: resource %s timed out\n" , name);
err = -EBUSY;
goto err_free;
}
}
nfp_cpp_mutex_free(dev_mutex);
return res;
err_free:
nfp_cpp_mutex_free(dev_mutex);
kfree(res);
return ERR_PTR(err);
}
/**
* 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);
kfree(res);
}
/**
* nfp_resource_wait ( ) - Wait for resource to appear
* @ cpp : NFP CPP handle
* @ name : Name of the resource
* @ secs : Number of seconds to wait
*
* Wait for resource to appear in the resource table , grab and release
* its lock . The wait is jiffies - based , don ' t expect fine granularity .
*
* Return : 0 on success , errno otherwise .
*/
int nfp_resource_wait(struct nfp_cpp *cpp, const char *name, unsigned int secs)
{
unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
unsigned long err_at = jiffies + secs * HZ;
struct nfp_resource *res;
while (true ) {
res = nfp_resource_acquire(cpp, name);
if (!IS_ERR(res)) {
nfp_resource_release(res);
return 0 ;
}
if (PTR_ERR(res) != -ENOENT) {
nfp_err(cpp, "error waiting for resource %s: %ld\n" ,
name, PTR_ERR(res));
return PTR_ERR(res);
}
if (time_is_before_eq_jiffies(err_at)) {
nfp_err(cpp, "timeout waiting for resource %s\n" , name);
return -ETIMEDOUT;
}
if (time_is_before_eq_jiffies(warn_at)) {
warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
nfp_info(cpp, "waiting for NFP resource %s\n" , name);
}
if (msleep_interruptible(10 )) {
nfp_err(cpp, "wait for resource %s interrupted\n" ,
name);
return -ERESTARTSYS;
}
}
}
/**
* nfp_resource_cpp_id ( ) - Return the cpp_id of a resource handle
* @ res : NFP Resource handle
*
* Return : NFP CPP ID
*/
u32 nfp_resource_cpp_id(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(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
*/
u64 nfp_resource_address(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
*/
u64 nfp_resource_size(struct nfp_resource *res)
{
return res->size;
}
/**
* nfp_resource_table_init ( ) - Run initial checks on the resource table
* @ cpp : NFP CPP handle
*
* Start - of - day init procedure for resource table . Must be called before
* any local resource table users may exist .
*
* Return : 0 on success , - errno on failure
*/
int nfp_resource_table_init(struct nfp_cpp *cpp)
{
struct nfp_cpp_mutex *dev_mutex;
int i, err;
err = nfp_cpp_mutex_reclaim(cpp, NFP_RESOURCE_TBL_TARGET,
NFP_RESOURCE_TBL_BASE);
if (err < 0 ) {
nfp_err(cpp, "Error: failed to reclaim resource table mutex\n" );
return err;
}
if (err)
nfp_warn(cpp, "Warning: busted main resource table mutex\n" );
dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
NFP_RESOURCE_TBL_BASE,
NFP_RESOURCE_TBL_KEY);
if (!dev_mutex)
return -ENOMEM;
if (nfp_cpp_mutex_lock(dev_mutex)) {
nfp_err(cpp, "Error: failed to claim resource table mutex\n" );
nfp_cpp_mutex_free(dev_mutex);
return -EINVAL;
}
/* Resource 0 is the dev_mutex, start from 1 */
for (i = 1 ; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
u64 addr = NFP_RESOURCE_TBL_BASE +
sizeof (struct nfp_resource_entry) * i;
err = nfp_cpp_mutex_reclaim(cpp, NFP_RESOURCE_TBL_TARGET, addr);
if (err < 0 ) {
nfp_err(cpp,
"Error: failed to reclaim resource %d mutex\n" ,
i);
goto err_unlock;
}
if (err)
nfp_warn(cpp, "Warning: busted resource %d mutex\n" , i);
}
err = 0 ;
err_unlock:
nfp_cpp_mutex_unlock(dev_mutex);
nfp_cpp_mutex_free(dev_mutex);
return err;
}
Messung V0.5 in Prozent C=87 H=95 G=90
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-10-12)
¤
*© Formatika GbR, Deutschland