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>

authored by Yinghai Lu and committed by Wim Van Sebroeck 90d241ed f712eacf

+14 -2
+14 -2
drivers/watchdog/sp5100_tco.c
··· 42 42 #define PFX TCO_MODULE_NAME ": " 43 43 44 44 /* internal variables */ 45 + static u32 tcobase_phys; 45 46 static void __iomem *tcobase; 46 47 static unsigned int pm_iobase; 47 48 static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */ ··· 306 305 /* Low three bits of BASE0 are reserved. */ 307 306 val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8); 308 307 308 + if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE, 309 + "SP5100 TCO")) { 310 + printk(KERN_ERR PFX "mmio address 0x%04x already in use\n", 311 + val); 312 + goto unreg_region; 313 + } 314 + tcobase_phys = val; 315 + 309 316 tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE); 310 317 if (tcobase == 0) { 311 318 printk(KERN_ERR PFX "failed to get tcobase address\n"); 312 - goto unreg_region; 319 + goto unreg_mem_region; 313 320 } 314 321 315 322 /* Enable watchdog decode bit */ ··· 355 346 /* Done */ 356 347 return 1; 357 348 358 - iounmap(tcobase); 349 + unreg_mem_region: 350 + release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); 359 351 unreg_region: 360 352 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 361 353 exit: ··· 411 401 412 402 exit: 413 403 iounmap(tcobase); 404 + release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); 414 405 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 415 406 return ret; 416 407 } ··· 425 414 /* Deregister */ 426 415 misc_deregister(&sp5100_tco_miscdev); 427 416 iounmap(tcobase); 417 + release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); 428 418 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 429 419 } 430 420