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

hi6220-mailbox.c (9131B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Hisilicon's Hi6220 mailbox driver
      4 *
      5 * Copyright (c) 2015 HiSilicon Limited.
      6 * Copyright (c) 2015 Linaro Limited.
      7 *
      8 * Author: Leo Yan <leo.yan@linaro.org>
      9 */
     10
     11#include <linux/device.h>
     12#include <linux/err.h>
     13#include <linux/interrupt.h>
     14#include <linux/io.h>
     15#include <linux/kfifo.h>
     16#include <linux/mailbox_controller.h>
     17#include <linux/module.h>
     18#include <linux/platform_device.h>
     19#include <linux/slab.h>
     20
     21#define MBOX_CHAN_MAX			32
     22
     23#define MBOX_TX				0x1
     24
     25/* Mailbox message length: 8 words */
     26#define MBOX_MSG_LEN			8
     27
     28/* Mailbox Registers */
     29#define MBOX_OFF(m)			(0x40 * (m))
     30#define MBOX_MODE_REG(m)		(MBOX_OFF(m) + 0x0)
     31#define MBOX_DATA_REG(m)		(MBOX_OFF(m) + 0x4)
     32
     33#define MBOX_STATE_MASK			(0xF << 4)
     34#define MBOX_STATE_IDLE			(0x1 << 4)
     35#define MBOX_STATE_TX			(0x2 << 4)
     36#define MBOX_STATE_RX			(0x4 << 4)
     37#define MBOX_STATE_ACK			(0x8 << 4)
     38#define MBOX_ACK_CONFIG_MASK		(0x1 << 0)
     39#define MBOX_ACK_AUTOMATIC		(0x1 << 0)
     40#define MBOX_ACK_IRQ			(0x0 << 0)
     41
     42/* IPC registers */
     43#define ACK_INT_RAW_REG(i)		((i) + 0x400)
     44#define ACK_INT_MSK_REG(i)		((i) + 0x404)
     45#define ACK_INT_STAT_REG(i)		((i) + 0x408)
     46#define ACK_INT_CLR_REG(i)		((i) + 0x40c)
     47#define ACK_INT_ENA_REG(i)		((i) + 0x500)
     48#define ACK_INT_DIS_REG(i)		((i) + 0x504)
     49#define DST_INT_RAW_REG(i)		((i) + 0x420)
     50
     51
     52struct hi6220_mbox_chan {
     53
     54	/*
     55	 * Description for channel's hardware info:
     56	 *  - direction: tx or rx
     57	 *  - dst irq: peer core's irq number
     58	 *  - ack irq: local irq number
     59	 *  - slot number
     60	 */
     61	unsigned int dir, dst_irq, ack_irq;
     62	unsigned int slot;
     63
     64	struct hi6220_mbox *parent;
     65};
     66
     67struct hi6220_mbox {
     68	struct device *dev;
     69
     70	int irq;
     71
     72	/* flag of enabling tx's irq mode */
     73	bool tx_irq_mode;
     74
     75	/* region for ipc event */
     76	void __iomem *ipc;
     77
     78	/* region for mailbox */
     79	void __iomem *base;
     80
     81	unsigned int chan_num;
     82	struct hi6220_mbox_chan *mchan;
     83
     84	void *irq_map_chan[MBOX_CHAN_MAX];
     85	struct mbox_chan *chan;
     86	struct mbox_controller controller;
     87};
     88
     89static void mbox_set_state(struct hi6220_mbox *mbox,
     90			   unsigned int slot, u32 val)
     91{
     92	u32 status;
     93
     94	status = readl(mbox->base + MBOX_MODE_REG(slot));
     95	status = (status & ~MBOX_STATE_MASK) | val;
     96	writel(status, mbox->base + MBOX_MODE_REG(slot));
     97}
     98
     99static void mbox_set_mode(struct hi6220_mbox *mbox,
    100			  unsigned int slot, u32 val)
    101{
    102	u32 mode;
    103
    104	mode = readl(mbox->base + MBOX_MODE_REG(slot));
    105	mode = (mode & ~MBOX_ACK_CONFIG_MASK) | val;
    106	writel(mode, mbox->base + MBOX_MODE_REG(slot));
    107}
    108
    109static bool hi6220_mbox_last_tx_done(struct mbox_chan *chan)
    110{
    111	struct hi6220_mbox_chan *mchan = chan->con_priv;
    112	struct hi6220_mbox *mbox = mchan->parent;
    113	u32 state;
    114
    115	/* Only set idle state for polling mode */
    116	BUG_ON(mbox->tx_irq_mode);
    117
    118	state = readl(mbox->base + MBOX_MODE_REG(mchan->slot));
    119	return ((state & MBOX_STATE_MASK) == MBOX_STATE_IDLE);
    120}
    121
    122static int hi6220_mbox_send_data(struct mbox_chan *chan, void *msg)
    123{
    124	struct hi6220_mbox_chan *mchan = chan->con_priv;
    125	struct hi6220_mbox *mbox = mchan->parent;
    126	unsigned int slot = mchan->slot;
    127	u32 *buf = msg;
    128	int i;
    129
    130	/* indicate as a TX channel */
    131	mchan->dir = MBOX_TX;
    132
    133	mbox_set_state(mbox, slot, MBOX_STATE_TX);
    134
    135	if (mbox->tx_irq_mode)
    136		mbox_set_mode(mbox, slot, MBOX_ACK_IRQ);
    137	else
    138		mbox_set_mode(mbox, slot, MBOX_ACK_AUTOMATIC);
    139
    140	for (i = 0; i < MBOX_MSG_LEN; i++)
    141		writel(buf[i], mbox->base + MBOX_DATA_REG(slot) + i * 4);
    142
    143	/* trigger remote request */
    144	writel(BIT(mchan->dst_irq), DST_INT_RAW_REG(mbox->ipc));
    145	return 0;
    146}
    147
    148static irqreturn_t hi6220_mbox_interrupt(int irq, void *p)
    149{
    150	struct hi6220_mbox *mbox = p;
    151	struct hi6220_mbox_chan *mchan;
    152	struct mbox_chan *chan;
    153	unsigned int state, intr_bit, i;
    154	u32 msg[MBOX_MSG_LEN];
    155
    156	state = readl(ACK_INT_STAT_REG(mbox->ipc));
    157	if (!state) {
    158		dev_warn(mbox->dev, "%s: spurious interrupt\n",
    159			 __func__);
    160		return IRQ_HANDLED;
    161	}
    162
    163	while (state) {
    164		intr_bit = __ffs(state);
    165		state &= (state - 1);
    166
    167		chan = mbox->irq_map_chan[intr_bit];
    168		if (!chan) {
    169			dev_warn(mbox->dev, "%s: unexpected irq vector %d\n",
    170				 __func__, intr_bit);
    171			continue;
    172		}
    173
    174		mchan = chan->con_priv;
    175		if (mchan->dir == MBOX_TX)
    176			mbox_chan_txdone(chan, 0);
    177		else {
    178			for (i = 0; i < MBOX_MSG_LEN; i++)
    179				msg[i] = readl(mbox->base +
    180					MBOX_DATA_REG(mchan->slot) + i * 4);
    181
    182			mbox_chan_received_data(chan, (void *)msg);
    183		}
    184
    185		/* clear IRQ source */
    186		writel(BIT(mchan->ack_irq), ACK_INT_CLR_REG(mbox->ipc));
    187		mbox_set_state(mbox, mchan->slot, MBOX_STATE_IDLE);
    188	}
    189
    190	return IRQ_HANDLED;
    191}
    192
    193static int hi6220_mbox_startup(struct mbox_chan *chan)
    194{
    195	struct hi6220_mbox_chan *mchan = chan->con_priv;
    196	struct hi6220_mbox *mbox = mchan->parent;
    197
    198	mchan->dir = 0;
    199
    200	/* enable interrupt */
    201	writel(BIT(mchan->ack_irq), ACK_INT_ENA_REG(mbox->ipc));
    202	return 0;
    203}
    204
    205static void hi6220_mbox_shutdown(struct mbox_chan *chan)
    206{
    207	struct hi6220_mbox_chan *mchan = chan->con_priv;
    208	struct hi6220_mbox *mbox = mchan->parent;
    209
    210	/* disable interrupt */
    211	writel(BIT(mchan->ack_irq), ACK_INT_DIS_REG(mbox->ipc));
    212	mbox->irq_map_chan[mchan->ack_irq] = NULL;
    213}
    214
    215static const struct mbox_chan_ops hi6220_mbox_ops = {
    216	.send_data    = hi6220_mbox_send_data,
    217	.startup      = hi6220_mbox_startup,
    218	.shutdown     = hi6220_mbox_shutdown,
    219	.last_tx_done = hi6220_mbox_last_tx_done,
    220};
    221
    222static struct mbox_chan *hi6220_mbox_xlate(struct mbox_controller *controller,
    223					   const struct of_phandle_args *spec)
    224{
    225	struct hi6220_mbox *mbox = dev_get_drvdata(controller->dev);
    226	struct hi6220_mbox_chan *mchan;
    227	struct mbox_chan *chan;
    228	unsigned int i = spec->args[0];
    229	unsigned int dst_irq = spec->args[1];
    230	unsigned int ack_irq = spec->args[2];
    231
    232	/* Bounds checking */
    233	if (i >= mbox->chan_num || dst_irq >= mbox->chan_num ||
    234	    ack_irq >= mbox->chan_num) {
    235		dev_err(mbox->dev,
    236			"Invalid channel idx %d dst_irq %d ack_irq %d\n",
    237			i, dst_irq, ack_irq);
    238		return ERR_PTR(-EINVAL);
    239	}
    240
    241	/* Is requested channel free? */
    242	chan = &mbox->chan[i];
    243	if (mbox->irq_map_chan[ack_irq] == (void *)chan) {
    244		dev_err(mbox->dev, "Channel in use\n");
    245		return ERR_PTR(-EBUSY);
    246	}
    247
    248	mchan = chan->con_priv;
    249	mchan->dst_irq = dst_irq;
    250	mchan->ack_irq = ack_irq;
    251
    252	mbox->irq_map_chan[ack_irq] = (void *)chan;
    253	return chan;
    254}
    255
    256static const struct of_device_id hi6220_mbox_of_match[] = {
    257	{ .compatible = "hisilicon,hi6220-mbox", },
    258	{},
    259};
    260MODULE_DEVICE_TABLE(of, hi6220_mbox_of_match);
    261
    262static int hi6220_mbox_probe(struct platform_device *pdev)
    263{
    264	struct device_node *node = pdev->dev.of_node;
    265	struct device *dev = &pdev->dev;
    266	struct hi6220_mbox *mbox;
    267	int i, err;
    268
    269	mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
    270	if (!mbox)
    271		return -ENOMEM;
    272
    273	mbox->dev = dev;
    274	mbox->chan_num = MBOX_CHAN_MAX;
    275	mbox->mchan = devm_kcalloc(dev,
    276		mbox->chan_num, sizeof(*mbox->mchan), GFP_KERNEL);
    277	if (!mbox->mchan)
    278		return -ENOMEM;
    279
    280	mbox->chan = devm_kcalloc(dev,
    281		mbox->chan_num, sizeof(*mbox->chan), GFP_KERNEL);
    282	if (!mbox->chan)
    283		return -ENOMEM;
    284
    285	mbox->irq = platform_get_irq(pdev, 0);
    286	if (mbox->irq < 0)
    287		return mbox->irq;
    288
    289	mbox->ipc = devm_platform_ioremap_resource(pdev, 0);
    290	if (IS_ERR(mbox->ipc)) {
    291		dev_err(dev, "ioremap ipc failed\n");
    292		return PTR_ERR(mbox->ipc);
    293	}
    294
    295	mbox->base = devm_platform_ioremap_resource(pdev, 1);
    296	if (IS_ERR(mbox->base)) {
    297		dev_err(dev, "ioremap buffer failed\n");
    298		return PTR_ERR(mbox->base);
    299	}
    300
    301	err = devm_request_irq(dev, mbox->irq, hi6220_mbox_interrupt, 0,
    302			dev_name(dev), mbox);
    303	if (err) {
    304		dev_err(dev, "Failed to register a mailbox IRQ handler: %d\n",
    305			err);
    306		return -ENODEV;
    307	}
    308
    309	mbox->controller.dev = dev;
    310	mbox->controller.chans = &mbox->chan[0];
    311	mbox->controller.num_chans = mbox->chan_num;
    312	mbox->controller.ops = &hi6220_mbox_ops;
    313	mbox->controller.of_xlate = hi6220_mbox_xlate;
    314
    315	for (i = 0; i < mbox->chan_num; i++) {
    316		mbox->chan[i].con_priv = &mbox->mchan[i];
    317		mbox->irq_map_chan[i] = NULL;
    318
    319		mbox->mchan[i].parent = mbox;
    320		mbox->mchan[i].slot   = i;
    321	}
    322
    323	/* mask and clear all interrupt vectors */
    324	writel(0x0,  ACK_INT_MSK_REG(mbox->ipc));
    325	writel(~0x0, ACK_INT_CLR_REG(mbox->ipc));
    326
    327	/* use interrupt for tx's ack */
    328	if (of_find_property(node, "hi6220,mbox-tx-noirq", NULL))
    329		mbox->tx_irq_mode = false;
    330	else
    331		mbox->tx_irq_mode = true;
    332
    333	if (mbox->tx_irq_mode)
    334		mbox->controller.txdone_irq = true;
    335	else {
    336		mbox->controller.txdone_poll = true;
    337		mbox->controller.txpoll_period = 5;
    338	}
    339
    340	err = devm_mbox_controller_register(dev, &mbox->controller);
    341	if (err) {
    342		dev_err(dev, "Failed to register mailbox %d\n", err);
    343		return err;
    344	}
    345
    346	platform_set_drvdata(pdev, mbox);
    347	dev_info(dev, "Mailbox enabled\n");
    348	return 0;
    349}
    350
    351static struct platform_driver hi6220_mbox_driver = {
    352	.driver = {
    353		.name = "hi6220-mbox",
    354		.of_match_table = hi6220_mbox_of_match,
    355	},
    356	.probe	= hi6220_mbox_probe,
    357};
    358
    359static int __init hi6220_mbox_init(void)
    360{
    361	return platform_driver_register(&hi6220_mbox_driver);
    362}
    363core_initcall(hi6220_mbox_init);
    364
    365static void __exit hi6220_mbox_exit(void)
    366{
    367	platform_driver_unregister(&hi6220_mbox_driver);
    368}
    369module_exit(hi6220_mbox_exit);
    370
    371MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
    372MODULE_DESCRIPTION("Hi6220 mailbox driver");
    373MODULE_LICENSE("GPL v2");