cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

event.c (4320B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2
      3/*
      4 * IBM ASM Service Processor Device Driver
      5 *
      6 * Copyright (C) IBM Corporation, 2004
      7 *
      8 * Author: Max Asböck <amax@us.ibm.com>
      9 */
     10
     11#include <linux/sched.h>
     12#include <linux/slab.h>
     13#include "ibmasm.h"
     14#include "lowlevel.h"
     15
     16/*
     17 * ASM service processor event handling routines.
     18 *
     19 * Events are signalled to the device drivers through interrupts.
     20 * They have the format of dot commands, with the type field set to
     21 * sp_event.
     22 * The driver does not interpret the events, it simply stores them in a
     23 * circular buffer.
     24 */
     25
     26static void wake_up_event_readers(struct service_processor *sp)
     27{
     28	struct event_reader *reader;
     29
     30	list_for_each_entry(reader, &sp->event_buffer->readers, node)
     31                wake_up_interruptible(&reader->wait);
     32}
     33
     34/*
     35 * receive_event
     36 * Called by the interrupt handler when a dot command of type sp_event is
     37 * received.
     38 * Store the event in the circular event buffer, wake up any sleeping
     39 * event readers.
     40 * There is no reader marker in the buffer, therefore readers are
     41 * responsible for keeping up with the writer, or they will lose events.
     42 */
     43void ibmasm_receive_event(struct service_processor *sp, void *data, unsigned int data_size)
     44{
     45	struct event_buffer *buffer = sp->event_buffer;
     46	struct ibmasm_event *event;
     47	unsigned long flags;
     48
     49	data_size = min(data_size, IBMASM_EVENT_MAX_SIZE);
     50
     51	spin_lock_irqsave(&sp->lock, flags);
     52	/* copy the event into the next slot in the circular buffer */
     53	event = &buffer->events[buffer->next_index];
     54	memcpy_fromio(event->data, data, data_size);
     55	event->data_size = data_size;
     56	event->serial_number = buffer->next_serial_number;
     57
     58	/* advance indices in the buffer */
     59	buffer->next_index = (buffer->next_index + 1) % IBMASM_NUM_EVENTS;
     60	buffer->next_serial_number++;
     61	spin_unlock_irqrestore(&sp->lock, flags);
     62
     63	wake_up_event_readers(sp);
     64}
     65
     66static inline int event_available(struct event_buffer *b, struct event_reader *r)
     67{
     68	return (r->next_serial_number < b->next_serial_number);
     69}
     70
     71/*
     72 * get_next_event
     73 * Called by event readers (initiated from user space through the file
     74 * system).
     75 * Sleeps until a new event is available.
     76 */
     77int ibmasm_get_next_event(struct service_processor *sp, struct event_reader *reader)
     78{
     79	struct event_buffer *buffer = sp->event_buffer;
     80	struct ibmasm_event *event;
     81	unsigned int index;
     82	unsigned long flags;
     83
     84	reader->cancelled = 0;
     85
     86	if (wait_event_interruptible(reader->wait,
     87			event_available(buffer, reader) || reader->cancelled))
     88		return -ERESTARTSYS;
     89
     90	if (!event_available(buffer, reader))
     91		return 0;
     92
     93	spin_lock_irqsave(&sp->lock, flags);
     94
     95	index = buffer->next_index;
     96	event = &buffer->events[index];
     97	while (event->serial_number < reader->next_serial_number) {
     98		index = (index + 1) % IBMASM_NUM_EVENTS;
     99		event = &buffer->events[index];
    100	}
    101	memcpy(reader->data, event->data, event->data_size);
    102	reader->data_size = event->data_size;
    103	reader->next_serial_number = event->serial_number + 1;
    104
    105	spin_unlock_irqrestore(&sp->lock, flags);
    106
    107	return event->data_size;
    108}
    109
    110void ibmasm_cancel_next_event(struct event_reader *reader)
    111{
    112        reader->cancelled = 1;
    113        wake_up_interruptible(&reader->wait);
    114}
    115
    116void ibmasm_event_reader_register(struct service_processor *sp, struct event_reader *reader)
    117{
    118	unsigned long flags;
    119
    120	reader->next_serial_number = sp->event_buffer->next_serial_number;
    121	init_waitqueue_head(&reader->wait);
    122	spin_lock_irqsave(&sp->lock, flags);
    123	list_add(&reader->node, &sp->event_buffer->readers);
    124	spin_unlock_irqrestore(&sp->lock, flags);
    125}
    126
    127void ibmasm_event_reader_unregister(struct service_processor *sp, struct event_reader *reader)
    128{
    129	unsigned long flags;
    130
    131	spin_lock_irqsave(&sp->lock, flags);
    132	list_del(&reader->node);
    133	spin_unlock_irqrestore(&sp->lock, flags);
    134}
    135
    136int ibmasm_event_buffer_init(struct service_processor *sp)
    137{
    138	struct event_buffer *buffer;
    139	struct ibmasm_event *event;
    140	int i;
    141
    142	buffer = kmalloc(sizeof(struct event_buffer), GFP_KERNEL);
    143	if (!buffer)
    144		return -ENOMEM;
    145
    146	buffer->next_index = 0;
    147	buffer->next_serial_number = 1;
    148
    149	event = buffer->events;
    150	for (i=0; i<IBMASM_NUM_EVENTS; i++, event++)
    151		event->serial_number = 0;
    152
    153	INIT_LIST_HEAD(&buffer->readers);
    154
    155	sp->event_buffer = buffer;
    156
    157	return 0;
    158}
    159
    160void ibmasm_event_buffer_exit(struct service_processor *sp)
    161{
    162	kfree(sp->event_buffer);
    163}