Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 14 Mar 2015 23:40:34 -0400
From:      Anthony Jenkins <Anthony.B.Jenkins@att.net>
To:        Ian Smith <smithi@nimnet.asn.au>
Cc:        freebsd-acpi@freebsd.org
Subject:   [PATCH] ACPI CMOS region support rev. 4
Message-ID:  <5504FF32.3020202@att.net>
In-Reply-To: <54F9D7E6.4050807@att.net>
References:  <20150222180817.GD27984@strugglingcoder.info> <54EB8C21.2080600@att.net> <2401337.2oUs7iAbtB@ralph.baldwin.cx> <54EF3D5D.4010106@att.net> <20150227222203.P38620@sola.nimnet.asn.au> <20150228125857.D1277@besplex.bde.org> <54F14368.4020807@att.net> <20150302002647.W42658@sola.nimnet.asn.au> <54F5E53D.1090601@att.net> <20150306025800.U46361@sola.nimnet.asn.au> <54F9D7E6.4050807@att.net>

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

How about this one? :-)  Sorry it's a week late.

Anthony

On 03/06/15 11:37, Anthony Jenkins wrote:
> On 03/06/2015 06:49 AM, Ian Smith wrote:
>> On Tue, 3 Mar 2015 11:45:49 -0500, Anthony Jenkins wrote:
>>  > On 03/01/2015 09:29 AM, Ian Smith wrote:
>>  [..]
>> Regarding systems without ACPI loaded, or active: what happens when the 
>> below AcpiInstallAddressSpaceHandler() call fails, but returns 0?  Would 
>> not that prevent rtc_start() from running atrtc_start() etc for non-ACPI 
>> clock initialisation and registration?
> Good catch, there's technically no reason to bail on rtc_start() if I
> fail to register the ACPI CMOS handler; it'll just never get called
> (same as old behaviour).  I'll change "Error" to "Warning" and remove
> the return 0.
>
>> I suppose there's a global kernel variable for acpi_is_active ono?
>>
>>  > +static int
>>  >  rtc_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
>>  >  {
>>  >
>>  > @@ -245,10 +323,17 @@
>>  >      int i;
>>  >
>>  >      sc = device_get_softc(dev);
>>  > +    sc->acpi_handle = acpi_get_handle(dev);
>>  >      sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid,
>>  >          IO_RTC, IO_RTC + 1, 2, RF_ACTIVE);
>>  >      if (sc->port_res == NULL)
>>  >              device_printf(dev, "Warning: Couldn't map I/O.\n");
>>  > +    if (ACPI_FAILURE(AcpiInstallAddressSpaceHandler(sc->acpi_handle,
>>  > +        ACPI_ADR_SPACE_CMOS, acpi_rtc_cmos_handler, NULL, sc)))
>>  > +    {
>>  > +            device_printf(dev, "Error registering ACPI CMOS address space handler.\n");
>>  > +            return 0;
>>  > +    }
>>  >      atrtc_start();
>>  >      clock_register(dev, 1000000);
>>  >      bzero(&sc->et, sizeof(struct eventtimer));
>>  > @@ -286,6 +371,15 @@
>>  >      return(0);
>>  >  }
>>  
>> Might that not matter for detach, as you're not testing for return code?
> Yeah I'd prefer to remember the failure to install the handler and
> conditionally uninstall it in the detach method.
>
> I'll fix up the logging and add these suggestions this weekend.
>
> Thanks,
> Anthony
>
>>  > +static int atrtc_detach(device_t dev)
>>  > +{
>>  > +    struct atrtc_softc *sc;
>>  > +
>>  > +    sc = device_get_softc(dev);
>>  > +    AcpiRemoveAddressSpaceHandler(sc->acpi_handle, 
>>  >          ACPI_ADR_SPACE_CMOS, acpi_rtc_cmos_handler);
>>  > +    return bus_generic_detach(dev);
>>  > +}
>>  
>> cheers, Ian
>> _______________________________________________
>> freebsd-acpi@freebsd.org mailing list
>> http://lists.freebsd.org/mailman/listinfo/freebsd-acpi
>> To unsubscribe, send any mail to "freebsd-acpi-unsubscribe@freebsd.org"
> _______________________________________________
> freebsd-acpi@freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-acpi
> To unsubscribe, send any mail to "freebsd-acpi-unsubscribe@freebsd.org"


--------------090406000600090209050409
Content-Type: text/x-patch;
 name="atrtc_c_rev4.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="atrtc_c_rev4.diff"

Index: sys/x86/isa/atrtc.c
===================================================================
--- sys/x86/isa/atrtc.c	(revision 279957)
+++ sys/x86/isa/atrtc.c	(working copy)
@@ -31,6 +31,7 @@
 __FBSDID("$FreeBSD$");
 
 #include "opt_isa.h"
+#include "opt_acpi.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -53,9 +54,17 @@
 #include <machine/intr_machdep.h>
 #include "clock_if.h"
 
+#include <contrib/dev/acpica/include/acpi.h>
+#include <contrib/dev/acpica/include/accommon.h>
+#include <dev/acpica/acpivar.h>
+
 #define	RTC_LOCK	do { if (!kdb_active) mtx_lock_spin(&clock_lock); } while (0)
 #define	RTC_UNLOCK	do { if (!kdb_active) mtx_unlock_spin(&clock_lock); } while (0)
 
+#define IO_DELAY()	(void)inb(0x84)
+#define IO_RTC_ADDR	(IO_RTC + 0)
+#define IO_RTC_DATA	(IO_RTC + 1)
+
 int	atrtcclock_disable = 0;
 
 static	int	rtc_reg = -1;
@@ -62,6 +71,12 @@
 static	u_char	rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
 static	u_char	rtc_statusb = RTCSB_24HR;
 
+static unsigned int atrtc_verbose = 0;
+SYSCTL_UINT(_debug, OID_AUTO, atrtc_verbose, CTLFLAG_RWTUN,
+	&atrtc_verbose, 0, "AT-RTC Debug Level (0-2)");
+#define ATRTC_DBG_PRINTF(level, format, ...) \
+	if (atrtc_verbose >= level) printf(format, ##__VA_ARGS__)
+
 /*
  * RTC support routines
  */
@@ -73,10 +88,10 @@
 
 	RTC_LOCK;
 	if (rtc_reg != reg) {
-		inb(0x84);
+		IO_DELAY();
 		outb(IO_RTC, reg);
 		rtc_reg = reg;
-		inb(0x84);
+		IO_DELAY();
 	}
 	val = inb(IO_RTC + 1);
 	RTC_UNLOCK;
@@ -89,16 +104,36 @@
 
 	RTC_LOCK;
 	if (rtc_reg != reg) {
-		inb(0x84);
+		IO_DELAY();
 		outb(IO_RTC, reg);
 		rtc_reg = reg;
-		inb(0x84);
+		IO_DELAY();
 	}
 	outb(IO_RTC + 1, val);
-	inb(0x84);
+	IO_DELAY();
 	RTC_UNLOCK;
 }
 
+static void
+acpi_cmos_read(ACPI_PHYSICAL_ADDRESS address, UINT8 *buf, UINT32 buflen)
+{
+	UINT32 offset;
+
+	for (offset = 0; offset < buflen; ++offset) {
+		buf[offset] = rtcin(address + offset) & 0xff;
+	}
+}
+
+static void
+acpi_cmos_write(ACPI_PHYSICAL_ADDRESS address, const UINT8 *buf, UINT32 buflen)
+{
+	UINT32 offset;
+
+	for (offset = 0; offset < buflen; ++offset) {
+		writertc(address + offset, buf[offset]);
+	}
+}
+
 static __inline int
 readrtc(int port)
 {
@@ -161,9 +196,68 @@
 	struct resource *intr_res;
 	void *intr_handler;
 	struct eventtimer et;
+	ACPI_HANDLE acpi_handle;	/* Handle of the PNP0B00 node */
+	int acpi_handle_registered;	/* 0 = acpi_handle not registered */
 };
 
 static int
+acpi_check_rtc_byteaccess(int is_read, u_long addr)
+{
+	int retval = 1;	/* Success */
+
+	if (is_read) {
+		/* Reading 0x0C will muck with interrupts */
+		if (addr == 0x0C)
+			retval = 0;
+	} else {
+		if (!((addr <= 0x05 && (addr & 0x01)) ||
+		   (addr >= 0x30 && addr < 0x40)))
+			retval = 0;
+	}
+	return retval;
+}
+
+static ACPI_STATUS
+acpi_rtc_cmos_handler(UINT32 function, ACPI_PHYSICAL_ADDRESS address,
+    UINT32 width, UINT64 *value, void *context, void *region_context)
+{
+	struct atrtc_softc *sc;
+
+	sc = (struct atrtc_softc *)context;
+	if (!value || !sc) {
+		ATRTC_DBG_PRINTF(1, "%s: NULL parameter.\n", __FUNCTION__);
+		return AE_BAD_PARAMETER;
+	}
+	if (width > 32 || (width & 0x07) || address >= 64) {
+		ATRTC_DBG_PRINTF(1, "%s: Invalid width (%u) or address (0x%08lx).\n",
+			__FUNCTION__, width, address);
+		return AE_BAD_PARAMETER;
+	}
+	if (!acpi_check_rtc_byteaccess(function == ACPI_READ, address)) {
+		ATRTC_DBG_PRINTF(1, "%s: Bad CMOS %s access at address 0x%08lx.\n",
+			__FUNCTION__, function == ACPI_READ ? "read" : "write", address);
+		return AE_BAD_PARAMETER;
+	}
+
+	switch (function) {
+		case ACPI_READ:
+			acpi_cmos_read(address, (UINT8 *)value, width >> 3);
+			break;
+		case ACPI_WRITE:
+			acpi_cmos_write(address, (const UINT8 *)value,
+			    width >> 3);
+			break;
+		default:
+			ATRTC_DBG_PRINTF(1, "%s: Invalid function: %d.\n", __FUNCTION__, function);
+			return AE_BAD_PARAMETER;
+	}
+	ATRTC_DBG_PRINTF(1, "%s: %-5s%02u address=%04lx value=%08x\n",
+			__FUNCTION__, function == ACPI_READ ? "READ" : "WRITE",
+			width >> 3, address, *((UINT32 *)value));
+	return AE_OK;
+}
+
+static int
 rtc_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
 {
 
@@ -245,10 +339,19 @@
 	int i;
 
 	sc = device_get_softc(dev);
+	sc->acpi_handle = acpi_get_handle(dev);
 	sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid,
 	    IO_RTC, IO_RTC + 1, 2, RF_ACTIVE);
 	if (sc->port_res == NULL)
 		device_printf(dev, "Warning: Couldn't map I/O.\n");
+	if (ACPI_FAILURE(AcpiInstallAddressSpaceHandler(sc->acpi_handle,
+					ACPI_ADR_SPACE_CMOS,
+					acpi_rtc_cmos_handler, NULL, sc)))
+	{
+		device_printf(dev, "Warning: Couldn't register ACPI CMOS address space handler.\n");
+		/* I assume the softc was memset() to 0? */
+	} else
+		sc->acpi_handle_registered = 1;
 	atrtc_start();
 	clock_register(dev, 1000000);
 	bzero(&sc->et, sizeof(struct eventtimer));
@@ -286,6 +389,17 @@
 	return(0);
 }
 
+static int atrtc_detach(device_t dev)
+{
+	struct atrtc_softc *sc;
+
+	sc = device_get_softc(dev);
+	if (sc->acpi_handle_registered)
+		AcpiRemoveAddressSpaceHandler(sc->acpi_handle,
+				ACPI_ADR_SPACE_CMOS, acpi_rtc_cmos_handler);
+	return bus_generic_detach(dev);
+}
+
 static int
 atrtc_resume(device_t dev)
 {
@@ -366,7 +480,7 @@
 	/* Device interface */
 	DEVMETHOD(device_probe,		atrtc_probe),
 	DEVMETHOD(device_attach,	atrtc_attach),
-	DEVMETHOD(device_detach,	bus_generic_detach),
+	DEVMETHOD(device_detach,	atrtc_detach),
 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
 	DEVMETHOD(device_suspend,	bus_generic_suspend),
 		/* XXX stop statclock? */

--------------090406000600090209050409--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5504FF32.3020202>