drivers/xen/events/events_fifo.c

Source file repositories/reference/linux-study-clean/drivers/xen/events/events_fifo.c

File Facts

System
Linux kernel
Corpus path
drivers/xen/events/events_fifo.c
Extension
.c
Size
11308 bytes
Lines
441
Domain
Driver Families
Bucket
drivers/xen
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 evtchn_fifo_queue {
	uint32_t head[EVTCHN_FIFO_MAX_QUEUES];
};

static DEFINE_PER_CPU(struct evtchn_fifo_control_block *, cpu_control_block);
static DEFINE_PER_CPU(struct evtchn_fifo_queue, cpu_queue);
static event_word_t *event_array[MAX_EVENT_ARRAY_PAGES] __read_mostly;
static unsigned event_array_pages __read_mostly;

/*
 * sync_set_bit() and friends must be unsigned long aligned.
 */
#if BITS_PER_LONG > 32

#define BM(w) (unsigned long *)((unsigned long)w & ~0x7UL)
#define EVTCHN_FIFO_BIT(b, w) \
    (((unsigned long)w & 0x4UL) ? (EVTCHN_FIFO_ ##b + 32) : EVTCHN_FIFO_ ##b)

#else

#define BM(w) ((unsigned long *)(w))
#define EVTCHN_FIFO_BIT(b, w) EVTCHN_FIFO_ ##b

#endif

static inline event_word_t *event_word_from_port(evtchn_port_t port)
{
	unsigned i = port / EVENT_WORDS_PER_PAGE;

	return event_array[i] + port % EVENT_WORDS_PER_PAGE;
}

static unsigned evtchn_fifo_max_channels(void)
{
	return EVTCHN_FIFO_NR_CHANNELS;
}

static unsigned evtchn_fifo_nr_channels(void)
{
	return event_array_pages * EVENT_WORDS_PER_PAGE;
}

static int init_control_block(int cpu,
                              struct evtchn_fifo_control_block *control_block)
{
	struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu);
	struct evtchn_init_control init_control;
	unsigned int i;

	/* Reset the control block and the local HEADs. */
	clear_page(control_block);
	for (i = 0; i < EVTCHN_FIFO_MAX_QUEUES; i++)
		q->head[i] = 0;

	init_control.control_gfn = virt_to_gfn(control_block);
	init_control.offset      = 0;
	init_control.vcpu        = xen_vcpu_nr(cpu);

	return HYPERVISOR_event_channel_op(EVTCHNOP_init_control, &init_control);
}

static void free_unused_array_pages(void)
{
	unsigned i;

	for (i = event_array_pages; i < MAX_EVENT_ARRAY_PAGES; i++) {
		if (!event_array[i])
			break;
		free_page((unsigned long)event_array[i]);
		event_array[i] = NULL;
	}
}

static void init_array_page(event_word_t *array_page)
{
	unsigned i;

	for (i = 0; i < EVENT_WORDS_PER_PAGE; i++)
		array_page[i] = 1 << EVTCHN_FIFO_MASKED;
}

static int evtchn_fifo_setup(evtchn_port_t port)
{
	unsigned new_array_pages;
	int ret;

	new_array_pages = port / EVENT_WORDS_PER_PAGE + 1;

	if (new_array_pages > MAX_EVENT_ARRAY_PAGES)
		return -EINVAL;

Annotation

Implementation Notes