root/arch/mips/netlogic/xlr/fmn.c

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

DEFINITIONS

This source file includes following definitions.
  1. fmn_message_handler
  2. xlr_percpu_fmn_init
  3. nlm_register_fmn_handler
  4. nlm_setup_fmn_irq

   1 /*
   2  * Copyright (c) 2003-2012 Broadcom Corporation
   3  * All Rights Reserved
   4  *
   5  * This software is available to you under a choice of one of two
   6  * licenses.  You may choose to be licensed under the terms of the GNU
   7  * General Public License (GPL) Version 2, available from the file
   8  * COPYING in the main directory of this source tree, or the Broadcom
   9  * license below:
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  *
  15  * 1. Redistributions of source code must retain the above copyright
  16  *    notice, this list of conditions and the following disclaimer.
  17  * 2. Redistributions in binary form must reproduce the above copyright
  18  *    notice, this list of conditions and the following disclaimer in
  19  *    the documentation and/or other materials provided with the
  20  *    distribution.
  21  *
  22  * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
  23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25  * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
  26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  29  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  31  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  32  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33  */
  34 
  35 #include <linux/kernel.h>
  36 #include <linux/irqreturn.h>
  37 #include <linux/irq.h>
  38 #include <linux/interrupt.h>
  39 
  40 #include <asm/mipsregs.h>
  41 #include <asm/netlogic/interrupt.h>
  42 #include <asm/netlogic/xlr/fmn.h>
  43 #include <asm/netlogic/common.h>
  44 
  45 #define COP2_CC_INIT_CPU_DEST(dest, conf) \
  46 do { \
  47         nlm_write_c2_cc##dest(0, conf[(dest * 8) + 0]); \
  48         nlm_write_c2_cc##dest(1, conf[(dest * 8) + 1]); \
  49         nlm_write_c2_cc##dest(2, conf[(dest * 8) + 2]); \
  50         nlm_write_c2_cc##dest(3, conf[(dest * 8) + 3]); \
  51         nlm_write_c2_cc##dest(4, conf[(dest * 8) + 4]); \
  52         nlm_write_c2_cc##dest(5, conf[(dest * 8) + 5]); \
  53         nlm_write_c2_cc##dest(6, conf[(dest * 8) + 6]); \
  54         nlm_write_c2_cc##dest(7, conf[(dest * 8) + 7]); \
  55 } while (0)
  56 
  57 struct fmn_message_handler {
  58         void (*action)(int, int, int, int, struct nlm_fmn_msg *, void *);
  59         void *arg;
  60 } msg_handlers[128];
  61 
  62 /*
  63  * FMN interrupt handler. We configure the FMN so that any messages in
  64  * any of the CPU buckets will trigger an interrupt on the CPU.
  65  * The message can be from any device on the FMN (like NAE/SAE/DMA).
  66  * The source station id is used to figure out which of the registered
  67  * handlers have to be called.
  68  */
  69 static irqreturn_t fmn_message_handler(int irq, void *data)
  70 {
  71         struct fmn_message_handler *hndlr;
  72         int bucket, rv;
  73         int size = 0, code = 0, src_stnid = 0;
  74         struct nlm_fmn_msg msg;
  75         uint32_t mflags, bkt_status;
  76 
  77         mflags = nlm_cop2_enable_irqsave();
  78         /* Disable message ring interrupt */
  79         nlm_fmn_setup_intr(irq, 0);
  80         while (1) {
  81                 /* 8 bkts per core, [24:31] each bit represents one bucket
  82                  * Bit is Zero if bucket is not empty */
  83                 bkt_status = (nlm_read_c2_status0() >> 24) & 0xff;
  84                 if (bkt_status == 0xff)
  85                         break;
  86                 for (bucket = 0; bucket < 8; bucket++) {
  87                         /* Continue on empty bucket */
  88                         if (bkt_status & (1 << bucket))
  89                                 continue;
  90                         rv = nlm_fmn_receive(bucket, &size, &code, &src_stnid,
  91                                                 &msg);
  92                         if (rv != 0)
  93                                 continue;
  94 
  95                         hndlr = &msg_handlers[src_stnid];
  96                         if (hndlr->action == NULL)
  97                                 pr_warn("No msgring handler for stnid %d\n",
  98                                                 src_stnid);
  99                         else {
 100                                 nlm_cop2_disable_irqrestore(mflags);
 101                                 hndlr->action(bucket, src_stnid, size, code,
 102                                         &msg, hndlr->arg);
 103                                 mflags = nlm_cop2_enable_irqsave();
 104                         }
 105                 }
 106         };
 107         /* Enable message ring intr, to any thread in core */
 108         nlm_fmn_setup_intr(irq, (1 << nlm_threads_per_core) - 1);
 109         nlm_cop2_disable_irqrestore(mflags);
 110         return IRQ_HANDLED;
 111 }
 112 
 113 struct irqaction fmn_irqaction = {
 114         .handler = fmn_message_handler,
 115         .flags = IRQF_PERCPU,
 116         .name = "fmn",
 117 };
 118 
 119 void xlr_percpu_fmn_init(void)
 120 {
 121         struct xlr_fmn_info *cpu_fmn_info;
 122         int *bucket_sizes;
 123         uint32_t flags;
 124         int id;
 125 
 126         BUG_ON(nlm_thread_id() != 0);
 127         id = nlm_core_id();
 128 
 129         bucket_sizes = xlr_board_fmn_config.bucket_size;
 130         cpu_fmn_info = &xlr_board_fmn_config.cpu[id];
 131         flags = nlm_cop2_enable_irqsave();
 132 
 133         /* Setup bucket sizes for the core. */
 134         nlm_write_c2_bucksize(0, bucket_sizes[id * 8 + 0]);
 135         nlm_write_c2_bucksize(1, bucket_sizes[id * 8 + 1]);
 136         nlm_write_c2_bucksize(2, bucket_sizes[id * 8 + 2]);
 137         nlm_write_c2_bucksize(3, bucket_sizes[id * 8 + 3]);
 138         nlm_write_c2_bucksize(4, bucket_sizes[id * 8 + 4]);
 139         nlm_write_c2_bucksize(5, bucket_sizes[id * 8 + 5]);
 140         nlm_write_c2_bucksize(6, bucket_sizes[id * 8 + 6]);
 141         nlm_write_c2_bucksize(7, bucket_sizes[id * 8 + 7]);
 142 
 143         /*
 144          * For sending FMN messages, we need credits on the destination
 145          * bucket. Program the credits this core has on the 128 possible
 146          * destination buckets.
 147          * We cannot use a loop here, because the the first argument has
 148          * to be a constant integer value.
 149          */
 150         COP2_CC_INIT_CPU_DEST(0, cpu_fmn_info->credit_config);
 151         COP2_CC_INIT_CPU_DEST(1, cpu_fmn_info->credit_config);
 152         COP2_CC_INIT_CPU_DEST(2, cpu_fmn_info->credit_config);
 153         COP2_CC_INIT_CPU_DEST(3, cpu_fmn_info->credit_config);
 154         COP2_CC_INIT_CPU_DEST(4, cpu_fmn_info->credit_config);
 155         COP2_CC_INIT_CPU_DEST(5, cpu_fmn_info->credit_config);
 156         COP2_CC_INIT_CPU_DEST(6, cpu_fmn_info->credit_config);
 157         COP2_CC_INIT_CPU_DEST(7, cpu_fmn_info->credit_config);
 158         COP2_CC_INIT_CPU_DEST(8, cpu_fmn_info->credit_config);
 159         COP2_CC_INIT_CPU_DEST(9, cpu_fmn_info->credit_config);
 160         COP2_CC_INIT_CPU_DEST(10, cpu_fmn_info->credit_config);
 161         COP2_CC_INIT_CPU_DEST(11, cpu_fmn_info->credit_config);
 162         COP2_CC_INIT_CPU_DEST(12, cpu_fmn_info->credit_config);
 163         COP2_CC_INIT_CPU_DEST(13, cpu_fmn_info->credit_config);
 164         COP2_CC_INIT_CPU_DEST(14, cpu_fmn_info->credit_config);
 165         COP2_CC_INIT_CPU_DEST(15, cpu_fmn_info->credit_config);
 166 
 167         /* enable FMN interrupts on this CPU */
 168         nlm_fmn_setup_intr(IRQ_FMN, (1 << nlm_threads_per_core) - 1);
 169         nlm_cop2_disable_irqrestore(flags);
 170 }
 171 
 172 
 173 /*
 174  * Register a FMN message handler with respect to the source station id
 175  * @stnid: source station id
 176  * @action: Handler function pointer
 177  */
 178 int nlm_register_fmn_handler(int start_stnid, int end_stnid,
 179         void (*action)(int, int, int, int, struct nlm_fmn_msg *, void *),
 180         void *arg)
 181 {
 182         int sstnid;
 183 
 184         for (sstnid = start_stnid; sstnid <= end_stnid; sstnid++) {
 185                 msg_handlers[sstnid].arg = arg;
 186                 smp_wmb();
 187                 msg_handlers[sstnid].action = action;
 188         }
 189         pr_debug("Registered FMN msg handler for stnid %d-%d\n",
 190                         start_stnid, end_stnid);
 191         return 0;
 192 }
 193 
 194 void nlm_setup_fmn_irq(void)
 195 {
 196         uint32_t flags;
 197 
 198         /* setup irq only once */
 199         setup_irq(IRQ_FMN, &fmn_irqaction);
 200 
 201         flags = nlm_cop2_enable_irqsave();
 202         nlm_fmn_setup_intr(IRQ_FMN, (1 << nlm_threads_per_core) - 1);
 203         nlm_cop2_disable_irqrestore(flags);
 204 }

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