2.6.13-rc5-mm1, remove uneeded function
Subsystems (3)
cover 2.6.13-rc5-mm1, remove uneeded function
After elimination of central DMI blacklist dmi_scan_machine() function became a wrapper for dmi_iterate(). This patch moves some code around to kill unneeded function.
arch/i386/kernel/dmi_scan.c | 85 ++++++++++++++++++++------------------------ 1 files changed, 40 insertions(+), 45 deletions(-)
arch/i386/kernel/dmi_scan.c +40 -45
@@ -84,49 +84,6 @@ static int __init dmi_checksum(u8 *buf)return sum ==0 ; } -static int __init dmi_iterate (void (*decode)(struct dmi_header *)) -{ -u8 buf[15 ]; -char __iomem *p, *q; - -/* -* no iounmap() for that ioremap(); it would be a no-op, but it's -* so early in setup that sucker gets confused into doing what -* it shouldn't if we actually call it. -*/ - p =ioremap (0xF0000 ,0x10000 ); -if (p ==NULL ) -return -1 ; - -for (q = p; q < p +0x10000 ; q +=16 ) { -memcpy_fromio (buf, q,15 ); -if ((memcmp (buf,"_DMI_" ,5 ) ==0 ) &&dmi_checksum (buf)) { -u16 num = (buf[13 ] <<8 ) | buf[12 ]; -u16 len = (buf[7 ] <<8 ) | buf[6 ]; -u32 base = (buf[11 ] <<24 ) | (buf[10 ] <<16 ) | - (buf[9 ] <<8 ) | buf[8 ]; - -/* -* DMI version 0.0 means that the real version is taken from -* the SMBIOS version, which we don't know at this point. -*/ -if (buf[14 ] !=0 ) -printk (KERN_INFO "DMI %d.%d present.\n" , - buf[14 ] >>4 , buf[14 ] &0xF ); -else -printk (KERN_INFO "DMI present.\n" ); - -dmi_printk ((KERN_INFO "%d structures occupying %d bytes.\n" , - num, len)); -dmi_printk ((KERN_INFO "DMI table at 0x%08X.\n" , base)); - -if (dmi_table (base,len, num, decode) ==0 ) -return 0 ; - } - } -return -1 ; -} -static char *dmi_ident[DMI_STRING_MAX ];/*
@@ -190,8 +147,46 @@ static void __init dmi_decode(struct dmivoid __init dmi_scan_machine (void ) { -if (dmi_iterate (dmi_decode)) -printk (KERN_INFO "DMI not present.\n" ); +u8 buf[15 ]; +char __iomem *p, *q; + +/* +* no iounmap() for that ioremap(); it would be a no-op, but it's +* so early in setup that sucker gets confused into doing what +* it shouldn't if we actually call it. +*/ + p =ioremap (0xF0000 ,0x10000 ); +if (p ==NULL ) + goto out; + +for (q = p; q < p +0x10000 ; q +=16 ) { +memcpy_fromio (buf, q,15 ); +if ((memcmp (buf,"_DMI_" ,5 ) ==0 ) &&dmi_checksum (buf)) { +u16 num = (buf[13 ] <<8 ) | buf[12 ]; +u16 len = (buf[7 ] <<8 ) | buf[6 ]; +u32 base = (buf[11 ] <<24 ) | (buf[10 ] <<16 ) | + (buf[9 ] <<8 ) | buf[8 ]; + +/* +* DMI version 0.0 means that the real version is taken from +* the SMBIOS version, which we don't know at this point. +*/ +if (buf[14 ] !=0 ) +printk (KERN_INFO "DMI %d.%d present.\n" , + buf[14 ] >>4 , buf[14 ] &0xF ); +else +printk (KERN_INFO "DMI present.\n" ); + +dmi_printk ((KERN_INFO "%d structures occupying %d bytes.\n" , + num, len)); +dmi_printk ((KERN_INFO "DMI table at 0x%08X.\n" , base)); + +if (dmi_table (base,len, num, dmi_decode) ==0 ) +return ; + } + } + +out:printk (KERN_INFO "DMI not present.\n" ); }
PATCH 1/5 2.6.13-rc5-mm1, remove old debugging code
DMI debugging code is unused for ages. This patch removes it.
arch/i386/kernel/dmi_scan.c | 21 --------------------- 1 files changed, 21 deletions(-)
arch/i386/kernel/dmi_scan.c +0 -21
@@ -12,13 +12,6 @@ struct dmi_header {u16 handle; }; -#undef DMI_DEBUG - -#ifdef DMI_DEBUG -#define dmi_printk (x) printk x -#else -#define dmi_printk (x) -#endif static char *__init dmi_string (struct dmi_header *dm,u8 s) {
@@ -117,29 +110,19 @@ static void __init dmi_decode(struct dmiswitch (dm->type) {case 0 : -dmi_printk (("BIOS Vendor: %s\n" ,dmi_string (dm, data[4 ])));dmi_save_ident (dm,DMI_BIOS_VENDOR ,4 ); -dmi_printk (("BIOS Version: %s\n" ,dmi_string (dm, data[5 ])));dmi_save_ident (dm,DMI_BIOS_VERSION ,5 ); -dmi_printk (("BIOS Release: %s\n" ,dmi_string (dm, data[8 ])));dmi_save_ident (dm,DMI_BIOS_DATE ,8 );break ;case 1 : -dmi_printk (("System Vendor: %s\n" ,dmi_string (dm, data[4 ])));dmi_save_ident (dm,DMI_SYS_VENDOR ,4 ); -dmi_printk (("Product Name: %s\n" ,dmi_string (dm, data[5 ])));dmi_save_ident (dm,DMI_PRODUCT_NAME ,5 ); -dmi_printk (("Version: %s\n" ,dmi_string (dm, data[6 ])));dmi_save_ident (dm,DMI_PRODUCT_VERSION ,6 ); -dmi_printk (("Serial Number: %s\n" ,dmi_string (dm, data[7 ])));dmi_save_ident (dm,DMI_PRODUCT_SERIAL ,7 );break ;case 2 : -dmi_printk (("Board Vendor: %s\n" ,dmi_string (dm, data[4 ])));dmi_save_ident (dm,DMI_BOARD_VENDOR ,4 ); -dmi_printk (("Board Name: %s\n" ,dmi_string (dm, data[5 ])));dmi_save_ident (dm,DMI_BOARD_NAME ,5 ); -dmi_printk (("Board Version: %s\n" ,dmi_string (dm, data[6 ])));dmi_save_ident (dm,DMI_BOARD_VERSION ,6 );break ; }
@@ -177,10 +160,6 @@ void __init dmi_scan_machine(void)else printk (KERN_INFO "DMI present.\n" ); -dmi_printk ((KERN_INFO "%d structures occupying %d bytes.\n" , - num, len)); -dmi_printk ((KERN_INFO "DMI table at 0x%08X.\n" , base)); -if (dmi_table (base,len, num, dmi_decode) ==0 )return ; }
PATCH 2/5 2.6.13-rc5-mm1, make dmi_string() behave like strdup()
This patch changes dmi_string() function to allocate string copy by itself, to avoid code duplication in the next patch.
arch/i386/kernel/dmi_scan.c | 39 +++++++++++++++++++++++---------------- 1 files changed, 23 insertions(+), 16 deletions(-)
arch/i386/kernel/dmi_scan.c +23 -16
@@ -16,15 +16,25 @@ struct dmi_header {static char *__init dmi_string (struct dmi_header *dm,u8 s) {u8 *bp = ((u8 *) dm) + dm->length; +char *str ="" ; -if (!s) -return "" ; - s--; -while (s >0 && *bp) { - bp +=strlen (bp) +1 ; +if (s) { s--; - } -return bp; +while (s >0 && *bp) { + bp +=strlen (bp) +1 ; + s--; + } + +if (*bp !=0 ) { + str =alloc_bootmem (strlen (bp) +1 ); +if (str !=NULL ) +strcpy (str, bp); +else +printk (KERN_ERR "dmi_string: out of memory.\n" ); + } + } + +return str; }/*
@@ -84,19 +94,16 @@ static char *dmi_ident[DMI_STRING_MAX];*/ static void __init dmi_save_ident (struct dmi_header *dm,int slot,int string) { -char *d = (char *)dm; -char *p =dmi_string (dm, d[string]); +char *p, *d = (char *) dm; -if (p ==NULL || *p ==0 ) -return ;if (dmi_ident[slot])return ; - dmi_ident[slot] =alloc_bootmem (strlen (p) +1 ); -if (dmi_ident[slot]) -strcpy (dmi_ident[slot], p); -else -printk (KERN_ERR "dmi_save_ident: out of memory.\n" ); + p =dmi_string (dm, d[string]); +if (p ==NULL ) +return ; + + dmi_ident[slot] = p; }/*
PATCH 3/5 2.6.13-rc5-mm1, add onboard devices discovery
This patch adds onboard devices and IPMI BMC discovery into DMI scan code. Drivers can use dmi_find_device() function to search for devices by type and name.
arch/i386/kernel/dmi_scan.c | 102 ++++++++++++++++++++++++++++++++++++++------ include/linux/dmi.h | 34 +++++++++++++- 2 files changed, 121 insertions(+), 15 deletions(-)
arch/i386/kernel/dmi_scan.c +90 -12
@@ -6,13 +6,6 @@#include <linux/bootmem.h> -struct dmi_header { -u8 type; -u8 length; -u16 handle; -}; - -static char *__init dmi_string (struct dmi_header *dm,u8 s) {u8 *bp = ((u8 *) dm) + dm->length;
@@ -88,6 +81,7 @@ static int __init dmi_checksum(u8 *buf) }static char *dmi_ident[DMI_STRING_MAX ]; +static LIST_HEAD (dmi_devices);/* * Save a DMI string
@@ -106,6 +100,58 @@ static void __init dmi_save_ident(struct dmi_ident[slot] = p; } +static void __init dmi_save_devices (struct dmi_header *dm) +{ +int i, count = (dm->length -sizeof (struct dmi_header )) /2 ; +struct dmi_device *dev; + +for (i =0 ; i < count; i++) { +char *d = ((char *) dm) + (i *2 ); + +/* Skip disabled device */ +if ((*d &0x80 ) ==0 ) +continue ; + + dev =alloc_bootmem (sizeof (*dev)); +if (!dev) { +printk (KERN_ERR "dmi_save_devices: out of memory.\n" ); +break ; + } + + dev->type = *d++ &0x7f ; + dev->name =dmi_string (dm, *d); + dev->device_data =NULL ; + +list_add (&dev->list, &dmi_devices); + } +} + +static void __init dmi_save_ipmi_device (struct dmi_header *dm) +{ +struct dmi_device *dev; +void * data; + + data =alloc_bootmem (dm->length); +if (data ==NULL ) { +printk (KERN_ERR "dmi_save_ipmi_device: out of memory.\n" ); +return ; + } + +memcpy (data, dm, dm->length); + + dev =alloc_bootmem (sizeof (*dev)); +if (!dev) { +printk (KERN_ERR "dmi_save_ipmi_device: out of memory.\n" ); +return ; + } + + dev->type =DMI_DEV_TYPE_IPMI ; + dev->name ="IPMI controller" ; + dev->device_data = data; + +list_add (&dev->list, &dmi_devices); +} +/* * Process a DMI table entry. Right now all we care about are the BIOS * and machine entries. For 2.5 we should pull the smbus controller info
@@ -113,25 +159,28 @@ static void __init dmi_save_ident(struct*/ static void __init dmi_decode (struct dmi_header *dm) { - u8 *data __attribute__((__unused__)) = (u8 *)dm; -switch (dm->type) { -case 0 : +case 0 :/* BIOS Information */ dmi_save_ident (dm,DMI_BIOS_VENDOR ,4 );dmi_save_ident (dm,DMI_BIOS_VERSION ,5 );dmi_save_ident (dm,DMI_BIOS_DATE ,8 );break ; -case 1 : +case 1 :/* System Information */ dmi_save_ident (dm,DMI_SYS_VENDOR ,4 );dmi_save_ident (dm,DMI_PRODUCT_NAME ,5 );dmi_save_ident (dm,DMI_PRODUCT_VERSION ,6 );dmi_save_ident (dm,DMI_PRODUCT_SERIAL ,7 );break ; -case 2 : +case 2 :/* Base Board Information */ dmi_save_ident (dm,DMI_BOARD_VENDOR ,4 );dmi_save_ident (dm,DMI_BOARD_NAME ,5 );dmi_save_ident (dm,DMI_BOARD_VERSION ,6 );break ; +case 10 :/* Onboard Devices Information */ +dmi_save_devices (dm); +break ; +case 38 :/* IPMI Device Information */ +dmi_save_ipmi_device (dm); } }
@@ -221,3 +270,32 @@ char *dmi_get_system_info(int field)return dmi_ident[field]; }EXPORT_SYMBOL (dmi_get_system_info); + +/** +* dmi_find_device - find onboard device by type/name +* @type: device type or %DMI_DEV_TYPE_ANY to match all device types +* @desc: device name string or %NULL to match all +* @from: previous device found in search, or %NULL for new search. +* +* Iterates through the list of known onboard devices. If a device is +* found with a matching @vendor and @device, a pointer to its device +* structure is returned. Otherwise, %NULL is returned. +* A new search is initiated by passing %NULL to the @from argument. +* If @from is not %NULL, searches continue from next device. +*/ +struct dmi_device *dmi_find_device (int type,const char *name, +struct dmi_device *from) +{ +struct list_head *d, *head = from ? &from->list : &dmi_devices; + +for (d = head->next; d != &dmi_devices; d = d->next) { + struct dmi_device *dev = list_entry(d, struct dmi_device, list); + +if (((type ==DMI_DEV_TYPE_ANY ) || (dev->type == type)) && + ((name ==NULL ) || (strcmp (dev->name, name) ==0 ))) +return dev; + } + +return NULL ; +} +EXPORT_SYMBOL (dmi_find_device);
include/linux/dmi.h +31 -3
@@ -16,6 +16,24 @@ enum dmi_field { DMI_STRING_MAX, }; +enum dmi_device_type { +DMI_DEV_TYPE_ANY =0 , +DMI_DEV_TYPE_OTHER , +DMI_DEV_TYPE_UNKNOWN , +DMI_DEV_TYPE_VIDEO , +DMI_DEV_TYPE_SCSI , +DMI_DEV_TYPE_ETHERNET , +DMI_DEV_TYPE_TOKENRING , +DMI_DEV_TYPE_SOUND , +DMI_DEV_TYPE_IPMI =-1 +}; + +struct dmi_header { +u8 type; +u8 length; +u16 handle; +}; +/* * DMI callbacks for problem boards */
@@ -26,22 +44,32 @@ struct dmi_strmatch {struct dmi_system_id {int (*callback)(struct dmi_system_id *); -char *ident; +const char *ident;struct dmi_strmatch matches[4 ];void *driver_data; }; -#define DMI_MATCH (a,b) { a, b } +#define DMI_MATCH (a, b) { a, b } + +struct dmi_device { +struct list_head list; +int type; +const char *name; +void *device_data;/* Type specific data */ +};#if defined(CONFIG_X86 ) && !defined(CONFIG_X86_64 )extern int dmi_check_system (struct dmi_system_id *list);extern char *dmi_get_system_info (int field); - +extern struct dmi_device *dmi_find_device (int type,const char *name, +struct dmi_device *from);#else static inline int dmi_check_system (struct dmi_system_id *list) {return 0 ; }static inline char *dmi_get_system_info (int field) {return NULL ; } +static struct dmi_device *dmi_find_device (int type,const char *name, +struct dmi_device *from) {return NULL ; }#endif
PATCH 4/5 2.6.13-rc5-mm1, IPMI, use dmi_find_device()
This patch replaces homebrew DMI scanning code in IPMI System Interface driver with dmi_find_device() call.
drivers/char/ipmi/ipmi_si_intf.c | 105 ++++++--------------------------------- 1 files changed, 17 insertions(+), 88 deletions(-)
drivers/char/ipmi/ipmi_si_intf.c +17 -88
@@ -75,6 +75,7 @@ static inline void add_usec_to_timer(str#include <asm/io.h> #include "ipmi_si_sm.h" #include <linux/init.h> +#include <linux/dmi.h> /* Measure times between events in the driver. */ #undef DEBUG_TIMING
@@ -1642,22 +1643,15 @@ typedef struct dmi_ipmi_datastatic dmi_ipmi_data_t dmi_data[SI_MAX_DRIVERS ];static int dmi_data_entries; -typedef struct dmi_header -{ -u8 type; -u8 length; -u16 handle; -}dmi_header_t ; - -static int decode_dmi (dmi_header_t __iomem *dm,int intf_num) +static int __init decode_dmi (struct dmi_header *dm,int intf_num) { -u8 __iomem *data = (u8 __iomem *)dm; +u8 *data = (u8 *)dm;unsigned long base_addr;u8 reg_spacing; -u8 len =readb (&dm->length); +u8 len = dm->length;dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num; - ipmi_data->type =readb (&data[4 ]); + ipmi_data->type = data[4 ];memcpy (&base_addr, data+8 ,sizeof (unsigned long ));if (len >=0x11 ) {
@@ -1672,12 +1666,12 @@ static int decode_dmi(dmi_header_t __iom }/* If bit 4 of byte 0x10 is set, then the lsb for the address is odd. */ - ipmi_data->base_addr = base_addr | ((readb (&data[0x10 ]) &0x10 ) >>4 ); + ipmi_data->base_addr = base_addr | ((data[0x10 ] &0x10 ) >>4 ); - ipmi_data->irq =readb (&data[0x11 ]); + ipmi_data->irq = data[0x11 ];/* The top two bits of byte 0x10 hold the register spacing. */ - reg_spacing = (readb (&data[0x10 ]) &0xC0 ) >>6 ; + reg_spacing = (data[0x10 ] &0xC0 ) >>6 ;switch (reg_spacing){case 0x00 :/* Byte boundaries */ ipmi_data->offset =1 ;
@@ -1705,7 +1699,7 @@ static int decode_dmi(dmi_header_t __iom ipmi_data->offset =1 ; } - ipmi_data->slave_addr =readb (&data[6 ]); + ipmi_data->slave_addr = data[6 ];if (is_new_interface (-1 , ipmi_data->addr_space,ipmi_data->base_addr)) { dmi_data_entries++;
@@ -1717,82 +1711,17 @@ static int decode_dmi(dmi_header_t __iomreturn -1 ; } -static int dmi_table (u32 base,int len,int num) -{ -u8 __iomem *buf; -struct dmi_header __iomem *dm; -u8 __iomem *data; -int i=1 ; -int status=-1 ; -int intf_num =0 ; - - buf =ioremap (base, len); -if (buf==NULL ) -return -1 ; - - data = buf; - -while (i<num && (data - buf) < len) - { - dm=(dmi_header_t __iomem *)data; - -if ((data-buf+readb (&dm->length)) >= len) -break ; - -if (readb (&dm->type) ==38 ) { -if (decode_dmi (dm, intf_num) ==0 ) { - intf_num++; -if (intf_num >=SI_MAX_DRIVERS ) -break ; - } - } - - data+=readb (&dm->length); -while ((data-buf) < len && (readb (data)||readb (data+1 ))) - data++; - data+=2 ; - i++; - } -iounmap (buf); - -return status; -} - -static inline int dmi_checksum (u8 *buf) -{ -u8 sum=0 ; -int a; - -for (a=0 ; a<15 ; a++) - sum+=buf[a]; -return (sum==0 ); -} - -static int dmi_decode (void ) +static void __init dmi_find_bmc (void ) { -u8 buf[15 ]; -u32 fp=0xF0000 ; - -#ifdef CONFIG_SIMNOW -return -1 ; -#endif +struct dmi_device *dev =NULL ; +int intf_num =0 ; -while (fp <0xFFFFF ) - { -isa_memcpy_fromio (buf, fp,15 ); -if (memcmp (buf,"_DMI_" ,5 )==0 &&dmi_checksum (buf)) - { -u16 num=buf[13 ]<<8 |buf[12 ]; -u16 len=buf[7 ]<<8 |buf[6 ]; -u32 base=buf[11 ]<<24 |buf[10 ]<<16 |buf[9 ]<<8 |buf[8 ]; +while ((dev =dmi_find_device (DMI_DEV_TYPE_IPMI ,NULL , dev))) { +if (intf_num >=SI_MAX_DRIVERS ) +break ; -if (dmi_table (base, len, num) ==0 ) -return 0 ; - } - fp+=16 ; +decode_dmi ((struct dmi_header *) dev->device_data, intf_num++); } - -return -1 ; }static int try_init_smbios (int intf_num,struct smi_info **new_info)
@@ -2382,7 +2311,7 @@ static __init int init_ipmi_si(void)printk (KERN_INFO "IPMI System Interface driver.\n" );#ifdef CONFIG_X86 -dmi_decode (); +dmi_find_bmc ();#endif rv =init_one_smi (0 , &(smi_infos[pos]));
PATCH 5/5 2.6.13-rc5-mm1, driver for IBM Automatic Server Restart watchdog
This patch adds driver for IBM Automatic Server Restart watchdog hardware found in some IBM eServer xSeries machines. This driver is based on the ugly driver provided by IBM. Driver was tested on IBM eServer 226.
drivers/char/watchdog/Kconfig | 10 + drivers/char/watchdog/Makefile | 1 drivers/char/watchdog/ibmasr.c | 407 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 418 insertions(+)
drivers/char/watchdog/ibmasr.c +407 -0
@@ -0,0 +1,407 @@ +/* +* IBM Automatic Server Restart driver. +* +* Copyright (c) 2005 Andrey Panin <[email protected]> +* +* Based on driver written by Pete Reynolds. +* Copyright (c) IBM Corporation, 1998-2004. +* +* This software may be used and distributed according to the terms +* of the GNU Public License, incorporated herein by reference. +*/ + +#include <linux/config.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/timer.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/dmi.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + + +enum { +ASMTYPE_UNKNOWN , +ASMTYPE_TOPAZ , +ASMTYPE_JASPER , +ASMTYPE_PEARL , +ASMTYPE_JUNIPER , +ASMTYPE_SPRUCE , +}; + +#define PFX "ibmasr: " + +#define TOPAZ_ASR_REG_OFFSET 4 +#define TOPAZ_ASR_TOGGLE 0x40 +#define TOPAZ_ASR_DISABLE 0x80 + +/* PEARL ASR S/W REGISTER SUPERIO PORT ADDRESSES */ +#define PEARL_BASE 0xe04 +#define PEARL_WRITE 0xe06 +#define PEARL_READ 0xe07 + +#define PEARL_ASR_DISABLE_MASK 0x80/* bit 7: disable = 1, enable = 0 */ +#define PEARL_ASR_TOGGLE_MASK 0x40/* bit 6: 0, then 1, then 0 */ + +/* JASPER OFFSET FROM SIO BASE ADDR TO ASR S/W REGISTERS. */ +#define JASPER_ASR_REG_OFFSET 0x38 + +#define JASPER_ASR_DISABLE_MASK 0x01/* bit 0: disable = 1, enable = 0 */ +#define JASPER_ASR_TOGGLE_MASK 0x02/* bit 1: 0, then 1, then 0 */ + +#define JUNIPER_BASE_ADDRESS 0x54b/* Base address of Juniper ASR */ +#define JUNIPER_ASR_DISABLE_MASK 0x01/* bit 0: disable = 1 enable = 0 */ +#define JUNIPER_ASR_TOGGLE_MASK 0x02/* bit 1: 0, then 1, then 0 */ + +#define SPRUCE_BASE_ADDRESS 0x118e/* Base address of Spruce ASR */ +#define SPRUCE_ASR_DISABLE_MASK 0x01/* bit 1: disable = 1 enable = 0 */ +#define SPRUCE_ASR_TOGGLE_MASK 0x02/* bit 0: 0, then 1, then 0 */ + + +static int nowayout =WATCHDOG_NOWAYOUT ; + +static unsigned long asr_is_open; +static char asr_expect_close; + +static unsigned int asr_type, asr_base, asr_length; +static unsigned int asr_read_addr, asr_write_addr; +static unsigned char asr_toggle_mask, asr_disable_mask; + +static void asr_toggle (void ) +{ +unsigned char reg =inb (asr_read_addr); + +outb (reg & ~asr_toggle_mask, asr_write_addr); + reg =inb (asr_read_addr); + +outb (reg | asr_toggle_mask, asr_write_addr); + reg =inb (asr_read_addr); + +outb (reg & ~asr_toggle_mask, asr_write_addr); + reg =inb (asr_read_addr); +} + +static void asr_enable (void ) +{ +unsigned char reg; + +if (asr_type ==ASMTYPE_TOPAZ ) { +/* asr_write_addr == asr_read_addr */ + reg =inb (asr_read_addr); +outb (reg & ~(TOPAZ_ASR_TOGGLE |TOPAZ_ASR_DISABLE ), + asr_read_addr); + }else { +/* +* First make sure the hardware timer is reset by toggling +* ASR hardware timer line. +*/ +asr_toggle (); + + reg =inb (asr_read_addr); +outb (reg & ~asr_disable_mask, asr_write_addr); + } + reg =inb (asr_read_addr); +} + +static void asr_disable (void ) +{ +unsigned char reg =inb (asr_read_addr); + +if (asr_type ==ASMTYPE_TOPAZ ) +/* asr_write_addr == asr_read_addr */ +outb (reg |TOPAZ_ASR_TOGGLE |TOPAZ_ASR_DISABLE , + asr_read_addr); +else { +outb (reg | asr_toggle_mask, asr_write_addr); + reg =inb (asr_read_addr); + +outb (reg | asr_disable_mask, asr_write_addr); + } + reg =inb (asr_read_addr); +} + +static int __init asr_get_base_address (void ) +{ +unsigned char low, high; +const char *type ="" ; + + asr_length =1 ; + +switch (asr_type) { +case ASMTYPE_TOPAZ : +/* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */ +outb (0x07 ,0x2e ); +outb (0x07 ,0x2f ); + +/* SELECT AND READ THE HIGH-NIBBLE OF THE GPIO BASE ADDRESS */ +outb (0x60 ,0x2e ); + high =inb (0x2f ); + +/* SELECT AND READ THE LOW-NIBBLE OF THE GPIO BASE ADDRESS */ +outb (0x61 ,0x2e ); + low =inb (0x2f ); + + asr_base = (high <<16 ) | low; + asr_read_addr = asr_write_addr = + asr_base +TOPAZ_ASR_REG_OFFSET ; + asr_length =5 ; + +break ; + +case ASMTYPE_JASPER : + type ="Jaspers " ; + +/* FIXME: need to use pci_config_lock here, but it's not exported */ + +/* spin_lock_irqsave(&pci_config_lock, flags);*/ + +/* Select the SuperIO chip in the PCI I/O port register */ +outl (0x8000f858 ,0xcf8 ); + +/* +* Read the base address for the SuperIO chip. +* Only the lower 16 bits are valid, but the address is word +* aligned so the last bit must be masked off. +*/ + asr_base =inl (0xcfc ) &0xfffe ; + +/* spin_unlock_irqrestore(&pci_config_lock, flags);*/ + + asr_read_addr = asr_write_addr = + asr_base +JASPER_ASR_REG_OFFSET ; + asr_toggle_mask =JASPER_ASR_TOGGLE_MASK ; + asr_disable_mask =JASPER_ASR_DISABLE_MASK ; + asr_length =JASPER_ASR_REG_OFFSET +1 ; + +break ; + +case ASMTYPE_PEARL : + type ="Pearls " ; + asr_base =PEARL_BASE ; + asr_read_addr =PEARL_READ ; + asr_write_addr =PEARL_WRITE ; + asr_toggle_mask =PEARL_ASR_TOGGLE_MASK ; + asr_disable_mask =PEARL_ASR_DISABLE_MASK ; + asr_length =4 ; +break ; + +case ASMTYPE_JUNIPER : + type ="Junipers " ; + asr_base =JUNIPER_BASE_ADDRESS ; + asr_read_addr = asr_write_addr = asr_base; + asr_toggle_mask =JUNIPER_ASR_TOGGLE_MASK ; + asr_disable_mask =JUNIPER_ASR_DISABLE_MASK ; +break ; + +case ASMTYPE_SPRUCE : + type ="Spruce's " ; + asr_base =SPRUCE_BASE_ADDRESS ; + asr_read_addr = asr_write_addr = asr_base; + asr_toggle_mask =SPRUCE_ASR_TOGGLE_MASK ; + asr_disable_mask =SPRUCE_ASR_DISABLE_MASK ; +break ; + } + +if (!request_region (asr_base, asr_length,"ibmasr" )) { + printk(KERN_ERR PFX "address %#x already in use\n", + asr_base); +return -EBUSY ; + } + + printk(KERN_INFO PFX "found %sASR @ addr %#x\n", type, asr_base); + +return 0 ; +} + + +static ssize_t asr_write (struct file *file,const char __user *buf, +size_t count,loff_t *ppos) +{ +if (count) { +if (!nowayout) { +size_t i; + +/* In case it was set long ago */ + asr_expect_close =0 ; + +for (i =0 ; i != count; i++) { +char c; +if (get_user (c, buf + i)) +return -EFAULT ; +if (c =='V' ) + asr_expect_close =42 ; + } + } +asr_toggle (); + } +return count; +} + +static int asr_ioctl (struct inode *inode,struct file *file, +unsigned int cmd,unsigned long arg) +{ +static const struct watchdog_info ident = { + .options =WDIOF_KEEPALIVEPING |WDIOF_SETTIMEOUT | +WDIOF_MAGICCLOSE , + .identity ="IBM ASR" + }; +void __user *argp = (void __user *)arg; +int __user *p = argp; +int heartbeat; + +switch (cmd) { +case WDIOC_GETSUPPORT : +return copy_to_user (argp, &ident,sizeof (ident)) ? + -EFAULT :0 ; + +case WDIOC_GETSTATUS : +case WDIOC_GETBOOTSTATUS : +return put_user (0 , p); + +case WDIOC_KEEPALIVE : +asr_toggle (); +return 0 ; + + +case WDIOC_SETTIMEOUT : +if (get_user (heartbeat, p)) +return -EFAULT ; +/* Fall */ + +case WDIOC_GETTIMEOUT : + heartbeat =256 ; +return put_user (heartbeat, p); + +case WDIOC_SETOPTIONS : { +int new_options, retval = -EINVAL ; + +if (get_user (new_options, p)) +return -EFAULT ; + +if (new_options &WDIOS_DISABLECARD ) { +asr_disable (); + retval =0 ; + } + +if (new_options &WDIOS_ENABLECARD ) { +asr_enable (); +asr_toggle (); + retval =0 ; + } + +return retval; + } + } + +return -ENOIOCTLCMD ; +} + +static int asr_open (struct inode *inode,struct file *file) +{ +if (test_and_set_bit (0 , &asr_is_open)) +return -EBUSY ; + +asr_toggle (); +asr_enable (); + +return nonseekable_open (inode, file); +} + +static int asr_release (struct inode *inode,struct file *file) +{ +if (asr_expect_close ==42 ) +asr_disable (); +else { + printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n"); +asr_toggle (); + } +clear_bit (0 , &asr_is_open); + asr_expect_close =0 ; +return 0 ; +} + +static struct file_operations asr_fops = { + .owner =THIS_MODULE , + .llseek = no_llseek, + .write = asr_write, + .ioctl = asr_ioctl, + .open = asr_open, + .release = asr_release, +}; + +static struct miscdevice asr_miscdev = { + .minor =WATCHDOG_MINOR , + .name ="watchdog" , + .fops = &asr_fops, +}; + + +struct ibmasr_id { +const char *desc; +int type; +}; + +static struct ibmasr_id __initdata ibmasr_id_table[] = { + {"IBM Automatic Server Restart - eserver xSeries 220" ,ASMTYPE_TOPAZ }, + {"IBM Automatic Server Restart - Machine Type 8673" ,ASMTYPE_PEARL }, + {"IBM Automatic Server Restart - Machine Type 8480" ,ASMTYPE_JASPER }, + {"IBM Automatic Server Restart - Machine Type 8482" ,ASMTYPE_JUNIPER }, + {"IBM Automatic Server Restart - Machine Type 8648" ,ASMTYPE_SPRUCE }, + {NULL } +}; + +static int __init ibmasr_init (void ) +{ +struct ibmasr_id *id; +int rc; + +for (id = ibmasr_id_table; id->desc; id++) { +if (dmi_find_device (DMI_DEV_TYPE_OTHER , id->desc,NULL )) { + asr_type = id->type; +break ; + } + } + +if (!asr_type) +return -ENODEV ; + + rc =misc_register (&asr_miscdev); +if (rc <0 ) { + printk(KERN_ERR PFX "failed to register misc device\n"); +return rc; + } + + rc =asr_get_base_address (); +if (rc) { +misc_deregister (&asr_miscdev); +return rc; + } + +return 0 ; +} + +static void __exit ibmasr_exit(void) +{ +if (!nowayout) +asr_disable (); + +misc_deregister (&asr_miscdev); + +release_region (asr_base, asr_length); +} + +module_init (ibmasr_init); +module_exit (ibmasr_exit); + +module_param (nowayout, int,0 ); +MODULE_PARM_DESC (nowayout,"Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)" ); + +MODULE_DESCRIPTION ("IBM Automatic Server Restart driver" ); +MODULE_AUTHOR ("Andrey Panin" ); +MODULE_LICENSE ("GPL" ); +MODULE_ALIAS_MISCDEV (WATCHDOG_MINOR );
drivers/char/watchdog/Kconfig +10 -0
@@ -548,6 +548,16 @@ config WDT_501_PCI can do this via the tachometer parameter. Only do this if you have a fan tachometer actually set up. +config IBMASR + tristate "IBM Automatic Server Restart" + depends on WATCHDOG && X86 + help + This is the driver for the IBM Automatic Server Restart watchdog + timer builtin into some eServer xSeries machines. + + To compile this driver as a module, choose M here: the + module will be called ibmasr. + # # USB-based Watchdog Cards #
drivers/char/watchdog/Makefile +1 -0
@@ -48,6 +48,7 @@ obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o obj-$(CONFIG_MACHZ_WDT) += machzwd.o +obj-$(CONFIG_IBMASR) += ibmasr.o # PowerPC Architecture obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
Re: [PATCH 5/5] 2.6.13-rc5-mm1, driver for IBM Automatic Server Restart watchdog
drivers/char/watchdog/ibmasr.c line 159
Quoted 12 lines · Andrey Panin
This patch adds driver for IBM Automatic Server Restart watchdog hardware found in some IBM eServer xSeries machines. This driver is based on the ugly driver provided by IBM. Driver was tested on IBM eServer 226.
...
drivers/char/watchdog/ibmasr.c +5
-0+ +case ASMTYPE_JASPER : + type ="Jaspers " ; + +/* FIXME: need to use pci_config_lock here, but it's not exported */
That's gregkh material.
Quoted 41 lines
drivers/char/watchdog/ibmasr.c +38
-0+ +/* spin_lock_irqsave(&pci_config_lock, flags);*/ + +/* Select the SuperIO chip in the PCI I/O port register */ +outl (0x8000f858 ,0xcf8 ); + +/* +* Read the base address for the SuperIO chip. +* Only the lower 16 bits are valid, but the address is word +* aligned so the last bit must be masked off. +*/ + asr_base =inl (0xcfc ) &0xfffe ; + +/* spin_unlock_irqrestore(&pci_config_lock, flags);*/ +static int asr_ioctl (struct inode *inode,struct file *file, +unsigned int cmd,unsigned long arg) +{ +static const struct watchdog_info ident = { + .options =WDIOF_KEEPALIVEPING |WDIOF_SETTIMEOUT | +WDIOF_MAGICCLOSE , + .identity ="IBM ASR" + }; +void __user *argp = (void __user *)arg; +int __user *p = argp; +int heartbeat; + +switch (cmd) { +case WDIOC_GETSUPPORT : +return copy_to_user (argp, &ident,sizeof (ident)) ? + -EFAULT :0 ; + +case WDIOC_GETSTATUS : +case WDIOC_GETBOOTSTATUS : +return put_user (0 , p); + +case WDIOC_KEEPALIVE : +asr_toggle (); +return 0 ;
drivers/char/watchdog/ibmasr.c line 278
Quoted 10 lines
drivers/char/watchdog/ibmasr.c +10
-0+ + +case WDIOC_SETTIMEOUT : +if (get_user (heartbeat, p)) +return -EFAULT ; +/* Fall */ + +case WDIOC_GETTIMEOUT : + heartbeat =256 ; +return put_user (heartbeat, p);
Something very wrong is happening with WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT. They're both no-ops and the effect of WDIOC_SETTIMEOUT is immidiately overwritten.
Re: [PATCH 5/5] 2.6.13-rc5-mm1, driver for IBM Automatic Server Restart watchdog
Quoted 63 lines · Andrew Morton
drivers/char/watchdog/ibmasr.c line 159
Quoted 12 lines · Andrey Panin
This patch adds driver for IBM Automatic Server Restart watchdog hardware found in some IBM eServer xSeries machines. This driver is based on the ugly driver provided by IBM. Driver was tested on IBM eServer 226.
...
drivers/char/watchdog/ibmasr.c +5
-0+ +case ASMTYPE_JASPER : + type ="Jaspers " ; + +/* FIXME: need to use pci_config_lock here, but it's not exported */ That's gregkh material.
Quoted 47 lines
drivers/char/watchdog/ibmasr.c +44
-0+ +/* spin_lock_irqsave(&pci_config_lock, flags);*/ + +/* Select the SuperIO chip in the PCI I/O port register */ +outl (0x8000f858 ,0xcf8 ); + +/* +* Read the base address for the SuperIO chip. +* Only the lower 16 bits are valid, but the address is word +* aligned so the last bit must be masked off. +*/ + asr_base =inl (0xcfc ) &0xfffe ; + +/* spin_unlock_irqrestore(&pci_config_lock, flags);*/ +static int asr_ioctl (struct inode *inode,struct file *file, +unsigned int cmd,unsigned long arg) +{ +static const struct watchdog_info ident = { + .options =WDIOF_KEEPALIVEPING |WDIOF_SETTIMEOUT | +WDIOF_MAGICCLOSE , + .identity ="IBM ASR" + }; +void __user *argp = (void __user *)arg; +int __user *p = argp; +int heartbeat; + +switch (cmd) { +case WDIOC_GETSUPPORT : +return copy_to_user (argp, &ident,sizeof (ident)) ? + -EFAULT :0 ; + +case WDIOC_GETSTATUS : +case WDIOC_GETBOOTSTATUS : +return put_user (0 , p); + +case WDIOC_KEEPALIVE : +asr_toggle (); +return 0 ; + + +case WDIOC_SETTIMEOUT : +if (get_user (heartbeat, p)) +return -EFAULT ; +/* Fall */
Quoted 8 lines
drivers/char/watchdog/ibmasr.c line 278
Quoted 4 lines
drivers/char/watchdog/ibmasr.c +4
-0+ +case WDIOC_GETTIMEOUT : + heartbeat =256 ; +return put_user (heartbeat, p);Something very wrong is happening with
WDIOC_SETTIMEOUTandWDIOC_GETTIMEOUT. They're both no-ops and the effect ofWDIOC_SETTIMEOUTis immidiately overwritten.
Hardware has fixed timeout value, so WDIOC_SETTIMEOUT is noop and WDIOC_GETTIMEOUT always returns 256.
Signature · 2 lines
Andrey Panin | Linux and UNIX system administrator [email protected] | PGP key: wwwkeys.pgp.net
Re: [PATCH 4/5] 2.6.13-rc5-mm1, IPMI, use dmi_find_device()
In reply to Andrey PaninAndrew, this patch (along with the patch 3/5) works fine for me and is an obvious improvement to the IPMI driver. You will need to remove the patch named dmi_table-counting-in-ipmi_si_intfc.patch first.
Thanks, Andrey.
-Corey
Quoted 171 lines · Andrey Panin
This patch replaces homebrew DMI scanning code in IPMI System Interface driver with
dmi_find_device()call.Signed-off-by Andrey Panin <[email protected]>drivers/char/ipmi/ipmi_si_intf.c | 105 ++++++--------------------------------- 1 files changed, 17 insertions(+), 88 deletions(-)diff -urdpNX
/usr/share/dontdifflinux-2.6.13-rc5-mm1.vanilla/drivers/char/ipmi/ipmi_si_intf.clinux-2.6.13-rc5-mm1/drivers/char/ipmi/ipmi_si_intf.cdrivers/char/ipmi/ipmi_si_intf.c +17
-88@@ -75,6 +75,7 @@ static inline void add_usec_to_timer(str#include <asm/io.h> #include "ipmi_si_sm.h" #include <linux/init.h> +#include <linux/dmi.h> /* Measure times between events in the driver. */ #undef DEBUG_TIMING@@ -1642,22 +1643,15 @@ typedef struct dmi_ipmi_datastatic dmi_ipmi_data_t dmi_data[SI_MAX_DRIVERS ];static int dmi_data_entries; -typedef struct dmi_header -{ -u8 type; -u8 length; -u16 handle; -}dmi_header_t ; - -static int decode_dmi (dmi_header_t __iomem *dm,int intf_num) +static int __init decode_dmi (struct dmi_header *dm,int intf_num) { -u8 __iomem *data = (u8 __iomem *)dm; +u8 *data = (u8 *)dm;unsigned long base_addr;u8 reg_spacing; -u8 len =readb (&dm->length); +u8 len = dm->length;dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num; - ipmi_data->type =readb (&data[4 ]); + ipmi_data->type = data[4 ];memcpy (&base_addr, data+8 ,sizeof (unsigned long ));if (len >=0x11 ) {@@ -1672,12 +1666,12 @@ static int decode_dmi(dmi_header_t __iom }/* If bit 4 of byte 0x10 is set, then the lsb for the address is odd. */ - ipmi_data->base_addr = base_addr | ((readb (&data[0x10 ]) &0x10 ) >>4 ); + ipmi_data->base_addr = base_addr | ((data[0x10 ] &0x10 ) >>4 ); - ipmi_data->irq =readb (&data[0x11 ]); + ipmi_data->irq = data[0x11 ];/* The top two bits of byte 0x10 hold the register spacing. */ - reg_spacing = (readb (&data[0x10 ]) &0xC0 ) >>6 ; + reg_spacing = (data[0x10 ] &0xC0 ) >>6 ;switch (reg_spacing){case 0x00 :/* Byte boundaries */ ipmi_data->offset =1 ;@@ -1705,7 +1699,7 @@ static int decode_dmi(dmi_header_t __iom ipmi_data->offset =1 ; } - ipmi_data->slave_addr =readb (&data[6 ]); + ipmi_data->slave_addr = data[6 ];if (is_new_interface (-1 , ipmi_data->addr_space,ipmi_data->base_addr)) { dmi_data_entries++;@@ -1717,82 +1711,17 @@ static int decode_dmi(dmi_header_t __iomreturn -1 ; } -static int dmi_table (u32 base,int len,int num) -{ -u8 __iomem *buf; -struct dmi_header __iomem *dm; -u8 __iomem *data; -int i=1 ; -int status=-1 ; -int intf_num =0 ; - - buf =ioremap (base, len); -if (buf==NULL ) -return -1 ; - - data = buf; - -while (i<num && (data - buf) < len) - { - dm=(dmi_header_t __iomem *)data; - -if ((data-buf+readb (&dm->length)) >= len) -break ; - -if (readb (&dm->type) ==38 ) { -if (decode_dmi (dm, intf_num) ==0 ) { - intf_num++; -if (intf_num >=SI_MAX_DRIVERS ) -break ; - } - } - - data+=readb (&dm->length); -while ((data-buf) < len && (readb (data)||readb (data+1 ))) - data++; - data+=2 ; - i++; - } -iounmap (buf); - -return status; -} - -static inline int dmi_checksum (u8 *buf) -{ -u8 sum=0 ; -int a; - -for (a=0 ; a<15 ; a++) - sum+=buf[a]; -return (sum==0 ); -} - -static int dmi_decode (void ) +static void __init dmi_find_bmc (void ) { -u8 buf[15 ]; -u32 fp=0xF0000 ; - -#ifdef CONFIG_SIMNOW -return -1 ; -#endif +struct dmi_device *dev =NULL ; +int intf_num =0 ; -while (fp <0xFFFFF ) - { -isa_memcpy_fromio (buf, fp,15 ); -if (memcmp (buf,"_DMI_" ,5 )==0 &&dmi_checksum (buf)) - { -u16 num=buf[13 ]<<8 |buf[12 ]; -u16 len=buf[7 ]<<8 |buf[6 ]; -u32 base=buf[11 ]<<24 |buf[10 ]<<16 |buf[9 ]<<8 |buf[8 ]; +while ((dev =dmi_find_device (DMI_DEV_TYPE_IPMI ,NULL , dev))) { +if (intf_num >=SI_MAX_DRIVERS ) +break ; -if (dmi_table (base, len, num) ==0 ) -return 0 ; - } - fp+=16 ; +decode_dmi ((struct dmi_header *) dev->device_data, intf_num++); } - -return -1 ; }static int try_init_smbios (int intf_num,struct smi_info **new_info)@@ -2382,7 +2311,7 @@ static __init int init_ipmi_si(void)printk (KERN_INFO "IPMI System Interface driver.\n" );#ifdef CONFIG_X86 -dmi_decode (); +dmi_find_bmc ();#endif rv =init_one_smi (0 , &(smi_infos[pos]));