root/drivers/misc/ibmasm/event.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wake_up_event_readers
  2. ibmasm_receive_event
  3. event_available
  4. ibmasm_get_next_event
  5. ibmasm_cancel_next_event
  6. ibmasm_event_reader_register
  7. ibmasm_event_reader_unregister
  8. ibmasm_event_buffer_init
  9. ibmasm_event_buffer_exit

   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 
  26 static 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  */
  43 void 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 
  66 static 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  */
  77 int 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 
 110 void ibmasm_cancel_next_event(struct event_reader *reader)
 111 {
 112         reader->cancelled = 1;
 113         wake_up_interruptible(&reader->wait);
 114 }
 115 
 116 void 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 
 127 void 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 
 136 int 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 
 160 void ibmasm_event_buffer_exit(struct service_processor *sp)
 161 {
 162         kfree(sp->event_buffer);
 163 }

/* [<][>][^][v][top][bottom][index][help] */