brintos

brintos / linux-shallow public Read only

0
0
Text · 4.2 KiB · 40ce75f Raw
164 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2 3/*4 * IBM ASM Service Processor Device Driver5 *6 * Copyright (C) IBM Corporation, 20047 *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 to21 * sp_event.22 * The driver does not interpret the events, it simply stores them in a23 * 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_event36 * Called by the interrupt handler when a dot command of type sp_event is37 * received.38 * Store the event in the circular event buffer, wake up any sleeping39 * event readers.40 * There is no reader marker in the buffer, therefore readers are41 * 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_event73 * Called by event readers (initiated from user space through the file74 * 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}164