 64f6ebe639
			
		
	
	
	64f6ebe639
	
	
	
		
			
			Rename macro nlm_cop2_enable() to nlm_cop2_enable_irqsave() and the macro nlm_cop2_restore to nlm_cop2_disable_irqrestore(). The new names will reflect the functionality better, and will make nlm_cop2_restore() available to be used later in COP2 save/restore patch. Signed-off-by: Jayachandran C <jchandra@broadcom.com> Cc: linux-mips@linux-mips.org Cc: ddaney.cavm@gmail.com Patchwork: https://patchwork.linux-mips.org/patch/5412/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
		
			
				
	
	
		
			204 lines
		
	
	
	
		
			6.9 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
	
		
			6.9 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2003-2012 Broadcom Corporation
 | |
|  * All Rights Reserved
 | |
|  *
 | |
|  * This software is available to you under a choice of one of two
 | |
|  * licenses.  You may choose to be licensed under the terms of the GNU
 | |
|  * General Public License (GPL) Version 2, available from the file
 | |
|  * COPYING in the main directory of this source tree, or the Broadcom
 | |
|  * license below:
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  *
 | |
|  * 1. Redistributions of source code must retain the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer.
 | |
|  * 2. Redistributions in binary form must reproduce the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer in
 | |
|  *    the documentation and/or other materials provided with the
 | |
|  *    distribution.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
 | |
|  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | |
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | |
|  * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
 | |
|  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | |
|  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | |
|  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 | |
|  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | |
|  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 | |
|  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 | |
|  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #include <linux/kernel.h>
 | |
| #include <linux/irqreturn.h>
 | |
| #include <linux/irq.h>
 | |
| #include <linux/interrupt.h>
 | |
| 
 | |
| #include <asm/mipsregs.h>
 | |
| #include <asm/netlogic/interrupt.h>
 | |
| #include <asm/netlogic/xlr/fmn.h>
 | |
| #include <asm/netlogic/common.h>
 | |
| 
 | |
| #define COP2_CC_INIT_CPU_DEST(dest, conf) \
 | |
| do { \
 | |
| 	nlm_write_c2_cc##dest(0, conf[(dest * 8) + 0]); \
 | |
| 	nlm_write_c2_cc##dest(1, conf[(dest * 8) + 1]); \
 | |
| 	nlm_write_c2_cc##dest(2, conf[(dest * 8) + 2]); \
 | |
| 	nlm_write_c2_cc##dest(3, conf[(dest * 8) + 3]); \
 | |
| 	nlm_write_c2_cc##dest(4, conf[(dest * 8) + 4]); \
 | |
| 	nlm_write_c2_cc##dest(5, conf[(dest * 8) + 5]); \
 | |
| 	nlm_write_c2_cc##dest(6, conf[(dest * 8) + 6]); \
 | |
| 	nlm_write_c2_cc##dest(7, conf[(dest * 8) + 7]); \
 | |
| } while (0)
 | |
| 
 | |
| struct fmn_message_handler {
 | |
| 	void (*action)(int, int, int, int, struct nlm_fmn_msg *, void *);
 | |
| 	void *arg;
 | |
| } msg_handlers[128];
 | |
| 
 | |
| /*
 | |
|  * FMN interrupt handler. We configure the FMN so that any messages in
 | |
|  * any of the CPU buckets will trigger an interrupt on the CPU.
 | |
|  * The message can be from any device on the FMN (like NAE/SAE/DMA).
 | |
|  * The source station id is used to figure out which of the registered
 | |
|  * handlers have to be called.
 | |
|  */
 | |
| static irqreturn_t fmn_message_handler(int irq, void *data)
 | |
| {
 | |
| 	struct fmn_message_handler *hndlr;
 | |
| 	int bucket, rv;
 | |
| 	int size = 0, code = 0, src_stnid = 0;
 | |
| 	struct nlm_fmn_msg msg;
 | |
| 	uint32_t mflags, bkt_status;
 | |
| 
 | |
| 	mflags = nlm_cop2_enable_irqsave();
 | |
| 	/* Disable message ring interrupt */
 | |
| 	nlm_fmn_setup_intr(irq, 0);
 | |
| 	while (1) {
 | |
| 		/* 8 bkts per core, [24:31] each bit represents one bucket
 | |
| 		 * Bit is Zero if bucket is not empty */
 | |
| 		bkt_status = (nlm_read_c2_status0() >> 24) & 0xff;
 | |
| 		if (bkt_status == 0xff)
 | |
| 			break;
 | |
| 		for (bucket = 0; bucket < 8; bucket++) {
 | |
| 			/* Continue on empty bucket */
 | |
| 			if (bkt_status & (1 << bucket))
 | |
| 				continue;
 | |
| 			rv = nlm_fmn_receive(bucket, &size, &code, &src_stnid,
 | |
| 						&msg);
 | |
| 			if (rv != 0)
 | |
| 				continue;
 | |
| 
 | |
| 			hndlr = &msg_handlers[src_stnid];
 | |
| 			if (hndlr->action == NULL)
 | |
| 				pr_warn("No msgring handler for stnid %d\n",
 | |
| 						src_stnid);
 | |
| 			else {
 | |
| 				nlm_cop2_disable_irqrestore(mflags);
 | |
| 				hndlr->action(bucket, src_stnid, size, code,
 | |
| 					&msg, hndlr->arg);
 | |
| 				mflags = nlm_cop2_enable_irqsave();
 | |
| 			}
 | |
| 		}
 | |
| 	};
 | |
| 	/* Enable message ring intr, to any thread in core */
 | |
| 	nlm_fmn_setup_intr(irq, (1 << nlm_threads_per_core) - 1);
 | |
| 	nlm_cop2_disable_irqrestore(mflags);
 | |
| 	return IRQ_HANDLED;
 | |
| }
 | |
| 
 | |
| struct irqaction fmn_irqaction = {
 | |
| 	.handler = fmn_message_handler,
 | |
| 	.flags = IRQF_PERCPU,
 | |
| 	.name = "fmn",
 | |
| };
 | |
| 
 | |
| void xlr_percpu_fmn_init(void)
 | |
| {
 | |
| 	struct xlr_fmn_info *cpu_fmn_info;
 | |
| 	int *bucket_sizes;
 | |
| 	uint32_t flags;
 | |
| 	int id;
 | |
| 
 | |
| 	BUG_ON(nlm_thread_id() != 0);
 | |
| 	id = nlm_core_id();
 | |
| 
 | |
| 	bucket_sizes = xlr_board_fmn_config.bucket_size;
 | |
| 	cpu_fmn_info = &xlr_board_fmn_config.cpu[id];
 | |
| 	flags = nlm_cop2_enable_irqsave();
 | |
| 
 | |
| 	/* Setup bucket sizes for the core. */
 | |
| 	nlm_write_c2_bucksize(0, bucket_sizes[id * 8 + 0]);
 | |
| 	nlm_write_c2_bucksize(1, bucket_sizes[id * 8 + 1]);
 | |
| 	nlm_write_c2_bucksize(2, bucket_sizes[id * 8 + 2]);
 | |
| 	nlm_write_c2_bucksize(3, bucket_sizes[id * 8 + 3]);
 | |
| 	nlm_write_c2_bucksize(4, bucket_sizes[id * 8 + 4]);
 | |
| 	nlm_write_c2_bucksize(5, bucket_sizes[id * 8 + 5]);
 | |
| 	nlm_write_c2_bucksize(6, bucket_sizes[id * 8 + 6]);
 | |
| 	nlm_write_c2_bucksize(7, bucket_sizes[id * 8 + 7]);
 | |
| 
 | |
| 	/*
 | |
| 	 * For sending FMN messages, we need credits on the destination
 | |
| 	 * bucket. Program the credits this core has on the 128 possible
 | |
| 	 * destination buckets.
 | |
| 	 * We cannot use a loop here, because the the first argument has
 | |
| 	 * to be a constant integer value.
 | |
| 	 */
 | |
| 	COP2_CC_INIT_CPU_DEST(0, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(1, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(2, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(3, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(4, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(5, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(6, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(7, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(8, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(9, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(10, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(11, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(12, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(13, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(14, cpu_fmn_info->credit_config);
 | |
| 	COP2_CC_INIT_CPU_DEST(15, cpu_fmn_info->credit_config);
 | |
| 
 | |
| 	/* enable FMN interrupts on this CPU */
 | |
| 	nlm_fmn_setup_intr(IRQ_FMN, (1 << nlm_threads_per_core) - 1);
 | |
| 	nlm_cop2_disable_irqrestore(flags);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Register a FMN message handler with respect to the source station id
 | |
|  * @stnid: source station id
 | |
|  * @action: Handler function pointer
 | |
|  */
 | |
| int nlm_register_fmn_handler(int start_stnid, int end_stnid,
 | |
| 	void (*action)(int, int, int, int, struct nlm_fmn_msg *, void *),
 | |
| 	void *arg)
 | |
| {
 | |
| 	int sstnid;
 | |
| 
 | |
| 	for (sstnid = start_stnid; sstnid <= end_stnid; sstnid++) {
 | |
| 		msg_handlers[sstnid].arg = arg;
 | |
| 		smp_wmb();
 | |
| 		msg_handlers[sstnid].action = action;
 | |
| 	}
 | |
| 	pr_debug("Registered FMN msg handler for stnid %d-%d\n",
 | |
| 			start_stnid, end_stnid);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void nlm_setup_fmn_irq(void)
 | |
| {
 | |
| 	uint32_t flags;
 | |
| 
 | |
| 	/* setup irq only once */
 | |
| 	setup_irq(IRQ_FMN, &fmn_irqaction);
 | |
| 
 | |
| 	flags = nlm_cop2_enable_irqsave();
 | |
| 	nlm_fmn_setup_intr(IRQ_FMN, (1 << nlm_threads_per_core) - 1);
 | |
| 	nlm_cop2_disable_irqrestore(flags);
 | |
| }
 |