aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2011-03-16 23:01:07 -0400
committerWim Van Sebroeck <wim@iguana.be>2011-03-29 07:05:57 -0400
commit90d241edd13bdeef70f264b569f7e150bf23621e (patch)
tree2d7ac02fec4664fee64c578c43603d02dc2dc4af /drivers/watchdog
parentf712eacf02ecfbf4f1686addb8c569841549b0b7 (diff)
watchdog: sp5100_tco.c: Check if firmware has set correct value in tcobase.
Stefano found SP5100 TCO watchdog driver using wrong address. [ 9.148536] SP5100 TCO timer: SP5100 TCO WatchDog Timer Driver v0.01 [ 9.148628] DEBUG __ioremap_caller WARNING address=b8fe00 size=8 valid=1 reserved=1 and e820 said that range is RAM. We should check if we can use that reading out. BIOS could just program wrong address there. Reported-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Signed-off-by:Yinghai Lu <yinghai@kernel.org> Acked-by: Mike Waychison <mikew@google.com> Tested-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Signed-off-by: Wim Van Sebroeck <wim@iguana.be> Cc: stable <stable@kernel.org>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/sp5100_tco.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index 1bc493848ed4..87e0527669d8 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -42,6 +42,7 @@
42#define PFX TCO_MODULE_NAME ": " 42#define PFX TCO_MODULE_NAME ": "
43 43
44/* internal variables */ 44/* internal variables */
45static u32 tcobase_phys;
45static void __iomem *tcobase; 46static void __iomem *tcobase;
46static unsigned int pm_iobase; 47static unsigned int pm_iobase;
47static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */ 48static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */
@@ -305,10 +306,18 @@ static unsigned char __devinit sp5100_tco_setupdevice(void)
305 /* Low three bits of BASE0 are reserved. */ 306 /* Low three bits of BASE0 are reserved. */
306 val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8); 307 val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8);
307 308
309 if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
310 "SP5100 TCO")) {
311 printk(KERN_ERR PFX "mmio address 0x%04x already in use\n",
312 val);
313 goto unreg_region;
314 }
315 tcobase_phys = val;
316
308 tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE); 317 tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE);
309 if (tcobase == 0) { 318 if (tcobase == 0) {
310 printk(KERN_ERR PFX "failed to get tcobase address\n"); 319 printk(KERN_ERR PFX "failed to get tcobase address\n");
311 goto unreg_region; 320 goto unreg_mem_region;
312 } 321 }
313 322
314 /* Enable watchdog decode bit */ 323 /* Enable watchdog decode bit */
@@ -346,7 +355,8 @@ static unsigned char __devinit sp5100_tco_setupdevice(void)
346 /* Done */ 355 /* Done */
347 return 1; 356 return 1;
348 357
349 iounmap(tcobase); 358unreg_mem_region:
359 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
350unreg_region: 360unreg_region:
351 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 361 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
352exit: 362exit:
@@ -401,6 +411,7 @@ static int __devinit sp5100_tco_init(struct platform_device *dev)
401 411
402exit: 412exit:
403 iounmap(tcobase); 413 iounmap(tcobase);
414 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
404 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 415 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
405 return ret; 416 return ret;
406} 417}
@@ -414,6 +425,7 @@ static void __devexit sp5100_tco_cleanup(void)
414 /* Deregister */ 425 /* Deregister */
415 misc_deregister(&sp5100_tco_miscdev); 426 misc_deregister(&sp5100_tco_miscdev);
416 iounmap(tcobase); 427 iounmap(tcobase);
428 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
417 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 429 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
418} 430}
419 431