Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation.
0004  *
0005  * Some ideas based on un-pushed work done by Vivek Mahajan, Jason Jin, and
0006  * Mingkai Hu from Freescale Semiconductor, Inc.
0007  */
0008 
0009 #include <linux/list.h>
0010 #include <linux/of_address.h>
0011 #include <linux/of_irq.h>
0012 #include <linux/of_platform.h>
0013 #include <linux/errno.h>
0014 #include <linux/err.h>
0015 #include <linux/export.h>
0016 #include <linux/slab.h>
0017 #include <asm/hw_irq.h>
0018 #include <asm/ppc-pci.h>
0019 #include <asm/mpic_msgr.h>
0020 
0021 #define MPIC_MSGR_REGISTERS_PER_BLOCK   4
0022 #define MPIC_MSGR_STRIDE        0x10
0023 #define MPIC_MSGR_MER_OFFSET        0x100
0024 #define MSGR_INUSE          0
0025 #define MSGR_FREE           1
0026 
0027 static struct mpic_msgr **mpic_msgrs;
0028 static unsigned int mpic_msgr_count;
0029 static DEFINE_RAW_SPINLOCK(msgrs_lock);
0030 
0031 static inline void _mpic_msgr_mer_write(struct mpic_msgr *msgr, u32 value)
0032 {
0033     out_be32(msgr->mer, value);
0034 }
0035 
0036 static inline u32 _mpic_msgr_mer_read(struct mpic_msgr *msgr)
0037 {
0038     return in_be32(msgr->mer);
0039 }
0040 
0041 static inline void _mpic_msgr_disable(struct mpic_msgr *msgr)
0042 {
0043     u32 mer = _mpic_msgr_mer_read(msgr);
0044 
0045     _mpic_msgr_mer_write(msgr, mer & ~(1 << msgr->num));
0046 }
0047 
0048 struct mpic_msgr *mpic_msgr_get(unsigned int reg_num)
0049 {
0050     unsigned long flags;
0051     struct mpic_msgr *msgr;
0052 
0053     /* Assume busy until proven otherwise.  */
0054     msgr = ERR_PTR(-EBUSY);
0055 
0056     if (reg_num >= mpic_msgr_count)
0057         return ERR_PTR(-ENODEV);
0058 
0059     raw_spin_lock_irqsave(&msgrs_lock, flags);
0060     msgr = mpic_msgrs[reg_num];
0061     if (msgr->in_use == MSGR_FREE)
0062         msgr->in_use = MSGR_INUSE;
0063     raw_spin_unlock_irqrestore(&msgrs_lock, flags);
0064 
0065     return msgr;
0066 }
0067 EXPORT_SYMBOL_GPL(mpic_msgr_get);
0068 
0069 void mpic_msgr_put(struct mpic_msgr *msgr)
0070 {
0071     unsigned long flags;
0072 
0073     raw_spin_lock_irqsave(&msgr->lock, flags);
0074     msgr->in_use = MSGR_FREE;
0075     _mpic_msgr_disable(msgr);
0076     raw_spin_unlock_irqrestore(&msgr->lock, flags);
0077 }
0078 EXPORT_SYMBOL_GPL(mpic_msgr_put);
0079 
0080 void mpic_msgr_enable(struct mpic_msgr *msgr)
0081 {
0082     unsigned long flags;
0083     u32 mer;
0084 
0085     raw_spin_lock_irqsave(&msgr->lock, flags);
0086     mer = _mpic_msgr_mer_read(msgr);
0087     _mpic_msgr_mer_write(msgr, mer | (1 << msgr->num));
0088     raw_spin_unlock_irqrestore(&msgr->lock, flags);
0089 }
0090 EXPORT_SYMBOL_GPL(mpic_msgr_enable);
0091 
0092 void mpic_msgr_disable(struct mpic_msgr *msgr)
0093 {
0094     unsigned long flags;
0095 
0096     raw_spin_lock_irqsave(&msgr->lock, flags);
0097     _mpic_msgr_disable(msgr);
0098     raw_spin_unlock_irqrestore(&msgr->lock, flags);
0099 }
0100 EXPORT_SYMBOL_GPL(mpic_msgr_disable);
0101 
0102 /* The following three functions are used to compute the order and number of
0103  * the message register blocks.  They are clearly very inefficient.  However,
0104  * they are called *only* a few times during device initialization.
0105  */
0106 static unsigned int mpic_msgr_number_of_blocks(void)
0107 {
0108     unsigned int count;
0109     struct device_node *aliases;
0110 
0111     count = 0;
0112     aliases = of_find_node_by_name(NULL, "aliases");
0113 
0114     if (aliases) {
0115         char buf[32];
0116 
0117         for (;;) {
0118             snprintf(buf, sizeof(buf), "mpic-msgr-block%d", count);
0119             if (!of_find_property(aliases, buf, NULL))
0120                 break;
0121 
0122             count += 1;
0123         }
0124     }
0125 
0126     return count;
0127 }
0128 
0129 static unsigned int mpic_msgr_number_of_registers(void)
0130 {
0131     return mpic_msgr_number_of_blocks() * MPIC_MSGR_REGISTERS_PER_BLOCK;
0132 }
0133 
0134 static int mpic_msgr_block_number(struct device_node *node)
0135 {
0136     struct device_node *aliases;
0137     unsigned int index, number_of_blocks;
0138     char buf[64];
0139 
0140     number_of_blocks = mpic_msgr_number_of_blocks();
0141     aliases = of_find_node_by_name(NULL, "aliases");
0142     if (!aliases)
0143         return -1;
0144 
0145     for (index = 0; index < number_of_blocks; ++index) {
0146         struct property *prop;
0147 
0148         snprintf(buf, sizeof(buf), "mpic-msgr-block%d", index);
0149         prop = of_find_property(aliases, buf, NULL);
0150         if (node == of_find_node_by_path(prop->value))
0151             break;
0152     }
0153 
0154     return index == number_of_blocks ? -1 : index;
0155 }
0156 
0157 /* The probe function for a single message register block.
0158  */
0159 static int mpic_msgr_probe(struct platform_device *dev)
0160 {
0161     void __iomem *msgr_block_addr;
0162     int block_number;
0163     struct resource rsrc;
0164     unsigned int i;
0165     unsigned int irq_index;
0166     struct device_node *np = dev->dev.of_node;
0167     unsigned int receive_mask;
0168     const unsigned int *prop;
0169 
0170     if (!np) {
0171         dev_err(&dev->dev, "Device OF-Node is NULL");
0172         return -EFAULT;
0173     }
0174 
0175     /* Allocate the message register array upon the first device
0176      * registered.
0177      */
0178     if (!mpic_msgrs) {
0179         mpic_msgr_count = mpic_msgr_number_of_registers();
0180         dev_info(&dev->dev, "Found %d message registers\n",
0181                 mpic_msgr_count);
0182 
0183         mpic_msgrs = kcalloc(mpic_msgr_count, sizeof(*mpic_msgrs),
0184                              GFP_KERNEL);
0185         if (!mpic_msgrs) {
0186             dev_err(&dev->dev,
0187                 "No memory for message register blocks\n");
0188             return -ENOMEM;
0189         }
0190     }
0191     dev_info(&dev->dev, "Of-device full name %pOF\n", np);
0192 
0193     /* IO map the message register block. */
0194     of_address_to_resource(np, 0, &rsrc);
0195     msgr_block_addr = devm_ioremap(&dev->dev, rsrc.start, resource_size(&rsrc));
0196     if (!msgr_block_addr) {
0197         dev_err(&dev->dev, "Failed to iomap MPIC message registers");
0198         return -EFAULT;
0199     }
0200 
0201     /* Ensure the block has a defined order. */
0202     block_number = mpic_msgr_block_number(np);
0203     if (block_number < 0) {
0204         dev_err(&dev->dev,
0205             "Failed to find message register block alias\n");
0206         return -ENODEV;
0207     }
0208     dev_info(&dev->dev, "Setting up message register block %d\n",
0209             block_number);
0210 
0211     /* Grab the receive mask which specifies what registers can receive
0212      * interrupts.
0213      */
0214     prop = of_get_property(np, "mpic-msgr-receive-mask", NULL);
0215     receive_mask = (prop) ? *prop : 0xF;
0216 
0217     /* Build up the appropriate message register data structures. */
0218     for (i = 0, irq_index = 0; i < MPIC_MSGR_REGISTERS_PER_BLOCK; ++i) {
0219         struct mpic_msgr *msgr;
0220         unsigned int reg_number;
0221 
0222         msgr = kzalloc(sizeof(struct mpic_msgr), GFP_KERNEL);
0223         if (!msgr) {
0224             dev_err(&dev->dev, "No memory for message register\n");
0225             return -ENOMEM;
0226         }
0227 
0228         reg_number = block_number * MPIC_MSGR_REGISTERS_PER_BLOCK + i;
0229         msgr->base = msgr_block_addr + i * MPIC_MSGR_STRIDE;
0230         msgr->mer = (u32 *)((u8 *)msgr->base + MPIC_MSGR_MER_OFFSET);
0231         msgr->in_use = MSGR_FREE;
0232         msgr->num = i;
0233         raw_spin_lock_init(&msgr->lock);
0234 
0235         if (receive_mask & (1 << i)) {
0236             msgr->irq = irq_of_parse_and_map(np, irq_index);
0237             if (!msgr->irq) {
0238                 dev_err(&dev->dev,
0239                         "Missing interrupt specifier");
0240                 kfree(msgr);
0241                 return -EFAULT;
0242             }
0243             irq_index += 1;
0244         } else {
0245             msgr->irq = 0;
0246         }
0247 
0248         mpic_msgrs[reg_number] = msgr;
0249         mpic_msgr_disable(msgr);
0250         dev_info(&dev->dev, "Register %d initialized: irq %d\n",
0251                 reg_number, msgr->irq);
0252 
0253     }
0254 
0255     return 0;
0256 }
0257 
0258 static const struct of_device_id mpic_msgr_ids[] = {
0259     {
0260         .compatible = "fsl,mpic-v3.1-msgr",
0261         .data = NULL,
0262     },
0263     {}
0264 };
0265 
0266 static struct platform_driver mpic_msgr_driver = {
0267     .driver = {
0268         .name = "mpic-msgr",
0269         .of_match_table = mpic_msgr_ids,
0270     },
0271     .probe = mpic_msgr_probe,
0272 };
0273 
0274 static __init int mpic_msgr_init(void)
0275 {
0276     return platform_driver_register(&mpic_msgr_driver);
0277 }
0278 subsys_initcall(mpic_msgr_init);