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

mailbox-xgene-slimpro.c (6595B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * APM X-Gene SLIMpro MailBox Driver
      4 *
      5 * Copyright (c) 2015, Applied Micro Circuits Corporation
      6 * Author: Feng Kan fkan@apm.com
      7 */
      8#include <linux/acpi.h>
      9#include <linux/delay.h>
     10#include <linux/interrupt.h>
     11#include <linux/io.h>
     12#include <linux/mailbox_controller.h>
     13#include <linux/module.h>
     14#include <linux/of.h>
     15#include <linux/platform_device.h>
     16#include <linux/spinlock.h>
     17
     18#define MBOX_CON_NAME			"slimpro-mbox"
     19#define MBOX_REG_SET_OFFSET		0x1000
     20#define MBOX_CNT			8
     21#define MBOX_STATUS_AVAIL_MASK		BIT(16)
     22#define MBOX_STATUS_ACK_MASK		BIT(0)
     23
     24/* Configuration and Status Registers */
     25#define REG_DB_IN		0x00
     26#define REG_DB_DIN0		0x04
     27#define REG_DB_DIN1		0x08
     28#define REG_DB_OUT		0x10
     29#define REG_DB_DOUT0		0x14
     30#define REG_DB_DOUT1		0x18
     31#define REG_DB_STAT		0x20
     32#define REG_DB_STATMASK		0x24
     33
     34/**
     35 * X-Gene SlimPRO mailbox channel information
     36 *
     37 * @dev:	Device to which it is attached
     38 * @chan:	Pointer to mailbox communication channel
     39 * @reg:	Base address to access channel registers
     40 * @irq:	Interrupt number of the channel
     41 * @rx_msg:	Received message storage
     42 */
     43struct slimpro_mbox_chan {
     44	struct device		*dev;
     45	struct mbox_chan	*chan;
     46	void __iomem		*reg;
     47	int			irq;
     48	u32			rx_msg[3];
     49};
     50
     51/**
     52 * X-Gene SlimPRO Mailbox controller data
     53 *
     54 * X-Gene SlimPRO Mailbox controller has 8 communication channels.
     55 * Each channel has a separate IRQ number assigned to it.
     56 *
     57 * @mb_ctrl:	Representation of the communication channel controller
     58 * @mc:		Array of SlimPRO mailbox channels of the controller
     59 * @chans:	Array of mailbox communication channels
     60 *
     61 */
     62struct slimpro_mbox {
     63	struct mbox_controller		mb_ctrl;
     64	struct slimpro_mbox_chan	mc[MBOX_CNT];
     65	struct mbox_chan		chans[MBOX_CNT];
     66};
     67
     68static void mb_chan_send_msg(struct slimpro_mbox_chan *mb_chan, u32 *msg)
     69{
     70	writel(msg[1], mb_chan->reg + REG_DB_DOUT0);
     71	writel(msg[2], mb_chan->reg + REG_DB_DOUT1);
     72	writel(msg[0], mb_chan->reg + REG_DB_OUT);
     73}
     74
     75static void mb_chan_recv_msg(struct slimpro_mbox_chan *mb_chan)
     76{
     77	mb_chan->rx_msg[1] = readl(mb_chan->reg + REG_DB_DIN0);
     78	mb_chan->rx_msg[2] = readl(mb_chan->reg + REG_DB_DIN1);
     79	mb_chan->rx_msg[0] = readl(mb_chan->reg + REG_DB_IN);
     80}
     81
     82static int mb_chan_status_ack(struct slimpro_mbox_chan *mb_chan)
     83{
     84	u32 val = readl(mb_chan->reg + REG_DB_STAT);
     85
     86	if (val & MBOX_STATUS_ACK_MASK) {
     87		writel(MBOX_STATUS_ACK_MASK, mb_chan->reg + REG_DB_STAT);
     88		return 1;
     89	}
     90	return 0;
     91}
     92
     93static int mb_chan_status_avail(struct slimpro_mbox_chan *mb_chan)
     94{
     95	u32 val = readl(mb_chan->reg + REG_DB_STAT);
     96
     97	if (val & MBOX_STATUS_AVAIL_MASK) {
     98		mb_chan_recv_msg(mb_chan);
     99		writel(MBOX_STATUS_AVAIL_MASK, mb_chan->reg + REG_DB_STAT);
    100		return 1;
    101	}
    102	return 0;
    103}
    104
    105static irqreturn_t slimpro_mbox_irq(int irq, void *id)
    106{
    107	struct slimpro_mbox_chan *mb_chan = id;
    108
    109	if (mb_chan_status_ack(mb_chan))
    110		mbox_chan_txdone(mb_chan->chan, 0);
    111
    112	if (mb_chan_status_avail(mb_chan))
    113		mbox_chan_received_data(mb_chan->chan, mb_chan->rx_msg);
    114
    115	return IRQ_HANDLED;
    116}
    117
    118static int slimpro_mbox_send_data(struct mbox_chan *chan, void *msg)
    119{
    120	struct slimpro_mbox_chan *mb_chan = chan->con_priv;
    121
    122	mb_chan_send_msg(mb_chan, msg);
    123	return 0;
    124}
    125
    126static int slimpro_mbox_startup(struct mbox_chan *chan)
    127{
    128	struct slimpro_mbox_chan *mb_chan = chan->con_priv;
    129	int rc;
    130	u32 val;
    131
    132	rc = devm_request_irq(mb_chan->dev, mb_chan->irq, slimpro_mbox_irq, 0,
    133			      MBOX_CON_NAME, mb_chan);
    134	if (unlikely(rc)) {
    135		dev_err(mb_chan->dev, "failed to register mailbox interrupt %d\n",
    136			mb_chan->irq);
    137		return rc;
    138	}
    139
    140	/* Enable HW interrupt */
    141	writel(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK,
    142	       mb_chan->reg + REG_DB_STAT);
    143	/* Unmask doorbell status interrupt */
    144	val = readl(mb_chan->reg + REG_DB_STATMASK);
    145	val &= ~(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK);
    146	writel(val, mb_chan->reg + REG_DB_STATMASK);
    147
    148	return 0;
    149}
    150
    151static void slimpro_mbox_shutdown(struct mbox_chan *chan)
    152{
    153	struct slimpro_mbox_chan *mb_chan = chan->con_priv;
    154	u32 val;
    155
    156	/* Mask doorbell status interrupt */
    157	val = readl(mb_chan->reg + REG_DB_STATMASK);
    158	val |= (MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK);
    159	writel(val, mb_chan->reg + REG_DB_STATMASK);
    160
    161	devm_free_irq(mb_chan->dev, mb_chan->irq, mb_chan);
    162}
    163
    164static const struct mbox_chan_ops slimpro_mbox_ops = {
    165	.send_data = slimpro_mbox_send_data,
    166	.startup = slimpro_mbox_startup,
    167	.shutdown = slimpro_mbox_shutdown,
    168};
    169
    170static int slimpro_mbox_probe(struct platform_device *pdev)
    171{
    172	struct slimpro_mbox *ctx;
    173	void __iomem *mb_base;
    174	int rc;
    175	int i;
    176
    177	ctx = devm_kzalloc(&pdev->dev, sizeof(struct slimpro_mbox), GFP_KERNEL);
    178	if (!ctx)
    179		return -ENOMEM;
    180
    181	platform_set_drvdata(pdev, ctx);
    182
    183	mb_base = devm_platform_ioremap_resource(pdev, 0);
    184	if (IS_ERR(mb_base))
    185		return PTR_ERR(mb_base);
    186
    187	/* Setup mailbox links */
    188	for (i = 0; i < MBOX_CNT; i++) {
    189		ctx->mc[i].irq = platform_get_irq(pdev, i);
    190		if (ctx->mc[i].irq < 0) {
    191			if (i == 0) {
    192				dev_err(&pdev->dev, "no available IRQ\n");
    193				return -EINVAL;
    194			}
    195			dev_info(&pdev->dev, "no IRQ for channel %d\n", i);
    196			break;
    197		}
    198
    199		ctx->mc[i].dev = &pdev->dev;
    200		ctx->mc[i].reg = mb_base + i * MBOX_REG_SET_OFFSET;
    201		ctx->mc[i].chan = &ctx->chans[i];
    202		ctx->chans[i].con_priv = &ctx->mc[i];
    203	}
    204
    205	/* Setup mailbox controller */
    206	ctx->mb_ctrl.dev = &pdev->dev;
    207	ctx->mb_ctrl.chans = ctx->chans;
    208	ctx->mb_ctrl.txdone_irq = true;
    209	ctx->mb_ctrl.ops = &slimpro_mbox_ops;
    210	ctx->mb_ctrl.num_chans = i;
    211
    212	rc = devm_mbox_controller_register(&pdev->dev, &ctx->mb_ctrl);
    213	if (rc) {
    214		dev_err(&pdev->dev,
    215			"APM X-Gene SLIMpro MailBox register failed:%d\n", rc);
    216		return rc;
    217	}
    218
    219	dev_info(&pdev->dev, "APM X-Gene SLIMpro MailBox registered\n");
    220	return 0;
    221}
    222
    223static const struct of_device_id slimpro_of_match[] = {
    224	{.compatible = "apm,xgene-slimpro-mbox" },
    225	{ },
    226};
    227MODULE_DEVICE_TABLE(of, slimpro_of_match);
    228
    229#ifdef CONFIG_ACPI
    230static const struct acpi_device_id slimpro_acpi_ids[] = {
    231	{"APMC0D01", 0},
    232	{}
    233};
    234MODULE_DEVICE_TABLE(acpi, slimpro_acpi_ids);
    235#endif
    236
    237static struct platform_driver slimpro_mbox_driver = {
    238	.probe	= slimpro_mbox_probe,
    239	.driver	= {
    240		.name = "xgene-slimpro-mbox",
    241		.of_match_table = of_match_ptr(slimpro_of_match),
    242		.acpi_match_table = ACPI_PTR(slimpro_acpi_ids)
    243	},
    244};
    245
    246static int __init slimpro_mbox_init(void)
    247{
    248	return platform_driver_register(&slimpro_mbox_driver);
    249}
    250
    251static void __exit slimpro_mbox_exit(void)
    252{
    253	platform_driver_unregister(&slimpro_mbox_driver);
    254}
    255
    256subsys_initcall(slimpro_mbox_init);
    257module_exit(slimpro_mbox_exit);
    258
    259MODULE_DESCRIPTION("APM X-Gene SLIMpro Mailbox Driver");
    260MODULE_LICENSE("GPL");