From patchwork Tue Apr 19 16:59:35 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Meador Inge X-Patchwork-Id: 92037 X-Patchwork-Delegate: benh@kernel.crashing.org Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from ozlabs.org (localhost [IPv6:::1]) by ozlabs.org (Postfix) with ESMTP id AA976B74B8 for ; Wed, 20 Apr 2011 03:34:26 +1000 (EST) Received: from relay1.mentorg.com (relay1.mentorg.com [192.94.38.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "relay1.mentorg.com", Issuer "Entrust Certification Authority - L1B" (not verified)) by ozlabs.org (Postfix) with ESMTPS id DB7D1B700D; Wed, 20 Apr 2011 03:34:13 +1000 (EST) Received: from svr-orw-exc-10.mgc.mentorg.com ([147.34.98.58]) by relay1.mentorg.com with esmtp id 1QCEHc-0007a3-Ja from meador_inge@mentor.com ; Tue, 19 Apr 2011 10:00:12 -0700 Received: from na2-mail.mgc.mentorg.com ([134.86.114.213]) by SVR-ORW-EXC-10.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.4675); Tue, 19 Apr 2011 09:56:55 -0700 Received: from localhost.localdomain ([172.30.88.197]) by na2-mail.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.3959); Tue, 19 Apr 2011 11:00:10 -0600 From: Meador Inge To: linuxppc-dev@lists.ozlabs.org Subject: [PATCH 2/2] powerpc: add support for MPIC message register API Date: Tue, 19 Apr 2011 11:59:35 -0500 Message-Id: <1303232375-25014-3-git-send-email-meador_inge@mentor.com> X-Mailer: git-send-email 1.6.3.3 In-Reply-To: <1303232375-25014-1-git-send-email-meador_inge@mentor.com> References: <1303232375-25014-1-git-send-email-meador_inge@mentor.com> X-OriginalArrivalTime: 19 Apr 2011 17:00:10.0219 (UTC) FILETIME=[3DF3F3B0:01CBFEB3] Cc: openmcapi-dev@googlegroups.com, devicetree-discuss@lists.ozlabs.org, Hollis Blanchard X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Some MPIC implementations contain one or more blocks of message registers that are used to send messages between cores via IPIs. A simple API has been added to access (get/put, read, write, etc ...) these message registers. The available message registers are initially discovered via nodes in the device tree. A separate commit contains a binding for the message register nodes. Signed-off-by: Meador Inge Cc: Benjamin Herrenschmidt Cc: Hollis Blanchard --- arch/powerpc/include/asm/mpic_msgr.h | 35 +++++ arch/powerpc/platforms/Kconfig | 8 + arch/powerpc/sysdev/Makefile | 3 +- arch/powerpc/sysdev/mpic_msgr.c | 279 ++++++++++++++++++++++++++++++++++ 4 files changed, 324 insertions(+), 1 deletions(-) create mode 100644 arch/powerpc/include/asm/mpic_msgr.h create mode 100644 arch/powerpc/sysdev/mpic_msgr.c diff --git a/arch/powerpc/include/asm/mpic_msgr.h b/arch/powerpc/include/asm/mpic_msgr.h new file mode 100644 index 0000000..370dcb4 --- /dev/null +++ b/arch/powerpc/include/asm/mpic_msgr.h @@ -0,0 +1,35 @@ +/* + * Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation. + * + * This program 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; version 2 of the + * License. + * + */ + +#ifndef _ASM_MPIC_MSGR_H +#define _ASM_MPIC_MSGR_H + +#include + +struct mpic_msgr { + u32 __iomem *addr; + u32 __iomem *mer; + u32 __iomem *msr; + int irq; + atomic_t in_use; + int num; +}; + +extern struct mpic_msgr* mpic_msgr_get(unsigned int reg_num); +extern void mpic_msgr_put(struct mpic_msgr* msgr); +extern void mpic_msgr_enable(struct mpic_msgr *msgr); +extern void mpic_msgr_disable(struct mpic_msgr *msgr); +extern void mpic_msgr_write(struct mpic_msgr *msgr, u32 message); +extern u32 mpic_msgr_read(struct mpic_msgr *msgr); +extern void mpic_msgr_clear(struct mpic_msgr *msgr); +extern void mpic_msgr_set_destination(struct mpic_msgr *msgr, u32 cpu_num); +extern int mpic_msgr_get_irq(struct mpic_msgr *msgr); + +#endif diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index f7b0772..4d65593 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -78,6 +78,14 @@ config MPIC_WEIRD bool default n +config MPIC_MSGR + bool "MPIC message register support" + depends on MPIC + default n + help + Enables support for the MPIC message registers. These + registers are used for inter-processor communication. + config PPC_I8259 bool default n diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 1e0c933..6d40185 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -3,7 +3,8 @@ subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror ccflags-$(CONFIG_PPC64) := -mno-minimal-toc mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o -obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) +mpic-msgr-obj-$(CONFIG_MPIC_MSGR) += mpic_msgr.o +obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) $(mpic-msgr-obj-y) fsl-msi-obj-$(CONFIG_PCI_MSI) += fsl_msi.o obj-$(CONFIG_PPC_MSI_BITMAP) += msi_bitmap.o diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c new file mode 100644 index 0000000..352bfa6 --- /dev/null +++ b/arch/powerpc/sysdev/mpic_msgr.c @@ -0,0 +1,279 @@ +/* + * Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation. + * + * Some ideas based on un-pushed work done by Vivek Mahajan, Jason Jin, and + * Mingkai Hu from Freescale Semiconductor, Inc. + * + * This program 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; version 2 of the + * License. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MPIC_MSGR_REGISTERS_PER_BLOCK 4 +#define MSGR_INUSE 0 +#define MSGR_FREE 1 + +/* Internal structure used *only* for IO mapping register blocks. */ +struct mpic_msgr_block { + struct msgr { + u32 msgr; + u8 res[12]; + } msgrs[MPIC_MSGR_REGISTERS_PER_BLOCK]; + u8 res0[192]; + u32 mer; + u8 res1[12]; + u32 msr; +}; + +static struct mpic_msgr **mpic_msgrs = 0; +static unsigned int mpic_msgr_count = 0; + +struct mpic_msgr* mpic_msgr_get(unsigned int reg_num) +{ + struct mpic_msgr* msgr; + + if (reg_num >= mpic_msgr_count) + return ERR_PTR(-ENODEV); + + msgr = mpic_msgrs[reg_num]; + + if (atomic_cmpxchg(&msgr->in_use, MSGR_FREE, MSGR_INUSE) == MSGR_FREE) + return msgr; + + return ERR_PTR(-EBUSY); +} +EXPORT_SYMBOL(mpic_msgr_get); + +void mpic_msgr_put(struct mpic_msgr* msgr) +{ + atomic_set(&msgr->in_use, MSGR_FREE); +} +EXPORT_SYMBOL(mpic_msgr_put); + +void mpic_msgr_enable(struct mpic_msgr *msgr) +{ + out_be32(msgr->mer, in_be32(msgr->mer) | (1 << msgr->num)); +} +EXPORT_SYMBOL(mpic_msgr_enable); + +void mpic_msgr_disable(struct mpic_msgr *msgr) +{ + out_be32(msgr->mer, in_be32(msgr->mer) & ~(1 << msgr->num)); +} +EXPORT_SYMBOL(mpic_msgr_disable); + +void mpic_msgr_write(struct mpic_msgr *msgr, u32 message) +{ + out_be32(msgr->addr, message); +} +EXPORT_SYMBOL(mpic_msgr_write); + +u32 mpic_msgr_read(struct mpic_msgr *msgr) +{ + return in_be32(msgr->addr); +} +EXPORT_SYMBOL(mpic_msgr_read); + +void mpic_msgr_clear(struct mpic_msgr *msgr) +{ + (void) mpic_msgr_read(msgr); +} +EXPORT_SYMBOL(mpic_msgr_clear); + +void mpic_msgr_set_destination(struct mpic_msgr *msgr, u32 cpu_num) +{ + out_be32(msgr->addr, 1 << cpu_num); +} +EXPORT_SYMBOL(mpic_msgr_set_destination); + +int mpic_msgr_get_irq(struct mpic_msgr *msgr) +{ + return msgr->irq; +} +EXPORT_SYMBOL(mpic_msgr_get_irq); + +/* The following three functions are used to compute the order and number of + * the message register blocks. They are clearly very inefficent. However, + * they are called *only* a few times during device initialization. + */ +static unsigned int mpic_msgr_number_of_blocks(void) +{ + unsigned int count; + struct device_node *aliases; + + count = 0; + aliases = of_find_node_by_name(NULL, "aliases"); + + if (aliases) { + char buf[32]; + + for (;;) { + snprintf(buf, sizeof(buf), "msgr-block%d", count); + if (!of_find_property(aliases, buf, NULL)) + break; + + count += 1; + } + } + + return count; +} + +static unsigned int mpic_msgr_number_of_registers(void) +{ + return mpic_msgr_number_of_blocks() * MPIC_MSGR_REGISTERS_PER_BLOCK; +} + +static int mpic_msgr_block_number(struct device_node *node) +{ + struct device_node *aliases; + unsigned int index, number_of_blocks; + char buf[64]; + + number_of_blocks = mpic_msgr_number_of_blocks(); + aliases = of_find_node_by_name(NULL, "aliases"); + if (!aliases) + return -1; + + for (index = 0; index < number_of_blocks; ++index) { + struct property *prop; + + snprintf(buf, sizeof(buf), "msgr-block%d", index); + prop = of_find_property(aliases, buf, NULL); + if (node == of_find_node_by_path(prop->value)) + break; + } + + return index == number_of_blocks ? -1 : index; +} + +/* The probe function for a single message register block. + */ +static __devinit int mpic_msgr_probe(struct platform_device *dev) +{ + struct mpic_msgr_block __iomem *msgr_block; + int block_number; + struct resource rsrc; + unsigned int i; + unsigned int irq_index; + struct device_node *np = dev->dev.of_node; + unsigned int receive_mask; + const unsigned int *prop; + + if (!np) { + dev_err(&dev->dev, "Device OF-Node is NULL"); + return -EFAULT; + } + + /* Allocate the message register array upon the first device + * registered. + */ + if (!mpic_msgrs) { + mpic_msgr_count = mpic_msgr_number_of_registers(); + dev_info(&dev->dev, "Found %d message registers\n", mpic_msgr_count); + + mpic_msgrs = kzalloc(sizeof(struct mpic_msgr) * mpic_msgr_count, + GFP_KERNEL); + if (!mpic_msgrs) { + dev_err(&dev->dev, "No memory for message register blocks\n"); + return -ENOMEM; + } + } + dev_info(&dev->dev, "Of-device full name %s\n", np->full_name); + + /* IO map the message register block. */ + of_address_to_resource(np, 0, &rsrc); + msgr_block = ioremap(rsrc.start, rsrc.end - rsrc.start); + if (!msgr_block) { + dev_err(&dev->dev, "Failed to iomap MPIC message registers"); + return -EFAULT; + } + + /* Ensure the block has a defined order. */ + block_number = mpic_msgr_block_number(np); + if (block_number < 0) { + dev_err(&dev->dev, "Failed to find message register block alias\n"); + return -ENODEV; + } + dev_info(&dev->dev, "Setting up message register block %d\n", block_number); + + /* Grab the receive mask which specifies what registers can receive + * interrupts. + */ + prop = of_get_property(np, "msg-receive-mask", NULL); + receive_mask = (prop) ? *prop : 0xF; + + /* Build up the appropriate message register data structures. */ + for (i = 0, irq_index = 0; i < MPIC_MSGR_REGISTERS_PER_BLOCK; ++i) { + struct mpic_msgr *msgr; + unsigned int reg_number; + + msgr = kzalloc(sizeof(struct mpic_msgr), GFP_KERNEL); + if (!msgr) { + dev_err(&dev->dev, "No memory for message register\n"); + return -ENOMEM; + } + + reg_number = block_number * MPIC_MSGR_REGISTERS_PER_BLOCK + i; + msgr->addr = &msgr_block->msgrs[i].msgr; + msgr->mer = &msgr_block->mer; + msgr->msr = &msgr_block->msr; + atomic_set(&msgr->in_use, MSGR_FREE); + msgr->num = reg_number; + + if (receive_mask & (1 << i)) { + struct resource irq; + + if (of_irq_to_resource(np, irq_index, &irq) == NO_IRQ) { + dev_err(&dev->dev, "Missing interrupt specifier"); + kfree(msgr); + return -EFAULT; + } + msgr->irq = irq.start; + irq_index += 1; + } else { + msgr->irq = NO_IRQ; + } + + mpic_msgrs[reg_number] = msgr; + mpic_msgr_disable(msgr); + dev_info(&dev->dev, "Register %d initialized: irq %d\n", + msgr->num, msgr->irq); + + } + + return 0; +} + +static const struct of_device_id mpic_msgr_ids[] = { + { + .compatible = "fsl,mpic-v3.1-msgr", + .data = NULL, + }, + {} +}; + +static struct platform_driver mpic_msgr_driver = { + .driver = { + .name = "mpic-msgr", + .owner = THIS_MODULE, + .of_match_table = mpic_msgr_ids, + }, + .probe = mpic_msgr_probe, +}; + +static __init int mpic_msgr_init(void) +{ + return platform_driver_register(&mpic_msgr_driver); +} +subsys_initcall(mpic_msgr_init);