Commit eb0e90a8 authored by Maximilian Luz's avatar Maximilian Luz Committed by Hans de Goede

platform/surface: aggregator: Add dedicated bus and device type

The Surface Aggregator EC provides varying functionality, depending on
the Surface device. To manage this functionality, we use dedicated
client devices for each subsystem or virtual device of the EC. While
some of these clients are described as standard devices in ACPI and the
corresponding client drivers can be implemented as platform drivers in
the kernel (making use of the controller API already present), many
devices, especially on newer Surface models, cannot be found there.

To simplify management of these devices, we introduce a new bus and
client device type for the Surface Aggregator subsystem. The new device
type takes care of managing the controller reference, essentially
guaranteeing its validity for as long as the client device exists, thus
alleviating the need to manually establish device links for that purpose
in the client driver (as has to be done with the platform devices).
Signed-off-by: default avatarMaximilian Luz <luzmaximilian@gmail.com>
Reviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20201221183959.1186143-7-luzmaximilian@gmail.comSigned-off-by: default avatarHans de Goede <hdegoede@redhat.com>
parent 02be44f6
...@@ -41,6 +41,18 @@ menuconfig SURFACE_AGGREGATOR ...@@ -41,6 +41,18 @@ menuconfig SURFACE_AGGREGATOR
module, y if you want to build it into the kernel and n if you don't module, y if you want to build it into the kernel and n if you don't
want it at all. want it at all.
config SURFACE_AGGREGATOR_BUS
bool "Surface System Aggregator Module Bus"
depends on SURFACE_AGGREGATOR
default y
help
Expands the Surface System Aggregator Module (SSAM) core driver by
providing a dedicated bus and client-device type.
This bus and device type are intended to provide and simplify support
for non-platform and non-ACPI SSAM devices, i.e. SSAM devices that are
not auto-detectable via the conventional means (e.g. ACPI).
config SURFACE_AGGREGATOR_ERROR_INJECTION config SURFACE_AGGREGATOR_ERROR_INJECTION
bool "Surface System Aggregator Module Error Injection Capabilities" bool "Surface System Aggregator Module Error Injection Capabilities"
depends on SURFACE_AGGREGATOR depends on SURFACE_AGGREGATOR
......
...@@ -11,3 +11,7 @@ surface_aggregator-objs += ssh_parser.o ...@@ -11,3 +11,7 @@ surface_aggregator-objs += ssh_parser.o
surface_aggregator-objs += ssh_packet_layer.o surface_aggregator-objs += ssh_packet_layer.o
surface_aggregator-objs += ssh_request_layer.o surface_aggregator-objs += ssh_request_layer.o
surface_aggregator-objs += controller.o surface_aggregator-objs += controller.o
ifeq ($(CONFIG_SURFACE_AGGREGATOR_BUS),y)
surface_aggregator-objs += bus.o
endif
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Surface System Aggregator Module bus and device integration.
*
* Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
*/
#ifndef _SURFACE_AGGREGATOR_BUS_H
#define _SURFACE_AGGREGATOR_BUS_H
#include <linux/surface_aggregator/controller.h>
#ifdef CONFIG_SURFACE_AGGREGATOR_BUS
void ssam_controller_remove_clients(struct ssam_controller *ctrl);
int ssam_bus_register(void);
void ssam_bus_unregister(void);
#else /* CONFIG_SURFACE_AGGREGATOR_BUS */
static inline void ssam_controller_remove_clients(struct ssam_controller *ctrl) {}
static inline int ssam_bus_register(void) { return 0; }
static inline void ssam_bus_unregister(void) {}
#endif /* CONFIG_SURFACE_AGGREGATOR_BUS */
#endif /* _SURFACE_AGGREGATOR_BUS_H */
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/surface_aggregator/controller.h> #include <linux/surface_aggregator/controller.h>
#include "bus.h"
#include "controller.h" #include "controller.h"
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
...@@ -739,6 +741,9 @@ static void ssam_serial_hub_remove(struct serdev_device *serdev) ...@@ -739,6 +741,9 @@ static void ssam_serial_hub_remove(struct serdev_device *serdev)
sysfs_remove_group(&serdev->dev.kobj, &ssam_sam_group); sysfs_remove_group(&serdev->dev.kobj, &ssam_sam_group);
ssam_controller_lock(ctrl); ssam_controller_lock(ctrl);
/* Remove all client devices. */
ssam_controller_remove_clients(ctrl);
/* Act as if suspending to silence events. */ /* Act as if suspending to silence events. */
status = ssam_ctrl_notif_display_off(ctrl); status = ssam_ctrl_notif_display_off(ctrl);
if (status) { if (status) {
...@@ -791,6 +796,10 @@ static int __init ssam_core_init(void) ...@@ -791,6 +796,10 @@ static int __init ssam_core_init(void)
{ {
int status; int status;
status = ssam_bus_register();
if (status)
goto err_bus;
status = ssh_ctrl_packet_cache_init(); status = ssh_ctrl_packet_cache_init();
if (status) if (status)
goto err_cpkg; goto err_cpkg;
...@@ -810,6 +819,8 @@ static int __init ssam_core_init(void) ...@@ -810,6 +819,8 @@ static int __init ssam_core_init(void)
err_evitem: err_evitem:
ssh_ctrl_packet_cache_destroy(); ssh_ctrl_packet_cache_destroy();
err_cpkg: err_cpkg:
ssam_bus_unregister();
err_bus:
return status; return status;
} }
module_init(ssam_core_init); module_init(ssam_core_init);
...@@ -819,6 +830,7 @@ static void __exit ssam_core_exit(void) ...@@ -819,6 +830,7 @@ static void __exit ssam_core_exit(void)
serdev_device_driver_unregister(&ssam_serial_hub); serdev_device_driver_unregister(&ssam_serial_hub);
ssam_event_item_cache_destroy(); ssam_event_item_cache_destroy();
ssh_ctrl_packet_cache_destroy(); ssh_ctrl_packet_cache_destroy();
ssam_bus_unregister();
} }
module_exit(ssam_core_exit); module_exit(ssam_core_exit);
......
...@@ -846,4 +846,22 @@ struct auxiliary_device_id { ...@@ -846,4 +846,22 @@ struct auxiliary_device_id {
kernel_ulong_t driver_data; kernel_ulong_t driver_data;
}; };
/* Surface System Aggregator Module */
#define SSAM_MATCH_TARGET 0x1
#define SSAM_MATCH_INSTANCE 0x2
#define SSAM_MATCH_FUNCTION 0x4
struct ssam_device_id {
__u8 match_flags;
__u8 domain;
__u8 category;
__u8 target;
__u8 instance;
__u8 function;
kernel_ulong_t driver_data;
};
#endif /* LINUX_MOD_DEVICETABLE_H */ #endif /* LINUX_MOD_DEVICETABLE_H */
This diff is collapsed.
...@@ -246,5 +246,13 @@ int main(void) ...@@ -246,5 +246,13 @@ int main(void)
DEVID(auxiliary_device_id); DEVID(auxiliary_device_id);
DEVID_FIELD(auxiliary_device_id, name); DEVID_FIELD(auxiliary_device_id, name);
DEVID(ssam_device_id);
DEVID_FIELD(ssam_device_id, match_flags);
DEVID_FIELD(ssam_device_id, domain);
DEVID_FIELD(ssam_device_id, category);
DEVID_FIELD(ssam_device_id, target);
DEVID_FIELD(ssam_device_id, instance);
DEVID_FIELD(ssam_device_id, function);
return 0; return 0;
} }
...@@ -1375,6 +1375,28 @@ static int do_auxiliary_entry(const char *filename, void *symval, char *alias) ...@@ -1375,6 +1375,28 @@ static int do_auxiliary_entry(const char *filename, void *symval, char *alias)
return 1; return 1;
} }
/*
* Looks like: ssam:dNcNtNiNfN
*
* N is exactly 2 digits, where each is an upper-case hex digit.
*/
static int do_ssam_entry(const char *filename, void *symval, char *alias)
{
DEF_FIELD(symval, ssam_device_id, match_flags);
DEF_FIELD(symval, ssam_device_id, domain);
DEF_FIELD(symval, ssam_device_id, category);
DEF_FIELD(symval, ssam_device_id, target);
DEF_FIELD(symval, ssam_device_id, instance);
DEF_FIELD(symval, ssam_device_id, function);
sprintf(alias, "ssam:d%02Xc%02X", domain, category);
ADD(alias, "t", match_flags & SSAM_MATCH_TARGET, target);
ADD(alias, "i", match_flags & SSAM_MATCH_INSTANCE, instance);
ADD(alias, "f", match_flags & SSAM_MATCH_FUNCTION, function);
return 1;
}
/* Does namelen bytes of name exactly match the symbol? */ /* Does namelen bytes of name exactly match the symbol? */
static bool sym_is(const char *name, unsigned namelen, const char *symbol) static bool sym_is(const char *name, unsigned namelen, const char *symbol)
{ {
...@@ -1450,6 +1472,7 @@ static const struct devtable devtable[] = { ...@@ -1450,6 +1472,7 @@ static const struct devtable devtable[] = {
{"wmi", SIZE_wmi_device_id, do_wmi_entry}, {"wmi", SIZE_wmi_device_id, do_wmi_entry},
{"mhi", SIZE_mhi_device_id, do_mhi_entry}, {"mhi", SIZE_mhi_device_id, do_mhi_entry},
{"auxiliary", SIZE_auxiliary_device_id, do_auxiliary_entry}, {"auxiliary", SIZE_auxiliary_device_id, do_auxiliary_entry},
{"ssam", SIZE_ssam_device_id, do_ssam_entry},
}; };
/* Create MODULE_ALIAS() statements. /* Create MODULE_ALIAS() statements.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment