cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mpic_msgr.c (6829B)


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