irq.c 6.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/*******************************************************************************
    OpenAirInterface 
    Copyright(c) 1999 - 2014 Eurecom

    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.


    OpenAirInterface is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with OpenAirInterface.The full GNU General Public License is 
    included in this distribution in the file called "COPYING". If not, 
    see <http://www.gnu.org/licenses/>.

   Contact Information
   OpenAirInterface Admin: openair_admin@eurecom.fr
   OpenAirInterface Tech : openair_tech@eurecom.fr
   OpenAirInterface Dev  : openair4g-devel@eurecom.fr
  
   Address      : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.

 *******************************************************************************/
 
 /** irq.c
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
      - IRQ Handler: IRQ from Leon to PCIe/Kernel: exmimo_irq_handler
      - sends received packets to userspace

      - send command from PC to Leon and trigger IRQ on Leon using CONTROL1 register
      - commands are defined in $OPENAIR0/express-mimo/software/pcie_interface.h

      - added: pass card_id as parameter to tasklet and irq handler

   Authors: 
       Raymond Knopp <raymond.knopp@eurecom.fr>
       Matthias Ihmig <matthias.ihmig@mytum.de>, 2011, 2013
   */

#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/swab.h>

#include "openair_device.h"
#include "extern.h"

unsigned int openair_bh_cnt;

int get_frame_done = 0;

void pcie_printk(int card_id);

void openair_do_tasklet (unsigned long card_id);
DECLARE_TASKLET (openair_tasklet, openair_do_tasklet, 0);

irqreturn_t openair_irq_handler(int irq, void *cookie)
{
    unsigned int irqval;
    unsigned int irqcmd = EXMIMO_NOP;
    unsigned long card_id; // = (unsigned long) cookie;
67
    unsigned int pcie_control = PCIE_CONTROL2;
68 69 70 71 72 73 74 75 76

    // check interrupt status register
    //pci_read_config_word(pdev[0],6 , &irqval);
    
    // find card_id. cookie is set by request_irq and static, so we will always find it
    for (card_id=0; card_id<MAX_CARDS; card_id++)
        if ( pdev[card_id] == cookie )
            break;

ghaddab's avatar
 
ghaddab committed
77 78 79 80 81
    if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY)
      pcie_control = PCIE_CONTROL1;
    else
      pcie_control = PCIE_CONTROL2;

82 83 84 85 86 87 88 89 90 91
    //printk("irq hndl called: card_id=%i, irqval=%i\n", card_id, irqval);

    // get AHBPCIE interrupt line (bit 7) to determine if IRQ was for us from ExMIMO card, or from a different device
    // reading CONTROL0 will also clear this bit and the LEON-to-PC IRQ line
    irqval = ioread32(bar[card_id]+PCIE_CONTROL0);

    irqcmd = ioread32(bar[card_id]+pcie_control);
    //printk("IRQ handler: ctrl0: %08x, ctrl1: %08x, ctrl2: %08x, status: %08x\n", irqval, ioread32(bar[card_id]+PCIE_CONTROL1), ioread32(bar[card_id]+PCIE_CONTROL2), ioread32(bar[card_id]+PCIE_STATUS));
    
    if ( (irqval & 0x80) == 0 )  {  // CTRL0.bit7 is no set -> IRQ is not from ExMIMO i.e. not for us 
ghaddab's avatar
 
ghaddab committed
92 93 94 95 96 97 98 99 100 101 102 103 104
        if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_CMDREGISTERS){
          if (irqcmd != EXMIMO_NOP && irqcmd != EXMIMO_CONTROL2_COOKIE) {          
            if (irqcmd == GET_FRAME_DONE)
            {
              get_frame_done = 1;
            }
            openair_tasklet.data = card_id; 
            tasklet_schedule(&openair_tasklet);
            openair_bh_cnt++;
            return IRQ_HANDLED;
          }
          else
          {
105
            return IRQ_NONE;
ghaddab's avatar
 
ghaddab committed
106 107 108 109
          }
        }
        else
          return IRQ_NONE;
110
    }
111 112
    else
    {
ghaddab's avatar
 
ghaddab committed
113 114 115 116
    if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY){
    // clear PCIE interrupt (bit 7 of register 0x0)
    iowrite32(irqval&0xffffff7f,bar[card_id]+PCIE_CONTROL0);
    }
117 118 119 120 121 122 123 124 125 126
    if (irqcmd == GET_FRAME_DONE)
    {
        get_frame_done = 1;
    }
    
    openair_tasklet.data = card_id;
    tasklet_schedule(&openair_tasklet);
    openair_bh_cnt++;

    return IRQ_HANDLED;
127
    }
128 129 130 131 132 133
}

void openair_do_tasklet (unsigned long card_id)
{
    int save_irq_cnt = openair_bh_cnt;
    unsigned int irqcmd;
134
    unsigned int pcie_control = PCIE_CONTROL2;
135 136
    openair_bh_cnt = 0;
    
ghaddab's avatar
 
ghaddab committed
137 138 139 140 141
    if (exmimo_pci_kvirt[card_id].exmimo_id_ptr->board_swrev == BOARD_SWREV_LEGACY)
      pcie_control = PCIE_CONTROL1;
    else
      pcie_control = PCIE_CONTROL2;

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
    irqcmd = ioread32(bar[card_id]+pcie_control);
    
    if (save_irq_cnt > 1)
        printk("[openair][IRQ tasklet(%ld)]: Warning: received more than 1 PCIE IRQ (openair_bh_cnt=%i), only the last one is acted upon(irqcmd= %i (0x%X)\n", card_id, openair_bh_cnt, irqcmd, irqcmd);
    
    switch( irqcmd )
    {
        case PCI_PRINTK:
            // printk("Got PCIe interrupt for printk ...\n");
            pcie_printk((int) card_id);
            break;
            
        case GET_FRAME_DONE:
            printk("[openair][IRQ tasklet] : Got PCIe interrupt for GET_FRAME_DONE ...\n");
            break;
            
        case EXMIMO_NOP:
            printk("[openair][IRQ tasklet] : Received IRQ, with CONTROL0.bit7(IRQ Leon2PC) set, but irqcmd = EXMIMO_NOP. This should not happen with bitstreams built after June 3rd 2013.\n");
            break;
            
        default:
            printk("[openair][IRQ tasklet] : Got unknown PCIe cmd: card_id = %li, irqcmd(CONTROL1) = %i (0x%X)\n", card_id, irqcmd, irqcmd);
    }
    
    iowrite32(EXMIMO_NOP, bar[card_id]+pcie_control);
}   

void pcie_printk(int card_id)
{
    char *buffer = exmimo_pci_kvirt[card_id].printk_buffer_ptr;
    unsigned int len = ((unsigned int *)buffer)[0];
    unsigned int off=0,i;
    unsigned char *dword;
    unsigned char tmp;

    //printk("In pci_fifo_printk : buffer %p, len %d: \n",buffer,len);
    printk("[LEON card%d]: ", card_id);

180
    if (len<1024)
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
    {
        if ( (len&3) >0 )
            off=1;
    
        for (i=0; i<(off+(len>>2)); i++)
        {
            dword = &((unsigned char *)buffer)[(1+i)<<2];
            tmp = dword[3];
            dword[3] = dword[0];
            dword[0] = tmp;
            tmp = dword[2];
            dword[2] = dword[1];
            dword[1] = tmp;
        }
        for (i=0; i<len; i++)
            printk("%c",((char*)&buffer[4])[i]);
    }
}