Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 10 Mar 2010 15:27:13 +0200
From:      Andriy Gapon <avg@icyb.net.ua>
To:        volker@vwsoft.com
Cc:        hackers@freebsd.org
Subject:   Re: southbridge recognition
Message-ID:  <4B979E31.1050509@icyb.net.ua>
In-Reply-To: <4B96BB82.5090805@vwsoft.com>
References:  <4B96BB82.5090805@vwsoft.com>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------060602050004030601060907
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

on 09/03/2010 23:20 volker@vwsoft.com said the following:
> Hi!
> 
> For some driver enhancements, I need to decide (by code) which
> southbridge (Intel, AMD is all that matters) the driver is facing.
> 
> What's the best (portable wise) way to distinguish the chipset?
> 
> Intel supports two pages of 128 byte CMOS RAM, AMD supports 1 page of
> 256 byte (addressing is different).
> 
> Is there any way to query the CMOS RAM size? I failed to find a way
> while reading Intel & AMD chipset documentation. Older chipsets
> supported only 64 (very old) or 128 byte. Recent (as of for the last 15
> years or so) chipsets supports more.
> 
> As our current nvram(4) driver only works with 128 byte RAM size, is
> anybody interested in seeing the nvram(4) driver enhanced for extended
> memory areas? I do have working code but that assumes an Intel ICH or
> 440LX chipset (fails for SB{67]xx for some reason :).
> 
> Thank you for any pointers!

Volker,

BTW, I have a couple of local patches/hacks for this myself.
But without any auto detection.
Maybe you could find some bits of them useful.

piix4-rtc-nvram-quirk.diff - enables access to upper 128 bytes on PIIX4 (440BX)
systems in chipset configuration

intel-rtc-nvram.diff - enables access to upper 128 bytes, Intel way

dev-nvram.diff - changes behavior of /dev/nvram to what is more convenient for me,
breaks compatibility with existing apps using it (if any by now):
1) bytes are counted from offset zero, not 14, but the first 14 bytes (RTC status
and control) are always 0xff
2) checksum is not recalculated, it's left for userland to do (not all systems
might want to do that in old BIOS way)

amd-cmos-nvram.diff - enables access to upper 128 bytes, AMD way

Two last patches are on top of the intel-rtc-nvram.diff patch, not against the
clean tree.

-- 
Andriy Gapon

--------------060602050004030601060907
Content-Type: text/plain;
 name="piix4-rtc-nvram-quirk.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="piix4-rtc-nvram-quirk.diff"

diff --git a/sys/dev/pci/fixup_pci.c b/sys/dev/pci/fixup_pci.c
index 13fc4b1..566e503 100644
--- a/sys/dev/pci/fixup_pci.c
+++ b/sys/dev/pci/fixup_pci.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
 static int	fixup_pci_probe(device_t dev);
 static void	fixwsc_natoma(device_t dev);
 static void	fixc1_nforce2(device_t dev);
+static void	fixrtc_piix4(device_t dev);
 
 static device_method_t fixup_pci_methods[] = {
     /* Device interface */
@@ -77,6 +78,9 @@ fixup_pci_probe(device_t dev)
     case 0x12378086:		/* Intel 82440FX (Natoma) */
 	fixwsc_natoma(dev);
 	break;
+    case 0x71108086:		/* Intel PIIX4 */
+	fixrtc_piix4(dev);
+	break;
     case 0x01e010de:		/* nVidia nForce2 */
 	fixc1_nforce2(dev);
 	break;
@@ -105,6 +109,21 @@ fixwsc_natoma(device_t dev)
 #endif
 }
 
+/* Enable access to upper 128-byte bank of RTC NVRAM */
+static void
+fixrtc_piix4(device_t dev)
+{
+    uint8_t		rtccfg;
+
+    rtccfg = pci_read_config(dev, 0xcb, 1);
+    if (!(rtccfg & 0x04)) {
+	printf("Enabling access to RTC NVRAM upper 128-byte extended bank\n");
+	rtccfg |= 0x04;
+	pci_write_config(dev, 0xcb, rtccfg, 1);
+    }
+}
+
+
 /*
  * Set the SYSTEM_IDLE_TIMEOUT to 80 ns on nForce2 systems to work
  * around a hang that is triggered when the CPU generates a very fast

--------------060602050004030601060907
Content-Type: text/plain;
 name="intel-rtc-nvram.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="intel-rtc-nvram.diff"

diff --git a/sys/dev/nvram/nvram.c b/sys/dev/nvram/nvram.c
index 164287e..7c323f7 100644
--- a/sys/dev/nvram/nvram.c
+++ b/sys/dev/nvram/nvram.c
@@ -53,7 +53,7 @@
  */
 
 #define NVRAM_FIRST	RTC_DIAG	/* 14 */
-#define NVRAM_LAST	128
+#define NVRAM_LAST	256
 
 #define CKSUM_FIRST	2
 #define CKSUM_LAST	31
@@ -113,6 +113,7 @@ nvram_write(struct cdev *dev, struct uio *uio, int flags)
 	u_char v;
 	int error = 0;
 	int i;
+	int recalc = 0;
 	uint16_t sum;
 
 	sx_xlock(&nvram_lock);
@@ -129,20 +130,24 @@ nvram_write(struct cdev *dev, struct uio *uio, int flags)
 	/* Bring in user data and write */
 	while (uio->uio_resid > 0 && error == 0) {
 		nv_off = uio->uio_offset + NVRAM_FIRST;
-		if (nv_off < NVRAM_FIRST || nv_off >= NVRAM_LAST) {
-			sx_xunlock(&nvram_lock);
-			return (0);	/* Signal EOF */
-		}
+		if (nv_off < NVRAM_FIRST || nv_off >= NVRAM_LAST)
+			break;
+		if (nv_off >= (NVRAM_FIRST + CKSUM_FIRST)
+		    && nv_off <= (NVRAM_FIRST + CKSUM_LAST))
+			recalc = 1;
+
 		/* Single byte at a time */
 		error = uiomove(&v, 1, uio);
 		writertc(nv_off, v);
 	}
 	/* Recalculate checksum afterwards */
-	sum = 0;
-	for (i = CKSUM_FIRST; i <= CKSUM_LAST; i++)
-		sum += rtcin(NVRAM_FIRST + i);
-	writertc(NVRAM_FIRST + CKSUM_MSB, sum >> 8);
-	writertc(NVRAM_FIRST + CKSUM_LSB, sum);
+	if (recalc) {
+		sum = 0;
+		for (i = CKSUM_FIRST; i <= CKSUM_LAST; i++)
+			sum += rtcin(NVRAM_FIRST + i);
+		writertc(NVRAM_FIRST + CKSUM_MSB, sum >> 8);
+		writertc(NVRAM_FIRST + CKSUM_LSB, sum);
+	}
 	sx_xunlock(&nvram_lock);
 	return (error);
 }
diff --git a/sys/isa/rtc.h b/sys/isa/rtc.h
index 018a4ed..43a9c15 100644
--- a/sys/isa/rtc.h
+++ b/sys/isa/rtc.h
@@ -115,12 +115,12 @@
 extern  struct mtx clock_lock;
 extern	int atrtcclock_disable;
 int	atrtc_setup_clock(void);
-int	rtcin(int reg);
+u_char	rtcin(u_char reg);
 void	atrtc_start(void);
 void	atrtc_rate(unsigned rate);
 void	atrtc_enable_intr(void);
 void	atrtc_restore(void);
-void	writertc(int reg, u_char val);
+void	writertc(u_char reg, u_char val);
 #endif
 
 #endif /* _I386_ISA_RTC_H_ */
diff --git a/sys/x86/isa/atrtc.c b/sys/x86/isa/atrtc.c
index 777c720..9f9f0ac 100644
--- a/sys/x86/isa/atrtc.c
+++ b/sys/x86/isa/atrtc.c
@@ -59,35 +59,51 @@ static	u_char	rtc_statusb = RTCSB_24HR;
  * RTC support routines
  */
 
-int
-rtcin(int reg)
+u_char
+rtcin(u_char reg)
 {
 	u_char val;
+	int idxr;
+	int datr;
+
+	if (reg & 0x80)
+		idxr = IO_RTC + 2; /* upper bank */
+	else
+		idxr = IO_RTC;     /* lower bank */
+	datr = idxr + 1;
 
 	RTC_LOCK;
 	if (rtc_reg != reg) {
 		inb(0x84);
-		outb(IO_RTC, reg);
+		outb(idxr, reg & 0x7f);
 		rtc_reg = reg;
 		inb(0x84);
 	}
-	val = inb(IO_RTC + 1);
+	val = inb(datr);
 	RTC_UNLOCK;
 	return (val);
 }
 
 void
-writertc(int reg, u_char val)
+writertc(u_char reg, u_char val)
 {
+	int idxr;
+	int datr;
+
+	if (reg & 0x80)
+		idxr = IO_RTC + 2; /* upper bank */
+	else
+		idxr = IO_RTC;     /* lower bank */
+	datr = idxr + 1;
 
 	RTC_LOCK;
 	if (rtc_reg != reg) {
 		inb(0x84);
-		outb(IO_RTC, reg);
+		outb(idxr, reg & 0x7f);
 		rtc_reg = reg;
 		inb(0x84);
 	}
-	outb(IO_RTC + 1, val);
+	outb(datr, val);
 	inb(0x84);
 	RTC_UNLOCK;
 }

--------------060602050004030601060907
Content-Type: text/plain;
 name="dev-nvram.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="dev-nvram.diff"

diff --git a/sys/dev/nvram/nvram.c b/sys/dev/nvram/nvram.c
index 7c323f7..716f4b9 100644
--- a/sys/dev/nvram/nvram.c
+++ b/sys/dev/nvram/nvram.c
@@ -39,33 +39,15 @@
 
 #include <isa/rtc.h>
 
-/*
- * Linux-style /dev/nvram driver
- *
- * cmos ram starts at bytes 14 through 128, for a total of 114 bytes.
- * The driver exposes byte 14 as file offset 0.
- *
- * Offsets 2 through 31 are checksummed at offset 32, 33.
- * In order to avoid the possibility of making the machine unbootable at the
- * bios level (press F1 to continue!), we refuse to allow writes if we do
- * not see a pre-existing valid checksum.  If the existing sum is invalid,
- * then presumably we do not know how to make a sum that the bios will accept.
- */
 
 #define NVRAM_FIRST	RTC_DIAG	/* 14 */
-#define NVRAM_LAST	256
-
-#define CKSUM_FIRST	2
-#define CKSUM_LAST	31
-#define CKSUM_MSB	32
-#define CKSUM_LSB	33
+#define NVRAM_LAST	0xff
 
 static d_open_t		nvram_open;
 static d_read_t		nvram_read;
 static d_write_t	nvram_write;
 
 static struct cdev *nvram_dev;
-static struct sx nvram_lock;
 
 static struct cdevsw nvram_cdevsw = {
 	.d_version =	D_VERSION,
@@ -94,12 +76,19 @@ nvram_read(struct cdev *dev, struct uio *uio, int flags)
 	u_char v;
 	int error = 0;
 
+	if (uio->uio_offset < 0)
+		return 0;
+
 	while (uio->uio_resid > 0 && error == 0) {
-		nv_off = uio->uio_offset + NVRAM_FIRST;
-		if (nv_off < NVRAM_FIRST || nv_off >= NVRAM_LAST)
+		nv_off = uio->uio_offset;
+		if (nv_off > NVRAM_LAST)
 			return (0);	/* Signal EOF */
+
 		/* Single byte at a time */
-		v = rtcin(nv_off);
+		if (nv_off < NVRAM_FIRST)
+			v = 0xff;
+		else
+			v = rtcin(nv_off);
 		error = uiomove(&v, 1, uio);
 	}
 	return (error);
@@ -112,44 +101,28 @@ nvram_write(struct cdev *dev, struct uio *uio, int flags)
 	int nv_off;
 	u_char v;
 	int error = 0;
-	int i;
-	int recalc = 0;
-	uint16_t sum;
-
-	sx_xlock(&nvram_lock);
-
-	/* Assert that we understand the existing checksum first!  */
-	sum = rtcin(NVRAM_FIRST + CKSUM_MSB) << 8 |
-	      rtcin(NVRAM_FIRST + CKSUM_LSB);
-	for (i = CKSUM_FIRST; i <= CKSUM_LAST; i++)
-		sum -= rtcin(NVRAM_FIRST + i);
-	if (sum != 0) {
-		sx_xunlock(&nvram_lock);
-		return (EIO);
-	}
+
+	if (uio->uio_offset < 0)
+		return 0;
+
 	/* Bring in user data and write */
-	while (uio->uio_resid > 0 && error == 0) {
-		nv_off = uio->uio_offset + NVRAM_FIRST;
-		if (nv_off < NVRAM_FIRST || nv_off >= NVRAM_LAST)
-			break;
-		if (nv_off >= (NVRAM_FIRST + CKSUM_FIRST)
-		    && nv_off <= (NVRAM_FIRST + CKSUM_LAST))
-			recalc = 1;
+	while (uio->uio_resid > 0) {
+		nv_off = uio->uio_offset;
+		if (nv_off > NVRAM_LAST)
+			return (0);
 
 		/* Single byte at a time */
 		error = uiomove(&v, 1, uio);
+		if (error)
+			return (error);
+
+		if (nv_off < NVRAM_FIRST)
+			continue;
+
 		writertc(nv_off, v);
 	}
-	/* Recalculate checksum afterwards */
-	if (recalc) {
-		sum = 0;
-		for (i = CKSUM_FIRST; i <= CKSUM_LAST; i++)
-			sum += rtcin(NVRAM_FIRST + i);
-		writertc(NVRAM_FIRST + CKSUM_MSB, sum >> 8);
-		writertc(NVRAM_FIRST + CKSUM_LSB, sum);
-	}
-	sx_xunlock(&nvram_lock);
-	return (error);
+
+	return (0);
 }
 
 static int
@@ -157,14 +130,12 @@ nvram_modevent(module_t mod __unused, int type, void *data __unused)
 {
 	switch (type) {
 	case MOD_LOAD:
-		sx_init(&nvram_lock, "nvram");
 		nvram_dev = make_dev(&nvram_cdevsw, 0,
 		    UID_ROOT, GID_KMEM, 0640, "nvram");
 		break;
 	case MOD_UNLOAD:
 	case MOD_SHUTDOWN:
 		destroy_dev(nvram_dev);
-		sx_destroy(&nvram_lock);
 		break;
 	default:
 		return (EOPNOTSUPP);

--------------060602050004030601060907
Content-Type: text/plain;
 name="amd-cmos-nvram.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="amd-cmos-nvram.diff"

diff --git a/sys/amd64/conf/NOTES b/sys/amd64/conf/NOTES
index 8b56e54..d18736e 100644
--- a/sys/amd64/conf/NOTES
+++ b/sys/amd64/conf/NOTES
@@ -86,6 +86,11 @@ options 	BPF_JITTER
 # Provide read/write access to the memory in the clock chip.
 device		nvram		# Access to rtc cmos via /dev/nvram
 
+# Whether 72h/73h access to RTC NVRAM should use 7-bit index and
+# access only 128 bytes of upper bank (Intel chipsets) or it can
+# use 8-bit index and access all 256 bytes of NVRAM (AMD chipsets).
+#options 	RTC_8BIT_EXTINDEX
+
 
 #####################################################################
 # MISCELLANEOUS DEVICES AND OPTIONS
diff --git a/sys/conf/options.amd64 b/sys/conf/options.amd64
index 5617da4..30af3cc 100644
--- a/sys/conf/options.amd64
+++ b/sys/conf/options.amd64
@@ -61,3 +61,6 @@ KDTRACE_FRAME		opt_kdtrace.h
 BPF_JITTER		opt_bpf.h
 
 XENHVM			opt_global.h
+
+# ISA options
+RTC_8BIT_EXTINDEX	opt_isa.h
diff --git a/sys/conf/options.i386 b/sys/conf/options.i386
index 83f8286..a4ce060 100644
--- a/sys/conf/options.i386
+++ b/sys/conf/options.i386
@@ -117,3 +117,7 @@ BPF_JITTER		opt_bpf.h
 
 NATIVE			opt_global.h
 XEN			opt_global.h
+
+# ISA options
+RTC_8BIT_EXTINDEX	opt_isa.h
+
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index af3da83..4fb11ae 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -261,6 +261,11 @@ options 	BPF_JITTER
 # Provide read/write access to the memory in the clock chip.
 device		nvram		# Access to rtc cmos via /dev/nvram
 
+# Whether 72h/73h access to RTC NVRAM should use 7-bit index and
+# access only 128 bytes of upper bank (Intel chipsets) or it can
+# use 8-bit index and access all 256 bytes of NVRAM (AMD chipsets).
+#options 	RTC_8BIT_EXTINDEX
+
 
 #####################################################################
 # MISCELLANEOUS DEVICES AND OPTIONS
diff --git a/sys/x86/isa/atrtc.c b/sys/x86/isa/atrtc.c
index 9f9f0ac..a77e14c 100644
--- a/sys/x86/isa/atrtc.c
+++ b/sys/x86/isa/atrtc.c
@@ -75,7 +75,11 @@ rtcin(u_char reg)
 	RTC_LOCK;
 	if (rtc_reg != reg) {
 		inb(0x84);
+#ifndef RTC_8BIT_EXTINDEX
 		outb(idxr, reg & 0x7f);
+#else
+		outb(idxr, reg);
+#endif
 		rtc_reg = reg;
 		inb(0x84);
 	}
@@ -99,7 +103,11 @@ writertc(u_char reg, u_char val)
 	RTC_LOCK;
 	if (rtc_reg != reg) {
 		inb(0x84);
+#ifndef RTC_8BIT_EXTINDEX
 		outb(idxr, reg & 0x7f);
+#else
+		outb(idxr, reg);
+#endif
 		rtc_reg = reg;
 		inb(0x84);
 	}

--------------060602050004030601060907--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4B979E31.1050509>