Commit c8fc40cd authored by David Brownell's avatar David Brownell Committed by Linus Torvalds

rtc-cmos: export second NVRAM bank

Teach rtc-cmos about the second bank of registers found on most modern x86
systems, giving access to 128 bytes more NVRAM.

This version only sees that extra NVRAM when both register banks are
provided as part of *one* PNP resource.  Since BIOS on some systems
presents them using two IO resources, and nothing merges them, this can't
always show all the NVRAM.  (We're supposed to be able to use PNP id
PNP0b01 too, but BIOS tables doesn't often seem to use that particular
option.)
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 1f3ccaed
...@@ -143,6 +143,43 @@ static inline int hpet_unregister_irq_handler(irq_handler_t handler) ...@@ -143,6 +143,43 @@ static inline int hpet_unregister_irq_handler(irq_handler_t handler)
/*----------------------------------------------------------------*/ /*----------------------------------------------------------------*/
#ifdef RTC_PORT
/* Most newer x86 systems have two register banks, the first used
* for RTC and NVRAM and the second only for NVRAM. Caller must
* own rtc_lock ... and we won't worry about access during NMI.
*/
#define can_bank2 true
static inline unsigned char cmos_read_bank2(unsigned char addr)
{
outb(addr, RTC_PORT(2));
return inb(RTC_PORT(3));
}
static inline void cmos_write_bank2(unsigned char val, unsigned char addr)
{
outb(addr, RTC_PORT(2));
outb(val, RTC_PORT(2));
}
#else
#define can_bank2 false
static inline unsigned char cmos_read_bank2(unsigned char addr)
{
return 0;
}
static inline void cmos_write_bank2(unsigned char val, unsigned char addr)
{
}
#endif
/*----------------------------------------------------------------*/
static int cmos_read_time(struct device *dev, struct rtc_time *t) static int cmos_read_time(struct device *dev, struct rtc_time *t)
{ {
/* REVISIT: if the clock has a "century" register, use /* REVISIT: if the clock has a "century" register, use
...@@ -491,12 +528,21 @@ cmos_nvram_read(struct kobject *kobj, struct bin_attribute *attr, ...@@ -491,12 +528,21 @@ cmos_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
if (unlikely(off >= attr->size)) if (unlikely(off >= attr->size))
return 0; return 0;
if (unlikely(off < 0))
return -EINVAL;
if ((off + count) > attr->size) if ((off + count) > attr->size)
count = attr->size - off; count = attr->size - off;
off += NVRAM_OFFSET;
spin_lock_irq(&rtc_lock); spin_lock_irq(&rtc_lock);
for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++) for (retval = 0; count; count--, off++, retval++) {
if (off < 128)
*buf++ = CMOS_READ(off); *buf++ = CMOS_READ(off);
else if (can_bank2)
*buf++ = cmos_read_bank2(off);
else
break;
}
spin_unlock_irq(&rtc_lock); spin_unlock_irq(&rtc_lock);
return retval; return retval;
...@@ -512,6 +558,8 @@ cmos_nvram_write(struct kobject *kobj, struct bin_attribute *attr, ...@@ -512,6 +558,8 @@ cmos_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
cmos = dev_get_drvdata(container_of(kobj, struct device, kobj)); cmos = dev_get_drvdata(container_of(kobj, struct device, kobj));
if (unlikely(off >= attr->size)) if (unlikely(off >= attr->size))
return -EFBIG; return -EFBIG;
if (unlikely(off < 0))
return -EINVAL;
if ((off + count) > attr->size) if ((off + count) > attr->size)
count = attr->size - off; count = attr->size - off;
...@@ -520,15 +568,20 @@ cmos_nvram_write(struct kobject *kobj, struct bin_attribute *attr, ...@@ -520,15 +568,20 @@ cmos_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
* here. If userspace is smart enough to know what fields of * here. If userspace is smart enough to know what fields of
* NVRAM to update, updating checksums is also part of its job. * NVRAM to update, updating checksums is also part of its job.
*/ */
off += NVRAM_OFFSET;
spin_lock_irq(&rtc_lock); spin_lock_irq(&rtc_lock);
for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++) { for (retval = 0; count; count--, off++, retval++) {
/* don't trash RTC registers */ /* don't trash RTC registers */
if (off == cmos->day_alrm if (off == cmos->day_alrm
|| off == cmos->mon_alrm || off == cmos->mon_alrm
|| off == cmos->century) || off == cmos->century)
buf++; buf++;
else else if (off < 128)
CMOS_WRITE(*buf++, off); CMOS_WRITE(*buf++, off);
else if (can_bank2)
cmos_write_bank2(*buf++, off);
else
break;
} }
spin_unlock_irq(&rtc_lock); spin_unlock_irq(&rtc_lock);
...@@ -631,8 +684,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) ...@@ -631,8 +684,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
/* Heuristic to deduce NVRAM size ... do what the legacy NVRAM /* Heuristic to deduce NVRAM size ... do what the legacy NVRAM
* driver did, but don't reject unknown configs. Old hardware * driver did, but don't reject unknown configs. Old hardware
* won't address 128 bytes, and for now we ignore the way newer * won't address 128 bytes. Newer chips have multiple banks,
* chips can address 256 bytes (using two more i/o ports). * though they may not be listed in one I/O resource.
*/ */
#if defined(CONFIG_ATARI) #if defined(CONFIG_ATARI)
address_space = 64; address_space = 64;
...@@ -642,6 +695,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) ...@@ -642,6 +695,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes. #warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
address_space = 128; address_space = 128;
#endif #endif
if (can_bank2 && ports->end > (ports->start + 1))
address_space = 256;
/* For ACPI systems extension info comes from the FADT. On others, /* For ACPI systems extension info comes from the FADT. On others,
* board specific setup provides it as appropriate. Systems where * board specific setup provides it as appropriate. Systems where
...@@ -740,7 +795,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) ...@@ -740,7 +795,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
goto cleanup2; goto cleanup2;
} }
pr_info("%s: alarms up to one %s%s%s\n", pr_info("%s: alarms up to one %s%s, %zd bytes nvram, %s irqs\n",
cmos_rtc.rtc->dev.bus_id, cmos_rtc.rtc->dev.bus_id,
is_valid_irq(rtc_irq) is_valid_irq(rtc_irq)
? (cmos_rtc.mon_alrm ? (cmos_rtc.mon_alrm
...@@ -749,6 +804,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) ...@@ -749,6 +804,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
? "month" : "day")) ? "month" : "day"))
: "no", : "no",
cmos_rtc.century ? ", y3k" : "", cmos_rtc.century ? ", y3k" : "",
nvram.size,
is_hpet_enabled() ? ", hpet irqs" : ""); is_hpet_enabled() ? ", hpet irqs" : "");
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment