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