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

rtc: fall back to requesting only the ports we actually use

Firmware like PNPBIOS or ACPI can report the address space consumed by the
RTC. The actual space consumed may be less than the size (RTC_IO_EXTENT)
assumed by the RTC driver.

The PNP core doesn't request resources yet, but I'd like to make it do so.
If/when it does, the RTC_IO_EXTENT request may fail, which prevents the RTC
driver from loading.

Since we only use the RTC index and data registers at RTC_PORT(0) and
RTC_PORT(1), we can fall back to requesting just enough space for those.

If the PNP core requests resources, this results in typical I/O port usage
like this:

0070-0073 : 00:06 <-- PNP device 00:06 responds to 70-73
0070-0071 : rtc <-- RTC driver uses only 70-71

instead of the current:

0070-0077 : rtc <-- RTC_IO_EXTENT == 8

Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: David Brownell <david-b@pacbell.net>
Cc: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Bjorn Helgaas and committed by
Linus Torvalds
9626f1f1 4c06be10

+33 -6
+30 -6
drivers/char/rtc.c
··· 918 918 }; 919 919 #endif 920 920 921 + static resource_size_t rtc_size; 922 + 923 + static struct resource * __init rtc_request_region(resource_size_t size) 924 + { 925 + struct resource *r; 926 + 927 + if (RTC_IOMAPPED) 928 + r = request_region(RTC_PORT(0), size, "rtc"); 929 + else 930 + r = request_mem_region(RTC_PORT(0), size, "rtc"); 931 + 932 + if (r) 933 + rtc_size = size; 934 + 935 + return r; 936 + } 937 + 921 938 static void rtc_release_region(void) 922 939 { 923 940 if (RTC_IOMAPPED) 924 - release_region(RTC_PORT(0), RTC_IO_EXTENT); 941 + release_region(RTC_PORT(0), rtc_size); 925 942 else 926 - release_mem_region(RTC_PORT(0), RTC_IO_EXTENT); 943 + release_mem_region(RTC_PORT(0), rtc_size); 927 944 } 928 945 929 946 static int __init rtc_init(void) ··· 993 976 } 994 977 no_irq: 995 978 #else 996 - if (RTC_IOMAPPED) 997 - r = request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc"); 998 - else 999 - r = request_mem_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc"); 979 + r = rtc_request_region(RTC_IO_EXTENT); 980 + 981 + /* 982 + * If we've already requested a smaller range (for example, because 983 + * PNPBIOS or ACPI told us how the device is configured), the request 984 + * above might fail because it's too big. 985 + * 986 + * If so, request just the range we actually use. 987 + */ 988 + if (!r) 989 + r = rtc_request_region(RTC_IO_EXTENT_USED); 1000 990 if (!r) { 1001 991 #ifdef RTC_IRQ 1002 992 rtc_has_irq = 0;
+3
include/linux/mc146818rtc.h
··· 109 109 #ifndef ARCH_RTC_LOCATION /* Override by <asm/mc146818rtc.h>? */ 110 110 111 111 #define RTC_IO_EXTENT 0x8 112 + #define RTC_IO_EXTENT_USED 0x2 112 113 #define RTC_IOMAPPED 1 /* Default to I/O mapping. */ 113 114 115 + #else 116 + #define RTC_IO_EXTENT_USED RTC_IO_EXTENT 114 117 #endif /* ARCH_RTC_LOCATION */ 115 118 116 119 #endif /* _MC146818RTC_H */