git: 45b49a0f96e0 - stable/13 - device: add device_get_property and device_has_property

From: Marcin Wojtas <mw_at_FreeBSD.org>
Date: Tue, 29 Mar 2022 22:59:54 UTC
The branch stable/13 has been updated by mw:

URL: https://cgit.FreeBSD.org/src/commit/?id=45b49a0f96e0ec70a7a35a83c74346413fb9eb76

commit 45b49a0f96e0ec70a7a35a83c74346413fb9eb76
Author:     Bartlomiej Grzesik <bag@semihalf.com>
AuthorDate: 2021-07-30 08:57:06 +0000
Commit:     Marcin Wojtas <mw@FreeBSD.org>
CommitDate: 2022-03-29 22:24:26 +0000

    device: add device_get_property and device_has_property
    
    Generialize bus specific property accessors. Those functions allow driver code
    to access device specific information.
    
    Currently there is only support for FDT and ACPI buses.
    
    Reviewed by: manu, mw
    Sponsored by: Semihalf
    Differential revision: https://reviews.freebsd.org/D31597
    
    (cherry picked from commit 3f9a00e3b577dcca57e331842e0baf2dbdf9325f)
    
    acpi: Fix error code returned in acpi_bus_get_prop
    
    ACPI implementation of device_get_property would return "-1" when
    property was found, but it's type wasn't supported.
    This causes device_has_property to return false in that scenario, which
    arguably could be considered as incorrect.
    
    Fix that by returning "0" in that case.
    
    Reviewed by: bz, mw
    Tested by: mw
    MFC after: 2 weeks
    Obtained from: Semihalf
    Differential Revision: https://reviews.freebsd.org/D33103
    
    (cherry picked from commit d9ed1dcc5c6894e376e6e4ef6f2554dd056baf4e)
---
 share/man/man9/BUS_GET_PROPERTY.9    | 65 ++++++++++++++++++++++++++++++++++
 share/man/man9/Makefile              |  2 ++
 share/man/man9/device_get_property.9 | 67 ++++++++++++++++++++++++++++++++++++
 sys/dev/acpica/acpi.c                | 38 ++++++++++++++++++++
 sys/dev/fdt/simplebus.c              | 16 +++++++++
 sys/kern/bus_if.m                    | 31 +++++++++++++++++
 sys/kern/subr_bus.c                  | 14 ++++++++
 sys/sys/bus.h                        |  2 ++
 8 files changed, 235 insertions(+)

diff --git a/share/man/man9/BUS_GET_PROPERTY.9 b/share/man/man9/BUS_GET_PROPERTY.9
new file mode 100644
index 000000000000..89edbd95b68c
--- /dev/null
+++ b/share/man/man9/BUS_GET_PROPERTY.9
@@ -0,0 +1,65 @@
+.\" -
+.\" SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+.\"
+.\" Copyright (c) 2021 Semihalf
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 19, 2021
+.Dt BUS_GET_PROPERTY 9
+.Os
+.Sh NAME
+.Nm BUS_GET_PROPERTY
+.Nd get child's specific property
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/bus.h
+.Ft ssize_t
+.Fn BUS_GET_PROPERTY "device_t dev" "device_t child" "const char *propname" \
+    "void *propvalue" "size_t size"
+.Sh DESCRIPTION
+The
+.Fn BUS_GET_PROPERTY
+method
+is called from driver code which wants to access child's specific data stored
+on the bus.
+Property consits of its name and value.
+Implementation shall copy to
+.Fa propvalue
+at most
+.Fa size
+bytes.
+.Sh NOTES
+If
+.Fa propvalue
+is NULL or
+.Fa size
+is zero, then implementation shall only return size of the property.
+.Sh RETURN VALUES
+Property's size if successful, otherwise -1.
+.Sh SEE ALSO
+.Xr device 9 ,
+.Xr device_get_property 9
+.Sh AUTHORS
+This manual page was written by
+.An Bartlomiej Grzesik .
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index 73ebdef29180..a7c3d69f4e70 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -44,6 +44,7 @@ MAN=	accept_filter.9 \
 	bus_generic_read_ivar.9 \
 	bus_generic_shutdown.9 \
 	BUS_GET_CPUS.9 \
+	BUS_GET_PROPERTY.9 \
 	bus_get_resource.9 \
 	bus_map_resource.9 \
 	BUS_NEW_PASS.9 \
@@ -106,6 +107,7 @@ MAN=	accept_filter.9 \
 	device_get_ivars.9 \
 	device_get_name.9 \
 	device_get_parent.9 \
+	device_get_property.9 \
 	device_get_softc.9 \
 	device_get_state.9 \
 	device_get_sysctl.9 \
diff --git a/share/man/man9/device_get_property.9 b/share/man/man9/device_get_property.9
new file mode 100644
index 000000000000..1d9bd5058b1a
--- /dev/null
+++ b/share/man/man9/device_get_property.9
@@ -0,0 +1,67 @@
+.\" -
+.\" SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+.\"
+.\" Copyright (c) 2021 Semihalf
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 19, 2021
+.Dt DEVICE_GET_PROPERTY 9
+.Os
+.Sh NAME
+.Nm device_get_property ,
+.Nm device_has_property
+.Nd access device specific data
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/bus.h
+.Ft ssize_t
+.Fn device_get_property "device_t dev" "const char *prop" "void *val" "size_t sz"
+.Ft bool
+.Fn device_has_property "device_t dev" "const char *prop"
+.Sh DESCRIPTION
+Access device specific data provided by the parent bus.
+Drivers can use these properties to obtain device capabilities and set
+necessary quirks.
+.Sh NOTES
+You can pass NULL as pointer to property's value when calling
+.Fn device_get_property
+to obtain its size.
+.Pp
+Currently this interface is implemented by
+.Xr simplebus 4
+and
+.Xr acpi 4 .
+.Sh RETURN VALUES
+.Fn device_get_property
+if successful returns property's size, otherwise returns -1.
+.Pp
+.Fn device_has_property
+returns true if given property was found.
+.Sh SEE ALSO
+.Xr acpi 4 ,
+.Xr simplebus 4 ,
+.Xr device 9
+.Sh AUTHORS
+This manual page was written by
+.An Bartlomiej Grzesik .
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index 8cbd916634b0..f25559d6b7ea 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -144,6 +144,8 @@ static void	acpi_delete_resource(device_t bus, device_t child, int type,
 		    int rid);
 static uint32_t	acpi_isa_get_logicalid(device_t dev);
 static int	acpi_isa_get_compatid(device_t dev, uint32_t *cids, int count);
+static ssize_t acpi_bus_get_prop(device_t bus, device_t child, const char *propname,
+		    void *propvalue, size_t size);
 static int	acpi_device_id_probe(device_t bus, device_t dev, char **ids, char **match);
 static ACPI_STATUS acpi_device_eval_obj(device_t bus, device_t dev,
 		    ACPI_STRING pathname, ACPI_OBJECT_LIST *parameters,
@@ -223,6 +225,7 @@ static device_method_t acpi_methods[] = {
     DEVMETHOD(bus_hint_device_unit,	acpi_hint_device_unit),
     DEVMETHOD(bus_get_cpus,		acpi_get_cpus),
     DEVMETHOD(bus_get_domain,		acpi_get_domain),
+    DEVMETHOD(bus_get_property,		acpi_bus_get_prop),
 
     /* ACPI bus */
     DEVMETHOD(acpi_id_probe,		acpi_device_id_probe),
@@ -1823,6 +1826,41 @@ acpi_find_dsd(device_t bus, device_t dev)
 	return (AE_NOT_FOUND);
 }
 
+static ssize_t
+acpi_bus_get_prop(device_t bus, device_t child, const char *propname,
+    void *propvalue, size_t size)
+{
+	ACPI_STATUS status;
+	const ACPI_OBJECT *obj;
+
+	status = acpi_device_get_prop(bus, child, __DECONST(char *, propname),
+		&obj);
+	if (ACPI_FAILURE(status))
+		return (-1);
+
+	switch (obj->Type) {
+	case ACPI_TYPE_INTEGER:
+		if (propvalue != NULL && size >= sizeof(uint64_t))
+			*((uint64_t *) propvalue) = obj->Integer.Value;
+		return (sizeof(uint64_t));
+
+	case ACPI_TYPE_STRING:
+		if (propvalue != NULL && size > 0)
+			memcpy(propvalue, obj->String.Pointer,
+			    MIN(size, obj->String.Length));
+		return (obj->String.Length);
+
+	case ACPI_TYPE_BUFFER:
+		if (propvalue != NULL && size > 0)
+			memcpy(propvalue, obj->Buffer.Pointer,
+			    MIN(size, obj->Buffer.Length));
+		return (obj->Buffer.Length);
+
+	default:
+		return (0);
+	}
+}
+
 int
 acpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate)
 {
diff --git a/sys/dev/fdt/simplebus.c b/sys/dev/fdt/simplebus.c
index 4496d2caaad7..ba4e58955bd2 100644
--- a/sys/dev/fdt/simplebus.c
+++ b/sys/dev/fdt/simplebus.c
@@ -54,6 +54,9 @@ static device_t		simplebus_add_child(device_t dev, u_int order,
     const char *name, int unit);
 static struct resource_list *simplebus_get_resource_list(device_t bus,
     device_t child);
+
+static ssize_t		simplebus_get_property(device_t bus, device_t child,
+    const char *propname, void *propvalue, size_t size);
 /*
  * ofw_bus interface
  */
@@ -89,6 +92,7 @@ static device_method_t	simplebus_methods[] = {
 	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
 	DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str),
 	DEVMETHOD(bus_get_resource_list, simplebus_get_resource_list),
+	DEVMETHOD(bus_get_property,	simplebus_get_property),
 
 	/* ofw_bus interface */
 	DEVMETHOD(ofw_bus_get_devinfo,	simplebus_get_devinfo),
@@ -350,6 +354,18 @@ simplebus_get_resource_list(device_t bus __unused, device_t child)
 	return (&ndi->rl);
 }
 
+static ssize_t
+simplebus_get_property(device_t bus, device_t child, const char *propname,
+    void *propvalue, size_t size)
+{
+	phandle_t node = ofw_bus_get_node(child);
+
+	if (propvalue == NULL || size == 0)
+		return (OF_getproplen(node, propname));
+
+	return (OF_getencprop(node, propname, propvalue, size));
+}
+
 static struct resource *
 simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
diff --git a/sys/kern/bus_if.m b/sys/kern/bus_if.m
index 250f2192e573..463d3fe38872 100644
--- a/sys/kern/bus_if.m
+++ b/sys/kern/bus_if.m
@@ -88,6 +88,13 @@ CODE {
 		*newstart = start;
 		return (0);
 	}
+
+	static ssize_t
+	null_get_property(device_t dev, device_t child, const char *propname,
+	    void *propvalue, size_t size)
+	{
+		return (-1);
+	}
 };
 
 /**
@@ -932,3 +939,27 @@ METHOD int reset_child {
 	device_t _child;
 	int _flags;
 };
+
+/**
+ * @brief Gets child's specific property
+ *
+ * The bus_get_property can be used to access device
+ * specific properties stored on the bus. If _propvalue
+ * is NULL or _size is 0, then method only returns size
+ * of the property.
+ *
+ * @param _dev			the bus device
+ * @param _child		the child device
+ * @param _propname		property name
+ * @param _propvalue	property value destination
+ * @param _size			property value size
+ *
+ * @returns size of property if successful otherwise -1
+ */
+METHOD ssize_t get_property {
+	device_t _dev;
+	device_t _child;
+	const char *_propname;
+	void *_propvalue;
+	size_t _size;
+} DEFAULT null_get_property;
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index 84333535dbfc..3949e0b29220 100644
--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -2650,6 +2650,20 @@ device_verbose(device_t dev)
 	dev->flags &= ~DF_QUIET;
 }
 
+ssize_t
+device_get_property(device_t dev, const char *prop, void *val, size_t sz)
+{
+	device_t bus = device_get_parent(dev);
+
+	return (BUS_GET_PROPERTY(bus, dev, prop, val, sz));
+}
+
+bool
+device_has_property(device_t dev, const char *prop)
+{
+	return (device_get_property(dev, prop, NULL, 0) >= 0);
+}
+
 /**
  * @brief Return non-zero if the DF_QUIET_CHIDLREN flag is set on the device
  */
diff --git a/sys/sys/bus.h b/sys/sys/bus.h
index 80fdeb7cd61d..4c7d094c24b0 100644
--- a/sys/sys/bus.h
+++ b/sys/sys/bus.h
@@ -626,6 +626,8 @@ int	device_set_unit(device_t dev, int unit);	/* XXX DONT USE XXX */
 int	device_shutdown(device_t dev);
 void	device_unbusy(device_t dev);
 void	device_verbose(device_t dev);
+ssize_t	device_get_property(device_t dev, const char *prop, void *val, size_t sz);
+bool device_has_property(device_t dev, const char *prop);
 
 /*
  * Access functions for devclass.