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

spi-slave-time.c (3004B)


      1/*
      2 * SPI slave handler reporting uptime at reception of previous SPI message
      3 *
      4 * This SPI slave handler sends the time of reception of the last SPI message
      5 * as two 32-bit unsigned integers in binary format and in network byte order,
      6 * representing the number of seconds and fractional seconds (in microseconds)
      7 * since boot up.
      8 *
      9 * Copyright (C) 2016-2017 Glider bvba
     10 *
     11 * This file is subject to the terms and conditions of the GNU General Public
     12 * License.  See the file "COPYING" in the main directory of this archive
     13 * for more details.
     14 *
     15 * Usage (assuming /dev/spidev2.0 corresponds to the SPI master on the remote
     16 * system):
     17 *
     18 *   # spidev_test -D /dev/spidev2.0 -p dummy-8B
     19 *   spi mode: 0x0
     20 *   bits per word: 8
     21 *   max speed: 500000 Hz (500 KHz)
     22 *   RX | 00 00 04 6D 00 09 5B BB ...
     23 *		^^^^^    ^^^^^^^^
     24 *		seconds  microseconds
     25 */
     26
     27#include <linux/completion.h>
     28#include <linux/module.h>
     29#include <linux/sched/clock.h>
     30#include <linux/spi/spi.h>
     31
     32
     33struct spi_slave_time_priv {
     34	struct spi_device *spi;
     35	struct completion finished;
     36	struct spi_transfer xfer;
     37	struct spi_message msg;
     38	__be32 buf[2];
     39};
     40
     41static int spi_slave_time_submit(struct spi_slave_time_priv *priv);
     42
     43static void spi_slave_time_complete(void *arg)
     44{
     45	struct spi_slave_time_priv *priv = arg;
     46	int ret;
     47
     48	ret = priv->msg.status;
     49	if (ret)
     50		goto terminate;
     51
     52	ret = spi_slave_time_submit(priv);
     53	if (ret)
     54		goto terminate;
     55
     56	return;
     57
     58terminate:
     59	dev_info(&priv->spi->dev, "Terminating\n");
     60	complete(&priv->finished);
     61}
     62
     63static int spi_slave_time_submit(struct spi_slave_time_priv *priv)
     64{
     65	u32 rem_us;
     66	int ret;
     67	u64 ts;
     68
     69	ts = local_clock();
     70	rem_us = do_div(ts, 1000000000) / 1000;
     71
     72	priv->buf[0] = cpu_to_be32(ts);
     73	priv->buf[1] = cpu_to_be32(rem_us);
     74
     75	spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1);
     76
     77	priv->msg.complete = spi_slave_time_complete;
     78	priv->msg.context = priv;
     79
     80	ret = spi_async(priv->spi, &priv->msg);
     81	if (ret)
     82		dev_err(&priv->spi->dev, "spi_async() failed %d\n", ret);
     83
     84	return ret;
     85}
     86
     87static int spi_slave_time_probe(struct spi_device *spi)
     88{
     89	struct spi_slave_time_priv *priv;
     90	int ret;
     91
     92	priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
     93	if (!priv)
     94		return -ENOMEM;
     95
     96	priv->spi = spi;
     97	init_completion(&priv->finished);
     98	priv->xfer.tx_buf = priv->buf;
     99	priv->xfer.len = sizeof(priv->buf);
    100
    101	ret = spi_slave_time_submit(priv);
    102	if (ret)
    103		return ret;
    104
    105	spi_set_drvdata(spi, priv);
    106	return 0;
    107}
    108
    109static void spi_slave_time_remove(struct spi_device *spi)
    110{
    111	struct spi_slave_time_priv *priv = spi_get_drvdata(spi);
    112
    113	spi_slave_abort(spi);
    114	wait_for_completion(&priv->finished);
    115}
    116
    117static struct spi_driver spi_slave_time_driver = {
    118	.driver = {
    119		.name	= "spi-slave-time",
    120	},
    121	.probe		= spi_slave_time_probe,
    122	.remove		= spi_slave_time_remove,
    123};
    124module_spi_driver(spi_slave_time_driver);
    125
    126MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
    127MODULE_DESCRIPTION("SPI slave reporting uptime at previous SPI message");
    128MODULE_LICENSE("GPL v2");