#ifndef _SYS_PERCPU_H_
#define _SYS_PERCPU_H_
#ifndef CACHELINESIZE
#define CACHELINESIZE 64
#endif
#ifndef __upunused
#ifdef MULTIPROCESSOR
#define __upunused
#else
#define __upunused __attribute__((__unused__))
#endif
#endif
struct cpumem {
void *mem;
};
struct cpumem_iter {
unsigned int cpu;
} __upunused;
struct counters_ref {
uint64_t g;
uint64_t *c;
};
#ifdef _KERNEL
#include <sys/atomic.h>
struct pool;
struct cpumem *cpumem_get(struct pool *);
void cpumem_put(struct pool *, struct cpumem *);
struct cpumem *cpumem_malloc(size_t, int);
struct cpumem *cpumem_malloc_ncpus(struct cpumem *, size_t, int);
void cpumem_free(struct cpumem *, int, size_t);
void *cpumem_first(struct cpumem_iter *, struct cpumem *);
void *cpumem_next(struct cpumem_iter *, struct cpumem *);
static inline void *
cpumem_enter(struct cpumem *cm)
{
#ifdef MULTIPROCESSOR
return (cm[cpu_number()].mem);
#else
return (cm);
#endif
}
static inline void
cpumem_leave(struct cpumem *cm, void *mem)
{
}
#ifdef MULTIPROCESSOR
#define CPUMEM_BOOT_MEMORY(_name, _sz) \
static struct { \
unsigned char mem[_sz]; \
struct cpumem cpumem; \
} __aligned(CACHELINESIZE) _name##_boot_cpumem = { \
.cpumem = { _name##_boot_cpumem.mem } \
}
#define CPUMEM_BOOT_INITIALIZER(_name) \
{ &_name##_boot_cpumem.cpumem }
#else
#define CPUMEM_BOOT_MEMORY(_name, _sz) \
static struct { \
unsigned char mem[_sz]; \
} __aligned(sizeof(uint64_t)) _name##_boot_cpumem
#define CPUMEM_BOOT_INITIALIZER(_name) \
{ (struct cpumem *)&_name##_boot_cpumem.mem }
#endif
#define CPUMEM_FOREACH(_var, _iter, _cpumem) \
for ((_var) = cpumem_first((_iter), (_cpumem)); \
(_var) != NULL; \
(_var) = cpumem_next((_iter), (_cpumem)))
struct cpumem *counters_alloc(unsigned int);
struct cpumem *counters_alloc_ncpus(struct cpumem *, unsigned int);
void counters_free(struct cpumem *, unsigned int);
void counters_read(struct cpumem *, uint64_t *, unsigned int,
uint64_t *);
void counters_zero(struct cpumem *, unsigned int);
static inline uint64_t *
counters_enter(struct counters_ref *ref, struct cpumem *cm)
{
ref->c = cpumem_enter(cm);
#ifdef MULTIPROCESSOR
ref->g = ++(*ref->c);
membar_producer();
return (ref->c + 1);
#else
return (ref->c);
#endif
}
static inline void
counters_leave(struct counters_ref *ref, struct cpumem *cm)
{
#ifdef MULTIPROCESSOR
membar_producer();
(*ref->c) = ++ref->g;
#endif
cpumem_leave(cm, ref->c);
}
static inline void
counters_inc(struct cpumem *cm, unsigned int c)
{
struct counters_ref ref;
uint64_t *counters;
counters = counters_enter(&ref, cm);
counters[c]++;
counters_leave(&ref, cm);
}
static inline void
counters_dec(struct cpumem *cm, unsigned int c)
{
struct counters_ref ref;
uint64_t *counters;
counters = counters_enter(&ref, cm);
counters[c]--;
counters_leave(&ref, cm);
}
static inline void
counters_add(struct cpumem *cm, unsigned int c, uint64_t v)
{
struct counters_ref ref;
uint64_t *counters;
counters = counters_enter(&ref, cm);
counters[c] += v;
counters_leave(&ref, cm);
}
static inline void
counters_pkt(struct cpumem *cm, unsigned int c, unsigned int b, uint64_t v)
{
struct counters_ref ref;
uint64_t *counters;
counters = counters_enter(&ref, cm);
counters[c]++;
counters[b] += v;
counters_leave(&ref, cm);
}
#ifdef MULTIPROCESSOR
#define COUNTERS_BOOT_MEMORY(_name, _n) \
CPUMEM_BOOT_MEMORY(_name, ((_n) + 1) * sizeof(uint64_t))
#else
#define COUNTERS_BOOT_MEMORY(_name, _n) \
CPUMEM_BOOT_MEMORY(_name, (_n) * sizeof(uint64_t))
#endif
#define COUNTERS_BOOT_INITIALIZER(_name) CPUMEM_BOOT_INITIALIZER(_name)
#endif
#endif