diff options
Diffstat (limited to 'Documentation')
-rw-r--r-- | Documentation/DocBook/Makefile | 3 | ||||
-rw-r--r-- | Documentation/DocBook/genericirq.tmpl | 474 | ||||
-rw-r--r-- | Documentation/IRQ.txt | 22 | ||||
-rw-r--r-- | Documentation/feature-removal-schedule.txt | 10 | ||||
-rw-r--r-- | Documentation/kernel-parameters.txt | 9 | ||||
-rw-r--r-- | Documentation/keys-request-key.txt | 54 | ||||
-rw-r--r-- | Documentation/keys.txt | 29 | ||||
-rw-r--r-- | Documentation/watchdog/pcwd-watchdog.txt | 75 | ||||
-rw-r--r-- | Documentation/watchdog/src/watchdog-simple.c | 15 | ||||
-rw-r--r-- | Documentation/watchdog/src/watchdog-test.c | 68 | ||||
-rw-r--r-- | Documentation/watchdog/watchdog-api.txt | 56 | ||||
-rw-r--r-- | Documentation/watchdog/watchdog.txt | 23 |
12 files changed, 706 insertions, 132 deletions
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 5a2882d275ba..66e1cf733571 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -10,7 +10,8 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \ kernel-hacking.xml kernel-locking.xml deviceiobook.xml \ procfs-guide.xml writing_usb_driver.xml \ kernel-api.xml journal-api.xml lsm.xml usb.xml \ - gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml + gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ + genericirq.xml ### # The build process is as follows (targets): diff --git a/Documentation/DocBook/genericirq.tmpl b/Documentation/DocBook/genericirq.tmpl new file mode 100644 index 000000000000..0f4a4b6321e4 --- /dev/null +++ b/Documentation/DocBook/genericirq.tmpl @@ -0,0 +1,474 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" + "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []> + +<book id="Generic-IRQ-Guide"> + <bookinfo> + <title>Linux generic IRQ handling</title> + + <authorgroup> + <author> + <firstname>Thomas</firstname> + <surname>Gleixner</surname> + <affiliation> + <address> + <email>tglx@linutronix.de</email> + </address> + </affiliation> + </author> + <author> + <firstname>Ingo</firstname> + <surname>Molnar</surname> + <affiliation> + <address> + <email>mingo@elte.hu</email> + </address> + </affiliation> + </author> + </authorgroup> + + <copyright> + <year>2005-2006</year> + <holder>Thomas Gleixner</holder> + </copyright> + <copyright> + <year>2005-2006</year> + <holder>Ingo Molnar</holder> + </copyright> + + <legalnotice> + <para> + This documentation is free software; you can redistribute + it and/or modify it under the terms of the GNU General Public + License version 2 as published by the Free Software Foundation. + </para> + + <para> + This program is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + </para> + + <para> + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + </para> + + <para> + For more details see the file COPYING in the source + distribution of Linux. + </para> + </legalnotice> + </bookinfo> + +<toc></toc> + + <chapter id="intro"> + <title>Introduction</title> + <para> + The generic interrupt handling layer is designed to provide a + complete abstraction of interrupt handling for device drivers. + It is able to handle all the different types of interrupt controller + hardware. Device drivers use generic API functions to request, enable, + disable and free interrupts. The drivers do not have to know anything + about interrupt hardware details, so they can be used on different + platforms without code changes. + </para> + <para> + This documentation is provided to developers who want to implement + an interrupt subsystem based for their architecture, with the help + of the generic IRQ handling layer. + </para> + </chapter> + + <chapter id="rationale"> + <title>Rationale</title> + <para> + The original implementation of interrupt handling in Linux is using + the __do_IRQ() super-handler, which is able to deal with every + type of interrupt logic. + </para> + <para> + Originally, Russell King identified different types of handlers to + build a quite universal set for the ARM interrupt handler + implementation in Linux 2.5/2.6. He distinguished between: + <itemizedlist> + <listitem><para>Level type</para></listitem> + <listitem><para>Edge type</para></listitem> + <listitem><para>Simple type</para></listitem> + </itemizedlist> + In the SMP world of the __do_IRQ() super-handler another type + was identified: + <itemizedlist> + <listitem><para>Per CPU type</para></listitem> + </itemizedlist> + </para> + <para> + This split implementation of highlevel IRQ handlers allows us to + optimize the flow of the interrupt handling for each specific + interrupt type. This reduces complexity in that particular codepath + and allows the optimized handling of a given type. + </para> + <para> + The original general IRQ implementation used hw_interrupt_type + structures and their ->ack(), ->end() [etc.] callbacks to + differentiate the flow control in the super-handler. This leads to + a mix of flow logic and lowlevel hardware logic, and it also leads + to unnecessary code duplication: for example in i386, there is a + ioapic_level_irq and a ioapic_edge_irq irq-type which share many + of the lowlevel details but have different flow handling. + </para> + <para> + A more natural abstraction is the clean separation of the + 'irq flow' and the 'chip details'. + </para> + <para> + Analysing a couple of architecture's IRQ subsystem implementations + reveals that most of them can use a generic set of 'irq flow' + methods and only need to add the chip level specific code. + The separation is also valuable for (sub)architectures + which need specific quirks in the irq flow itself but not in the + chip-details - and thus provides a more transparent IRQ subsystem + design. + </para> + <para> + Each interrupt descriptor is assigned its own highlevel flow + handler, which is normally one of the generic + implementations. (This highlevel flow handler implementation also + makes it simple to provide demultiplexing handlers which can be + found in embedded platforms on various architectures.) + </para> + <para> + The separation makes the generic interrupt handling layer more + flexible and extensible. For example, an (sub)architecture can + use a generic irq-flow implementation for 'level type' interrupts + and add a (sub)architecture specific 'edge type' implementation. + </para> + <para> + To make the transition to the new model easier and prevent the + breakage of existing implementations, the __do_IRQ() super-handler + is still available. This leads to a kind of duality for the time + being. Over time the new model should be used in more and more + architectures, as it enables smaller and cleaner IRQ subsystems. + </para> + </chapter> + <chapter id="bugs"> + <title>Known Bugs And Assumptions</title> + <para> + None (knock on wood). + </para> + </chapter> + + <chapter id="Abstraction"> + <title>Abstraction layers</title> + <para> + There are three main levels of abstraction in the interrupt code: + <orderedlist> + <listitem><para>Highlevel driver API</para></listitem> + <listitem><para>Highlevel IRQ flow handlers</para></listitem> + <listitem><para>Chiplevel hardware encapsulation</para></listitem> + </orderedlist> + </para> + <sect1> + <title>Interrupt control flow</title> + <para> + Each interrupt is described by an interrupt descriptor structure + irq_desc. The interrupt is referenced by an 'unsigned int' numeric + value which selects the corresponding interrupt decription structure + in the descriptor structures array. + The descriptor structure contains status information and pointers + to the interrupt flow method and the interrupt chip structure + which are assigned to this interrupt. + </para> + <para> + Whenever an interrupt triggers, the lowlevel arch code calls into + the generic interrupt code by calling desc->handle_irq(). + This highlevel IRQ handling function only uses desc->chip primitives + referenced by the assigned chip descriptor structure. + </para> + </sect1> + <sect1> + <title>Highlevel Driver API</title> + <para> + The highlevel Driver API consists of following functions: + <itemizedlist> + <listitem><para>request_irq()</para></listitem> + <listitem><para>free_irq()</para></listitem> + <listitem><para>disable_irq()</para></listitem> + <listitem><para>enable_irq()</para></listitem> + <listitem><para>disable_irq_nosync() (SMP only)</para></listitem> + <listitem><para>synchronize_irq() (SMP only)</para></listitem> + <listitem><para>set_irq_type()</para></listitem> + <listitem><para>set_irq_wake()</para></listitem> + <listitem><para>set_irq_data()</para></listitem> + <listitem><para>set_irq_chip()</para></listitem> + <listitem><para>set_irq_chip_data()</para></listitem> + </itemizedlist> + See the autogenerated function documentation for details. + </para> + </sect1> + <sect1> + <title>Highlevel IRQ flow handlers</title> + <para> + The generic layer provides a set of pre-defined irq-flow methods: + <itemizedlist> + <listitem><para>handle_level_irq</para></listitem> + <listitem><para>handle_edge_irq</para></listitem> + <listitem><para>handle_simple_irq</para></listitem> + <listitem><para>handle_percpu_irq</para></listitem> + </itemizedlist> + The interrupt flow handlers (either predefined or architecture + specific) are assigned to specific interrupts by the architecture + either during bootup or during device initialization. + </para> + <sect2> + <title>Default flow implementations</title> + <sect3> + <title>Helper functions</title> + <para> + The helper functions call the chip primitives and + are used by the default flow implementations. + The following helper functions are implemented (simplified excerpt): + <programlisting> +default_enable(irq) +{ + desc->chip->unmask(irq); +} + +default_disable(irq) +{ + if (!delay_disable(irq)) + desc->chip->mask(irq); +} + +default_ack(irq) +{ + chip->ack(irq); +} + +default_mask_ack(irq) +{ + if (chip->mask_ack) { + chip->mask_ack(irq); + } else { + chip->mask(irq); + chip->ack(irq); + } +} + +noop(irq) +{ +} + + </programlisting> + </para> + </sect3> + </sect2> + <sect2> + <title>Default flow handler implementations</title> + <sect3> + <title>Default Level IRQ flow handler</title> + <para> + handle_level_irq provides a generic implementation + for level-triggered interrupts. + </para> + <para> + The following control flow is implemented (simplified excerpt): + <programlisting> +desc->chip->start(); +handle_IRQ_event(desc->action); +desc->chip->end(); + </programlisting> + </para> + </sect3> + <sect3> + <title>Default Edge IRQ flow handler</title> + <para> + handle_edge_irq provides a generic implementation + for edge-triggered interrupts. + </para> + <para> + The following control flow is implemented (simplified excerpt): + <programlisting> +if (desc->status & running) { + desc->chip->hold(); + desc->status |= pending | masked; + return; +} +desc->chip->start(); +desc->status |= running; +do { + if (desc->status & masked) + desc->chip->enable(); + desc-status &= ~pending; + handle_IRQ_event(desc->action); +} while (status & pending); +desc-status &= ~running; +desc->chip->end(); + </programlisting> + </para> + </sect3> + <sect3> + <title>Default simple IRQ flow handler</title> + <para> + handle_simple_irq provides a generic implementation + for simple interrupts. + </para> + <para> + Note: The simple flow handler does not call any + handler/chip primitives. + </para> + <para> + The following control flow is implemented (simplified excerpt): + <programlisting> +handle_IRQ_event(desc->action); + </programlisting> + </para> + </sect3> + <sect3> + <title>Default per CPU flow handler</title> + <para> + handle_percpu_irq provides a generic implementation + for per CPU interrupts. + </para> + <para> + Per CPU interrupts are only available on SMP and + the handler provides a simplified version without + locking. + </para> + <para> + The following control flow is implemented (simplified excerpt): + <programlisting> +desc->chip->start(); +handle_IRQ_event(desc->action); +desc->chip->end(); + </programlisting> + </para> + </sect3> + </sect2> + <sect2> + <title>Quirks and optimizations</title> + <para> + The generic functions are intended for 'clean' architectures and chips, + which have no platform-specific IRQ handling quirks. If an architecture + needs to implement quirks on the 'flow' level then it can do so by + overriding the highlevel irq-flow handler. + </para> + </sect2> + <sect2> + <title>Delayed interrupt disable</title> + <para> + This per interrupt selectable feature, which was introduced by Russell + King in the ARM interrupt implementation, does not mask an interrupt + at the hardware level when disable_irq() is called. The interrupt is + kept enabled and is masked in the flow handler when an interrupt event + happens. This prevents losing edge interrupts on hardware which does + not store an edge interrupt event while the interrupt is disabled at + the hardware level. When an interrupt arrives while the IRQ_DISABLED + flag is set, then the interrupt is masked at the hardware level and + the IRQ_PENDING bit is set. When the interrupt is re-enabled by + enable_irq() the pending bit is checked and if it is set, the + interrupt is resent either via hardware or by a software resend + mechanism. (It's necessary to enable CONFIG_HARDIRQS_SW_RESEND when + you want to use the delayed interrupt disable feature and your + hardware is not capable of retriggering an interrupt.) + The delayed interrupt disable can be runtime enabled, per interrupt, + by setting the IRQ_DELAYED_DISABLE flag in the irq_desc status field. + </para> + </sect2> + </sect1> + <sect1> + <title>Chiplevel hardware encapsulation</title> + <para> + The chip level hardware descriptor structure irq_chip + contains all the direct chip relevant functions, which + can be utilized by the irq flow implementations. + <itemizedlist> + <listitem><para>ack()</para></listitem> + <listitem><para>mask_ack() - Optional, recommended for performance</para></listitem> + <listitem><para>mask()</para></listitem> + <listitem><para>unmask()</para></listitem> + <listitem><para>retrigger() - Optional</para></listitem> + <listitem><para>set_type() - Optional</para></listitem> + <listitem><para>set_wake() - Optional</para></listitem> + </itemizedlist> + These primitives are strictly intended to mean what they say: ack means + ACK, masking means masking of an IRQ line, etc. It is up to the flow + handler(s) to use these basic units of lowlevel functionality. + </para> + </sect1> + </chapter> + + <chapter id="doirq"> + <title>__do_IRQ entry point</title> + <para> + The original implementation __do_IRQ() is an alternative entry + point for all types of interrupts. + </para> + <para> + This handler turned out to be not suitable for all + interrupt hardware and was therefore reimplemented with split + functionality for egde/level/simple/percpu interrupts. This is not + only a functional optimization. It also shortens code paths for + interrupts. + </para> + <para> + To make use of the split implementation, replace the call to + __do_IRQ by a call to desc->chip->handle_irq() and associate + the appropriate handler function to desc->chip->handle_irq(). + In most cases the generic handler implementations should + be sufficient. + </para> + </chapter> + + <chapter id="locking"> + <title>Locking on SMP</title> + <para> + The locking of chip registers is up to the architecture that + defines the chip primitives. There is a chip->lock field that can be used + for serialization, but the generic layer does not touch it. The per-irq + structure is protected via desc->lock, by the generic layer. + </para> + </chapter> + <chapter id="structs"> + <title>Structures</title> + <para> + This chapter contains the autogenerated documentation of the structures which are + used in the generic IRQ layer. + </para> +!Iinclude/linux/irq.h + </chapter> + + <chapter id="pubfunctions"> + <title>Public Functions Provided</title> + <para> + This chapter contains the autogenerated documentation of the kernel API functions + which are exported. + </para> +!Ekernel/irq/manage.c +!Ekernel/irq/chip.c + </chapter> + + <chapter id="intfunctions"> + <title>Internal Functions Provided</title> + <para> + This chapter contains the autogenerated documentation of the internal functions. + </para> +!Ikernel/irq/handle.c +!Ikernel/irq/chip.c + </chapter> + + <chapter id="credits"> + <title>Credits</title> + <para> + The following people have contributed to this document: + <orderedlist> + <listitem><para>Thomas Gleixner<email>tglx@linutronix.de</email></para></listitem> + <listitem><para>Ingo Molnar<email>mingo@elte.hu</email></para></listitem> + </orderedlist> + </para> + </chapter> +</book> diff --git a/Documentation/IRQ.txt b/Documentation/IRQ.txt new file mode 100644 index 000000000000..1011e7175021 --- /dev/null +++ b/Documentation/IRQ.txt @@ -0,0 +1,22 @@ +What is an IRQ? + +An IRQ is an interrupt request from a device. +Currently they can come in over a pin, or over a packet. +Several devices may be connected to the same pin thus +sharing an IRQ. + +An IRQ number is a kernel identifier used to talk about a hardware +interrupt source. Typically this is an index into the global irq_desc +array, but except for what linux/interrupt.h implements the details +are architecture specific. + +An IRQ number is an enumeration of the possible interrupt sources on a +machine. Typically what is enumerated is the number of input pins on +all of the interrupt controller in the system. In the case of ISA +what is enumerated are the 16 input pins on the two i8259 interrupt +controllers. + +Architectures can assign additional meaning to the IRQ numbers, and +are encouraged to in the case where there is any manual configuration +of the hardware involved. The ISA IRQs are a classic example of +assigning this kind of additional meaning. diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 027285d0c26c..033ac91da07a 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -177,6 +177,16 @@ Who: Jean Delvare <khali@linux-fr.org> --------------------------- +What: Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports + (temporary transition config option provided until then) + The transition config option will also be removed at the same time. +When: before 2.6.19 +Why: Unused symbols are both increasing the size of the kernel binary + and are often a sign of "wrong API" +Who: Arjan van de Ven <arjan@linux.intel.com> + +--------------------------- + What: remove EXPORT_SYMBOL(tasklist_lock) When: August 2006 Files: kernel/fork.c diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 0d189c93eeaf..25f8d20dac53 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1689,9 +1689,14 @@ running once the system is up. decrease the size and leave more room for directly mapped kernel RAM. - vmhalt= [KNL,S390] + vmhalt= [KNL,S390] Perform z/VM CP command after system halt. + Format: <command> - vmpoff= [KNL,S390] + vmpanic= [KNL,S390] Perform z/VM CP command after kernel panic. + Format: <command> + + vmpoff= [KNL,S390] Perform z/VM CP command after power off. + Format: <command> waveartist= [HW,OSS] Format: <io>,<irq>,<dma>,<dma2> diff --git a/Documentation/keys-request-key.txt b/Documentation/keys-request-key.txt index 22488d791168..c1f64fdf84cb 100644 --- a/Documentation/keys-request-key.txt +++ b/Documentation/keys-request-key.txt @@ -3,16 +3,23 @@ =================== The key request service is part of the key retention service (refer to -Documentation/keys.txt). This document explains more fully how that the -requesting algorithm works. +Documentation/keys.txt). This document explains more fully how the requesting +algorithm works. The process starts by either the kernel requesting a service by calling -request_key(): +request_key*(): struct key *request_key(const struct key_type *type, const char *description, const char *callout_string); +or: + + struct key *request_key_with_auxdata(const struct key_type *type, + const char *description, + const char *callout_string, + void *aux); + Or by userspace invoking the request_key system call: key_serial_t request_key(const char *type, @@ -20,16 +27,26 @@ Or by userspace invoking the request_key system call: const char *callout_info, key_serial_t dest_keyring); -The main difference between the two access points is that the in-kernel -interface does not need to link the key to a keyring to prevent it from being -immediately destroyed. The kernel interface returns a pointer directly to the -key, and it's up to the caller to destroy the key. +The main difference between the access points is that the in-kernel interface +does not need to link the key to a keyring to prevent it from being immediately +destroyed. The kernel interface returns a pointer directly to the key, and +it's up to the caller to destroy the key. + +The request_key_with_auxdata() call is like the in-kernel request_key() call, +except that it permits auxiliary data to be passed to the upcaller (the default +is NULL). This is only useful for those key types that define their own upcall +mechanism rather than using /sbin/request-key. The userspace interface links the key to a keyring associated with the process to prevent the key from going away, and returns the serial number of the key to the caller. +The following example assumes that the key types involved don't define their +own upcall mechanisms. If they do, then those should be substituted for the +forking and execution of /sbin/request-key. + + =========== THE PROCESS =========== @@ -40,8 +57,8 @@ A request proceeds in the following manner: interface]. (2) request_key() searches the process's subscribed keyrings to see if there's - a suitable key there. If there is, it returns the key. If there isn't, and - callout_info is not set, an error is returned. Otherwise the process + a suitable key there. If there is, it returns the key. If there isn't, + and callout_info is not set, an error is returned. Otherwise the process proceeds to the next step. (3) request_key() sees that A doesn't have the desired key yet, so it creates @@ -62,7 +79,7 @@ A request proceeds in the following manner: instantiation. (7) The program may want to access another key from A's context (say a - Kerberos TGT key). It just requests the appropriate key, and the keyring + Kerberos TGT key). It just requests the appropriate key, and the keyring search notes that the session keyring has auth key V in its bottom level. This will permit it to then search the keyrings of process A with the @@ -79,10 +96,11 @@ A request proceeds in the following manner: (10) The program then exits 0 and request_key() deletes key V and returns key U to the caller. -This also extends further. If key W (step 7 above) didn't exist, key W would be -created uninstantiated, another auth key (X) would be created (as per step 3) -and another copy of /sbin/request-key spawned (as per step 4); but the context -specified by auth key X will still be process A, as it was in auth key V. +This also extends further. If key W (step 7 above) didn't exist, key W would +be created uninstantiated, another auth key (X) would be created (as per step +3) and another copy of /sbin/request-key spawned (as per step 4); but the +context specified by auth key X will still be process A, as it was in auth key +V. This is because process A's keyrings can't simply be attached to /sbin/request-key at the appropriate places because (a) execve will discard two @@ -118,17 +136,17 @@ A search of any particular keyring proceeds in the following fashion: (2) It considers all the non-keyring keys within that keyring and, if any key matches the criteria specified, calls key_permission(SEARCH) on it to see - if the key is allowed to be found. If it is, that key is returned; if + if the key is allowed to be found. If it is, that key is returned; if not, the search continues, and the error code is retained if of higher priority than the one currently set. (3) It then considers all the keyring-type keys in the keyring it's currently - searching. It calls key_permission(SEARCH) on each keyring, and if this + searching. It calls key_permission(SEARCH) on each keyring, and if this grants permission, it recurses, executing steps (2) and (3) on that keyring. The process stops immediately a valid key is found with permission granted to -use it. Any error from a previous match attempt is discarded and the key is +use it. Any error from a previous match attempt is discarded and the key is returned. When search_process_keyrings() is invoked, it performs the following searches @@ -153,7 +171,7 @@ The moment one succeeds, all pending errors are discarded and the found key is returned. Only if all these fail does the whole thing fail with the highest priority -error. Note that several errors may have come from LSM. +error. Note that several errors may have come from LSM. The error priority is: diff --git a/Documentation/keys.txt b/Documentation/keys.txt index 61c0fad2fe2f..e373f0212843 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt @@ -780,6 +780,17 @@ payload contents" for more information. See also Documentation/keys-request-key.txt. +(*) To search for a key, passing auxiliary data to the upcaller, call: + + struct key *request_key_with_auxdata(const struct key_type *type, + const char *description, + const char *callout_string, + void *aux); + + This is identical to request_key(), except that the auxiliary data is + passed to the key_type->request_key() op if it exists. + + (*) When it is no longer required, the key should be released using: void key_put(struct key *key); @@ -1031,6 +1042,24 @@ The structure has a number of fields, some of which are mandatory: as might happen when the userspace buffer is accessed. + (*) int (*request_key)(struct key *key, struct key *authkey, const char *op, + void *aux); + + This method is optional. If provided, request_key() and + request_key_with_auxdata() will invoke this function rather than + upcalling to /sbin/request-key to operate upon a key of this type. + + The aux parameter is as passed to request_key_with_auxdata() or is NULL + otherwise. Also passed are the key to be operated upon, the + authorisation key for this operation and the operation type (currently + only "create"). + + This function should return only when the upcall is complete. Upon return + the authorisation key will be revoked, and the target key will be + negatively instantiated if it is still uninstantiated. The error will be + returned to the caller of request_key*(). + + ============================ REQUEST-KEY CALLBACK SERVICE ============================ diff --git a/Documentation/watchdog/pcwd-watchdog.txt b/Documentation/watchdog/pcwd-watchdog.txt index 12187a33e310..d9ee6336c1d4 100644 --- a/Documentation/watchdog/pcwd-watchdog.txt +++ b/Documentation/watchdog/pcwd-watchdog.txt @@ -22,78 +22,9 @@ to run the program with an "&" to run it in the background!) If you want to write a program to be compatible with the PC Watchdog - driver, simply do the following: - --- Snippet of code -- -/* - * Watchdog Driver Test Program - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <linux/types.h> -#include <linux/watchdog.h> - -int fd; - -/* - * This function simply sends an IOCTL to the driver, which in turn ticks - * the PC Watchdog card to reset its internal timer so it doesn't trigger - * a computer reset. - */ -void keep_alive(void) -{ - int dummy; - - ioctl(fd, WDIOC_KEEPALIVE, &dummy); -} - -/* - * The main program. Run the program with "-d" to disable the card, - * or "-e" to enable the card. - */ -int main(int argc, char *argv[]) -{ - fd = open("/dev/watchdog", O_WRONLY); - - if (fd == -1) { - fprintf(stderr, "Watchdog device not enabled.\n"); - fflush(stderr); - exit(-1); - } - - if (argc > 1) { - if (!strncasecmp(argv[1], "-d", 2)) { - ioctl(fd, WDIOC_SETOPTIONS, WDIOS_DISABLECARD); - fprintf(stderr, "Watchdog card disabled.\n"); - fflush(stderr); - exit(0); - } else if (!strncasecmp(argv[1], "-e", 2)) { - ioctl(fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD); - fprintf(stderr, "Watchdog card enabled.\n"); - fflush(stderr); - exit(0); - } else { - fprintf(stderr, "-d to disable, -e to enable.\n"); - fprintf(stderr, "run by itself to tick the card.\n"); - fflush(stderr); - exit(0); - } - } else { - fprintf(stderr, "Watchdog Ticking Away!\n"); - fflush(stderr); - } - - while(1) { - keep_alive(); - sleep(1); - } -} --- End snippet -- + driver, simply use of modify the watchdog test program: + Documentation/watchdog/src/watchdog-test.c + Other IOCTL functions include: diff --git a/Documentation/watchdog/src/watchdog-simple.c b/Documentation/watchdog/src/watchdog-simple.c new file mode 100644 index 000000000000..85cf17c48669 --- /dev/null +++ b/Documentation/watchdog/src/watchdog-simple.c @@ -0,0 +1,15 @@ +#include <stdlib.h> +#include <fcntl.h> + +int main(int argc, const char *argv[]) { + int fd = open("/dev/watchdog", O_WRONLY); + if (fd == -1) { + perror("watchdog"); + exit(1); + } + while (1) { + write(fd, "\0", 1); + fsync(fd); + sleep(10); + } +} diff --git a/Documentation/watchdog/src/watchdog-test.c b/Documentation/watchdog/src/watchdog-test.c new file mode 100644 index 000000000000..65f6c19cb865 --- /dev/null +++ b/Documentation/watchdog/src/watchdog-test.c @@ -0,0 +1,68 @@ +/* + * Watchdog Driver Test Program + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/types.h> +#include <linux/watchdog.h> + +int fd; + +/* + * This function simply sends an IOCTL to the driver, which in turn ticks + * the PC Watchdog card to reset its internal timer so it doesn't trigger + * a computer reset. + */ +void keep_alive(void) +{ + int dummy; + + ioctl(fd, WDIOC_KEEPALIVE, &dummy); +} + +/* + * The main program. Run the program with "-d" to disable the card, + * or "-e" to enable the card. + */ +int main(int argc, char *argv[]) +{ + fd = open("/dev/watchdog", O_WRONLY); + + if (fd == -1) { + fprintf(stderr, "Watchdog device not enabled.\n"); + fflush(stderr); + exit(-1); + } + + if (argc > 1) { + if (!strncasecmp(argv[1], "-d", 2)) { + ioctl(fd, WDIOC_SETOPTIONS, WDIOS_DISABLECARD); + fprintf(stderr, "Watchdog card disabled.\n"); + fflush(stderr); + exit(0); + } else if (!strncasecmp(argv[1], "-e", 2)) { + ioctl(fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD); + fprintf(stderr, "Watchdog card enabled.\n"); + fflush(stderr); + exit(0); + } else { + fprintf(stderr, "-d to disable, -e to enable.\n"); + fprintf(stderr, "run by itself to tick the card.\n"); + fflush(stderr); + exit(0); + } + } else { + fprintf(stderr, "Watchdog Ticking Away!\n"); + fflush(stderr); + } + + while(1) { + keep_alive(); + sleep(1); + } +} diff --git a/Documentation/watchdog/watchdog-api.txt b/Documentation/watchdog/watchdog-api.txt index 21ed51173662..958ff3d48be3 100644 --- a/Documentation/watchdog/watchdog-api.txt +++ b/Documentation/watchdog/watchdog-api.txt @@ -34,22 +34,7 @@ activates as soon as /dev/watchdog is opened and will reboot unless the watchdog is pinged within a certain time, this time is called the timeout or margin. The simplest way to ping the watchdog is to write some data to the device. So a very simple watchdog daemon would look -like this: - -#include <stdlib.h> -#include <fcntl.h> - -int main(int argc, const char *argv[]) { - int fd=open("/dev/watchdog",O_WRONLY); - if (fd==-1) { - perror("watchdog"); - exit(1); - } - while(1) { - write(fd, "\0", 1); - sleep(10); - } -} +like this source file: see Documentation/watchdog/src/watchdog-simple.c A more advanced driver could for example check that a HTTP server is still responding before doing the write call to ping the watchdog. @@ -110,7 +95,40 @@ current timeout using the GETTIMEOUT ioctl. ioctl(fd, WDIOC_GETTIMEOUT, &timeout); printf("The timeout was is %d seconds\n", timeout); -Envinronmental monitoring: +Pretimeouts: + +Some watchdog timers can be set to have a trigger go off before the +actual time they will reset the system. This can be done with an NMI, +interrupt, or other mechanism. This allows Linux to record useful +information (like panic information and kernel coredumps) before it +resets. + + pretimeout = 10; + ioctl(fd, WDIOC_SETPRETIMEOUT, &pretimeout); + +Note that the pretimeout is the number of seconds before the time +when the timeout will go off. It is not the number of seconds until +the pretimeout. So, for instance, if you set the timeout to 60 seconds +and the pretimeout to 10 seconds, the pretimout will go of in 50 +seconds. Setting a pretimeout to zero disables it. + +There is also a get function for getting the pretimeout: + + ioctl(fd, WDIOC_GETPRETIMEOUT, &timeout); + printf("The pretimeout was is %d seconds\n", timeout); + +Not all watchdog drivers will support a pretimeout. + +Get the number of seconds before reboot: + +Some watchdog drivers have the ability to report the remaining time +before the system will reboot. The WDIOC_GETTIMELEFT is the ioctl +that returns the number of seconds before reboot. + + ioctl(fd, WDIOC_GETTIMELEFT, &timeleft); + printf("The timeout was is %d seconds\n", timeleft); + +Environmental monitoring: All watchdog drivers are required return more information about the system, some do temperature, fan and power level monitoring, some can tell you @@ -169,6 +187,10 @@ The watchdog saw a keepalive ping since it was last queried. WDIOF_SETTIMEOUT Can set/get the timeout +The watchdog can do pretimeouts. + + WDIOF_PRETIMEOUT Pretimeout (in seconds), get/set + For those drivers that return any bits set in the option field, the GETSTATUS and GETBOOTSTATUS ioctls can be used to ask for the current diff --git a/Documentation/watchdog/watchdog.txt b/Documentation/watchdog/watchdog.txt index dffda29c8799..4b1ff69cc19a 100644 --- a/Documentation/watchdog/watchdog.txt +++ b/Documentation/watchdog/watchdog.txt @@ -65,28 +65,7 @@ The external event interfaces on the WDT boards are not currently supported. Minor numbers are however allocated for it. -Example Watchdog Driver ------------------------ - -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> - -int main(int argc, const char *argv[]) -{ - int fd=open("/dev/watchdog",O_WRONLY); - if(fd==-1) - { - perror("watchdog"); - exit(1); - } - while(1) - { - write(fd,"\0",1); - fsync(fd); - sleep(10); - } -} +Example Watchdog Driver: see Documentation/watchdog/src/watchdog-simple.c Contact Information |