Linux Audio

Check our new training course

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