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

heartbeat.c (3636B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Generic heartbeat driver for regular LED banks
      4 *
      5 * Copyright (C) 2007 - 2010  Paul Mundt
      6 *
      7 * Most SH reference boards include a number of individual LEDs that can
      8 * be independently controlled (either via a pre-defined hardware
      9 * function or via the LED class, if desired -- the hardware tends to
     10 * encapsulate some of the same "triggers" that the LED class supports,
     11 * so there's not too much value in it).
     12 *
     13 * Additionally, most of these boards also have a LED bank that we've
     14 * traditionally used for strobing the load average. This use case is
     15 * handled by this driver, rather than giving each LED bit position its
     16 * own struct device.
     17 */
     18#include <linux/init.h>
     19#include <linux/platform_device.h>
     20#include <linux/sched.h>
     21#include <linux/sched/loadavg.h>
     22#include <linux/timer.h>
     23#include <linux/io.h>
     24#include <linux/slab.h>
     25#include <asm/heartbeat.h>
     26
     27#define DRV_NAME "heartbeat"
     28#define DRV_VERSION "0.1.2"
     29
     30static unsigned char default_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
     31
     32static inline void heartbeat_toggle_bit(struct heartbeat_data *hd,
     33					unsigned bit, unsigned int inverted)
     34{
     35	unsigned int new;
     36
     37	new = (1 << hd->bit_pos[bit]);
     38	if (inverted)
     39		new = ~new;
     40
     41	new &= hd->mask;
     42
     43	switch (hd->regsize) {
     44	case 32:
     45		new |= ioread32(hd->base) & ~hd->mask;
     46		iowrite32(new, hd->base);
     47		break;
     48	case 16:
     49		new |= ioread16(hd->base) & ~hd->mask;
     50		iowrite16(new, hd->base);
     51		break;
     52	default:
     53		new |= ioread8(hd->base) & ~hd->mask;
     54		iowrite8(new, hd->base);
     55		break;
     56	}
     57}
     58
     59static void heartbeat_timer(struct timer_list *t)
     60{
     61	struct heartbeat_data *hd = from_timer(hd, t, timer);
     62	static unsigned bit = 0, up = 1;
     63
     64	heartbeat_toggle_bit(hd, bit, hd->flags & HEARTBEAT_INVERTED);
     65
     66	bit += up;
     67	if ((bit == 0) || (bit == (hd->nr_bits)-1))
     68		up = -up;
     69
     70	mod_timer(&hd->timer, jiffies + (110 - ((300 << FSHIFT) /
     71			((avenrun[0] / 5) + (3 << FSHIFT)))));
     72}
     73
     74static int heartbeat_drv_probe(struct platform_device *pdev)
     75{
     76	struct resource *res;
     77	struct heartbeat_data *hd;
     78	int i;
     79
     80	if (unlikely(pdev->num_resources != 1)) {
     81		dev_err(&pdev->dev, "invalid number of resources\n");
     82		return -EINVAL;
     83	}
     84
     85	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
     86	if (unlikely(res == NULL)) {
     87		dev_err(&pdev->dev, "invalid resource\n");
     88		return -EINVAL;
     89	}
     90
     91	if (pdev->dev.platform_data) {
     92		hd = pdev->dev.platform_data;
     93	} else {
     94		hd = kzalloc(sizeof(struct heartbeat_data), GFP_KERNEL);
     95		if (unlikely(!hd))
     96			return -ENOMEM;
     97	}
     98
     99	hd->base = ioremap(res->start, resource_size(res));
    100	if (unlikely(!hd->base)) {
    101		dev_err(&pdev->dev, "ioremap failed\n");
    102
    103		if (!pdev->dev.platform_data)
    104			kfree(hd);
    105
    106		return -ENXIO;
    107	}
    108
    109	if (!hd->nr_bits) {
    110		hd->bit_pos = default_bit_pos;
    111		hd->nr_bits = ARRAY_SIZE(default_bit_pos);
    112	}
    113
    114	hd->mask = 0;
    115	for (i = 0; i < hd->nr_bits; i++)
    116		hd->mask |= (1 << hd->bit_pos[i]);
    117
    118	if (!hd->regsize) {
    119		switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
    120		case IORESOURCE_MEM_32BIT:
    121			hd->regsize = 32;
    122			break;
    123		case IORESOURCE_MEM_16BIT:
    124			hd->regsize = 16;
    125			break;
    126		case IORESOURCE_MEM_8BIT:
    127		default:
    128			hd->regsize = 8;
    129			break;
    130		}
    131	}
    132
    133	timer_setup(&hd->timer, heartbeat_timer, 0);
    134	platform_set_drvdata(pdev, hd);
    135
    136	return mod_timer(&hd->timer, jiffies + 1);
    137}
    138
    139static struct platform_driver heartbeat_driver = {
    140	.probe		= heartbeat_drv_probe,
    141	.driver		= {
    142		.name			= DRV_NAME,
    143		.suppress_bind_attrs	= true,
    144	},
    145};
    146
    147static int __init heartbeat_init(void)
    148{
    149	printk(KERN_NOTICE DRV_NAME ": version %s loaded\n", DRV_VERSION);
    150	return platform_driver_register(&heartbeat_driver);
    151}
    152device_initcall(heartbeat_init);