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

pps_parport.c (5657B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * pps_parport.c -- kernel parallel port PPS client
      4 *
      5 * Copyright (C) 2009   Alexander Gordeev <lasaine@lvk.cs.msu.su>
      6 */
      7
      8
      9/*
     10 * TODO:
     11 * implement echo over SEL pin
     12 */
     13
     14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     15
     16#include <linux/kernel.h>
     17#include <linux/module.h>
     18#include <linux/init.h>
     19#include <linux/irqnr.h>
     20#include <linux/time.h>
     21#include <linux/slab.h>
     22#include <linux/parport.h>
     23#include <linux/pps_kernel.h>
     24
     25/* module parameters */
     26
     27#define CLEAR_WAIT_MAX		100
     28#define CLEAR_WAIT_MAX_ERRORS	5
     29
     30static unsigned int clear_wait = 100;
     31MODULE_PARM_DESC(clear_wait,
     32	"Maximum number of port reads when polling for signal clear,"
     33	" zero turns clear edge capture off entirely");
     34module_param(clear_wait, uint, 0);
     35
     36static DEFINE_IDA(pps_client_index);
     37
     38/* internal per port structure */
     39struct pps_client_pp {
     40	struct pardevice *pardev;	/* parport device */
     41	struct pps_device *pps;		/* PPS device */
     42	unsigned int cw;		/* port clear timeout */
     43	unsigned int cw_err;		/* number of timeouts */
     44	int index;			/* device number */
     45};
     46
     47static inline int signal_is_set(struct parport *port)
     48{
     49	return (port->ops->read_status(port) & PARPORT_STATUS_ACK) != 0;
     50}
     51
     52/* parport interrupt handler */
     53static void parport_irq(void *handle)
     54{
     55	struct pps_event_time ts_assert, ts_clear;
     56	struct pps_client_pp *dev = handle;
     57	struct parport *port = dev->pardev->port;
     58	unsigned int i;
     59	unsigned long flags;
     60
     61	/* first of all we get the time stamp... */
     62	pps_get_ts(&ts_assert);
     63
     64	if (dev->cw == 0)
     65		/* clear edge capture disabled */
     66		goto out_assert;
     67
     68	/* try capture the clear edge */
     69
     70	/* We have to disable interrupts here. The idea is to prevent
     71	 * other interrupts on the same processor to introduce random
     72	 * lags while polling the port. Reading from IO port is known
     73	 * to take approximately 1us while other interrupt handlers can
     74	 * take much more potentially.
     75	 *
     76	 * Interrupts won't be disabled for a long time because the
     77	 * number of polls is limited by clear_wait parameter which is
     78	 * kept rather low. So it should never be an issue.
     79	 */
     80	local_irq_save(flags);
     81	/* check the signal (no signal means the pulse is lost this time) */
     82	if (!signal_is_set(port)) {
     83		local_irq_restore(flags);
     84		dev_err(dev->pps->dev, "lost the signal\n");
     85		goto out_assert;
     86	}
     87
     88	/* poll the port until the signal is unset */
     89	for (i = dev->cw; i; i--)
     90		if (!signal_is_set(port)) {
     91			pps_get_ts(&ts_clear);
     92			local_irq_restore(flags);
     93			dev->cw_err = 0;
     94			goto out_both;
     95		}
     96	local_irq_restore(flags);
     97
     98	/* timeout */
     99	dev->cw_err++;
    100	if (dev->cw_err >= CLEAR_WAIT_MAX_ERRORS) {
    101		dev_err(dev->pps->dev, "disabled clear edge capture after %d"
    102				" timeouts\n", dev->cw_err);
    103		dev->cw = 0;
    104		dev->cw_err = 0;
    105	}
    106
    107out_assert:
    108	/* fire assert event */
    109	pps_event(dev->pps, &ts_assert,
    110			PPS_CAPTUREASSERT, NULL);
    111	return;
    112
    113out_both:
    114	/* fire assert event */
    115	pps_event(dev->pps, &ts_assert,
    116			PPS_CAPTUREASSERT, NULL);
    117	/* fire clear event */
    118	pps_event(dev->pps, &ts_clear,
    119			PPS_CAPTURECLEAR, NULL);
    120	return;
    121}
    122
    123static void parport_attach(struct parport *port)
    124{
    125	struct pardev_cb pps_client_cb;
    126	int index;
    127	struct pps_client_pp *device;
    128	struct pps_source_info info = {
    129		.name		= KBUILD_MODNAME,
    130		.path		= "",
    131		.mode		= PPS_CAPTUREBOTH | \
    132				  PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
    133				  PPS_ECHOASSERT | PPS_ECHOCLEAR | \
    134				  PPS_CANWAIT | PPS_TSFMT_TSPEC,
    135		.owner		= THIS_MODULE,
    136		.dev		= NULL
    137	};
    138
    139	if (clear_wait > CLEAR_WAIT_MAX) {
    140		pr_err("clear_wait value should be not greater then %d\n",
    141		       CLEAR_WAIT_MAX);
    142		return;
    143	}
    144
    145	device = kzalloc(sizeof(struct pps_client_pp), GFP_KERNEL);
    146	if (!device) {
    147		pr_err("memory allocation failed, not attaching\n");
    148		return;
    149	}
    150
    151	index = ida_simple_get(&pps_client_index, 0, 0, GFP_KERNEL);
    152	memset(&pps_client_cb, 0, sizeof(pps_client_cb));
    153	pps_client_cb.private = device;
    154	pps_client_cb.irq_func = parport_irq;
    155	pps_client_cb.flags = PARPORT_FLAG_EXCL;
    156	device->pardev = parport_register_dev_model(port,
    157						    KBUILD_MODNAME,
    158						    &pps_client_cb,
    159						    index);
    160	if (!device->pardev) {
    161		pr_err("couldn't register with %s\n", port->name);
    162		goto err_free;
    163	}
    164
    165	if (parport_claim_or_block(device->pardev) < 0) {
    166		pr_err("couldn't claim %s\n", port->name);
    167		goto err_unregister_dev;
    168	}
    169
    170	device->pps = pps_register_source(&info,
    171			PPS_CAPTUREBOTH | PPS_OFFSETASSERT | PPS_OFFSETCLEAR);
    172	if (IS_ERR(device->pps)) {
    173		pr_err("couldn't register PPS source\n");
    174		goto err_release_dev;
    175	}
    176
    177	device->cw = clear_wait;
    178
    179	port->ops->enable_irq(port);
    180	device->index = index;
    181
    182	pr_info("attached to %s\n", port->name);
    183
    184	return;
    185
    186err_release_dev:
    187	parport_release(device->pardev);
    188err_unregister_dev:
    189	parport_unregister_device(device->pardev);
    190err_free:
    191	ida_simple_remove(&pps_client_index, index);
    192	kfree(device);
    193}
    194
    195static void parport_detach(struct parport *port)
    196{
    197	struct pardevice *pardev = port->cad;
    198	struct pps_client_pp *device;
    199
    200	/* FIXME: oooh, this is ugly! */
    201	if (!pardev || strcmp(pardev->name, KBUILD_MODNAME))
    202		/* not our port */
    203		return;
    204
    205	device = pardev->private;
    206
    207	port->ops->disable_irq(port);
    208	pps_unregister_source(device->pps);
    209	parport_release(pardev);
    210	parport_unregister_device(pardev);
    211	ida_simple_remove(&pps_client_index, device->index);
    212	kfree(device);
    213}
    214
    215static struct parport_driver pps_parport_driver = {
    216	.name = KBUILD_MODNAME,
    217	.match_port = parport_attach,
    218	.detach = parport_detach,
    219	.devmodel = true,
    220};
    221module_parport_driver(pps_parport_driver);
    222
    223MODULE_AUTHOR("Alexander Gordeev <lasaine@lvk.cs.msu.su>");
    224MODULE_DESCRIPTION("parallel port PPS client");
    225MODULE_LICENSE("GPL");