Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

watchdog: sp5100_tco: Remove code that may cause a boot failure

A problem was found on PC's with the SB700 chipset: The PC fails to
load BIOS after running the 3.8.x kernel until the power is completely
cut off. It occurs in all 3.8.x versions and the mainline version as of
2/4. The issue does not occur with the 3.7.x builds.

There are two methods for accessing the watchdog registers.

1. Re-programming a resource address obtained by allocate_resource()
to chipset.
2. Use the direct memory-mapped IO access.

The method 1 can be used by all the chipsets (SP5100, SB7x0, SB8x0 or
later). However, experience shows that only PC with the SB8x0 (or
later) chipsets can use the method 2.

This patch removes the method 1, because the critical problem was found.
That's why the watchdog timer was able to be used on SP5100 and SB7x0
chipsets until now.

Link: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1116835
Link: https://lkml.org/lkml/2013/2/14/271

Signed-off-by: Takahisa Tanaka <mc74hc00@gmail.com>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Cc: stable <stable@vger.kernel.org>

authored by

Takahisa Tanaka and committed by
Wim Van Sebroeck
18e43212 9217cbb8

+6 -120
+6 -120
drivers/watchdog/sp5100_tco.c
··· 40 40 #include "sp5100_tco.h" 41 41 42 42 /* Module and version information */ 43 - #define TCO_VERSION "0.03" 43 + #define TCO_VERSION "0.05" 44 44 #define TCO_MODULE_NAME "SP5100 TCO timer" 45 45 #define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION 46 46 47 47 /* internal variables */ 48 48 static u32 tcobase_phys; 49 - static u32 resbase_phys; 50 49 static u32 tco_wdt_fired; 51 50 static void __iomem *tcobase; 52 51 static unsigned int pm_iobase; ··· 53 54 static unsigned long timer_alive; 54 55 static char tco_expect_close; 55 56 static struct pci_dev *sp5100_tco_pci; 56 - static struct resource wdt_res = { 57 - .name = "Watchdog Timer", 58 - .flags = IORESOURCE_MEM, 59 - }; 60 57 61 58 /* the watchdog platform device */ 62 59 static struct platform_device *sp5100_tco_platform_device; ··· 69 74 module_param(nowayout, bool, 0); 70 75 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started." 71 76 " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 72 - 73 - static unsigned int force_addr; 74 - module_param(force_addr, uint, 0); 75 - MODULE_PARM_DESC(force_addr, "Force the use of specified MMIO address." 76 - " ONLY USE THIS PARAMETER IF YOU REALLY KNOW" 77 - " WHAT YOU ARE DOING (default=none)"); 78 77 79 78 /* 80 79 * Some TCO specific functions ··· 161 172 val = inb(SP5100_IO_PM_DATA_REG); 162 173 val |= SP5100_PM_WATCHDOG_SECOND_RES; 163 174 val &= ~SP5100_PM_WATCHDOG_DISABLE; 164 - outb(val, SP5100_IO_PM_DATA_REG); 165 - } 166 - } 167 - 168 - static void tco_timer_disable(void) 169 - { 170 - int val; 171 - 172 - if (sp5100_tco_pci->revision >= 0x40) { 173 - /* For SB800 or later */ 174 - /* Enable watchdog decode bit and Disable watchdog timer */ 175 - outb(SB800_PM_WATCHDOG_CONTROL, SB800_IO_PM_INDEX_REG); 176 - val = inb(SB800_IO_PM_DATA_REG); 177 - val |= SB800_PCI_WATCHDOG_DECODE_EN; 178 - val |= SB800_PM_WATCHDOG_DISABLE; 179 - outb(val, SB800_IO_PM_DATA_REG); 180 - } else { 181 - /* For SP5100 or SB7x0 */ 182 - /* Enable watchdog decode bit */ 183 - pci_read_config_dword(sp5100_tco_pci, 184 - SP5100_PCI_WATCHDOG_MISC_REG, 185 - &val); 186 - 187 - val |= SP5100_PCI_WATCHDOG_DECODE_EN; 188 - 189 - pci_write_config_dword(sp5100_tco_pci, 190 - SP5100_PCI_WATCHDOG_MISC_REG, 191 - val); 192 - 193 - /* Disable Watchdog timer */ 194 - outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG); 195 - val = inb(SP5100_IO_PM_DATA_REG); 196 - val |= SP5100_PM_WATCHDOG_DISABLE; 197 175 outb(val, SP5100_IO_PM_DATA_REG); 198 176 } 199 177 } ··· 317 361 { 318 362 struct pci_dev *dev = NULL; 319 363 const char *dev_name = NULL; 320 - u32 val, tmp_val; 364 + u32 val; 321 365 u32 index_reg, data_reg, base_addr; 322 366 323 367 /* Match the PCI device */ ··· 415 459 } else 416 460 pr_debug("SBResource_MMIO is disabled(0x%04x)\n", val); 417 461 418 - /* 419 - * Lastly re-programming the watchdog timer MMIO address, 420 - * This method is a last resort... 421 - * 422 - * Before re-programming, to ensure that the watchdog timer 423 - * is disabled, disable the watchdog timer. 424 - */ 425 - tco_timer_disable(); 426 - 427 - if (force_addr) { 428 - /* 429 - * Force the use of watchdog timer MMIO address, and aligned to 430 - * 8byte boundary. 431 - */ 432 - force_addr &= ~0x7; 433 - val = force_addr; 434 - 435 - pr_info("Force the use of 0x%04x as MMIO address\n", val); 436 - } else { 437 - /* 438 - * Get empty slot into the resource tree for watchdog timer. 439 - */ 440 - if (allocate_resource(&iomem_resource, 441 - &wdt_res, 442 - SP5100_WDT_MEM_MAP_SIZE, 443 - 0xf0000000, 444 - 0xfffffff8, 445 - 0x8, 446 - NULL, 447 - NULL)) { 448 - pr_err("MMIO allocation failed\n"); 449 - goto unreg_region; 450 - } 451 - 452 - val = resbase_phys = wdt_res.start; 453 - pr_debug("Got 0x%04x from resource tree\n", val); 454 - } 455 - 456 - /* Restore to the low three bits */ 457 - outb(base_addr+0, index_reg); 458 - tmp_val = val | (inb(data_reg) & 0x7); 459 - 460 - /* Re-programming the watchdog timer base address */ 461 - outb(base_addr+0, index_reg); 462 - outb((tmp_val >> 0) & 0xff, data_reg); 463 - outb(base_addr+1, index_reg); 464 - outb((tmp_val >> 8) & 0xff, data_reg); 465 - outb(base_addr+2, index_reg); 466 - outb((tmp_val >> 16) & 0xff, data_reg); 467 - outb(base_addr+3, index_reg); 468 - outb((tmp_val >> 24) & 0xff, data_reg); 469 - 470 - if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE, 471 - dev_name)) { 472 - pr_err("MMIO address 0x%04x already in use\n", val); 473 - goto unreg_resource; 474 - } 462 + pr_notice("failed to find MMIO address, giving up.\n"); 463 + goto unreg_region; 475 464 476 465 setup_wdt: 477 466 tcobase_phys = val; ··· 456 555 457 556 unreg_mem_region: 458 557 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); 459 - unreg_resource: 460 - if (resbase_phys) 461 - release_resource(&wdt_res); 462 558 unreg_region: 463 559 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 464 560 exit: ··· 465 567 static int sp5100_tco_init(struct platform_device *dev) 466 568 { 467 569 int ret; 468 - char addr_str[16]; 469 570 470 571 /* 471 572 * Check whether or not the hardware watchdog is there. If found, then ··· 496 599 clear_bit(0, &timer_alive); 497 600 498 601 /* Show module parameters */ 499 - if (force_addr == tcobase_phys) 500 - /* The force_addr is vaild */ 501 - sprintf(addr_str, "0x%04x", force_addr); 502 - else 503 - strcpy(addr_str, "none"); 504 - 505 - pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d, " 506 - "force_addr=%s)\n", 507 - tcobase, heartbeat, nowayout, addr_str); 602 + pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n", 603 + tcobase, heartbeat, nowayout); 508 604 509 605 return 0; 510 606 511 607 exit: 512 608 iounmap(tcobase); 513 609 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); 514 - if (resbase_phys) 515 - release_resource(&wdt_res); 516 610 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 517 611 return ret; 518 612 } ··· 518 630 misc_deregister(&sp5100_tco_miscdev); 519 631 iounmap(tcobase); 520 632 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); 521 - if (resbase_phys) 522 - release_resource(&wdt_res); 523 633 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 524 634 } 525 635