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

qcom_glink_smem.c (7093B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2016, Linaro Ltd
      4 */
      5
      6#include <linux/io.h>
      7#include <linux/module.h>
      8#include <linux/of.h>
      9#include <linux/of_address.h>
     10#include <linux/interrupt.h>
     11#include <linux/platform_device.h>
     12#include <linux/mfd/syscon.h>
     13#include <linux/slab.h>
     14#include <linux/rpmsg.h>
     15#include <linux/idr.h>
     16#include <linux/circ_buf.h>
     17#include <linux/soc/qcom/smem.h>
     18#include <linux/sizes.h>
     19#include <linux/delay.h>
     20#include <linux/regmap.h>
     21#include <linux/workqueue.h>
     22#include <linux/list.h>
     23
     24#include <linux/rpmsg/qcom_glink.h>
     25
     26#include "qcom_glink_native.h"
     27
     28#define FIFO_FULL_RESERVE 8
     29#define FIFO_ALIGNMENT 8
     30#define TX_BLOCKED_CMD_RESERVE 8 /* size of struct read_notif_request */
     31
     32#define SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR	478
     33#define SMEM_GLINK_NATIVE_XPRT_FIFO_0		479
     34#define SMEM_GLINK_NATIVE_XPRT_FIFO_1		480
     35
     36struct glink_smem_pipe {
     37	struct qcom_glink_pipe native;
     38
     39	__le32 *tail;
     40	__le32 *head;
     41
     42	void *fifo;
     43
     44	int remote_pid;
     45};
     46
     47#define to_smem_pipe(p) container_of(p, struct glink_smem_pipe, native)
     48
     49static size_t glink_smem_rx_avail(struct qcom_glink_pipe *np)
     50{
     51	struct glink_smem_pipe *pipe = to_smem_pipe(np);
     52	size_t len;
     53	void *fifo;
     54	u32 head;
     55	u32 tail;
     56
     57	if (!pipe->fifo) {
     58		fifo = qcom_smem_get(pipe->remote_pid,
     59				     SMEM_GLINK_NATIVE_XPRT_FIFO_1, &len);
     60		if (IS_ERR(fifo)) {
     61			pr_err("failed to acquire RX fifo handle: %ld\n",
     62			       PTR_ERR(fifo));
     63			return 0;
     64		}
     65
     66		pipe->fifo = fifo;
     67		pipe->native.length = len;
     68	}
     69
     70	head = le32_to_cpu(*pipe->head);
     71	tail = le32_to_cpu(*pipe->tail);
     72
     73	if (head < tail)
     74		return pipe->native.length - tail + head;
     75	else
     76		return head - tail;
     77}
     78
     79static void glink_smem_rx_peak(struct qcom_glink_pipe *np,
     80			       void *data, unsigned int offset, size_t count)
     81{
     82	struct glink_smem_pipe *pipe = to_smem_pipe(np);
     83	size_t len;
     84	u32 tail;
     85
     86	tail = le32_to_cpu(*pipe->tail);
     87	tail += offset;
     88	if (tail >= pipe->native.length)
     89		tail -= pipe->native.length;
     90
     91	len = min_t(size_t, count, pipe->native.length - tail);
     92	if (len)
     93		memcpy_fromio(data, pipe->fifo + tail, len);
     94
     95	if (len != count)
     96		memcpy_fromio(data + len, pipe->fifo, (count - len));
     97}
     98
     99static void glink_smem_rx_advance(struct qcom_glink_pipe *np,
    100				  size_t count)
    101{
    102	struct glink_smem_pipe *pipe = to_smem_pipe(np);
    103	u32 tail;
    104
    105	tail = le32_to_cpu(*pipe->tail);
    106
    107	tail += count;
    108	if (tail >= pipe->native.length)
    109		tail -= pipe->native.length;
    110
    111	*pipe->tail = cpu_to_le32(tail);
    112}
    113
    114static size_t glink_smem_tx_avail(struct qcom_glink_pipe *np)
    115{
    116	struct glink_smem_pipe *pipe = to_smem_pipe(np);
    117	u32 head;
    118	u32 tail;
    119	u32 avail;
    120
    121	head = le32_to_cpu(*pipe->head);
    122	tail = le32_to_cpu(*pipe->tail);
    123
    124	if (tail <= head)
    125		avail = pipe->native.length - head + tail;
    126	else
    127		avail = tail - head;
    128
    129	if (avail < (FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE))
    130		avail = 0;
    131	else
    132		avail -= FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE;
    133
    134	return avail;
    135}
    136
    137static unsigned int glink_smem_tx_write_one(struct glink_smem_pipe *pipe,
    138					    unsigned int head,
    139					    const void *data, size_t count)
    140{
    141	size_t len;
    142
    143	len = min_t(size_t, count, pipe->native.length - head);
    144	if (len)
    145		memcpy(pipe->fifo + head, data, len);
    146
    147	if (len != count)
    148		memcpy(pipe->fifo, data + len, count - len);
    149
    150	head += count;
    151	if (head >= pipe->native.length)
    152		head -= pipe->native.length;
    153
    154	return head;
    155}
    156
    157static void glink_smem_tx_write(struct qcom_glink_pipe *glink_pipe,
    158				const void *hdr, size_t hlen,
    159				const void *data, size_t dlen)
    160{
    161	struct glink_smem_pipe *pipe = to_smem_pipe(glink_pipe);
    162	unsigned int head;
    163
    164	head = le32_to_cpu(*pipe->head);
    165
    166	head = glink_smem_tx_write_one(pipe, head, hdr, hlen);
    167	head = glink_smem_tx_write_one(pipe, head, data, dlen);
    168
    169	/* Ensure head is always aligned to 8 bytes */
    170	head = ALIGN(head, 8);
    171	if (head >= pipe->native.length)
    172		head -= pipe->native.length;
    173
    174	/* Ensure ordering of fifo and head update */
    175	wmb();
    176
    177	*pipe->head = cpu_to_le32(head);
    178}
    179
    180static void qcom_glink_smem_release(struct device *dev)
    181{
    182	kfree(dev);
    183}
    184
    185struct qcom_glink *qcom_glink_smem_register(struct device *parent,
    186					    struct device_node *node)
    187{
    188	struct glink_smem_pipe *rx_pipe;
    189	struct glink_smem_pipe *tx_pipe;
    190	struct qcom_glink *glink;
    191	struct device *dev;
    192	u32 remote_pid;
    193	__le32 *descs;
    194	size_t size;
    195	int ret;
    196
    197	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    198	if (!dev)
    199		return ERR_PTR(-ENOMEM);
    200
    201	dev->parent = parent;
    202	dev->of_node = node;
    203	dev->release = qcom_glink_smem_release;
    204	dev_set_name(dev, "%s:%pOFn", dev_name(parent->parent), node);
    205	ret = device_register(dev);
    206	if (ret) {
    207		pr_err("failed to register glink edge\n");
    208		put_device(dev);
    209		return ERR_PTR(ret);
    210	}
    211
    212	ret = of_property_read_u32(dev->of_node, "qcom,remote-pid",
    213				   &remote_pid);
    214	if (ret) {
    215		dev_err(dev, "failed to parse qcom,remote-pid\n");
    216		goto err_put_dev;
    217	}
    218
    219	rx_pipe = devm_kzalloc(dev, sizeof(*rx_pipe), GFP_KERNEL);
    220	tx_pipe = devm_kzalloc(dev, sizeof(*tx_pipe), GFP_KERNEL);
    221	if (!rx_pipe || !tx_pipe) {
    222		ret = -ENOMEM;
    223		goto err_put_dev;
    224	}
    225
    226	ret = qcom_smem_alloc(remote_pid,
    227			      SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, 32);
    228	if (ret && ret != -EEXIST) {
    229		dev_err(dev, "failed to allocate glink descriptors\n");
    230		goto err_put_dev;
    231	}
    232
    233	descs = qcom_smem_get(remote_pid,
    234			      SMEM_GLINK_NATIVE_XPRT_DESCRIPTOR, &size);
    235	if (IS_ERR(descs)) {
    236		dev_err(dev, "failed to acquire xprt descriptor\n");
    237		ret = PTR_ERR(descs);
    238		goto err_put_dev;
    239	}
    240
    241	if (size != 32) {
    242		dev_err(dev, "glink descriptor of invalid size\n");
    243		ret = -EINVAL;
    244		goto err_put_dev;
    245	}
    246
    247	tx_pipe->tail = &descs[0];
    248	tx_pipe->head = &descs[1];
    249	rx_pipe->tail = &descs[2];
    250	rx_pipe->head = &descs[3];
    251
    252	ret = qcom_smem_alloc(remote_pid, SMEM_GLINK_NATIVE_XPRT_FIFO_0,
    253			      SZ_16K);
    254	if (ret && ret != -EEXIST) {
    255		dev_err(dev, "failed to allocate TX fifo\n");
    256		goto err_put_dev;
    257	}
    258
    259	tx_pipe->fifo = qcom_smem_get(remote_pid, SMEM_GLINK_NATIVE_XPRT_FIFO_0,
    260				      &tx_pipe->native.length);
    261	if (IS_ERR(tx_pipe->fifo)) {
    262		dev_err(dev, "failed to acquire TX fifo\n");
    263		ret = PTR_ERR(tx_pipe->fifo);
    264		goto err_put_dev;
    265	}
    266
    267	rx_pipe->native.avail = glink_smem_rx_avail;
    268	rx_pipe->native.peak = glink_smem_rx_peak;
    269	rx_pipe->native.advance = glink_smem_rx_advance;
    270	rx_pipe->remote_pid = remote_pid;
    271
    272	tx_pipe->native.avail = glink_smem_tx_avail;
    273	tx_pipe->native.write = glink_smem_tx_write;
    274	tx_pipe->remote_pid = remote_pid;
    275
    276	*rx_pipe->tail = 0;
    277	*tx_pipe->head = 0;
    278
    279	glink = qcom_glink_native_probe(dev,
    280					GLINK_FEATURE_INTENT_REUSE,
    281					&rx_pipe->native, &tx_pipe->native,
    282					false);
    283	if (IS_ERR(glink)) {
    284		ret = PTR_ERR(glink);
    285		goto err_put_dev;
    286	}
    287
    288	return glink;
    289
    290err_put_dev:
    291	device_unregister(dev);
    292
    293	return ERR_PTR(ret);
    294}
    295EXPORT_SYMBOL_GPL(qcom_glink_smem_register);
    296
    297void qcom_glink_smem_unregister(struct qcom_glink *glink)
    298{
    299	qcom_glink_native_remove(glink);
    300	qcom_glink_native_unregister(glink);
    301}
    302EXPORT_SYMBOL_GPL(qcom_glink_smem_unregister);
    303
    304MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@linaro.org>");
    305MODULE_DESCRIPTION("Qualcomm GLINK SMEM driver");
    306MODULE_LICENSE("GPL v2");