root/arch/powerpc/platforms/pseries/io_event_irq.c

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

DEFINITIONS

This source file includes following definitions.
  1. ioei_find_event
  2. ioei_interrupt
  3. ioei_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright 2010 2011 Mark Nelson and Tseng-Hui (Frank) Lin, IBM Corporation
   4  */
   5 
   6 #include <linux/errno.h>
   7 #include <linux/slab.h>
   8 #include <linux/export.h>
   9 #include <linux/irq.h>
  10 #include <linux/interrupt.h>
  11 #include <linux/of.h>
  12 #include <linux/list.h>
  13 #include <linux/notifier.h>
  14 
  15 #include <asm/machdep.h>
  16 #include <asm/rtas.h>
  17 #include <asm/irq.h>
  18 #include <asm/io_event_irq.h>
  19 
  20 #include "pseries.h"
  21 
  22 /*
  23  * IO event interrupt is a mechanism provided by RTAS to return
  24  * information about hardware error and non-error events. Device
  25  * drivers can register their event handlers to receive events.
  26  * Device drivers are expected to use atomic_notifier_chain_register()
  27  * and atomic_notifier_chain_unregister() to register and unregister
  28  * their event handlers. Since multiple IO event types and scopes
  29  * share an IO event interrupt, the event handlers are called one
  30  * by one until the IO event is claimed by one of the handlers.
  31  * The event handlers are expected to return NOTIFY_OK if the
  32  * event is handled by the event handler or NOTIFY_DONE if the
  33  * event does not belong to the handler.
  34  *
  35  * Usage:
  36  *
  37  * Notifier function:
  38  * #include <asm/io_event_irq.h>
  39  * int event_handler(struct notifier_block *nb, unsigned long val, void *data) {
  40  *      p = (struct pseries_io_event_sect_data *) data;
  41  *      if (! is_my_event(p->scope, p->event_type)) return NOTIFY_DONE;
  42  *              :
  43  *              :
  44  *      return NOTIFY_OK;
  45  * }
  46  * struct notifier_block event_nb = {
  47  *      .notifier_call = event_handler,
  48  * }
  49  *
  50  * Registration:
  51  * atomic_notifier_chain_register(&pseries_ioei_notifier_list, &event_nb);
  52  *
  53  * Unregistration:
  54  * atomic_notifier_chain_unregister(&pseries_ioei_notifier_list, &event_nb);
  55  */
  56 
  57 ATOMIC_NOTIFIER_HEAD(pseries_ioei_notifier_list);
  58 EXPORT_SYMBOL_GPL(pseries_ioei_notifier_list);
  59 
  60 static int ioei_check_exception_token;
  61 
  62 static char ioei_rtas_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
  63 
  64 /**
  65  * Find the data portion of an IO Event section from event log.
  66  * @elog: RTAS error/event log.
  67  *
  68  * Return:
  69  *      pointer to a valid IO event section data. NULL if not found.
  70  */
  71 static struct pseries_io_event * ioei_find_event(struct rtas_error_log *elog)
  72 {
  73         struct pseries_errorlog *sect;
  74 
  75         /* We should only ever get called for io-event interrupts, but if
  76          * we do get called for another type then something went wrong so
  77          * make some noise about it.
  78          * RTAS_TYPE_IO only exists in extended event log version 6 or later.
  79          * No need to check event log version.
  80          */
  81         if (unlikely(rtas_error_type(elog) != RTAS_TYPE_IO)) {
  82                 printk_once(KERN_WARNING"io_event_irq: Unexpected event type %d",
  83                             rtas_error_type(elog));
  84                 return NULL;
  85         }
  86 
  87         sect = get_pseries_errorlog(elog, PSERIES_ELOG_SECT_ID_IO_EVENT);
  88         if (unlikely(!sect)) {
  89                 printk_once(KERN_WARNING "io_event_irq: RTAS extended event "
  90                             "log does not contain an IO Event section. "
  91                             "Could be a bug in system firmware!\n");
  92                 return NULL;
  93         }
  94         return (struct pseries_io_event *) &sect->data;
  95 }
  96 
  97 /*
  98  * PAPR:
  99  * - check-exception returns the first found error or event and clear that
 100  *   error or event so it is reported once.
 101  * - Each interrupt returns one event. If a plateform chooses to report
 102  *   multiple events through a single interrupt, it must ensure that the
 103  *   interrupt remains asserted until check-exception has been used to
 104  *   process all out-standing events for that interrupt.
 105  *
 106  * Implementation notes:
 107  * - Events must be processed in the order they are returned. Hence,
 108  *   sequential in nature.
 109  * - The owner of an event is determined by combinations of scope,
 110  *   event type, and sub-type. There is no easy way to pre-sort clients
 111  *   by scope or event type alone. For example, Torrent ISR route change
 112  *   event is reported with scope 0x00 (Not Applicable) rather than
 113  *   0x3B (Torrent-hub). It is better to let the clients to identify
 114  *   who owns the event.
 115  */
 116 
 117 static irqreturn_t ioei_interrupt(int irq, void *dev_id)
 118 {
 119         struct pseries_io_event *event;
 120         int rtas_rc;
 121 
 122         for (;;) {
 123                 rtas_rc = rtas_call(ioei_check_exception_token, 6, 1, NULL,
 124                                     RTAS_VECTOR_EXTERNAL_INTERRUPT,
 125                                     virq_to_hw(irq),
 126                                     RTAS_IO_EVENTS, 1 /* Time Critical */,
 127                                     __pa(ioei_rtas_buf),
 128                                     RTAS_DATA_BUF_SIZE);
 129                 if (rtas_rc != 0)
 130                         break;
 131 
 132                 event = ioei_find_event((struct rtas_error_log *)ioei_rtas_buf);
 133                 if (!event)
 134                         continue;
 135 
 136                 atomic_notifier_call_chain(&pseries_ioei_notifier_list,
 137                                            0, event);
 138         }
 139         return IRQ_HANDLED;
 140 }
 141 
 142 static int __init ioei_init(void)
 143 {
 144         struct device_node *np;
 145 
 146         ioei_check_exception_token = rtas_token("check-exception");
 147         if (ioei_check_exception_token == RTAS_UNKNOWN_SERVICE)
 148                 return -ENODEV;
 149 
 150         np = of_find_node_by_path("/event-sources/ibm,io-events");
 151         if (np) {
 152                 request_event_sources_irqs(np, ioei_interrupt, "IO_EVENT");
 153                 pr_info("IBM I/O event interrupts enabled\n");
 154                 of_node_put(np);
 155         } else {
 156                 return -ENODEV;
 157         }
 158         return 0;
 159 }
 160 machine_subsys_initcall(pseries, ioei_init);
 161 

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