|
@@ -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,
|
|
|
|
|
|
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++)
|
|
|
|
- *buf++ = CMOS_READ(off);
|
|
|
|
|
|
+ for (retval = 0; count; count--, off++, retval++) {
|
|
|
|
+ if (off < 128)
|
|
|
|
+ *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,
|
|
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,
|
|
* 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)
|
|
|
|
|
|
/* 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
|
|
|
|
- * chips can address 256 bytes (using two more i/o ports).
|
|
|
|
|
|
+ * won't address 128 bytes. Newer chips have multiple banks,
|
|
|
|
+ * 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)
|
|
#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)
|
|
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)
|
|
? "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;
|