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);