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

ip22-reset.c (5075B)


      1/*
      2 * This file is subject to the terms and conditions of the GNU General Public
      3 * License.  See the file "COPYING" in the main directory of this archive
      4 * for more details.
      5 *
      6 * Copyright (C) 1997, 1998, 2001, 03, 05, 06 by Ralf Baechle
      7 */
      8#include <linux/linkage.h>
      9#include <linux/init.h>
     10#include <linux/rtc/ds1286.h>
     11#include <linux/interrupt.h>
     12#include <linux/kernel.h>
     13#include <linux/sched/signal.h>
     14#include <linux/panic_notifier.h>
     15#include <linux/pm.h>
     16#include <linux/timer.h>
     17
     18#include <asm/io.h>
     19#include <asm/irq.h>
     20#include <asm/reboot.h>
     21#include <asm/sgialib.h>
     22#include <asm/sgi/ioc.h>
     23#include <asm/sgi/hpc3.h>
     24#include <asm/sgi/mc.h>
     25#include <asm/sgi/ip22.h>
     26
     27/*
     28 * Just powerdown if init hasn't done after POWERDOWN_TIMEOUT seconds.
     29 * I'm not sure if this feature is a good idea, for now it's here just to
     30 * make the power button make behave just like under IRIX.
     31 */
     32#define POWERDOWN_TIMEOUT	120
     33
     34/*
     35 * Blink frequency during reboot grace period and when panicked.
     36 */
     37#define POWERDOWN_FREQ		(HZ / 4)
     38#define PANIC_FREQ		(HZ / 8)
     39
     40static struct timer_list power_timer, blink_timer, debounce_timer;
     41static unsigned long blink_timer_timeout;
     42
     43#define MACHINE_PANICKED		1
     44#define MACHINE_SHUTTING_DOWN	2
     45
     46static int machine_state;
     47
     48static void __noreturn sgi_machine_power_off(void)
     49{
     50	unsigned int tmp;
     51
     52	local_irq_disable();
     53
     54	/* Disable watchdog */
     55	tmp = hpc3c0->rtcregs[RTC_CMD] & 0xff;
     56	hpc3c0->rtcregs[RTC_CMD] = tmp | RTC_WAM;
     57	hpc3c0->rtcregs[RTC_WSEC] = 0;
     58	hpc3c0->rtcregs[RTC_WHSEC] = 0;
     59
     60	while (1) {
     61		sgioc->panel = ~SGIOC_PANEL_POWERON;
     62		/* Good bye cruel world ...  */
     63
     64		/* If we're still running, we probably got sent an alarm
     65		   interrupt.  Read the flag to clear it.  */
     66		tmp = hpc3c0->rtcregs[RTC_HOURS_ALARM];
     67	}
     68}
     69
     70static void __noreturn sgi_machine_restart(char *command)
     71{
     72	if (machine_state & MACHINE_SHUTTING_DOWN)
     73		sgi_machine_power_off();
     74	sgimc->cpuctrl0 |= SGIMC_CCTRL0_SYSINIT;
     75	while (1);
     76}
     77
     78static void __noreturn sgi_machine_halt(void)
     79{
     80	if (machine_state & MACHINE_SHUTTING_DOWN)
     81		sgi_machine_power_off();
     82	ArcEnterInteractiveMode();
     83}
     84
     85static void power_timeout(struct timer_list *unused)
     86{
     87	sgi_machine_power_off();
     88}
     89
     90static void blink_timeout(struct timer_list *unused)
     91{
     92	/* XXX fix this for fullhouse  */
     93	sgi_ioc_reset ^= (SGIOC_RESET_LC0OFF|SGIOC_RESET_LC1OFF);
     94	sgioc->reset = sgi_ioc_reset;
     95
     96	mod_timer(&blink_timer, jiffies + blink_timer_timeout);
     97}
     98
     99static void debounce(struct timer_list *unused)
    100{
    101	del_timer(&debounce_timer);
    102	if (sgint->istat1 & SGINT_ISTAT1_PWR) {
    103		/* Interrupt still being sent. */
    104		debounce_timer.expires = jiffies + (HZ / 20); /* 0.05s	*/
    105		add_timer(&debounce_timer);
    106
    107		sgioc->panel = SGIOC_PANEL_POWERON | SGIOC_PANEL_POWERINTR |
    108			       SGIOC_PANEL_VOLDNINTR | SGIOC_PANEL_VOLDNHOLD |
    109			       SGIOC_PANEL_VOLUPINTR | SGIOC_PANEL_VOLUPHOLD;
    110
    111		return;
    112	}
    113
    114	if (machine_state & MACHINE_PANICKED)
    115		sgimc->cpuctrl0 |= SGIMC_CCTRL0_SYSINIT;
    116
    117	enable_irq(SGI_PANEL_IRQ);
    118}
    119
    120static inline void power_button(void)
    121{
    122	if (machine_state & MACHINE_PANICKED)
    123		return;
    124
    125	if ((machine_state & MACHINE_SHUTTING_DOWN) ||
    126			kill_cad_pid(SIGINT, 1)) {
    127		/* No init process or button pressed twice.  */
    128		sgi_machine_power_off();
    129	}
    130
    131	machine_state |= MACHINE_SHUTTING_DOWN;
    132	blink_timer_timeout = POWERDOWN_FREQ;
    133	blink_timeout(&blink_timer);
    134
    135	timer_setup(&power_timer, power_timeout, 0);
    136	power_timer.expires = jiffies + POWERDOWN_TIMEOUT * HZ;
    137	add_timer(&power_timer);
    138}
    139
    140static irqreturn_t panel_int(int irq, void *dev_id)
    141{
    142	unsigned int buttons;
    143
    144	buttons = sgioc->panel;
    145	sgioc->panel = SGIOC_PANEL_POWERON | SGIOC_PANEL_POWERINTR;
    146
    147	if (sgint->istat1 & SGINT_ISTAT1_PWR) {
    148		/* Wait until interrupt goes away */
    149		disable_irq_nosync(SGI_PANEL_IRQ);
    150		timer_setup(&debounce_timer, debounce, 0);
    151		debounce_timer.expires = jiffies + 5;
    152		add_timer(&debounce_timer);
    153	}
    154
    155	/* Power button was pressed
    156	 * ioc.ps page 22: "The Panel Register is called Power Control by Full
    157	 * House. Only lowest 2 bits are used. Guiness uses upper four bits
    158	 * for volume control". This is not true, all bits are pulled high
    159	 * on fullhouse */
    160	if (!(buttons & SGIOC_PANEL_POWERINTR))
    161		power_button();
    162
    163	return IRQ_HANDLED;
    164}
    165
    166static int panic_event(struct notifier_block *this, unsigned long event,
    167		      void *ptr)
    168{
    169	if (machine_state & MACHINE_PANICKED)
    170		return NOTIFY_DONE;
    171	machine_state |= MACHINE_PANICKED;
    172
    173	blink_timer_timeout = PANIC_FREQ;
    174	blink_timeout(&blink_timer);
    175
    176	return NOTIFY_DONE;
    177}
    178
    179static struct notifier_block panic_block = {
    180	.notifier_call	= panic_event,
    181};
    182
    183static int __init reboot_setup(void)
    184{
    185	int res;
    186
    187	_machine_restart = sgi_machine_restart;
    188	_machine_halt = sgi_machine_halt;
    189	pm_power_off = sgi_machine_power_off;
    190
    191	res = request_irq(SGI_PANEL_IRQ, panel_int, 0, "Front Panel", NULL);
    192	if (res) {
    193		printk(KERN_ERR "Allocation of front panel IRQ failed\n");
    194		return res;
    195	}
    196
    197	timer_setup(&blink_timer, blink_timeout, 0);
    198	atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
    199
    200	return 0;
    201}
    202
    203subsys_initcall(reboot_setup);