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

imx-scu-irq.c (3898B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright 2019 NXP
      4 *
      5 * Implementation of the SCU IRQ functions using MU.
      6 *
      7 */
      8
      9#include <dt-bindings/firmware/imx/rsrc.h>
     10#include <linux/firmware/imx/ipc.h>
     11#include <linux/firmware/imx/sci.h>
     12#include <linux/mailbox_client.h>
     13#include <linux/suspend.h>
     14
     15#define IMX_SC_IRQ_FUNC_ENABLE	1
     16#define IMX_SC_IRQ_FUNC_STATUS	2
     17#define IMX_SC_IRQ_NUM_GROUP	4
     18
     19static u32 mu_resource_id;
     20
     21struct imx_sc_msg_irq_get_status {
     22	struct imx_sc_rpc_msg hdr;
     23	union {
     24		struct {
     25			u16 resource;
     26			u8 group;
     27			u8 reserved;
     28		} __packed req;
     29		struct {
     30			u32 status;
     31		} resp;
     32	} data;
     33};
     34
     35struct imx_sc_msg_irq_enable {
     36	struct imx_sc_rpc_msg hdr;
     37	u32 mask;
     38	u16 resource;
     39	u8 group;
     40	u8 enable;
     41} __packed;
     42
     43static struct imx_sc_ipc *imx_sc_irq_ipc_handle;
     44static struct work_struct imx_sc_irq_work;
     45static ATOMIC_NOTIFIER_HEAD(imx_scu_irq_notifier_chain);
     46
     47int imx_scu_irq_register_notifier(struct notifier_block *nb)
     48{
     49	return atomic_notifier_chain_register(
     50		&imx_scu_irq_notifier_chain, nb);
     51}
     52EXPORT_SYMBOL(imx_scu_irq_register_notifier);
     53
     54int imx_scu_irq_unregister_notifier(struct notifier_block *nb)
     55{
     56	return atomic_notifier_chain_unregister(
     57		&imx_scu_irq_notifier_chain, nb);
     58}
     59EXPORT_SYMBOL(imx_scu_irq_unregister_notifier);
     60
     61static int imx_scu_irq_notifier_call_chain(unsigned long status, u8 *group)
     62{
     63	return atomic_notifier_call_chain(&imx_scu_irq_notifier_chain,
     64		status, (void *)group);
     65}
     66
     67static void imx_scu_irq_work_handler(struct work_struct *work)
     68{
     69	struct imx_sc_msg_irq_get_status msg;
     70	struct imx_sc_rpc_msg *hdr = &msg.hdr;
     71	u32 irq_status;
     72	int ret;
     73	u8 i;
     74
     75	for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) {
     76		hdr->ver = IMX_SC_RPC_VERSION;
     77		hdr->svc = IMX_SC_RPC_SVC_IRQ;
     78		hdr->func = IMX_SC_IRQ_FUNC_STATUS;
     79		hdr->size = 2;
     80
     81		msg.data.req.resource = mu_resource_id;
     82		msg.data.req.group = i;
     83
     84		ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true);
     85		if (ret) {
     86			pr_err("get irq group %d status failed, ret %d\n",
     87			       i, ret);
     88			return;
     89		}
     90
     91		irq_status = msg.data.resp.status;
     92		if (!irq_status)
     93			continue;
     94
     95		pm_system_wakeup();
     96		imx_scu_irq_notifier_call_chain(irq_status, &i);
     97	}
     98}
     99
    100int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable)
    101{
    102	struct imx_sc_msg_irq_enable msg;
    103	struct imx_sc_rpc_msg *hdr = &msg.hdr;
    104	int ret;
    105
    106	if (!imx_sc_irq_ipc_handle)
    107		return -EPROBE_DEFER;
    108
    109	hdr->ver = IMX_SC_RPC_VERSION;
    110	hdr->svc = IMX_SC_RPC_SVC_IRQ;
    111	hdr->func = IMX_SC_IRQ_FUNC_ENABLE;
    112	hdr->size = 3;
    113
    114	msg.resource = mu_resource_id;
    115	msg.group = group;
    116	msg.mask = mask;
    117	msg.enable = enable;
    118
    119	ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true);
    120	if (ret)
    121		pr_err("enable irq failed, group %d, mask %d, ret %d\n",
    122			group, mask, ret);
    123
    124	return ret;
    125}
    126EXPORT_SYMBOL(imx_scu_irq_group_enable);
    127
    128static void imx_scu_irq_callback(struct mbox_client *c, void *msg)
    129{
    130	schedule_work(&imx_sc_irq_work);
    131}
    132
    133int imx_scu_enable_general_irq_channel(struct device *dev)
    134{
    135	struct of_phandle_args spec;
    136	struct mbox_client *cl;
    137	struct mbox_chan *ch;
    138	int ret = 0, i = 0;
    139
    140	ret = imx_scu_get_handle(&imx_sc_irq_ipc_handle);
    141	if (ret)
    142		return ret;
    143
    144	cl = devm_kzalloc(dev, sizeof(*cl), GFP_KERNEL);
    145	if (!cl)
    146		return -ENOMEM;
    147
    148	cl->dev = dev;
    149	cl->rx_callback = imx_scu_irq_callback;
    150
    151	/* SCU general IRQ uses general interrupt channel 3 */
    152	ch = mbox_request_channel_byname(cl, "gip3");
    153	if (IS_ERR(ch)) {
    154		ret = PTR_ERR(ch);
    155		dev_err(dev, "failed to request mbox chan gip3, ret %d\n", ret);
    156		devm_kfree(dev, cl);
    157		return ret;
    158	}
    159
    160	INIT_WORK(&imx_sc_irq_work, imx_scu_irq_work_handler);
    161
    162	if (!of_parse_phandle_with_args(dev->of_node, "mboxes",
    163				       "#mbox-cells", 0, &spec))
    164		i = of_alias_get_id(spec.np, "mu");
    165
    166	/* use mu1 as general mu irq channel if failed */
    167	if (i < 0)
    168		i = 1;
    169
    170	mu_resource_id = IMX_SC_R_MU_0A + i;
    171
    172	return ret;
    173}
    174EXPORT_SYMBOL(imx_scu_enable_general_irq_channel);