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

arm_mhu_db.c (8504B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2013-2015 Fujitsu Semiconductor Ltd.
      4 * Copyright (C) 2015 Linaro Ltd.
      5 * Based on ARM MHU driver by Jassi Brar <jaswinder.singh@linaro.org>
      6 * Copyright (C) 2020 ARM Ltd.
      7 */
      8
      9#include <linux/amba/bus.h>
     10#include <linux/device.h>
     11#include <linux/err.h>
     12#include <linux/interrupt.h>
     13#include <linux/io.h>
     14#include <linux/kernel.h>
     15#include <linux/mailbox_controller.h>
     16#include <linux/module.h>
     17#include <linux/of.h>
     18#include <linux/of_device.h>
     19
     20#define INTR_STAT_OFS	0x0
     21#define INTR_SET_OFS	0x8
     22#define INTR_CLR_OFS	0x10
     23
     24#define MHU_LP_OFFSET	0x0
     25#define MHU_HP_OFFSET	0x20
     26#define MHU_SEC_OFFSET	0x200
     27#define TX_REG_OFFSET	0x100
     28
     29#define MHU_CHANS	3	/* Secure, Non-Secure High and Low Priority */
     30#define MHU_CHAN_MAX	20	/* Max channels to save on unused RAM */
     31#define MHU_NUM_DOORBELLS	32
     32
     33struct mhu_db_link {
     34	unsigned int irq;
     35	void __iomem *tx_reg;
     36	void __iomem *rx_reg;
     37};
     38
     39struct arm_mhu {
     40	void __iomem *base;
     41	struct mhu_db_link mlink[MHU_CHANS];
     42	struct mbox_controller mbox;
     43	struct device *dev;
     44};
     45
     46/**
     47 * struct mhu_db_channel - ARM MHU Mailbox allocated channel information
     48 *
     49 * @mhu: Pointer to parent mailbox device
     50 * @pchan: Physical channel within which this doorbell resides in
     51 * @doorbell: doorbell number pertaining to this channel
     52 */
     53struct mhu_db_channel {
     54	struct arm_mhu *mhu;
     55	unsigned int pchan;
     56	unsigned int doorbell;
     57};
     58
     59static inline struct mbox_chan *
     60mhu_db_mbox_to_channel(struct mbox_controller *mbox, unsigned int pchan,
     61		       unsigned int doorbell)
     62{
     63	int i;
     64	struct mhu_db_channel *chan_info;
     65
     66	for (i = 0; i < mbox->num_chans; i++) {
     67		chan_info = mbox->chans[i].con_priv;
     68		if (chan_info && chan_info->pchan == pchan &&
     69		    chan_info->doorbell == doorbell)
     70			return &mbox->chans[i];
     71	}
     72
     73	return NULL;
     74}
     75
     76static void mhu_db_mbox_clear_irq(struct mbox_chan *chan)
     77{
     78	struct mhu_db_channel *chan_info = chan->con_priv;
     79	void __iomem *base = chan_info->mhu->mlink[chan_info->pchan].rx_reg;
     80
     81	writel_relaxed(BIT(chan_info->doorbell), base + INTR_CLR_OFS);
     82}
     83
     84static unsigned int mhu_db_mbox_irq_to_pchan_num(struct arm_mhu *mhu, int irq)
     85{
     86	unsigned int pchan;
     87
     88	for (pchan = 0; pchan < MHU_CHANS; pchan++)
     89		if (mhu->mlink[pchan].irq == irq)
     90			break;
     91	return pchan;
     92}
     93
     94static struct mbox_chan *
     95mhu_db_mbox_irq_to_channel(struct arm_mhu *mhu, unsigned int pchan)
     96{
     97	unsigned long bits;
     98	unsigned int doorbell;
     99	struct mbox_chan *chan = NULL;
    100	struct mbox_controller *mbox = &mhu->mbox;
    101	void __iomem *base = mhu->mlink[pchan].rx_reg;
    102
    103	bits = readl_relaxed(base + INTR_STAT_OFS);
    104	if (!bits)
    105		/* No IRQs fired in specified physical channel */
    106		return NULL;
    107
    108	/* An IRQ has fired, find the associated channel */
    109	for (doorbell = 0; bits; doorbell++) {
    110		if (!test_and_clear_bit(doorbell, &bits))
    111			continue;
    112
    113		chan = mhu_db_mbox_to_channel(mbox, pchan, doorbell);
    114		if (chan)
    115			break;
    116		dev_err(mbox->dev,
    117			"Channel not registered: pchan: %d doorbell: %d\n",
    118			pchan, doorbell);
    119	}
    120
    121	return chan;
    122}
    123
    124static irqreturn_t mhu_db_mbox_rx_handler(int irq, void *data)
    125{
    126	struct mbox_chan *chan;
    127	struct arm_mhu *mhu = data;
    128	unsigned int pchan = mhu_db_mbox_irq_to_pchan_num(mhu, irq);
    129
    130	while (NULL != (chan = mhu_db_mbox_irq_to_channel(mhu, pchan))) {
    131		mbox_chan_received_data(chan, NULL);
    132		mhu_db_mbox_clear_irq(chan);
    133	}
    134
    135	return IRQ_HANDLED;
    136}
    137
    138static bool mhu_db_last_tx_done(struct mbox_chan *chan)
    139{
    140	struct mhu_db_channel *chan_info = chan->con_priv;
    141	void __iomem *base = chan_info->mhu->mlink[chan_info->pchan].tx_reg;
    142
    143	if (readl_relaxed(base + INTR_STAT_OFS) & BIT(chan_info->doorbell))
    144		return false;
    145
    146	return true;
    147}
    148
    149static int mhu_db_send_data(struct mbox_chan *chan, void *data)
    150{
    151	struct mhu_db_channel *chan_info = chan->con_priv;
    152	void __iomem *base = chan_info->mhu->mlink[chan_info->pchan].tx_reg;
    153
    154	/* Send event to co-processor */
    155	writel_relaxed(BIT(chan_info->doorbell), base + INTR_SET_OFS);
    156
    157	return 0;
    158}
    159
    160static int mhu_db_startup(struct mbox_chan *chan)
    161{
    162	mhu_db_mbox_clear_irq(chan);
    163	return 0;
    164}
    165
    166static void mhu_db_shutdown(struct mbox_chan *chan)
    167{
    168	struct mhu_db_channel *chan_info = chan->con_priv;
    169	struct mbox_controller *mbox = &chan_info->mhu->mbox;
    170	int i;
    171
    172	for (i = 0; i < mbox->num_chans; i++)
    173		if (chan == &mbox->chans[i])
    174			break;
    175
    176	if (mbox->num_chans == i) {
    177		dev_warn(mbox->dev, "Request to free non-existent channel\n");
    178		return;
    179	}
    180
    181	/* Reset channel */
    182	mhu_db_mbox_clear_irq(chan);
    183	devm_kfree(mbox->dev, chan->con_priv);
    184	chan->con_priv = NULL;
    185}
    186
    187static struct mbox_chan *mhu_db_mbox_xlate(struct mbox_controller *mbox,
    188					   const struct of_phandle_args *spec)
    189{
    190	struct arm_mhu *mhu = dev_get_drvdata(mbox->dev);
    191	struct mhu_db_channel *chan_info;
    192	struct mbox_chan *chan;
    193	unsigned int pchan = spec->args[0];
    194	unsigned int doorbell = spec->args[1];
    195	int i;
    196
    197	/* Bounds checking */
    198	if (pchan >= MHU_CHANS || doorbell >= MHU_NUM_DOORBELLS) {
    199		dev_err(mbox->dev,
    200			"Invalid channel requested pchan: %d doorbell: %d\n",
    201			pchan, doorbell);
    202		return ERR_PTR(-EINVAL);
    203	}
    204
    205	/* Is requested channel free? */
    206	chan = mhu_db_mbox_to_channel(mbox, pchan, doorbell);
    207	if (chan) {
    208		dev_err(mbox->dev, "Channel in use: pchan: %d doorbell: %d\n",
    209			pchan, doorbell);
    210		return ERR_PTR(-EBUSY);
    211	}
    212
    213	/* Find the first free slot */
    214	for (i = 0; i < mbox->num_chans; i++)
    215		if (!mbox->chans[i].con_priv)
    216			break;
    217
    218	if (mbox->num_chans == i) {
    219		dev_err(mbox->dev, "No free channels left\n");
    220		return ERR_PTR(-EBUSY);
    221	}
    222
    223	chan = &mbox->chans[i];
    224
    225	chan_info = devm_kzalloc(mbox->dev, sizeof(*chan_info), GFP_KERNEL);
    226	if (!chan_info)
    227		return ERR_PTR(-ENOMEM);
    228
    229	chan_info->mhu = mhu;
    230	chan_info->pchan = pchan;
    231	chan_info->doorbell = doorbell;
    232
    233	chan->con_priv = chan_info;
    234
    235	dev_dbg(mbox->dev, "mbox: created channel phys: %d doorbell: %d\n",
    236		pchan, doorbell);
    237
    238	return chan;
    239}
    240
    241static const struct mbox_chan_ops mhu_db_ops = {
    242	.send_data = mhu_db_send_data,
    243	.startup = mhu_db_startup,
    244	.shutdown = mhu_db_shutdown,
    245	.last_tx_done = mhu_db_last_tx_done,
    246};
    247
    248static int mhu_db_probe(struct amba_device *adev, const struct amba_id *id)
    249{
    250	u32 cell_count;
    251	int i, err, max_chans;
    252	struct arm_mhu *mhu;
    253	struct mbox_chan *chans;
    254	struct device *dev = &adev->dev;
    255	struct device_node *np = dev->of_node;
    256	int mhu_reg[MHU_CHANS] = {
    257		MHU_LP_OFFSET, MHU_HP_OFFSET, MHU_SEC_OFFSET,
    258	};
    259
    260	if (!of_device_is_compatible(np, "arm,mhu-doorbell"))
    261		return -ENODEV;
    262
    263	err = of_property_read_u32(np, "#mbox-cells", &cell_count);
    264	if (err) {
    265		dev_err(dev, "failed to read #mbox-cells in '%pOF'\n", np);
    266		return err;
    267	}
    268
    269	if (cell_count == 2) {
    270		max_chans = MHU_CHAN_MAX;
    271	} else {
    272		dev_err(dev, "incorrect value of #mbox-cells in '%pOF'\n", np);
    273		return -EINVAL;
    274	}
    275
    276	mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL);
    277	if (!mhu)
    278		return -ENOMEM;
    279
    280	mhu->base = devm_ioremap_resource(dev, &adev->res);
    281	if (IS_ERR(mhu->base))
    282		return PTR_ERR(mhu->base);
    283
    284	chans = devm_kcalloc(dev, max_chans, sizeof(*chans), GFP_KERNEL);
    285	if (!chans)
    286		return -ENOMEM;
    287
    288	mhu->dev = dev;
    289	mhu->mbox.dev = dev;
    290	mhu->mbox.chans = chans;
    291	mhu->mbox.num_chans = max_chans;
    292	mhu->mbox.txdone_irq = false;
    293	mhu->mbox.txdone_poll = true;
    294	mhu->mbox.txpoll_period = 1;
    295
    296	mhu->mbox.of_xlate = mhu_db_mbox_xlate;
    297	amba_set_drvdata(adev, mhu);
    298
    299	mhu->mbox.ops = &mhu_db_ops;
    300
    301	err = devm_mbox_controller_register(dev, &mhu->mbox);
    302	if (err) {
    303		dev_err(dev, "Failed to register mailboxes %d\n", err);
    304		return err;
    305	}
    306
    307	for (i = 0; i < MHU_CHANS; i++) {
    308		int irq = mhu->mlink[i].irq = adev->irq[i];
    309
    310		if (irq <= 0) {
    311			dev_dbg(dev, "No IRQ found for Channel %d\n", i);
    312			continue;
    313		}
    314
    315		mhu->mlink[i].rx_reg = mhu->base + mhu_reg[i];
    316		mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET;
    317
    318		err = devm_request_threaded_irq(dev, irq, NULL,
    319						mhu_db_mbox_rx_handler,
    320						IRQF_ONESHOT, "mhu_db_link", mhu);
    321		if (err) {
    322			dev_err(dev, "Can't claim IRQ %d\n", irq);
    323			mbox_controller_unregister(&mhu->mbox);
    324			return err;
    325		}
    326	}
    327
    328	dev_info(dev, "ARM MHU Doorbell mailbox registered\n");
    329	return 0;
    330}
    331
    332static struct amba_id mhu_ids[] = {
    333	{
    334		.id	= 0x1bb098,
    335		.mask	= 0xffffff,
    336	},
    337	{ 0, 0 },
    338};
    339MODULE_DEVICE_TABLE(amba, mhu_ids);
    340
    341static struct amba_driver arm_mhu_db_driver = {
    342	.drv = {
    343		.name	= "mhu-doorbell",
    344	},
    345	.id_table	= mhu_ids,
    346	.probe		= mhu_db_probe,
    347};
    348module_amba_driver(arm_mhu_db_driver);
    349
    350MODULE_LICENSE("GPL v2");
    351MODULE_DESCRIPTION("ARM MHU Doorbell Driver");
    352MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");