linux/drivers/staging/mali/DX910-SW-99002-r5p1-01rel0/driver/src/devicedrv/mali/linux/mali_osk_irq.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010-2015 ARM Limited. All rights reserved.
   3 * 
   4 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
   5 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
   6 * 
   7 * A copy of the licence is included with the program, and can also be obtained from Free Software
   8 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   9 */
  10
  11/**
  12 * @file mali_osk_irq.c
  13 * Implementation of the OS abstraction layer for the kernel device driver
  14 */
  15
  16#include <linux/slab.h> /* For memory allocation */
  17#include <linux/interrupt.h>
  18#include <linux/wait.h>
  19#include <linux/sched.h>
  20
  21#include "mali_osk.h"
  22#include "mali_kernel_common.h"
  23
  24typedef struct _mali_osk_irq_t_struct {
  25        u32 irqnum;
  26        void *data;
  27        _mali_osk_irq_uhandler_t uhandler;
  28} mali_osk_irq_object_t;
  29
  30typedef irqreturn_t (*irq_handler_func_t)(int, void *, struct pt_regs *);
  31static irqreturn_t irq_handler_upper_half(int port_name, void *dev_id);   /* , struct pt_regs *regs*/
  32
  33#if defined(DEBUG)
  34
  35struct test_interrupt_data {
  36        _mali_osk_irq_ack_t ack_func;
  37        void *probe_data;
  38        mali_bool interrupt_received;
  39        wait_queue_head_t wq;
  40};
  41
  42static irqreturn_t test_interrupt_upper_half(int port_name, void *dev_id)
  43{
  44        irqreturn_t ret = IRQ_NONE;
  45        struct test_interrupt_data *data = (struct test_interrupt_data *)dev_id;
  46
  47        if (_MALI_OSK_ERR_OK == data->ack_func(data->probe_data)) {
  48                data->interrupt_received = MALI_TRUE;
  49                wake_up(&data->wq);
  50                ret = IRQ_HANDLED;
  51        }
  52
  53        return ret;
  54}
  55
  56static _mali_osk_errcode_t test_interrupt(u32 irqnum,
  57                _mali_osk_irq_trigger_t trigger_func,
  58                _mali_osk_irq_ack_t ack_func,
  59                void *probe_data,
  60                const char *description)
  61{
  62        unsigned long irq_flags = 0;
  63        struct test_interrupt_data data = {
  64                .ack_func = ack_func,
  65                .probe_data = probe_data,
  66                .interrupt_received = MALI_FALSE,
  67        };
  68
  69#if defined(CONFIG_MALI_SHARED_INTERRUPTS)
  70        irq_flags |= IRQF_SHARED;
  71#endif /* defined(CONFIG_MALI_SHARED_INTERRUPTS) */
  72
  73        if (0 != request_irq(irqnum, test_interrupt_upper_half, irq_flags, description, &data)) {
  74                MALI_DEBUG_PRINT(2, ("Unable to install test IRQ handler for core '%s'\n", description));
  75                return _MALI_OSK_ERR_FAULT;
  76        }
  77
  78        init_waitqueue_head(&data.wq);
  79
  80        trigger_func(probe_data);
  81        wait_event_timeout(data.wq, data.interrupt_received, 100);
  82
  83        free_irq(irqnum, &data);
  84
  85        if (data.interrupt_received) {
  86                MALI_DEBUG_PRINT(3, ("%s: Interrupt test OK\n", description));
  87                return _MALI_OSK_ERR_OK;
  88        } else {
  89                MALI_PRINT_ERROR(("%s: Failed interrupt test on %u\n", description, irqnum));
  90                return _MALI_OSK_ERR_FAULT;
  91        }
  92}
  93
  94#endif /* defined(DEBUG) */
  95
  96_mali_osk_irq_t *_mali_osk_irq_init(u32 irqnum, _mali_osk_irq_uhandler_t uhandler, void *int_data, _mali_osk_irq_trigger_t trigger_func, _mali_osk_irq_ack_t ack_func, void *probe_data, const char *description)
  97{
  98        mali_osk_irq_object_t *irq_object;
  99        unsigned long irq_flags = 0;
 100
 101#if defined(CONFIG_MALI_SHARED_INTERRUPTS)
 102        irq_flags |= IRQF_SHARED;
 103#endif /* defined(CONFIG_MALI_SHARED_INTERRUPTS) */
 104
 105        irq_object = kmalloc(sizeof(mali_osk_irq_object_t), GFP_KERNEL);
 106        if (NULL == irq_object) {
 107                return NULL;
 108        }
 109
 110        if (-1 == irqnum) {
 111                /* Probe for IRQ */
 112                if ((NULL != trigger_func) && (NULL != ack_func)) {
 113                        unsigned long probe_count = 3;
 114                        _mali_osk_errcode_t err;
 115                        int irq;
 116
 117                        MALI_DEBUG_PRINT(2, ("Probing for irq\n"));
 118
 119                        do {
 120                                unsigned long mask;
 121
 122                                mask = probe_irq_on();
 123                                trigger_func(probe_data);
 124
 125                                _mali_osk_time_ubusydelay(5);
 126
 127                                irq = probe_irq_off(mask);
 128                                err = ack_func(probe_data);
 129                        } while (irq < 0 && (err == _MALI_OSK_ERR_OK) && probe_count--);
 130
 131                        if (irq < 0 || (_MALI_OSK_ERR_OK != err)) irqnum = -1;
 132                        else irqnum = irq;
 133                } else irqnum = -1; /* no probe functions, fault */
 134
 135                if (-1 != irqnum) {
 136                        /* found an irq */
 137                        MALI_DEBUG_PRINT(2, ("Found irq %d\n", irqnum));
 138                } else {
 139                        MALI_DEBUG_PRINT(2, ("Probe for irq failed\n"));
 140                }
 141        }
 142
 143        irq_object->irqnum = irqnum;
 144        irq_object->uhandler = uhandler;
 145        irq_object->data = int_data;
 146
 147        if (-1 == irqnum) {
 148                MALI_DEBUG_PRINT(2, ("No IRQ for core '%s' found during probe\n", description));
 149                kfree(irq_object);
 150                return NULL;
 151        }
 152
 153#if defined(DEBUG)
 154        /* Verify that the configured interrupt settings are working */
 155        if (_MALI_OSK_ERR_OK != test_interrupt(irqnum, trigger_func, ack_func, probe_data, description)) {
 156                MALI_DEBUG_PRINT(2, ("Test of IRQ handler for core '%s' failed\n", description));
 157                kfree(irq_object);
 158                return NULL;
 159        }
 160#endif
 161
 162        if (0 != request_irq(irqnum, irq_handler_upper_half, irq_flags, description, irq_object)) {
 163                MALI_DEBUG_PRINT(2, ("Unable to install IRQ handler for core '%s'\n", description));
 164                kfree(irq_object);
 165                return NULL;
 166        }
 167
 168        return irq_object;
 169}
 170
 171void _mali_osk_irq_term(_mali_osk_irq_t *irq)
 172{
 173        mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)irq;
 174        free_irq(irq_object->irqnum, irq_object);
 175        kfree(irq_object);
 176}
 177
 178
 179/** This function is called directly in interrupt context from the OS just after
 180 * the CPU get the hw-irq from mali, or other devices on the same IRQ-channel.
 181 * It is registered one of these function for each mali core. When an interrupt
 182 * arrives this function will be called equal times as registered mali cores.
 183 * That means that we only check one mali core in one function call, and the
 184 * core we check for each turn is given by the \a dev_id variable.
 185 * If we detect an pending interrupt on the given core, we mask the interrupt
 186 * out by settging the core's IRQ_MASK register to zero.
 187 * Then we schedule the mali_core_irq_handler_bottom_half to run as high priority
 188 * work queue job.
 189 */
 190static irqreturn_t irq_handler_upper_half(int port_name, void *dev_id)   /* , struct pt_regs *regs*/
 191{
 192        irqreturn_t ret = IRQ_NONE;
 193        mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)dev_id;
 194
 195        if (_MALI_OSK_ERR_OK == irq_object->uhandler(irq_object->data)) {
 196                ret = IRQ_HANDLED;
 197        }
 198
 199        return ret;
 200}
 201