linux/drivers/misc/ibmasm/event.c
<<
>>
Prefs
   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 1;
 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}
 178