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_rpm.c (8073B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2016-2017, Linaro Ltd
      4 */
      5
      6#include <linux/idr.h>
      7#include <linux/interrupt.h>
      8#include <linux/io.h>
      9#include <linux/list.h>
     10#include <linux/mfd/syscon.h>
     11#include <linux/module.h>
     12#include <linux/of.h>
     13#include <linux/of_address.h>
     14#include <linux/platform_device.h>
     15#include <linux/regmap.h>
     16#include <linux/rpmsg.h>
     17#include <linux/slab.h>
     18#include <linux/workqueue.h>
     19#include <linux/mailbox_client.h>
     20
     21#include "rpmsg_internal.h"
     22#include "qcom_glink_native.h"
     23
     24#define RPM_TOC_SIZE		256
     25#define RPM_TOC_MAGIC		0x67727430 /* grt0 */
     26#define RPM_TOC_MAX_ENTRIES	((RPM_TOC_SIZE - sizeof(struct rpm_toc)) / \
     27				 sizeof(struct rpm_toc_entry))
     28
     29#define RPM_TX_FIFO_ID		0x61703272 /* ap2r */
     30#define RPM_RX_FIFO_ID		0x72326170 /* r2ap */
     31
     32#define to_rpm_pipe(p) container_of(p, struct glink_rpm_pipe, native)
     33
     34struct rpm_toc_entry {
     35	__le32 id;
     36	__le32 offset;
     37	__le32 size;
     38} __packed;
     39
     40struct rpm_toc {
     41	__le32 magic;
     42	__le32 count;
     43
     44	struct rpm_toc_entry entries[];
     45} __packed;
     46
     47struct glink_rpm_pipe {
     48	struct qcom_glink_pipe native;
     49
     50	void __iomem *tail;
     51	void __iomem *head;
     52
     53	void __iomem *fifo;
     54};
     55
     56static size_t glink_rpm_rx_avail(struct qcom_glink_pipe *glink_pipe)
     57{
     58	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
     59	unsigned int head;
     60	unsigned int tail;
     61
     62	head = readl(pipe->head);
     63	tail = readl(pipe->tail);
     64
     65	if (head < tail)
     66		return pipe->native.length - tail + head;
     67	else
     68		return head - tail;
     69}
     70
     71static void glink_rpm_rx_peak(struct qcom_glink_pipe *glink_pipe,
     72			      void *data, unsigned int offset, size_t count)
     73{
     74	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
     75	unsigned int tail;
     76	size_t len;
     77
     78	tail = readl(pipe->tail);
     79	tail += offset;
     80	if (tail >= pipe->native.length)
     81		tail -= pipe->native.length;
     82
     83	len = min_t(size_t, count, pipe->native.length - tail);
     84	if (len) {
     85		__ioread32_copy(data, pipe->fifo + tail,
     86				len / sizeof(u32));
     87	}
     88
     89	if (len != count) {
     90		__ioread32_copy(data + len, pipe->fifo,
     91				(count - len) / sizeof(u32));
     92	}
     93}
     94
     95static void glink_rpm_rx_advance(struct qcom_glink_pipe *glink_pipe,
     96				 size_t count)
     97{
     98	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
     99	unsigned int tail;
    100
    101	tail = readl(pipe->tail);
    102
    103	tail += count;
    104	if (tail >= pipe->native.length)
    105		tail -= pipe->native.length;
    106
    107	writel(tail, pipe->tail);
    108}
    109
    110static size_t glink_rpm_tx_avail(struct qcom_glink_pipe *glink_pipe)
    111{
    112	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
    113	unsigned int head;
    114	unsigned int tail;
    115
    116	head = readl(pipe->head);
    117	tail = readl(pipe->tail);
    118
    119	if (tail <= head)
    120		return pipe->native.length - head + tail;
    121	else
    122		return tail - head;
    123}
    124
    125static unsigned int glink_rpm_tx_write_one(struct glink_rpm_pipe *pipe,
    126					   unsigned int head,
    127					   const void *data, size_t count)
    128{
    129	size_t len;
    130
    131	len = min_t(size_t, count, pipe->native.length - head);
    132	if (len) {
    133		__iowrite32_copy(pipe->fifo + head, data,
    134				 len / sizeof(u32));
    135	}
    136
    137	if (len != count) {
    138		__iowrite32_copy(pipe->fifo, data + len,
    139				 (count - len) / sizeof(u32));
    140	}
    141
    142	head += count;
    143	if (head >= pipe->native.length)
    144		head -= pipe->native.length;
    145
    146	return head;
    147}
    148
    149static void glink_rpm_tx_write(struct qcom_glink_pipe *glink_pipe,
    150			       const void *hdr, size_t hlen,
    151			       const void *data, size_t dlen)
    152{
    153	struct glink_rpm_pipe *pipe = to_rpm_pipe(glink_pipe);
    154	size_t tlen = hlen + dlen;
    155	size_t aligned_dlen;
    156	unsigned int head;
    157	char padding[8] = {0};
    158	size_t pad;
    159
    160	/* Header length comes from glink native and is always 4 byte aligned */
    161	if (WARN(hlen % 4, "Glink Header length must be 4 bytes aligned\n"))
    162		return;
    163
    164	/*
    165	 * Move the unaligned tail of the message to the padding chunk, to
    166	 * ensure word aligned accesses
    167	 */
    168	aligned_dlen = ALIGN_DOWN(dlen, 4);
    169	if (aligned_dlen != dlen)
    170		memcpy(padding, data + aligned_dlen, dlen - aligned_dlen);
    171
    172	head = readl(pipe->head);
    173	head = glink_rpm_tx_write_one(pipe, head, hdr, hlen);
    174	head = glink_rpm_tx_write_one(pipe, head, data, aligned_dlen);
    175
    176	pad = ALIGN(tlen, 8) - ALIGN_DOWN(tlen, 4);
    177	if (pad)
    178		head = glink_rpm_tx_write_one(pipe, head, padding, pad);
    179	writel(head, pipe->head);
    180}
    181
    182static int glink_rpm_parse_toc(struct device *dev,
    183			       void __iomem *msg_ram,
    184			       size_t msg_ram_size,
    185			       struct glink_rpm_pipe *rx,
    186			       struct glink_rpm_pipe *tx)
    187{
    188	struct rpm_toc *toc;
    189	int num_entries;
    190	unsigned int id;
    191	size_t offset;
    192	size_t size;
    193	void *buf;
    194	int i;
    195
    196	buf = kzalloc(RPM_TOC_SIZE, GFP_KERNEL);
    197	if (!buf)
    198		return -ENOMEM;
    199
    200	__ioread32_copy(buf, msg_ram + msg_ram_size - RPM_TOC_SIZE,
    201			RPM_TOC_SIZE / sizeof(u32));
    202
    203	toc = buf;
    204
    205	if (le32_to_cpu(toc->magic) != RPM_TOC_MAGIC) {
    206		dev_err(dev, "RPM TOC has invalid magic\n");
    207		goto err_inval;
    208	}
    209
    210	num_entries = le32_to_cpu(toc->count);
    211	if (num_entries > RPM_TOC_MAX_ENTRIES) {
    212		dev_err(dev, "Invalid number of toc entries\n");
    213		goto err_inval;
    214	}
    215
    216	for (i = 0; i < num_entries; i++) {
    217		id = le32_to_cpu(toc->entries[i].id);
    218		offset = le32_to_cpu(toc->entries[i].offset);
    219		size = le32_to_cpu(toc->entries[i].size);
    220
    221		if (offset > msg_ram_size || offset + size > msg_ram_size) {
    222			dev_err(dev, "TOC entry with invalid size\n");
    223			continue;
    224		}
    225
    226		switch (id) {
    227		case RPM_RX_FIFO_ID:
    228			rx->native.length = size;
    229
    230			rx->tail = msg_ram + offset;
    231			rx->head = msg_ram + offset + sizeof(u32);
    232			rx->fifo = msg_ram + offset + 2 * sizeof(u32);
    233			break;
    234		case RPM_TX_FIFO_ID:
    235			tx->native.length = size;
    236
    237			tx->tail = msg_ram + offset;
    238			tx->head = msg_ram + offset + sizeof(u32);
    239			tx->fifo = msg_ram + offset + 2 * sizeof(u32);
    240			break;
    241		}
    242	}
    243
    244	if (!rx->fifo || !tx->fifo) {
    245		dev_err(dev, "Unable to find rx and tx descriptors\n");
    246		goto err_inval;
    247	}
    248
    249	kfree(buf);
    250	return 0;
    251
    252err_inval:
    253	kfree(buf);
    254	return -EINVAL;
    255}
    256
    257static int glink_rpm_probe(struct platform_device *pdev)
    258{
    259	struct qcom_glink *glink;
    260	struct glink_rpm_pipe *rx_pipe;
    261	struct glink_rpm_pipe *tx_pipe;
    262	struct device_node *np;
    263	void __iomem *msg_ram;
    264	size_t msg_ram_size;
    265	struct device *dev = &pdev->dev;
    266	struct resource r;
    267	int ret;
    268
    269	rx_pipe = devm_kzalloc(&pdev->dev, sizeof(*rx_pipe), GFP_KERNEL);
    270	tx_pipe = devm_kzalloc(&pdev->dev, sizeof(*tx_pipe), GFP_KERNEL);
    271	if (!rx_pipe || !tx_pipe)
    272		return -ENOMEM;
    273
    274	np = of_parse_phandle(dev->of_node, "qcom,rpm-msg-ram", 0);
    275	ret = of_address_to_resource(np, 0, &r);
    276	of_node_put(np);
    277	if (ret)
    278		return ret;
    279
    280	msg_ram = devm_ioremap(dev, r.start, resource_size(&r));
    281	msg_ram_size = resource_size(&r);
    282	if (!msg_ram)
    283		return -ENOMEM;
    284
    285	ret = glink_rpm_parse_toc(dev, msg_ram, msg_ram_size,
    286				  rx_pipe, tx_pipe);
    287	if (ret)
    288		return ret;
    289
    290	/* Pipe specific accessors */
    291	rx_pipe->native.avail = glink_rpm_rx_avail;
    292	rx_pipe->native.peak = glink_rpm_rx_peak;
    293	rx_pipe->native.advance = glink_rpm_rx_advance;
    294	tx_pipe->native.avail = glink_rpm_tx_avail;
    295	tx_pipe->native.write = glink_rpm_tx_write;
    296
    297	writel(0, tx_pipe->head);
    298	writel(0, rx_pipe->tail);
    299
    300	glink = qcom_glink_native_probe(&pdev->dev,
    301					0,
    302					&rx_pipe->native,
    303					&tx_pipe->native,
    304					true);
    305	if (IS_ERR(glink))
    306		return PTR_ERR(glink);
    307
    308	platform_set_drvdata(pdev, glink);
    309
    310	return 0;
    311}
    312
    313static int glink_rpm_remove(struct platform_device *pdev)
    314{
    315	struct qcom_glink *glink = platform_get_drvdata(pdev);
    316
    317	qcom_glink_native_remove(glink);
    318
    319	return 0;
    320}
    321
    322static const struct of_device_id glink_rpm_of_match[] = {
    323	{ .compatible = "qcom,glink-rpm" },
    324	{}
    325};
    326MODULE_DEVICE_TABLE(of, glink_rpm_of_match);
    327
    328static struct platform_driver glink_rpm_driver = {
    329	.probe = glink_rpm_probe,
    330	.remove = glink_rpm_remove,
    331	.driver = {
    332		.name = "qcom_glink_rpm",
    333		.of_match_table = glink_rpm_of_match,
    334	},
    335};
    336
    337static int __init glink_rpm_init(void)
    338{
    339	return platform_driver_register(&glink_rpm_driver);
    340}
    341subsys_initcall(glink_rpm_init);
    342
    343static void __exit glink_rpm_exit(void)
    344{
    345	platform_driver_unregister(&glink_rpm_driver);
    346}
    347module_exit(glink_rpm_exit);
    348
    349MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@linaro.org>");
    350MODULE_DESCRIPTION("Qualcomm GLINK RPM driver");
    351MODULE_LICENSE("GPL v2");