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

sgy_cts1000.c (4049B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Servergy CTS-1000 Setup
      4 *
      5 * Maintained by Ben Collins <ben.c@servergy.com>
      6 *
      7 * Copyright 2012 by Servergy, Inc.
      8 */
      9
     10#include <linux/platform_device.h>
     11#include <linux/device.h>
     12#include <linux/module.h>
     13#include <linux/of_gpio.h>
     14#include <linux/of_irq.h>
     15#include <linux/workqueue.h>
     16#include <linux/reboot.h>
     17#include <linux/interrupt.h>
     18
     19#include <asm/machdep.h>
     20
     21static struct device_node *halt_node;
     22
     23static const struct of_device_id child_match[] = {
     24	{
     25		.compatible = "sgy,gpio-halt",
     26	},
     27	{},
     28};
     29
     30static void gpio_halt_wfn(struct work_struct *work)
     31{
     32	/* Likely wont return */
     33	orderly_poweroff(true);
     34}
     35static DECLARE_WORK(gpio_halt_wq, gpio_halt_wfn);
     36
     37static void __noreturn gpio_halt_cb(void)
     38{
     39	enum of_gpio_flags flags;
     40	int trigger, gpio;
     41
     42	if (!halt_node)
     43		panic("No reset GPIO information was provided in DT\n");
     44
     45	gpio = of_get_gpio_flags(halt_node, 0, &flags);
     46
     47	if (!gpio_is_valid(gpio))
     48		panic("Provided GPIO is invalid\n");
     49
     50	trigger = (flags == OF_GPIO_ACTIVE_LOW);
     51
     52	printk(KERN_INFO "gpio-halt: triggering GPIO.\n");
     53
     54	/* Probably wont return */
     55	gpio_set_value(gpio, trigger);
     56
     57	panic("Halt failed\n");
     58}
     59
     60/* This IRQ means someone pressed the power button and it is waiting for us
     61 * to handle the shutdown/poweroff. */
     62static irqreturn_t gpio_halt_irq(int irq, void *__data)
     63{
     64	printk(KERN_INFO "gpio-halt: shutdown due to power button IRQ.\n");
     65	schedule_work(&gpio_halt_wq);
     66
     67        return IRQ_HANDLED;
     68};
     69
     70static int gpio_halt_probe(struct platform_device *pdev)
     71{
     72	enum of_gpio_flags flags;
     73	struct device_node *node = pdev->dev.of_node;
     74	int gpio, err, irq;
     75	int trigger;
     76
     77	if (!node)
     78		return -ENODEV;
     79
     80	/* If there's no matching child, this isn't really an error */
     81	halt_node = of_find_matching_node(node, child_match);
     82	if (!halt_node)
     83		return 0;
     84
     85	/* Technically we could just read the first one, but punish
     86	 * DT writers for invalid form. */
     87	if (of_gpio_count(halt_node) != 1)
     88		return -EINVAL;
     89
     90	/* Get the gpio number relative to the dynamic base. */
     91	gpio = of_get_gpio_flags(halt_node, 0, &flags);
     92	if (!gpio_is_valid(gpio))
     93		return -EINVAL;
     94
     95	err = gpio_request(gpio, "gpio-halt");
     96	if (err) {
     97		printk(KERN_ERR "gpio-halt: error requesting GPIO %d.\n",
     98		       gpio);
     99		halt_node = NULL;
    100		return err;
    101	}
    102
    103	trigger = (flags == OF_GPIO_ACTIVE_LOW);
    104
    105	gpio_direction_output(gpio, !trigger);
    106
    107	/* Now get the IRQ which tells us when the power button is hit */
    108	irq = irq_of_parse_and_map(halt_node, 0);
    109	err = request_irq(irq, gpio_halt_irq, IRQF_TRIGGER_RISING |
    110			  IRQF_TRIGGER_FALLING, "gpio-halt", halt_node);
    111	if (err) {
    112		printk(KERN_ERR "gpio-halt: error requesting IRQ %d for "
    113		       "GPIO %d.\n", irq, gpio);
    114		gpio_free(gpio);
    115		halt_node = NULL;
    116		return err;
    117	}
    118
    119	/* Register our halt function */
    120	ppc_md.halt = gpio_halt_cb;
    121	pm_power_off = gpio_halt_cb;
    122
    123	printk(KERN_INFO "gpio-halt: registered GPIO %d (%d trigger, %d"
    124	       " irq).\n", gpio, trigger, irq);
    125
    126	return 0;
    127}
    128
    129static int gpio_halt_remove(struct platform_device *pdev)
    130{
    131	if (halt_node) {
    132		int gpio = of_get_gpio(halt_node, 0);
    133		int irq = irq_of_parse_and_map(halt_node, 0);
    134
    135		free_irq(irq, halt_node);
    136
    137		ppc_md.halt = NULL;
    138		pm_power_off = NULL;
    139
    140		gpio_free(gpio);
    141
    142		halt_node = NULL;
    143	}
    144
    145	return 0;
    146}
    147
    148static const struct of_device_id gpio_halt_match[] = {
    149	/* We match on the gpio bus itself and scan the children since they
    150	 * wont be matched against us. We know the bus wont match until it
    151	 * has been registered too. */
    152	{
    153		.compatible = "fsl,qoriq-gpio",
    154	},
    155	{},
    156};
    157MODULE_DEVICE_TABLE(of, gpio_halt_match);
    158
    159static struct platform_driver gpio_halt_driver = {
    160	.driver = {
    161		.name		= "gpio-halt",
    162		.of_match_table = gpio_halt_match,
    163	},
    164	.probe		= gpio_halt_probe,
    165	.remove		= gpio_halt_remove,
    166};
    167
    168module_platform_driver(gpio_halt_driver);
    169
    170MODULE_DESCRIPTION("Driver to support GPIO triggered system halt for Servergy CTS-1000 Systems.");
    171MODULE_VERSION("1.0");
    172MODULE_AUTHOR("Ben Collins <ben.c@servergy.com>");
    173MODULE_LICENSE("GPL");