drivers/net/ethernet/marvell/prestera/prestera_counter.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/marvell/prestera/prestera_counter.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/marvell/prestera/prestera_counter.c
Extension
.c
Size
11271 bytes
Lines
474
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct prestera_counter {
	struct prestera_switch *sw;
	struct delayed_work stats_dw;
	struct mutex mtx;  /* protect block_list */
	struct prestera_counter_block **block_list;
	u32 total_read;
	u32 block_list_len;
	u32 curr_idx;
	bool is_fetching;
};

struct prestera_counter_block {
	struct list_head list;
	u32 id;
	u32 offset;
	u32 num_counters;
	u32 client;
	struct idr counter_idr;
	refcount_t refcnt;
	struct mutex mtx;  /* protect stats and counter_idr */
	struct prestera_counter_stats *stats;
	u8 *counter_flag;
	bool is_updating;
	bool full;
};

enum {
	COUNTER_FLAG_READY = 0,
	COUNTER_FLAG_INVALID = 1
};

static bool
prestera_counter_is_ready(struct prestera_counter_block *block, u32 id)
{
	return block->counter_flag[id - block->offset] == COUNTER_FLAG_READY;
}

static void prestera_counter_lock(struct prestera_counter *counter)
{
	mutex_lock(&counter->mtx);
}

static void prestera_counter_unlock(struct prestera_counter *counter)
{
	mutex_unlock(&counter->mtx);
}

static void prestera_counter_block_lock(struct prestera_counter_block *block)
{
	mutex_lock(&block->mtx);
}

static void prestera_counter_block_unlock(struct prestera_counter_block *block)
{
	mutex_unlock(&block->mtx);
}

static bool prestera_counter_block_incref(struct prestera_counter_block *block)
{
	return refcount_inc_not_zero(&block->refcnt);
}

static bool prestera_counter_block_decref(struct prestera_counter_block *block)
{
	return refcount_dec_and_test(&block->refcnt);
}

/* must be called with prestera_counter_block_lock() */
static void prestera_counter_stats_clear(struct prestera_counter_block *block,
					 u32 counter_id)
{
	memset(&block->stats[counter_id - block->offset], 0,
	       sizeof(*block->stats));
}

static struct prestera_counter_block *
prestera_counter_block_lookup_not_full(struct prestera_counter *counter,
				       u32 client)
{
	u32 i;

	prestera_counter_lock(counter);
	for (i = 0; i < counter->block_list_len; i++) {
		if (counter->block_list[i] &&
		    counter->block_list[i]->client == client &&
		    !counter->block_list[i]->full &&
		    prestera_counter_block_incref(counter->block_list[i])) {
			prestera_counter_unlock(counter);
			return counter->block_list[i];
		}

Annotation

Implementation Notes