Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Octeon Watchdog driver
0004  *
0005  * Copyright (C) 2007-2017 Cavium, Inc.
0006  *
0007  * Converted to use WATCHDOG_CORE by Aaro Koskinen <aaro.koskinen@iki.fi>.
0008  *
0009  * Some parts derived from wdt.c
0010  *
0011  *  (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
0012  *                      All Rights Reserved.
0013  *
0014  *  Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
0015  *  warranty for any of this software. This material is provided
0016  *  "AS-IS" and at no charge.
0017  *
0018  *  (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
0019  *
0020  * The OCTEON watchdog has a maximum timeout of 2^32 * io_clock.
0021  * For most systems this is less than 10 seconds, so to allow for
0022  * software to request longer watchdog heartbeats, we maintain software
0023  * counters to count multiples of the base rate.  If the system locks
0024  * up in such a manner that we can not run the software counters, the
0025  * only result is a watchdog reset sooner than was requested.  But
0026  * that is OK, because in this case userspace would likely not be able
0027  * to do anything anyhow.
0028  *
0029  * The hardware watchdog interval we call the period.  The OCTEON
0030  * watchdog goes through several stages, after the first period an
0031  * irq is asserted, then if it is not reset, after the next period NMI
0032  * is asserted, then after an additional period a chip wide soft reset.
0033  * So for the software counters, we reset watchdog after each period
0034  * and decrement the counter.  But for the last two periods we need to
0035  * let the watchdog progress to the NMI stage so we disable the irq
0036  * and let it proceed.  Once in the NMI, we print the register state
0037  * to the serial port and then wait for the reset.
0038  *
0039  * A watchdog is maintained for each CPU in the system, that way if
0040  * one CPU suffers a lockup, we also get a register dump and reset.
0041  * The userspace ping resets the watchdog on all CPUs.
0042  *
0043  * Before userspace opens the watchdog device, we still run the
0044  * watchdogs to catch any lockups that may be kernel related.
0045  *
0046  */
0047 
0048 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0049 
0050 #include <linux/interrupt.h>
0051 #include <linux/watchdog.h>
0052 #include <linux/cpumask.h>
0053 #include <linux/module.h>
0054 #include <linux/delay.h>
0055 #include <linux/cpu.h>
0056 #include <linux/irq.h>
0057 #include <linux/irqdomain.h>
0058 
0059 #include <asm/mipsregs.h>
0060 #include <asm/uasm.h>
0061 
0062 #include <asm/octeon/octeon.h>
0063 #include <asm/octeon/cvmx-boot-vector.h>
0064 #include <asm/octeon/cvmx-ciu2-defs.h>
0065 #include <asm/octeon/cvmx-rst-defs.h>
0066 
0067 /* Watchdog interrupt major block number (8 MSBs of intsn) */
0068 #define WD_BLOCK_NUMBER     0x01
0069 
0070 static int divisor;
0071 
0072 /* The count needed to achieve timeout_sec. */
0073 static unsigned int timeout_cnt;
0074 
0075 /* The maximum period supported. */
0076 static unsigned int max_timeout_sec;
0077 
0078 /* The current period.  */
0079 static unsigned int timeout_sec;
0080 
0081 /* Set to non-zero when userspace countdown mode active */
0082 static bool do_countdown;
0083 static unsigned int countdown_reset;
0084 static unsigned int per_cpu_countdown[NR_CPUS];
0085 
0086 static cpumask_t irq_enabled_cpus;
0087 
0088 #define WD_TIMO 60          /* Default heartbeat = 60 seconds */
0089 
0090 #define CVMX_GSERX_SCRATCH(offset) (CVMX_ADD_IO_SEG(0x0001180090000020ull) + ((offset) & 15) * 0x1000000ull)
0091 
0092 static int heartbeat = WD_TIMO;
0093 module_param(heartbeat, int, 0444);
0094 MODULE_PARM_DESC(heartbeat,
0095     "Watchdog heartbeat in seconds. (0 < heartbeat, default="
0096                 __MODULE_STRING(WD_TIMO) ")");
0097 
0098 static bool nowayout = WATCHDOG_NOWAYOUT;
0099 module_param(nowayout, bool, 0444);
0100 MODULE_PARM_DESC(nowayout,
0101     "Watchdog cannot be stopped once started (default="
0102                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0103 
0104 static int disable;
0105 module_param(disable, int, 0444);
0106 MODULE_PARM_DESC(disable,
0107     "Disable the watchdog entirely (default=0)");
0108 
0109 static struct cvmx_boot_vector_element *octeon_wdt_bootvector;
0110 
0111 void octeon_wdt_nmi_stage2(void);
0112 
0113 static int cpu2core(int cpu)
0114 {
0115 #ifdef CONFIG_SMP
0116     return cpu_logical_map(cpu) & 0x3f;
0117 #else
0118     return cvmx_get_core_num();
0119 #endif
0120 }
0121 
0122 /**
0123  * octeon_wdt_poke_irq - Poke the watchdog when an interrupt is received
0124  *
0125  * @cpl:
0126  * @dev_id:
0127  *
0128  * Returns
0129  */
0130 static irqreturn_t octeon_wdt_poke_irq(int cpl, void *dev_id)
0131 {
0132     int cpu = raw_smp_processor_id();
0133     unsigned int core = cpu2core(cpu);
0134     int node = cpu_to_node(cpu);
0135 
0136     if (do_countdown) {
0137         if (per_cpu_countdown[cpu] > 0) {
0138             /* We're alive, poke the watchdog */
0139             cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
0140             per_cpu_countdown[cpu]--;
0141         } else {
0142             /* Bad news, you are about to reboot. */
0143             disable_irq_nosync(cpl);
0144             cpumask_clear_cpu(cpu, &irq_enabled_cpus);
0145         }
0146     } else {
0147         /* Not open, just ping away... */
0148         cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
0149     }
0150     return IRQ_HANDLED;
0151 }
0152 
0153 /* From setup.c */
0154 extern int prom_putchar(char c);
0155 
0156 /**
0157  * octeon_wdt_write_string - Write a string to the uart
0158  *
0159  * @str:        String to write
0160  */
0161 static void octeon_wdt_write_string(const char *str)
0162 {
0163     /* Just loop writing one byte at a time */
0164     while (*str)
0165         prom_putchar(*str++);
0166 }
0167 
0168 /**
0169  * octeon_wdt_write_hex() - Write a hex number out of the uart
0170  *
0171  * @value:      Number to display
0172  * @digits:     Number of digits to print (1 to 16)
0173  */
0174 static void octeon_wdt_write_hex(u64 value, int digits)
0175 {
0176     int d;
0177     int v;
0178 
0179     for (d = 0; d < digits; d++) {
0180         v = (value >> ((digits - d - 1) * 4)) & 0xf;
0181         if (v >= 10)
0182             prom_putchar('a' + v - 10);
0183         else
0184             prom_putchar('0' + v);
0185     }
0186 }
0187 
0188 static const char reg_name[][3] = {
0189     "$0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
0190     "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
0191     "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
0192     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
0193 };
0194 
0195 /**
0196  * octeon_wdt_nmi_stage3:
0197  *
0198  * NMI stage 3 handler. NMIs are handled in the following manner:
0199  * 1) The first NMI handler enables CVMSEG and transfers from
0200  * the bootbus region into normal memory. It is careful to not
0201  * destroy any registers.
0202  * 2) The second stage handler uses CVMSEG to save the registers
0203  * and create a stack for C code. It then calls the third level
0204  * handler with one argument, a pointer to the register values.
0205  * 3) The third, and final, level handler is the following C
0206  * function that prints out some useful infomration.
0207  *
0208  * @reg:    Pointer to register state before the NMI
0209  */
0210 void octeon_wdt_nmi_stage3(u64 reg[32])
0211 {
0212     u64 i;
0213 
0214     unsigned int coreid = cvmx_get_core_num();
0215     /*
0216      * Save status and cause early to get them before any changes
0217      * might happen.
0218      */
0219     u64 cp0_cause = read_c0_cause();
0220     u64 cp0_status = read_c0_status();
0221     u64 cp0_error_epc = read_c0_errorepc();
0222     u64 cp0_epc = read_c0_epc();
0223 
0224     /* Delay so output from all cores output is not jumbled together. */
0225     udelay(85000 * coreid);
0226 
0227     octeon_wdt_write_string("\r\n*** NMI Watchdog interrupt on Core 0x");
0228     octeon_wdt_write_hex(coreid, 2);
0229     octeon_wdt_write_string(" ***\r\n");
0230     for (i = 0; i < 32; i++) {
0231         octeon_wdt_write_string("\t");
0232         octeon_wdt_write_string(reg_name[i]);
0233         octeon_wdt_write_string("\t0x");
0234         octeon_wdt_write_hex(reg[i], 16);
0235         if (i & 1)
0236             octeon_wdt_write_string("\r\n");
0237     }
0238     octeon_wdt_write_string("\terr_epc\t0x");
0239     octeon_wdt_write_hex(cp0_error_epc, 16);
0240 
0241     octeon_wdt_write_string("\tepc\t0x");
0242     octeon_wdt_write_hex(cp0_epc, 16);
0243     octeon_wdt_write_string("\r\n");
0244 
0245     octeon_wdt_write_string("\tstatus\t0x");
0246     octeon_wdt_write_hex(cp0_status, 16);
0247     octeon_wdt_write_string("\tcause\t0x");
0248     octeon_wdt_write_hex(cp0_cause, 16);
0249     octeon_wdt_write_string("\r\n");
0250 
0251     /* The CIU register is different for each Octeon model. */
0252     if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
0253         octeon_wdt_write_string("\tsrc_wd\t0x");
0254         octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_SRC_PPX_IP2_WDOG(coreid)), 16);
0255         octeon_wdt_write_string("\ten_wd\t0x");
0256         octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_EN_PPX_IP2_WDOG(coreid)), 16);
0257         octeon_wdt_write_string("\r\n");
0258         octeon_wdt_write_string("\tsrc_rml\t0x");
0259         octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_SRC_PPX_IP2_RML(coreid)), 16);
0260         octeon_wdt_write_string("\ten_rml\t0x");
0261         octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_EN_PPX_IP2_RML(coreid)), 16);
0262         octeon_wdt_write_string("\r\n");
0263         octeon_wdt_write_string("\tsum\t0x");
0264         octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_SUM_PPX_IP2(coreid)), 16);
0265         octeon_wdt_write_string("\r\n");
0266     } else if (!octeon_has_feature(OCTEON_FEATURE_CIU3)) {
0267         octeon_wdt_write_string("\tsum0\t0x");
0268         octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_SUM0(coreid * 2)), 16);
0269         octeon_wdt_write_string("\ten0\t0x");
0270         octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2)), 16);
0271         octeon_wdt_write_string("\r\n");
0272     }
0273 
0274     octeon_wdt_write_string("*** Chip soft reset soon ***\r\n");
0275 
0276     /*
0277      * G-30204: We must trigger a soft reset before watchdog
0278      * does an incomplete job of doing it.
0279      */
0280     if (OCTEON_IS_OCTEON3() && !OCTEON_IS_MODEL(OCTEON_CN70XX)) {
0281         u64 scr;
0282         unsigned int node = cvmx_get_node_num();
0283         unsigned int lcore = cvmx_get_local_core_num();
0284         union cvmx_ciu_wdogx ciu_wdog;
0285 
0286         /*
0287          * Wait for other cores to print out information, but
0288          * not too long.  Do the soft reset before watchdog
0289          * can trigger it.
0290          */
0291         do {
0292             ciu_wdog.u64 = cvmx_read_csr_node(node, CVMX_CIU_WDOGX(lcore));
0293         } while (ciu_wdog.s.cnt > 0x10000);
0294 
0295         scr = cvmx_read_csr_node(0, CVMX_GSERX_SCRATCH(0));
0296         scr |= 1 << 11; /* Indicate watchdog in bit 11 */
0297         cvmx_write_csr_node(0, CVMX_GSERX_SCRATCH(0), scr);
0298         cvmx_write_csr_node(0, CVMX_RST_SOFT_RST, 1);
0299     }
0300 }
0301 
0302 static int octeon_wdt_cpu_to_irq(int cpu)
0303 {
0304     unsigned int coreid;
0305     int node;
0306     int irq;
0307 
0308     coreid = cpu2core(cpu);
0309     node = cpu_to_node(cpu);
0310 
0311     if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
0312         struct irq_domain *domain;
0313         int hwirq;
0314 
0315         domain = octeon_irq_get_block_domain(node,
0316                              WD_BLOCK_NUMBER);
0317         hwirq = WD_BLOCK_NUMBER << 12 | 0x200 | coreid;
0318         irq = irq_find_mapping(domain, hwirq);
0319     } else {
0320         irq = OCTEON_IRQ_WDOG0 + coreid;
0321     }
0322     return irq;
0323 }
0324 
0325 static int octeon_wdt_cpu_pre_down(unsigned int cpu)
0326 {
0327     unsigned int core;
0328     int node;
0329     union cvmx_ciu_wdogx ciu_wdog;
0330 
0331     core = cpu2core(cpu);
0332 
0333     node = cpu_to_node(cpu);
0334 
0335     /* Poke the watchdog to clear out its state */
0336     cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
0337 
0338     /* Disable the hardware. */
0339     ciu_wdog.u64 = 0;
0340     cvmx_write_csr_node(node, CVMX_CIU_WDOGX(core), ciu_wdog.u64);
0341 
0342     free_irq(octeon_wdt_cpu_to_irq(cpu), octeon_wdt_poke_irq);
0343     return 0;
0344 }
0345 
0346 static int octeon_wdt_cpu_online(unsigned int cpu)
0347 {
0348     unsigned int core;
0349     unsigned int irq;
0350     union cvmx_ciu_wdogx ciu_wdog;
0351     int node;
0352     struct irq_domain *domain;
0353     int hwirq;
0354 
0355     core = cpu2core(cpu);
0356     node = cpu_to_node(cpu);
0357 
0358     octeon_wdt_bootvector[core].target_ptr = (u64)octeon_wdt_nmi_stage2;
0359 
0360     /* Disable it before doing anything with the interrupts. */
0361     ciu_wdog.u64 = 0;
0362     cvmx_write_csr_node(node, CVMX_CIU_WDOGX(core), ciu_wdog.u64);
0363 
0364     per_cpu_countdown[cpu] = countdown_reset;
0365 
0366     if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
0367         /* Must get the domain for the watchdog block */
0368         domain = octeon_irq_get_block_domain(node, WD_BLOCK_NUMBER);
0369 
0370         /* Get a irq for the wd intsn (hardware interrupt) */
0371         hwirq = WD_BLOCK_NUMBER << 12 | 0x200 | core;
0372         irq = irq_create_mapping(domain, hwirq);
0373         irqd_set_trigger_type(irq_get_irq_data(irq),
0374                       IRQ_TYPE_EDGE_RISING);
0375     } else
0376         irq = OCTEON_IRQ_WDOG0 + core;
0377 
0378     if (request_irq(irq, octeon_wdt_poke_irq,
0379             IRQF_NO_THREAD, "octeon_wdt", octeon_wdt_poke_irq))
0380         panic("octeon_wdt: Couldn't obtain irq %d", irq);
0381 
0382     /* Must set the irq affinity here */
0383     if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
0384         cpumask_t mask;
0385 
0386         cpumask_clear(&mask);
0387         cpumask_set_cpu(cpu, &mask);
0388         irq_set_affinity(irq, &mask);
0389     }
0390 
0391     cpumask_set_cpu(cpu, &irq_enabled_cpus);
0392 
0393     /* Poke the watchdog to clear out its state */
0394     cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
0395 
0396     /* Finally enable the watchdog now that all handlers are installed */
0397     ciu_wdog.u64 = 0;
0398     ciu_wdog.s.len = timeout_cnt;
0399     ciu_wdog.s.mode = 3;    /* 3 = Interrupt + NMI + Soft-Reset */
0400     cvmx_write_csr_node(node, CVMX_CIU_WDOGX(core), ciu_wdog.u64);
0401 
0402     return 0;
0403 }
0404 
0405 static int octeon_wdt_ping(struct watchdog_device __always_unused *wdog)
0406 {
0407     int cpu;
0408     int coreid;
0409     int node;
0410 
0411     if (disable)
0412         return 0;
0413 
0414     for_each_online_cpu(cpu) {
0415         coreid = cpu2core(cpu);
0416         node = cpu_to_node(cpu);
0417         cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(coreid), 1);
0418         per_cpu_countdown[cpu] = countdown_reset;
0419         if ((countdown_reset || !do_countdown) &&
0420             !cpumask_test_cpu(cpu, &irq_enabled_cpus)) {
0421             /* We have to enable the irq */
0422             enable_irq(octeon_wdt_cpu_to_irq(cpu));
0423             cpumask_set_cpu(cpu, &irq_enabled_cpus);
0424         }
0425     }
0426     return 0;
0427 }
0428 
0429 static void octeon_wdt_calc_parameters(int t)
0430 {
0431     unsigned int periods;
0432 
0433     timeout_sec = max_timeout_sec;
0434 
0435 
0436     /*
0437      * Find the largest interrupt period, that can evenly divide
0438      * the requested heartbeat time.
0439      */
0440     while ((t % timeout_sec) != 0)
0441         timeout_sec--;
0442 
0443     periods = t / timeout_sec;
0444 
0445     /*
0446      * The last two periods are after the irq is disabled, and
0447      * then to the nmi, so we subtract them off.
0448      */
0449 
0450     countdown_reset = periods > 2 ? periods - 2 : 0;
0451     heartbeat = t;
0452     timeout_cnt = ((octeon_get_io_clock_rate() / divisor) * timeout_sec) >> 8;
0453 }
0454 
0455 static int octeon_wdt_set_timeout(struct watchdog_device *wdog,
0456                   unsigned int t)
0457 {
0458     int cpu;
0459     int coreid;
0460     union cvmx_ciu_wdogx ciu_wdog;
0461     int node;
0462 
0463     if (t <= 0)
0464         return -1;
0465 
0466     octeon_wdt_calc_parameters(t);
0467 
0468     if (disable)
0469         return 0;
0470 
0471     for_each_online_cpu(cpu) {
0472         coreid = cpu2core(cpu);
0473         node = cpu_to_node(cpu);
0474         cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(coreid), 1);
0475         ciu_wdog.u64 = 0;
0476         ciu_wdog.s.len = timeout_cnt;
0477         ciu_wdog.s.mode = 3;    /* 3 = Interrupt + NMI + Soft-Reset */
0478         cvmx_write_csr_node(node, CVMX_CIU_WDOGX(coreid), ciu_wdog.u64);
0479         cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(coreid), 1);
0480     }
0481     octeon_wdt_ping(wdog); /* Get the irqs back on. */
0482     return 0;
0483 }
0484 
0485 static int octeon_wdt_start(struct watchdog_device *wdog)
0486 {
0487     octeon_wdt_ping(wdog);
0488     do_countdown = 1;
0489     return 0;
0490 }
0491 
0492 static int octeon_wdt_stop(struct watchdog_device *wdog)
0493 {
0494     do_countdown = 0;
0495     octeon_wdt_ping(wdog);
0496     return 0;
0497 }
0498 
0499 static const struct watchdog_info octeon_wdt_info = {
0500     .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
0501     .identity = "OCTEON",
0502 };
0503 
0504 static const struct watchdog_ops octeon_wdt_ops = {
0505     .owner      = THIS_MODULE,
0506     .start      = octeon_wdt_start,
0507     .stop       = octeon_wdt_stop,
0508     .ping       = octeon_wdt_ping,
0509     .set_timeout    = octeon_wdt_set_timeout,
0510 };
0511 
0512 static struct watchdog_device octeon_wdt = {
0513     .info   = &octeon_wdt_info,
0514     .ops    = &octeon_wdt_ops,
0515 };
0516 
0517 static enum cpuhp_state octeon_wdt_online;
0518 /**
0519  * octeon_wdt_init - Module/ driver initialization.
0520  *
0521  * Returns Zero on success
0522  */
0523 static int __init octeon_wdt_init(void)
0524 {
0525     int ret;
0526 
0527     octeon_wdt_bootvector = cvmx_boot_vector_get();
0528     if (!octeon_wdt_bootvector) {
0529         pr_err("Error: Cannot allocate boot vector.\n");
0530         return -ENOMEM;
0531     }
0532 
0533     if (OCTEON_IS_MODEL(OCTEON_CN68XX))
0534         divisor = 0x200;
0535     else if (OCTEON_IS_MODEL(OCTEON_CN78XX))
0536         divisor = 0x400;
0537     else
0538         divisor = 0x100;
0539 
0540     /*
0541      * Watchdog time expiration length = The 16 bits of LEN
0542      * represent the most significant bits of a 24 bit decrementer
0543      * that decrements every divisor cycle.
0544      *
0545      * Try for a timeout of 5 sec, if that fails a smaller number
0546      * of even seconds,
0547      */
0548     max_timeout_sec = 6;
0549     do {
0550         max_timeout_sec--;
0551         timeout_cnt = ((octeon_get_io_clock_rate() / divisor) * max_timeout_sec) >> 8;
0552     } while (timeout_cnt > 65535);
0553 
0554     BUG_ON(timeout_cnt == 0);
0555 
0556     octeon_wdt_calc_parameters(heartbeat);
0557 
0558     pr_info("Initial granularity %d Sec\n", timeout_sec);
0559 
0560     octeon_wdt.timeout  = timeout_sec;
0561     octeon_wdt.max_timeout  = UINT_MAX;
0562 
0563     watchdog_set_nowayout(&octeon_wdt, nowayout);
0564 
0565     ret = watchdog_register_device(&octeon_wdt);
0566     if (ret) {
0567         pr_err("watchdog_register_device() failed: %d\n", ret);
0568         return ret;
0569     }
0570 
0571     if (disable) {
0572         pr_notice("disabled\n");
0573         return 0;
0574     }
0575 
0576     cpumask_clear(&irq_enabled_cpus);
0577 
0578     ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "watchdog/octeon:online",
0579                 octeon_wdt_cpu_online, octeon_wdt_cpu_pre_down);
0580     if (ret < 0)
0581         goto err;
0582     octeon_wdt_online = ret;
0583     return 0;
0584 err:
0585     cvmx_write_csr(CVMX_MIO_BOOT_LOC_CFGX(0), 0);
0586     watchdog_unregister_device(&octeon_wdt);
0587     return ret;
0588 }
0589 
0590 /**
0591  * octeon_wdt_cleanup - Module / driver shutdown
0592  */
0593 static void __exit octeon_wdt_cleanup(void)
0594 {
0595     watchdog_unregister_device(&octeon_wdt);
0596 
0597     if (disable)
0598         return;
0599 
0600     cpuhp_remove_state(octeon_wdt_online);
0601 
0602     /*
0603      * Disable the boot-bus memory, the code it points to is soon
0604      * to go missing.
0605      */
0606     cvmx_write_csr(CVMX_MIO_BOOT_LOC_CFGX(0), 0);
0607 }
0608 
0609 MODULE_LICENSE("GPL");
0610 MODULE_AUTHOR("Cavium Inc. <support@cavium.com>");
0611 MODULE_DESCRIPTION("Cavium Inc. OCTEON Watchdog driver.");
0612 module_init(octeon_wdt_init);
0613 module_exit(octeon_wdt_cleanup);