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

mtk_scp_ipi.c (5366B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Copyright (c) 2019 MediaTek Inc.
      4
      5#include <asm/barrier.h>
      6#include <linux/clk.h>
      7#include <linux/err.h>
      8#include <linux/io.h>
      9#include <linux/kernel.h>
     10#include <linux/module.h>
     11#include <linux/platform_device.h>
     12#include <linux/remoteproc/mtk_scp.h>
     13
     14#include "mtk_common.h"
     15
     16/**
     17 * scp_ipi_register() - register an ipi function
     18 *
     19 * @scp:	mtk_scp structure
     20 * @id:		IPI ID
     21 * @handler:	IPI handler
     22 * @priv:	private data for IPI handler
     23 *
     24 * Register an ipi function to receive ipi interrupt from SCP.
     25 *
     26 * Return: 0 if ipi registers successfully, -error on error.
     27 */
     28int scp_ipi_register(struct mtk_scp *scp,
     29		     u32 id,
     30		     scp_ipi_handler_t handler,
     31		     void *priv)
     32{
     33	if (!scp)
     34		return -EPROBE_DEFER;
     35
     36	if (WARN_ON(id >= SCP_IPI_MAX) || WARN_ON(handler == NULL))
     37		return -EINVAL;
     38
     39	scp_ipi_lock(scp, id);
     40	scp->ipi_desc[id].handler = handler;
     41	scp->ipi_desc[id].priv = priv;
     42	scp_ipi_unlock(scp, id);
     43
     44	return 0;
     45}
     46EXPORT_SYMBOL_GPL(scp_ipi_register);
     47
     48/**
     49 * scp_ipi_unregister() - unregister an ipi function
     50 *
     51 * @scp:	mtk_scp structure
     52 * @id:		IPI ID
     53 *
     54 * Unregister an ipi function to receive ipi interrupt from SCP.
     55 */
     56void scp_ipi_unregister(struct mtk_scp *scp, u32 id)
     57{
     58	if (!scp)
     59		return;
     60
     61	if (WARN_ON(id >= SCP_IPI_MAX))
     62		return;
     63
     64	scp_ipi_lock(scp, id);
     65	scp->ipi_desc[id].handler = NULL;
     66	scp->ipi_desc[id].priv = NULL;
     67	scp_ipi_unlock(scp, id);
     68}
     69EXPORT_SYMBOL_GPL(scp_ipi_unregister);
     70
     71/*
     72 * scp_memcpy_aligned() - Copy src to dst, where dst is in SCP SRAM region.
     73 *
     74 * @dst:	Pointer to the destination buffer, should be in SCP SRAM region.
     75 * @src:	Pointer to the source buffer.
     76 * @len:	Length of the source buffer to be copied.
     77 *
     78 * Since AP access of SCP SRAM don't support byte write, this always write a
     79 * full word at a time, and may cause some extra bytes to be written at the
     80 * beginning & ending of dst.
     81 */
     82void scp_memcpy_aligned(void __iomem *dst, const void *src, unsigned int len)
     83{
     84	void __iomem *ptr;
     85	u32 val;
     86	unsigned int i = 0, remain;
     87
     88	if (!IS_ALIGNED((unsigned long)dst, 4)) {
     89		ptr = (void __iomem *)ALIGN_DOWN((unsigned long)dst, 4);
     90		i = 4 - (dst - ptr);
     91		val = readl_relaxed(ptr);
     92		memcpy((u8 *)&val + (4 - i), src, i);
     93		writel_relaxed(val, ptr);
     94	}
     95
     96	__iowrite32_copy(dst + i, src + i, (len - i) / 4);
     97	remain = (len - i) % 4;
     98
     99	if (remain > 0) {
    100		val = readl_relaxed(dst + len - remain);
    101		memcpy(&val, src + len - remain, remain);
    102		writel_relaxed(val, dst + len - remain);
    103	}
    104}
    105EXPORT_SYMBOL_GPL(scp_memcpy_aligned);
    106
    107/**
    108 * scp_ipi_lock() - Lock before operations of an IPI ID
    109 *
    110 * @scp:	mtk_scp structure
    111 * @id:		IPI ID
    112 *
    113 * Note: This should not be used by drivers other than mtk_scp.
    114 */
    115void scp_ipi_lock(struct mtk_scp *scp, u32 id)
    116{
    117	if (WARN_ON(id >= SCP_IPI_MAX))
    118		return;
    119	mutex_lock(&scp->ipi_desc[id].lock);
    120}
    121EXPORT_SYMBOL_GPL(scp_ipi_lock);
    122
    123/**
    124 * scp_ipi_lock() - Unlock after operations of an IPI ID
    125 *
    126 * @scp:	mtk_scp structure
    127 * @id:		IPI ID
    128 *
    129 * Note: This should not be used by drivers other than mtk_scp.
    130 */
    131void scp_ipi_unlock(struct mtk_scp *scp, u32 id)
    132{
    133	if (WARN_ON(id >= SCP_IPI_MAX))
    134		return;
    135	mutex_unlock(&scp->ipi_desc[id].lock);
    136}
    137EXPORT_SYMBOL_GPL(scp_ipi_unlock);
    138
    139/**
    140 * scp_ipi_send() - send data from AP to scp.
    141 *
    142 * @scp:	mtk_scp structure
    143 * @id:		IPI ID
    144 * @buf:	the data buffer
    145 * @len:	the data buffer length
    146 * @wait:	number of msecs to wait for ack. 0 to skip waiting.
    147 *
    148 * This function is thread-safe. When this function returns,
    149 * SCP has received the data and starts the processing.
    150 * When the processing completes, IPI handler registered
    151 * by scp_ipi_register will be called in interrupt context.
    152 *
    153 * Return: 0 if sending data successfully, -error on error.
    154 **/
    155int scp_ipi_send(struct mtk_scp *scp, u32 id, void *buf, unsigned int len,
    156		 unsigned int wait)
    157{
    158	struct mtk_share_obj __iomem *send_obj = scp->send_buf;
    159	unsigned long timeout;
    160	int ret;
    161
    162	if (WARN_ON(id <= SCP_IPI_INIT) || WARN_ON(id >= SCP_IPI_MAX) ||
    163	    WARN_ON(id == SCP_IPI_NS_SERVICE) ||
    164	    WARN_ON(len > sizeof(send_obj->share_buf)) || WARN_ON(!buf))
    165		return -EINVAL;
    166
    167	mutex_lock(&scp->send_lock);
    168
    169	ret = clk_prepare_enable(scp->clk);
    170	if (ret) {
    171		dev_err(scp->dev, "failed to enable clock\n");
    172		goto unlock_mutex;
    173	}
    174
    175	 /* Wait until SCP receives the last command */
    176	timeout = jiffies + msecs_to_jiffies(2000);
    177	do {
    178		if (time_after(jiffies, timeout)) {
    179			dev_err(scp->dev, "%s: IPI timeout!\n", __func__);
    180			ret = -ETIMEDOUT;
    181			goto clock_disable;
    182		}
    183	} while (readl(scp->reg_base + scp->data->host_to_scp_reg));
    184
    185	scp_memcpy_aligned(send_obj->share_buf, buf, len);
    186
    187	writel(len, &send_obj->len);
    188	writel(id, &send_obj->id);
    189
    190	scp->ipi_id_ack[id] = false;
    191	/* send the command to SCP */
    192	writel(scp->data->host_to_scp_int_bit,
    193	       scp->reg_base + scp->data->host_to_scp_reg);
    194
    195	if (wait) {
    196		/* wait for SCP's ACK */
    197		timeout = msecs_to_jiffies(wait);
    198		ret = wait_event_timeout(scp->ack_wq,
    199					 scp->ipi_id_ack[id],
    200					 timeout);
    201		scp->ipi_id_ack[id] = false;
    202		if (WARN(!ret, "scp ipi %d ack time out !", id))
    203			ret = -EIO;
    204		else
    205			ret = 0;
    206	}
    207
    208clock_disable:
    209	clk_disable_unprepare(scp->clk);
    210unlock_mutex:
    211	mutex_unlock(&scp->send_lock);
    212
    213	return ret;
    214}
    215EXPORT_SYMBOL_GPL(scp_ipi_send);
    216
    217MODULE_LICENSE("GPL v2");
    218MODULE_DESCRIPTION("MediaTek scp IPI interface");