forked from mirrors/linux
		
	 e1be24b2e1
			
		
	
	
		e1be24b2e1
		
	
	
	
	
		
			
			Now that the driver core can properly handle constant struct bus_type, move the ssam_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. It's also never used outside of drivers/platform/surface/aggregator/bus.c so make it static and don't export it as no one is using it. Cc: Maximilian Luz <luzmaximilian@gmail.com> Cc: Hans de Goede <hdegoede@redhat.com> Cc: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Cc: <platform-driver-x86@vger.kernel.org> Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Link: https://lore.kernel.org/r/2023121957-tapered-upswing-8326@gregkh Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
		
			
				
	
	
		
			632 lines
		
	
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			632 lines
		
	
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* SPDX-License-Identifier: GPL-2.0+ */
 | |
| /*
 | |
|  * Surface System Aggregator Module (SSAM) bus and client-device subsystem.
 | |
|  *
 | |
|  * Main interface for the surface-aggregator bus, surface-aggregator client
 | |
|  * devices, and respective drivers building on top of the SSAM controller.
 | |
|  * Provides support for non-platform/non-ACPI SSAM clients via dedicated
 | |
|  * subsystem.
 | |
|  *
 | |
|  * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
 | |
|  */
 | |
| 
 | |
| #ifndef _LINUX_SURFACE_AGGREGATOR_DEVICE_H
 | |
| #define _LINUX_SURFACE_AGGREGATOR_DEVICE_H
 | |
| 
 | |
| #include <linux/device.h>
 | |
| #include <linux/mod_devicetable.h>
 | |
| #include <linux/property.h>
 | |
| #include <linux/types.h>
 | |
| 
 | |
| #include <linux/surface_aggregator/controller.h>
 | |
| 
 | |
| 
 | |
| /* -- Surface System Aggregator Module bus. --------------------------------- */
 | |
| 
 | |
| /**
 | |
|  * enum ssam_device_domain - SAM device domain.
 | |
|  * @SSAM_DOMAIN_VIRTUAL:   Virtual device.
 | |
|  * @SSAM_DOMAIN_SERIALHUB: Physical device connected via Surface Serial Hub.
 | |
|  */
 | |
| enum ssam_device_domain {
 | |
| 	SSAM_DOMAIN_VIRTUAL   = 0x00,
 | |
| 	SSAM_DOMAIN_SERIALHUB = 0x01,
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * enum ssam_virtual_tc - Target categories for the virtual SAM domain.
 | |
|  * @SSAM_VIRTUAL_TC_HUB: Device hub category.
 | |
|  */
 | |
| enum ssam_virtual_tc {
 | |
| 	SSAM_VIRTUAL_TC_HUB = 0x00,
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * struct ssam_device_uid - Unique identifier for SSAM device.
 | |
|  * @domain:   Domain of the device.
 | |
|  * @category: Target category of the device.
 | |
|  * @target:   Target ID of the device.
 | |
|  * @instance: Instance ID of the device.
 | |
|  * @function: Sub-function of the device. This field can be used to split a
 | |
|  *            single SAM device into multiple virtual subdevices to separate
 | |
|  *            different functionality of that device and allow one driver per
 | |
|  *            such functionality.
 | |
|  */
 | |
| struct ssam_device_uid {
 | |
| 	u8 domain;
 | |
| 	u8 category;
 | |
| 	u8 target;
 | |
| 	u8 instance;
 | |
| 	u8 function;
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * Special values for device matching.
 | |
|  *
 | |
|  * These values are intended to be used with SSAM_DEVICE(), SSAM_VDEV(), and
 | |
|  * SSAM_SDEV() exclusively. Specifically, they are used to initialize the
 | |
|  * match_flags member of the device ID structure. Do not use them directly
 | |
|  * with struct ssam_device_id or struct ssam_device_uid.
 | |
|  */
 | |
| #define SSAM_SSH_TID_ANY	0xffff
 | |
| #define SSAM_SSH_IID_ANY	0xffff
 | |
| #define SSAM_SSH_FUN_ANY	0xffff
 | |
| 
 | |
| /**
 | |
|  * SSAM_DEVICE() - Initialize a &struct ssam_device_id with the given
 | |
|  * parameters.
 | |
|  * @d:   Domain of the device.
 | |
|  * @cat: Target category of the device.
 | |
|  * @tid: Target ID of the device.
 | |
|  * @iid: Instance ID of the device.
 | |
|  * @fun: Sub-function of the device.
 | |
|  *
 | |
|  * Initializes a &struct ssam_device_id with the given parameters. See &struct
 | |
|  * ssam_device_uid for details regarding the parameters. The special values
 | |
|  * %SSAM_SSH_TID_ANY, %SSAM_SSH_IID_ANY, and %SSAM_SSH_FUN_ANY can be used to specify that
 | |
|  * matching should ignore target ID, instance ID, and/or sub-function,
 | |
|  * respectively. This macro initializes the ``match_flags`` field based on the
 | |
|  * given parameters.
 | |
|  *
 | |
|  * Note: The parameters @d and @cat must be valid &u8 values, the parameters
 | |
|  * @tid, @iid, and @fun must be either valid &u8 values or %SSAM_SSH_TID_ANY,
 | |
|  * %SSAM_SSH_IID_ANY, or %SSAM_SSH_FUN_ANY, respectively. Other non-&u8 values are not
 | |
|  * allowed.
 | |
|  */
 | |
| #define SSAM_DEVICE(d, cat, tid, iid, fun)					\
 | |
| 	.match_flags = (((tid) != SSAM_SSH_TID_ANY) ? SSAM_MATCH_TARGET : 0)	\
 | |
| 		     | (((iid) != SSAM_SSH_IID_ANY) ? SSAM_MATCH_INSTANCE : 0)	\
 | |
| 		     | (((fun) != SSAM_SSH_FUN_ANY) ? SSAM_MATCH_FUNCTION : 0),	\
 | |
| 	.domain   = d,								\
 | |
| 	.category = cat,							\
 | |
| 	.target   = __builtin_choose_expr((tid) != SSAM_SSH_TID_ANY, (tid), 0),	\
 | |
| 	.instance = __builtin_choose_expr((iid) != SSAM_SSH_IID_ANY, (iid), 0),	\
 | |
| 	.function = __builtin_choose_expr((fun) != SSAM_SSH_FUN_ANY, (fun), 0)
 | |
| 
 | |
| /**
 | |
|  * SSAM_VDEV() - Initialize a &struct ssam_device_id as virtual device with
 | |
|  * the given parameters.
 | |
|  * @cat: Target category of the device.
 | |
|  * @tid: Target ID of the device.
 | |
|  * @iid: Instance ID of the device.
 | |
|  * @fun: Sub-function of the device.
 | |
|  *
 | |
|  * Initializes a &struct ssam_device_id with the given parameters in the
 | |
|  * virtual domain. See &struct ssam_device_uid for details regarding the
 | |
|  * parameters. The special values %SSAM_SSH_TID_ANY, %SSAM_SSH_IID_ANY, and
 | |
|  * %SSAM_SSH_FUN_ANY can be used to specify that matching should ignore target ID,
 | |
|  * instance ID, and/or sub-function, respectively. This macro initializes the
 | |
|  * ``match_flags`` field based on the given parameters.
 | |
|  *
 | |
|  * Note: The parameter @cat must be a valid &u8 value, the parameters @tid,
 | |
|  * @iid, and @fun must be either valid &u8 values or %SSAM_SSH_TID_ANY,
 | |
|  * %SSAM_SSH_IID_ANY, or %SSAM_SSH_FUN_ANY, respectively. Other non-&u8 values are not
 | |
|  * allowed.
 | |
|  */
 | |
| #define SSAM_VDEV(cat, tid, iid, fun) \
 | |
| 	SSAM_DEVICE(SSAM_DOMAIN_VIRTUAL, SSAM_VIRTUAL_TC_##cat, SSAM_SSH_TID_##tid, iid, fun)
 | |
| 
 | |
| /**
 | |
|  * SSAM_SDEV() - Initialize a &struct ssam_device_id as physical SSH device
 | |
|  * with the given parameters.
 | |
|  * @cat: Target category of the device.
 | |
|  * @tid: Target ID of the device.
 | |
|  * @iid: Instance ID of the device.
 | |
|  * @fun: Sub-function of the device.
 | |
|  *
 | |
|  * Initializes a &struct ssam_device_id with the given parameters in the SSH
 | |
|  * domain. See &struct ssam_device_uid for details regarding the parameters.
 | |
|  * The special values %SSAM_SSH_TID_ANY, %SSAM_SSH_IID_ANY, and
 | |
|  * %SSAM_SSH_FUN_ANY can be used to specify that matching should ignore target
 | |
|  * ID, instance ID, and/or sub-function, respectively. This macro initializes
 | |
|  * the ``match_flags`` field based on the given parameters.
 | |
|  *
 | |
|  * Note: The parameter @cat must be a valid &u8 value, the parameters @tid,
 | |
|  * @iid, and @fun must be either valid &u8 values or %SSAM_SSH_TID_ANY,
 | |
|  * %SSAM_SSH_IID_ANY, or %SSAM_SSH_FUN_ANY, respectively. Other non-&u8 values
 | |
|  * are not allowed.
 | |
|  */
 | |
| #define SSAM_SDEV(cat, tid, iid, fun) \
 | |
| 	SSAM_DEVICE(SSAM_DOMAIN_SERIALHUB, SSAM_SSH_TC_##cat, SSAM_SSH_TID_##tid, iid, fun)
 | |
| 
 | |
| /*
 | |
|  * enum ssam_device_flags - Flags for SSAM client devices.
 | |
|  * @SSAM_DEVICE_HOT_REMOVED_BIT:
 | |
|  *	The device has been hot-removed. Further communication with it may time
 | |
|  *	out and should be avoided.
 | |
|  */
 | |
| enum ssam_device_flags {
 | |
| 	SSAM_DEVICE_HOT_REMOVED_BIT = 0,
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * struct ssam_device - SSAM client device.
 | |
|  * @dev:   Driver model representation of the device.
 | |
|  * @ctrl:  SSAM controller managing this device.
 | |
|  * @uid:   UID identifying the device.
 | |
|  * @flags: Device state flags, see &enum ssam_device_flags.
 | |
|  */
 | |
| struct ssam_device {
 | |
| 	struct device dev;
 | |
| 	struct ssam_controller *ctrl;
 | |
| 
 | |
| 	struct ssam_device_uid uid;
 | |
| 
 | |
| 	unsigned long flags;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * struct ssam_device_driver - SSAM client device driver.
 | |
|  * @driver:      Base driver model structure.
 | |
|  * @match_table: Match table specifying which devices the driver should bind to.
 | |
|  * @probe:       Called when the driver is being bound to a device.
 | |
|  * @remove:      Called when the driver is being unbound from the device.
 | |
|  */
 | |
| struct ssam_device_driver {
 | |
| 	struct device_driver driver;
 | |
| 
 | |
| 	const struct ssam_device_id *match_table;
 | |
| 
 | |
| 	int  (*probe)(struct ssam_device *sdev);
 | |
| 	void (*remove)(struct ssam_device *sdev);
 | |
| };
 | |
| 
 | |
| #ifdef CONFIG_SURFACE_AGGREGATOR_BUS
 | |
| 
 | |
| extern const struct device_type ssam_device_type;
 | |
| 
 | |
| /**
 | |
|  * is_ssam_device() - Check if the given device is a SSAM client device.
 | |
|  * @d: The device to test the type of.
 | |
|  *
 | |
|  * Return: Returns %true if the specified device is of type &struct
 | |
|  * ssam_device, i.e. the device type points to %ssam_device_type, and %false
 | |
|  * otherwise.
 | |
|  */
 | |
| static inline bool is_ssam_device(struct device *d)
 | |
| {
 | |
| 	return d->type == &ssam_device_type;
 | |
| }
 | |
| 
 | |
| #else /* CONFIG_SURFACE_AGGREGATOR_BUS */
 | |
| 
 | |
| static inline bool is_ssam_device(struct device *d)
 | |
| {
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| #endif /* CONFIG_SURFACE_AGGREGATOR_BUS */
 | |
| 
 | |
| /**
 | |
|  * to_ssam_device() - Casts the given device to a SSAM client device.
 | |
|  * @d: The device to cast.
 | |
|  *
 | |
|  * Casts the given &struct device to a &struct ssam_device. The caller has to
 | |
|  * ensure that the given device is actually enclosed in a &struct ssam_device,
 | |
|  * e.g. by calling is_ssam_device().
 | |
|  *
 | |
|  * Return: Returns a pointer to the &struct ssam_device wrapping the given
 | |
|  * device @d.
 | |
|  */
 | |
| #define to_ssam_device(d)	container_of_const(d, struct ssam_device, dev)
 | |
| 
 | |
| /**
 | |
|  * to_ssam_device_driver() - Casts the given device driver to a SSAM client
 | |
|  * device driver.
 | |
|  * @d: The driver to cast.
 | |
|  *
 | |
|  * Casts the given &struct device_driver to a &struct ssam_device_driver. The
 | |
|  * caller has to ensure that the given driver is actually enclosed in a
 | |
|  * &struct ssam_device_driver.
 | |
|  *
 | |
|  * Return: Returns the pointer to the &struct ssam_device_driver wrapping the
 | |
|  * given device driver @d.
 | |
|  */
 | |
| #define to_ssam_device_driver(d)	container_of_const(d, struct ssam_device_driver, driver)
 | |
| 
 | |
| const struct ssam_device_id *ssam_device_id_match(const struct ssam_device_id *table,
 | |
| 						  const struct ssam_device_uid uid);
 | |
| 
 | |
| const struct ssam_device_id *ssam_device_get_match(const struct ssam_device *dev);
 | |
| 
 | |
| const void *ssam_device_get_match_data(const struct ssam_device *dev);
 | |
| 
 | |
| struct ssam_device *ssam_device_alloc(struct ssam_controller *ctrl,
 | |
| 				      struct ssam_device_uid uid);
 | |
| 
 | |
| int ssam_device_add(struct ssam_device *sdev);
 | |
| void ssam_device_remove(struct ssam_device *sdev);
 | |
| 
 | |
| /**
 | |
|  * ssam_device_mark_hot_removed() - Mark the given device as hot-removed.
 | |
|  * @sdev: The device to mark as hot-removed.
 | |
|  *
 | |
|  * Mark the device as having been hot-removed. This signals drivers using the
 | |
|  * device that communication with the device should be avoided and may lead to
 | |
|  * timeouts.
 | |
|  */
 | |
| static inline void ssam_device_mark_hot_removed(struct ssam_device *sdev)
 | |
| {
 | |
| 	dev_dbg(&sdev->dev, "marking device as hot-removed\n");
 | |
| 	set_bit(SSAM_DEVICE_HOT_REMOVED_BIT, &sdev->flags);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ssam_device_is_hot_removed() - Check if the given device has been
 | |
|  * hot-removed.
 | |
|  * @sdev: The device to check.
 | |
|  *
 | |
|  * Checks if the given device has been marked as hot-removed. See
 | |
|  * ssam_device_mark_hot_removed() for more details.
 | |
|  *
 | |
|  * Return: Returns ``true`` if the device has been marked as hot-removed.
 | |
|  */
 | |
| static inline bool ssam_device_is_hot_removed(struct ssam_device *sdev)
 | |
| {
 | |
| 	return test_bit(SSAM_DEVICE_HOT_REMOVED_BIT, &sdev->flags);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ssam_device_get() - Increment reference count of SSAM client device.
 | |
|  * @sdev: The device to increment the reference count of.
 | |
|  *
 | |
|  * Increments the reference count of the given SSAM client device by
 | |
|  * incrementing the reference count of the enclosed &struct device via
 | |
|  * get_device().
 | |
|  *
 | |
|  * See ssam_device_put() for the counter-part of this function.
 | |
|  *
 | |
|  * Return: Returns the device provided as input.
 | |
|  */
 | |
| static inline struct ssam_device *ssam_device_get(struct ssam_device *sdev)
 | |
| {
 | |
| 	return sdev ? to_ssam_device(get_device(&sdev->dev)) : NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ssam_device_put() - Decrement reference count of SSAM client device.
 | |
|  * @sdev: The device to decrement the reference count of.
 | |
|  *
 | |
|  * Decrements the reference count of the given SSAM client device by
 | |
|  * decrementing the reference count of the enclosed &struct device via
 | |
|  * put_device().
 | |
|  *
 | |
|  * See ssam_device_get() for the counter-part of this function.
 | |
|  */
 | |
| static inline void ssam_device_put(struct ssam_device *sdev)
 | |
| {
 | |
| 	if (sdev)
 | |
| 		put_device(&sdev->dev);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ssam_device_get_drvdata() - Get driver-data of SSAM client device.
 | |
|  * @sdev: The device to get the driver-data from.
 | |
|  *
 | |
|  * Return: Returns the driver-data of the given device, previously set via
 | |
|  * ssam_device_set_drvdata().
 | |
|  */
 | |
| static inline void *ssam_device_get_drvdata(struct ssam_device *sdev)
 | |
| {
 | |
| 	return dev_get_drvdata(&sdev->dev);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ssam_device_set_drvdata() - Set driver-data of SSAM client device.
 | |
|  * @sdev: The device to set the driver-data of.
 | |
|  * @data: The data to set the device's driver-data pointer to.
 | |
|  */
 | |
| static inline void ssam_device_set_drvdata(struct ssam_device *sdev, void *data)
 | |
| {
 | |
| 	dev_set_drvdata(&sdev->dev, data);
 | |
| }
 | |
| 
 | |
| int __ssam_device_driver_register(struct ssam_device_driver *d, struct module *o);
 | |
| void ssam_device_driver_unregister(struct ssam_device_driver *d);
 | |
| 
 | |
| /**
 | |
|  * ssam_device_driver_register() - Register a SSAM client device driver.
 | |
|  * @drv: The driver to register.
 | |
|  */
 | |
| #define ssam_device_driver_register(drv) \
 | |
| 	__ssam_device_driver_register(drv, THIS_MODULE)
 | |
| 
 | |
| /**
 | |
|  * module_ssam_device_driver() - Helper macro for SSAM device driver
 | |
|  * registration.
 | |
|  * @drv: The driver managed by this module.
 | |
|  *
 | |
|  * Helper macro to register a SSAM device driver via module_init() and
 | |
|  * module_exit(). This macro may only be used once per module and replaces the
 | |
|  * aforementioned definitions.
 | |
|  */
 | |
| #define module_ssam_device_driver(drv)			\
 | |
| 	module_driver(drv, ssam_device_driver_register,	\
 | |
| 		      ssam_device_driver_unregister)
 | |
| 
 | |
| 
 | |
| /* -- Helpers for controller and hub devices. ------------------------------- */
 | |
| 
 | |
| #ifdef CONFIG_SURFACE_AGGREGATOR_BUS
 | |
| 
 | |
| int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl,
 | |
| 			    struct fwnode_handle *node);
 | |
| void ssam_remove_clients(struct device *dev);
 | |
| 
 | |
| #else /* CONFIG_SURFACE_AGGREGATOR_BUS */
 | |
| 
 | |
| static inline int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl,
 | |
| 					  struct fwnode_handle *node)
 | |
| {
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static inline void ssam_remove_clients(struct device *dev) {}
 | |
| 
 | |
| #endif /* CONFIG_SURFACE_AGGREGATOR_BUS */
 | |
| 
 | |
| /**
 | |
|  * ssam_register_clients() - Register all client devices defined under the
 | |
|  * given parent device.
 | |
|  * @dev: The parent device under which clients should be registered.
 | |
|  * @ctrl: The controller with which client should be registered.
 | |
|  *
 | |
|  * Register all clients that have via firmware nodes been defined as children
 | |
|  * of the given (parent) device. The respective child firmware nodes will be
 | |
|  * associated with the correspondingly created child devices.
 | |
|  *
 | |
|  * The given controller will be used to instantiate the new devices. See
 | |
|  * ssam_device_add() for details.
 | |
|  *
 | |
|  * Return: Returns zero on success, nonzero on failure.
 | |
|  */
 | |
| static inline int ssam_register_clients(struct device *dev, struct ssam_controller *ctrl)
 | |
| {
 | |
| 	return __ssam_register_clients(dev, ctrl, dev_fwnode(dev));
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ssam_device_register_clients() - Register all client devices defined under
 | |
|  * the given SSAM parent device.
 | |
|  * @sdev: The parent device under which clients should be registered.
 | |
|  *
 | |
|  * Register all clients that have via firmware nodes been defined as children
 | |
|  * of the given (parent) device. The respective child firmware nodes will be
 | |
|  * associated with the correspondingly created child devices.
 | |
|  *
 | |
|  * The controller used by the parent device will be used to instantiate the new
 | |
|  * devices. See ssam_device_add() for details.
 | |
|  *
 | |
|  * Return: Returns zero on success, nonzero on failure.
 | |
|  */
 | |
| static inline int ssam_device_register_clients(struct ssam_device *sdev)
 | |
| {
 | |
| 	return ssam_register_clients(&sdev->dev, sdev->ctrl);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* -- Helpers for client-device requests. ----------------------------------- */
 | |
| 
 | |
| /**
 | |
|  * SSAM_DEFINE_SYNC_REQUEST_CL_N() - Define synchronous client-device SAM
 | |
|  * request function with neither argument nor return value.
 | |
|  * @name: Name of the generated function.
 | |
|  * @spec: Specification (&struct ssam_request_spec_md) defining the request.
 | |
|  *
 | |
|  * Defines a function executing the synchronous SAM request specified by
 | |
|  * @spec, with the request having neither argument nor return value. Device
 | |
|  * specifying parameters are not hard-coded, but instead are provided via the
 | |
|  * client device, specifically its UID, supplied when calling this function.
 | |
|  * The generated function takes care of setting up the request struct, buffer
 | |
|  * allocation, as well as execution of the request itself, returning once the
 | |
|  * request has been fully completed. The required transport buffer will be
 | |
|  * allocated on the stack.
 | |
|  *
 | |
|  * The generated function is defined as ``static int name(struct ssam_device
 | |
|  * *sdev)``, returning the status of the request, which is zero on success and
 | |
|  * negative on failure. The ``sdev`` parameter specifies both the target
 | |
|  * device of the request and by association the controller via which the
 | |
|  * request is sent.
 | |
|  *
 | |
|  * Refer to ssam_request_do_sync_onstack() for more details on the behavior of
 | |
|  * the generated function.
 | |
|  */
 | |
| #define SSAM_DEFINE_SYNC_REQUEST_CL_N(name, spec...)			\
 | |
| 	SSAM_DEFINE_SYNC_REQUEST_MD_N(__raw_##name, spec)		\
 | |
| 	static int name(struct ssam_device *sdev)			\
 | |
| 	{								\
 | |
| 		return __raw_##name(sdev->ctrl, sdev->uid.target,	\
 | |
| 				    sdev->uid.instance);		\
 | |
| 	}
 | |
| 
 | |
| /**
 | |
|  * SSAM_DEFINE_SYNC_REQUEST_CL_W() - Define synchronous client-device SAM
 | |
|  * request function with argument.
 | |
|  * @name:  Name of the generated function.
 | |
|  * @atype: Type of the request's argument.
 | |
|  * @spec:  Specification (&struct ssam_request_spec_md) defining the request.
 | |
|  *
 | |
|  * Defines a function executing the synchronous SAM request specified by
 | |
|  * @spec, with the request taking an argument of type @atype and having no
 | |
|  * return value. Device specifying parameters are not hard-coded, but instead
 | |
|  * are provided via the client device, specifically its UID, supplied when
 | |
|  * calling this function. The generated function takes care of setting up the
 | |
|  * request struct, buffer allocation, as well as execution of the request
 | |
|  * itself, returning once the request has been fully completed. The required
 | |
|  * transport buffer will be allocated on the stack.
 | |
|  *
 | |
|  * The generated function is defined as ``static int name(struct ssam_device
 | |
|  * *sdev, const atype *arg)``, returning the status of the request, which is
 | |
|  * zero on success and negative on failure. The ``sdev`` parameter specifies
 | |
|  * both the target device of the request and by association the controller via
 | |
|  * which the request is sent. The request's argument is specified via the
 | |
|  * ``arg`` pointer.
 | |
|  *
 | |
|  * Refer to ssam_request_do_sync_onstack() for more details on the behavior of
 | |
|  * the generated function.
 | |
|  */
 | |
| #define SSAM_DEFINE_SYNC_REQUEST_CL_W(name, atype, spec...)		\
 | |
| 	SSAM_DEFINE_SYNC_REQUEST_MD_W(__raw_##name, atype, spec)	\
 | |
| 	static int name(struct ssam_device *sdev, const atype *arg)	\
 | |
| 	{								\
 | |
| 		return __raw_##name(sdev->ctrl, sdev->uid.target,	\
 | |
| 				    sdev->uid.instance, arg);		\
 | |
| 	}
 | |
| 
 | |
| /**
 | |
|  * SSAM_DEFINE_SYNC_REQUEST_CL_R() - Define synchronous client-device SAM
 | |
|  * request function with return value.
 | |
|  * @name:  Name of the generated function.
 | |
|  * @rtype: Type of the request's return value.
 | |
|  * @spec:  Specification (&struct ssam_request_spec_md) defining the request.
 | |
|  *
 | |
|  * Defines a function executing the synchronous SAM request specified by
 | |
|  * @spec, with the request taking no argument but having a return value of
 | |
|  * type @rtype. Device specifying parameters are not hard-coded, but instead
 | |
|  * are provided via the client device, specifically its UID, supplied when
 | |
|  * calling this function. The generated function takes care of setting up the
 | |
|  * request struct, buffer allocation, as well as execution of the request
 | |
|  * itself, returning once the request has been fully completed. The required
 | |
|  * transport buffer will be allocated on the stack.
 | |
|  *
 | |
|  * The generated function is defined as ``static int name(struct ssam_device
 | |
|  * *sdev, rtype *ret)``, returning the status of the request, which is zero on
 | |
|  * success and negative on failure. The ``sdev`` parameter specifies both the
 | |
|  * target device of the request and by association the controller via which
 | |
|  * the request is sent. The request's return value is written to the memory
 | |
|  * pointed to by the ``ret`` parameter.
 | |
|  *
 | |
|  * Refer to ssam_request_do_sync_onstack() for more details on the behavior of
 | |
|  * the generated function.
 | |
|  */
 | |
| #define SSAM_DEFINE_SYNC_REQUEST_CL_R(name, rtype, spec...)		\
 | |
| 	SSAM_DEFINE_SYNC_REQUEST_MD_R(__raw_##name, rtype, spec)	\
 | |
| 	static int name(struct ssam_device *sdev, rtype *ret)		\
 | |
| 	{								\
 | |
| 		return __raw_##name(sdev->ctrl, sdev->uid.target,	\
 | |
| 				    sdev->uid.instance, ret);		\
 | |
| 	}
 | |
| 
 | |
| /**
 | |
|  * SSAM_DEFINE_SYNC_REQUEST_CL_WR() - Define synchronous client-device SAM
 | |
|  * request function with argument and return value.
 | |
|  * @name:  Name of the generated function.
 | |
|  * @atype: Type of the request's argument.
 | |
|  * @rtype: Type of the request's return value.
 | |
|  * @spec:  Specification (&struct ssam_request_spec_md) defining the request.
 | |
|  *
 | |
|  * Defines a function executing the synchronous SAM request specified by @spec,
 | |
|  * with the request taking an argument of type @atype and having a return value
 | |
|  * of type @rtype. Device specifying parameters are not hard-coded, but instead
 | |
|  * are provided via the client device, specifically its UID, supplied when
 | |
|  * calling this function. The generated function takes care of setting up the
 | |
|  * request struct, buffer allocation, as well as execution of the request
 | |
|  * itself, returning once the request has been fully completed. The required
 | |
|  * transport buffer will be allocated on the stack.
 | |
|  *
 | |
|  * The generated function is defined as ``static int name(struct ssam_device
 | |
|  * *sdev, const atype *arg, rtype *ret)``, returning the status of the request,
 | |
|  * which is zero on success and negative on failure. The ``sdev`` parameter
 | |
|  * specifies both the target device of the request and by association the
 | |
|  * controller via which the request is sent. The request's argument is
 | |
|  * specified via the ``arg`` pointer. The request's return value is written to
 | |
|  * the memory pointed to by the ``ret`` parameter.
 | |
|  *
 | |
|  * Refer to ssam_request_do_sync_onstack() for more details on the behavior of
 | |
|  * the generated function.
 | |
|  */
 | |
| #define SSAM_DEFINE_SYNC_REQUEST_CL_WR(name, atype, rtype, spec...)		\
 | |
| 	SSAM_DEFINE_SYNC_REQUEST_MD_WR(__raw_##name, atype, rtype, spec)	\
 | |
| 	static int name(struct ssam_device *sdev, const atype *arg, rtype *ret)	\
 | |
| 	{									\
 | |
| 		return __raw_##name(sdev->ctrl, sdev->uid.target,		\
 | |
| 				    sdev->uid.instance, arg, ret);		\
 | |
| 	}
 | |
| 
 | |
| 
 | |
| /* -- Helpers for client-device notifiers. ---------------------------------- */
 | |
| 
 | |
| /**
 | |
|  * ssam_device_notifier_register() - Register an event notifier for the
 | |
|  * specified client device.
 | |
|  * @sdev: The device the notifier should be registered on.
 | |
|  * @n:    The event notifier to register.
 | |
|  *
 | |
|  * Register an event notifier. Increment the usage counter of the associated
 | |
|  * SAM event if the notifier is not marked as an observer. If the event is not
 | |
|  * marked as an observer and is currently not enabled, it will be enabled
 | |
|  * during this call. If the notifier is marked as an observer, no attempt will
 | |
|  * be made at enabling any event and no reference count will be modified.
 | |
|  *
 | |
|  * Notifiers marked as observers do not need to be associated with one specific
 | |
|  * event, i.e. as long as no event matching is performed, only the event target
 | |
|  * category needs to be set.
 | |
|  *
 | |
|  * Return: Returns zero on success, %-ENOSPC if there have already been
 | |
|  * %INT_MAX notifiers for the event ID/type associated with the notifier block
 | |
|  * registered, %-ENOMEM if the corresponding event entry could not be
 | |
|  * allocated, %-ENODEV if the device is marked as hot-removed. If this is the
 | |
|  * first time that a notifier block is registered for the specific associated
 | |
|  * event, returns the status of the event-enable EC-command.
 | |
|  */
 | |
| static inline int ssam_device_notifier_register(struct ssam_device *sdev,
 | |
| 						struct ssam_event_notifier *n)
 | |
| {
 | |
| 	/*
 | |
| 	 * Note that this check does not provide any guarantees whatsoever as
 | |
| 	 * hot-removal could happen at any point and we can't protect against
 | |
| 	 * it. Nevertheless, if we can detect hot-removal, bail early to avoid
 | |
| 	 * communication timeouts.
 | |
| 	 */
 | |
| 	if (ssam_device_is_hot_removed(sdev))
 | |
| 		return -ENODEV;
 | |
| 
 | |
| 	return ssam_notifier_register(sdev->ctrl, n);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * ssam_device_notifier_unregister() - Unregister an event notifier for the
 | |
|  * specified client device.
 | |
|  * @sdev: The device the notifier has been registered on.
 | |
|  * @n:    The event notifier to unregister.
 | |
|  *
 | |
|  * Unregister an event notifier. Decrement the usage counter of the associated
 | |
|  * SAM event if the notifier is not marked as an observer. If the usage counter
 | |
|  * reaches zero, the event will be disabled.
 | |
|  *
 | |
|  * In case the device has been marked as hot-removed, the event will not be
 | |
|  * disabled on the EC, as in those cases any attempt at doing so may time out.
 | |
|  *
 | |
|  * Return: Returns zero on success, %-ENOENT if the given notifier block has
 | |
|  * not been registered on the controller. If the given notifier block was the
 | |
|  * last one associated with its specific event, returns the status of the
 | |
|  * event-disable EC-command.
 | |
|  */
 | |
| static inline int ssam_device_notifier_unregister(struct ssam_device *sdev,
 | |
| 						  struct ssam_event_notifier *n)
 | |
| {
 | |
| 	return __ssam_notifier_unregister(sdev->ctrl, n,
 | |
| 					  !ssam_device_is_hot_removed(sdev));
 | |
| }
 | |
| 
 | |
| #endif /* _LINUX_SURFACE_AGGREGATOR_DEVICE_H */
 |