linux/arch/powerpc/sysdev/mpic_msgr.c
<<
>>
Prefs
   1/*
   2 * Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation.
   3 *
   4 * Some ideas based on un-pushed work done by Vivek Mahajan, Jason Jin, and
   5 * Mingkai Hu from Freescale Semiconductor, Inc.
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License
   9 * as published by the Free Software Foundation; version 2 of the
  10 * License.
  11 *
  12 */
  13
  14#include <linux/list.h>
  15#include <linux/of_platform.h>
  16#include <linux/errno.h>
  17#include <linux/err.h>
  18#include <linux/export.h>
  19#include <linux/slab.h>
  20#include <asm/prom.h>
  21#include <asm/hw_irq.h>
  22#include <asm/ppc-pci.h>
  23#include <asm/mpic_msgr.h>
  24
  25#define MPIC_MSGR_REGISTERS_PER_BLOCK   4
  26#define MPIC_MSGR_STRIDE                0x10
  27#define MPIC_MSGR_MER_OFFSET            0x100
  28#define MSGR_INUSE                      0
  29#define MSGR_FREE                       1
  30
  31static struct mpic_msgr **mpic_msgrs;
  32static unsigned int mpic_msgr_count;
  33static DEFINE_RAW_SPINLOCK(msgrs_lock);
  34
  35static inline void _mpic_msgr_mer_write(struct mpic_msgr *msgr, u32 value)
  36{
  37        out_be32(msgr->mer, value);
  38}
  39
  40static inline u32 _mpic_msgr_mer_read(struct mpic_msgr *msgr)
  41{
  42        return in_be32(msgr->mer);
  43}
  44
  45static inline void _mpic_msgr_disable(struct mpic_msgr *msgr)
  46{
  47        u32 mer = _mpic_msgr_mer_read(msgr);
  48
  49        _mpic_msgr_mer_write(msgr, mer & ~(1 << msgr->num));
  50}
  51
  52struct mpic_msgr *mpic_msgr_get(unsigned int reg_num)
  53{
  54        unsigned long flags;
  55        struct mpic_msgr *msgr;
  56
  57        /* Assume busy until proven otherwise.  */
  58        msgr = ERR_PTR(-EBUSY);
  59
  60        if (reg_num >= mpic_msgr_count)
  61                return ERR_PTR(-ENODEV);
  62
  63        raw_spin_lock_irqsave(&msgrs_lock, flags);
  64        msgr = mpic_msgrs[reg_num];
  65        if (msgr->in_use == MSGR_FREE)
  66                msgr->in_use = MSGR_INUSE;
  67        raw_spin_unlock_irqrestore(&msgrs_lock, flags);
  68
  69        return msgr;
  70}
  71EXPORT_SYMBOL_GPL(mpic_msgr_get);
  72
  73void mpic_msgr_put(struct mpic_msgr *msgr)
  74{
  75        unsigned long flags;
  76
  77        raw_spin_lock_irqsave(&msgr->lock, flags);
  78        msgr->in_use = MSGR_FREE;
  79        _mpic_msgr_disable(msgr);
  80        raw_spin_unlock_irqrestore(&msgr->lock, flags);
  81}
  82EXPORT_SYMBOL_GPL(mpic_msgr_put);
  83
  84void mpic_msgr_enable(struct mpic_msgr *msgr)
  85{
  86        unsigned long flags;
  87        u32 mer;
  88
  89        raw_spin_lock_irqsave(&msgr->lock, flags);
  90        mer = _mpic_msgr_mer_read(msgr);
  91        _mpic_msgr_mer_write(msgr, mer | (1 << msgr->num));
  92        raw_spin_unlock_irqrestore(&msgr->lock, flags);
  93}
  94EXPORT_SYMBOL_GPL(mpic_msgr_enable);
  95
  96void mpic_msgr_disable(struct mpic_msgr *msgr)
  97{
  98        unsigned long flags;
  99
 100        raw_spin_lock_irqsave(&msgr->lock, flags);
 101        _mpic_msgr_disable(msgr);
 102        raw_spin_unlock_irqrestore(&msgr->lock, flags);
 103}
 104EXPORT_SYMBOL_GPL(mpic_msgr_disable);
 105
 106/* The following three functions are used to compute the order and number of
 107 * the message register blocks.  They are clearly very inefficent.  However,
 108 * they are called *only* a few times during device initialization.
 109 */
 110static unsigned int mpic_msgr_number_of_blocks(void)
 111{
 112        unsigned int count;
 113        struct device_node *aliases;
 114
 115        count = 0;
 116        aliases = of_find_node_by_name(NULL, "aliases");
 117
 118        if (aliases) {
 119                char buf[32];
 120
 121                for (;;) {
 122                        snprintf(buf, sizeof(buf), "mpic-msgr-block%d", count);
 123                        if (!of_find_property(aliases, buf, NULL))
 124                                break;
 125
 126                        count += 1;
 127                }
 128        }
 129
 130        return count;
 131}
 132
 133static unsigned int mpic_msgr_number_of_registers(void)
 134{
 135        return mpic_msgr_number_of_blocks() * MPIC_MSGR_REGISTERS_PER_BLOCK;
 136}
 137
 138static int mpic_msgr_block_number(struct device_node *node)
 139{
 140        struct device_node *aliases;
 141        unsigned int index, number_of_blocks;
 142        char buf[64];
 143
 144        number_of_blocks = mpic_msgr_number_of_blocks();
 145        aliases = of_find_node_by_name(NULL, "aliases");
 146        if (!aliases)
 147                return -1;
 148
 149        for (index = 0; index < number_of_blocks; ++index) {
 150                struct property *prop;
 151
 152                snprintf(buf, sizeof(buf), "mpic-msgr-block%d", index);
 153                prop = of_find_property(aliases, buf, NULL);
 154                if (node == of_find_node_by_path(prop->value))
 155                        break;
 156        }
 157
 158        return index == number_of_blocks ? -1 : index;
 159}
 160
 161/* The probe function for a single message register block.
 162 */
 163static int mpic_msgr_probe(struct platform_device *dev)
 164{
 165        void __iomem *msgr_block_addr;
 166        int block_number;
 167        struct resource rsrc;
 168        unsigned int i;
 169        unsigned int irq_index;
 170        struct device_node *np = dev->dev.of_node;
 171        unsigned int receive_mask;
 172        const unsigned int *prop;
 173
 174        if (!np) {
 175                dev_err(&dev->dev, "Device OF-Node is NULL");
 176                return -EFAULT;
 177        }
 178
 179        /* Allocate the message register array upon the first device
 180         * registered.
 181         */
 182        if (!mpic_msgrs) {
 183                mpic_msgr_count = mpic_msgr_number_of_registers();
 184                dev_info(&dev->dev, "Found %d message registers\n",
 185                                mpic_msgr_count);
 186
 187                mpic_msgrs = kcalloc(mpic_msgr_count, sizeof(*mpic_msgrs),
 188                                                         GFP_KERNEL);
 189                if (!mpic_msgrs) {
 190                        dev_err(&dev->dev,
 191                                "No memory for message register blocks\n");
 192                        return -ENOMEM;
 193                }
 194        }
 195        dev_info(&dev->dev, "Of-device full name %s\n", np->full_name);
 196
 197        /* IO map the message register block. */
 198        of_address_to_resource(np, 0, &rsrc);
 199        msgr_block_addr = ioremap(rsrc.start, rsrc.end - rsrc.start);
 200        if (!msgr_block_addr) {
 201                dev_err(&dev->dev, "Failed to iomap MPIC message registers");
 202                return -EFAULT;
 203        }
 204
 205        /* Ensure the block has a defined order. */
 206        block_number = mpic_msgr_block_number(np);
 207        if (block_number < 0) {
 208                dev_err(&dev->dev,
 209                        "Failed to find message register block alias\n");
 210                return -ENODEV;
 211        }
 212        dev_info(&dev->dev, "Setting up message register block %d\n",
 213                        block_number);
 214
 215        /* Grab the receive mask which specifies what registers can receive
 216         * interrupts.
 217         */
 218        prop = of_get_property(np, "mpic-msgr-receive-mask", NULL);
 219        receive_mask = (prop) ? *prop : 0xF;
 220
 221        /* Build up the appropriate message register data structures. */
 222        for (i = 0, irq_index = 0; i < MPIC_MSGR_REGISTERS_PER_BLOCK; ++i) {
 223                struct mpic_msgr *msgr;
 224                unsigned int reg_number;
 225
 226                msgr = kzalloc(sizeof(struct mpic_msgr), GFP_KERNEL);
 227                if (!msgr) {
 228                        dev_err(&dev->dev, "No memory for message register\n");
 229                        return -ENOMEM;
 230                }
 231
 232                reg_number = block_number * MPIC_MSGR_REGISTERS_PER_BLOCK + i;
 233                msgr->base = msgr_block_addr + i * MPIC_MSGR_STRIDE;
 234                msgr->mer = (u32 *)((u8 *)msgr->base + MPIC_MSGR_MER_OFFSET);
 235                msgr->in_use = MSGR_FREE;
 236                msgr->num = i;
 237                raw_spin_lock_init(&msgr->lock);
 238
 239                if (receive_mask & (1 << i)) {
 240                        msgr->irq = irq_of_parse_and_map(np, irq_index);
 241                        if (msgr->irq == NO_IRQ) {
 242                                dev_err(&dev->dev,
 243                                                "Missing interrupt specifier");
 244                                kfree(msgr);
 245                                return -EFAULT;
 246                        }
 247                        irq_index += 1;
 248                } else {
 249                        msgr->irq = NO_IRQ;
 250                }
 251
 252                mpic_msgrs[reg_number] = msgr;
 253                mpic_msgr_disable(msgr);
 254                dev_info(&dev->dev, "Register %d initialized: irq %d\n",
 255                                reg_number, msgr->irq);
 256
 257        }
 258
 259        return 0;
 260}
 261
 262static const struct of_device_id mpic_msgr_ids[] = {
 263        {
 264                .compatible = "fsl,mpic-v3.1-msgr",
 265                .data = NULL,
 266        },
 267        {}
 268};
 269
 270static struct platform_driver mpic_msgr_driver = {
 271        .driver = {
 272                .name = "mpic-msgr",
 273                .of_match_table = mpic_msgr_ids,
 274        },
 275        .probe = mpic_msgr_probe,
 276};
 277
 278static __init int mpic_msgr_init(void)
 279{
 280        return platform_driver_register(&mpic_msgr_driver);
 281}
 282subsys_initcall(mpic_msgr_init);
 283