Module Name:    src
Committed By:   thorpej
Date:           Wed Jan 27 05:11:54 UTC 2021

Modified Files:
        src/sys/dev/acpi: acpi_util.c acpivar.h

Log Message:
Introduce weighted matching for ACPI autoconfiguration, and provide
acpi_compatible_match() based around device_compatible_entry.  Matches
against _HID score big, matches against _CID are weighted in the
standard most-to-least-specific ordering, less than _HID.

Also provide a maching value for _CLS, that's always less than _HID
and _CID matches, and use that in acpi_match_class().

Also provide acpi_compatible_lookup(), that returing the matching
entry based on the same criteria.


To generate a diff of this commit:
cvs rdiff -u -r1.22 -r1.23 src/sys/dev/acpi/acpi_util.c
cvs rdiff -u -r1.83 -r1.84 src/sys/dev/acpi/acpivar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/acpi/acpi_util.c
diff -u src/sys/dev/acpi/acpi_util.c:1.22 src/sys/dev/acpi/acpi_util.c:1.23
--- src/sys/dev/acpi/acpi_util.c:1.22	Tue Jan 26 00:23:16 2021
+++ src/sys/dev/acpi/acpi_util.c	Wed Jan 27 05:11:54 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: acpi_util.c,v 1.22 2021/01/26 00:23:16 jmcneill Exp $ */
+/*	$NetBSD: acpi_util.c,v 1.23 2021/01/27 05:11:54 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2003, 2007, 2021 The NetBSD Foundation, Inc.
@@ -65,7 +65,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_util.c,v 1.22 2021/01/26 00:23:16 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_util.c,v 1.23 2021/01/27 05:11:54 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/kmem.h>
@@ -306,7 +306,7 @@ acpi_name(ACPI_HANDLE handle)
 }
 
 /*
- * Pack _HID and _CID ID strings into an OpenFirmware-like
+ * Pack _HID and _CID ID strings into an OpenFirmware-style
  * string list.
  */
 char *
@@ -314,49 +314,143 @@ acpi_pack_compat_list(ACPI_DEVICE_INFO *
 {
 	KASSERT(sizep != NULL);
 
-	char *strlist, *cp;
-	size_t len = 0;
+	char *sl = NULL;
+	size_t slsize = 0;
 	uint32_t i;
 
-	/*
-	 * First calculate the total size required.
-	 * N.B. PNP Device ID length includes terminating NUL.
-	 */
 	if ((ad->Valid & ACPI_VALID_HID) != 0) {
-		len += ad->HardwareId.Length;
+		strlist_append(&sl, &slsize, ad->HardwareId.String);
 	}
 
 	if ((ad->Valid & ACPI_VALID_CID) != 0) {
 		for (i = 0; i < ad->CompatibleIdList.Count; i++) {
-			len += ad->CompatibleIdList.Ids[i].Length;
+			strlist_append(&sl, &slsize,
+			    ad->CompatibleIdList.Ids[i].String);
 		}
 	}
 
-	*sizep = len;
-	if (len == 0) {
-		return NULL;
+	*sizep = slsize;
+	return sl;
+}
+
+/*
+ * The ACPI_PNP_DEVICE_ID type is somewhat inconvenient for us to
+ * use.  We'll need some temporary space to pack it into an array
+ * of C strings.  Room for 8 should be plenty, but we can allocate
+ * more if necessary.
+ */
+#define	ACPI_COMPATSTR_MAX	8
+
+static const char **
+acpi_compatible_alloc_strarray(ACPI_PNP_DEVICE_ID *ids,
+    unsigned int count, const char **buf)
+{
+	unsigned int i;
+
+	buf = kmem_tmpbuf_alloc(count * sizeof(const char *),
+	    buf, ACPI_COMPATSTR_MAX * sizeof(const char *), KM_SLEEP);
+	for (i = 0; i < count; i++) {
+		buf[i] = ids[i].String;
+	}
+	return buf;
+}
+
+static void
+acpi_compatible_free_strarray(const char **cpp, unsigned int count,
+    const char **buf)
+{
+	kmem_tmpbuf_free(cpp, count * sizeof(const char *), buf);
+}
+
+/*
+ * acpi_compatible_match --
+ *
+ *	Returns a weighted match value, comparing the _HID and _CID
+ *	IDs against a driver's compatbility data.
+ */
+int
+acpi_compatible_match(const struct acpi_attach_args * const aa,
+    const struct device_compatible_entry * const dce)
+{
+	const char *strings[ACPI_COMPATSTR_MAX * sizeof(const char *)];
+	const char **cpp;
+
+	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) {
+		return 0;
 	}
 
-	cp = strlist = kmem_alloc(len, KM_SLEEP);
+	ACPI_DEVICE_INFO *ad = aa->aa_node->ad_devinfo;
 
 	if ((ad->Valid & ACPI_VALID_HID) != 0) {
-		memcpy(cp, ad->HardwareId.String, ad->HardwareId.Length);
-		cp += ad->HardwareId.Length;
+		strings[0] = ad->HardwareId.String;
+
+		/* Matching _HID wins big. */
+		if (device_compatible_pmatch(strings, 1, dce) != 0) {
+			return ACPI_MATCHSCORE_HID;
+		}
 	}
 
 	if ((ad->Valid & ACPI_VALID_CID) != 0) {
-		for (i = 0; i < ad->CompatibleIdList.Count; i++) {
-			memcpy(cp, ad->CompatibleIdList.Ids[i].String,
-			    ad->CompatibleIdList.Ids[i].Length);
-			cp += ad->CompatibleIdList.Ids[i].Length;
+		cpp = acpi_compatible_alloc_strarray(ad->CompatibleIdList.Ids,
+		    ad->CompatibleIdList.Count, strings);
+		int rv;
+
+		rv = device_compatible_pmatch(cpp,
+		    ad->CompatibleIdList.Count, dce);
+		acpi_compatible_free_strarray(cpp, ad->CompatibleIdList.Count,
+		    strings);
+		if (rv) {
+			rv = (rv - 1) + ACPI_MATCHSCORE_CID;
+			if (rv > ACPI_MATCHSCORE_CID_MAX) {
+				rv = ACPI_MATCHSCORE_CID_MAX;
+			}
+			return rv;
 		}
 	}
 
-	KASSERT((size_t)(cp - strlist) == len);
-
-	return strlist;
+	return 0;
 }
 
+/*
+ * acpi_compatible_lookup --
+ *
+ *	Returns the device_compatible_entry that matches the _HID
+ *	or _CID ID.
+ */
+const struct device_compatible_entry *
+acpi_compatible_lookup(const struct acpi_attach_args * const aa,
+    const struct device_compatible_entry * const dce)
+{
+	const struct device_compatible_entry *rv = NULL;
+	const char *strings[ACPI_COMPATSTR_MAX];
+	const char **cpp;
+
+	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) {
+		return NULL;
+	}
+
+	ACPI_DEVICE_INFO *ad = aa->aa_node->ad_devinfo;
+
+	if ((ad->Valid & ACPI_VALID_HID) != 0) {
+		strings[0] = ad->HardwareId.String;
+
+		rv = device_compatible_plookup(strings, 1, dce);
+		if (rv != NULL)
+			return rv;
+	}
+
+	if ((ad->Valid & ACPI_VALID_CID) != 0) {
+		cpp = acpi_compatible_alloc_strarray(ad->CompatibleIdList.Ids,
+		    ad->CompatibleIdList.Count, strings);
+
+		rv = device_compatible_plookup(cpp,
+		    ad->CompatibleIdList.Count, dce);
+		acpi_compatible_free_strarray(cpp, ad->CompatibleIdList.Count,
+		    strings);
+	}
+
+	return rv;
+}
 
 /*
  * Match given IDs against _HID and _CIDs.
@@ -428,7 +522,7 @@ acpi_match_class(ACPI_HANDLE handle, uin
 done:
 	if (buf.Pointer)
 		ACPI_FREE(buf.Pointer);
-	return match;
+	return match ? ACPI_MATCHSCORE_CLS : 0;
 }
 
 /*

Index: src/sys/dev/acpi/acpivar.h
diff -u src/sys/dev/acpi/acpivar.h:1.83 src/sys/dev/acpi/acpivar.h:1.84
--- src/sys/dev/acpi/acpivar.h:1.83	Sun Dec  6 11:38:28 2020
+++ src/sys/dev/acpi/acpivar.h	Wed Jan 27 05:11:54 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: acpivar.h,v 1.83 2020/12/06 11:38:28 jmcneill Exp $	*/
+/*	$NetBSD: acpivar.h,v 1.84 2021/01/27 05:11:54 thorpej Exp $	*/
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -195,6 +195,12 @@ struct acpi_attach_args {
 	bus_dma_tag_t aa_dmat64;	/* PCI 64bit DMA tag */
 };
 
+/* ACPI driver matching scores. */
+#define	ACPI_MATCHSCORE_HID		100	/* matched _HID */
+#define	ACPI_MATCHSCORE_CID_MAX		49
+#define	ACPI_MATCHSCORE_CID		10	/* matched _CID */
+#define	ACPI_MATCHSCORE_CLS		1	/* matched _CLS */
+
 /*
  * ACPI resources:
  *
@@ -306,6 +312,12 @@ int		acpi_probe(void);
 void		acpi_disable(void);
 int		acpi_check(device_t, const char *);
 
+int		acpi_compatible_match(const struct acpi_attach_args *,
+		    const struct device_compatible_entry *);
+const struct device_compatible_entry *
+		acpi_compatible_lookup(const struct acpi_attach_args *,
+		    const struct device_compatible_entry *);
+
 bool    	acpi_device_present(ACPI_HANDLE);
 
 int		acpi_reset(void);

Reply via email to