On Sun, Nov 15, 2020 at 9:25 PM Maximilian Luz <luzmaximilian@xxxxxxxxx> wrote:
Add Surface System Aggregator Module core and Surface Serial Hub driver,
required for the embedded controller found on Microsoft Surface devices.
The Surface System Aggregator Module (SSAM, SAM or Surface Aggregator)
is an embedded controller (EC) found on 4th and later generation
Microsoft Surface devices, with the exception of the Surface Go series.
This EC provides various functionality, depending on the device in
question. This can include battery status and thermal reporting (5th and
later generations), but also HID keyboard (6th+) and touchpad input
(7th+) on Surface Laptop and Surface Book 3 series devices.
This patch provides the basic necessities for communication with the SAM
EC on 5th and later generation devices. On these devices, the EC
provides an interface that acts as serial device, called the Surface
Serial Hub (SSH). 4th generation devices, on which the EC interface is
provided via an HID-over-I2C device, are not supported by this patch.
Specifically, this patch adds a driver for the SSH device (device HID
MSHW0084 in ACPI), as well as a controller structure and associated API.
This represents the functional core of the Surface Aggregator kernel
subsystem, introduced with this patch, and will be expanded upon in
subsequent commits.
The SSH driver acts as the main attachment point for this subsystem and
sets-up and manages the controller structure. The controller in turn
provides a basic communication interface, allowing to send requests from
host to EC and receiving the corresponding responses, as well as
managing and receiving events, sent from EC to host. It is structured
into multiple layers, with the top layer presenting the API used by
other kernel drivers and the lower layers modeled after the serial
protocol used for communication.
Said other drivers are then responsible for providing the (Surface model
specific) functionality accessible through the EC (e.g. battery status
reporting, thermal information, ...) via said controller structure and
API, and will be added in future commits.
...
+menuconfig SURFACE_AGGREGATOR
+ tristate "Microsoft Surface System Aggregator Module Subsystem and Drivers"
+ depends on SERIAL_DEV_BUS
+ depends on ACPI
+ select CRC_CCITT
+ help
+ The Surface System Aggregator Module (Surface SAM or SSAM) is an
+ embedded controller (EC) found on 5th- and later-generation Microsoft
+ Surface devices (i.e. Surface Pro 5, Surface Book 2, Surface Laptop,
+ and newer, with exception of Surface Go series devices).
+
+ Depending on the device in question, this EC provides varying
+ functionality, including:
+ - EC access from ACPI via Surface ACPI Notify (5th- and 6th-generation)
+ - battery status information (all devices)
+ - thermal sensor access (all devices)
+ - performance mode / cooling mode control (all devices)
+ - clipboard detachment system control (Surface Book 2 and 3)
+ - HID / keyboard input (Surface Laptops, Surface Book 3)
+
+ This option controls whether the Surface SAM subsystem core will be
+ built. This includes a driver for the Surface Serial Hub (SSH), which
+ is the device responsible for the communication with the EC, and a
+ basic kernel interface exposing the EC functionality to other client
+ drivers, i.e. allowing them to make requests to the EC and receive
+ events from it. Selecting this option alone will not provide any
+ client drivers and therefore no functionality beyond the in-kernel
+ interface. Said functionality is the responsibility of the respective
+ client drivers.
+
+ Note: While 4th-generation Surface devices also make use of a SAM EC,
+ due to a difference in the communication interface of the controller,
+ only 5th and later generations are currently supported. Specifically,
+ devices using SAM-over-SSH are supported, whereas devices using
+ SAM-over-HID, which is used on the 4th generation, are currently not
+ supported.
From this help text I didn't get if it will be a module or what if I
chose the above?
...
+/* -- Safe counters. -------------------------------------------------------- */
Why can't XArray be used here?
...
+
+
One blank line is enough
...
+static bool ssam_event_matches_notifier(
+ const struct ssam_event_notifier *notif,
+ const struct ssam_event *event)
Perhaps
static bool
ssam_event_matches_notifier(const struct ssam_event_notifier *n,
const struct ssam_event *event)
(or even switch to 100 limit, also note notif ->n — no need to repeat same word)
...
+ nb = rcu_dereference_raw(nh->head);
+ while (nb) {
+ nf = container_of(nb, struct ssam_event_notifier, base);
+ next_nb = rcu_dereference_raw(nb->next);
+
+ if (ssam_event_matches_notifier(nf, event)) {
+ ret = (ret & SSAM_NOTIF_STATE_MASK) | nb->fn(nf, event);
+ if (ret & SSAM_NOTIF_STOP)
+ break;
The returned value is a bitmask?!
What are you returning at the end?
+ }
+
+ nb = next_nb;
+ }
...
+static int __ssam_nfblk_insert(struct ssam_nf_head *nh, struct ssam_notifier_block *nb)
+{
+ struct ssam_notifier_block **link = &nh->head;
+
+ while ((*link) != NULL) {
+ if (unlikely((*link) == nb)) {
+ WARN(1, "double register detected");
+ return -EINVAL;
+ }
+
+ if (nb->priority > (*link)->priority)
+ break;
+
+ link = &((*link)->next);
+ }
+
+ nb->next = *link;
+ rcu_assign_pointer(*link, nb);
+
+ return 0;
+}
If you need RCU (which is also the Q per se), why not use RCU list?
...
+ while ((*link) != NULL) {
Redundant parentheses, redundant ' != NULL' part.
+ if ((*link) == nb)
+ return link;
+
+ link = &((*link)->next);
+ }
...
+ * struct ssam_nf_refcount_entry - RB-tree entry for referecnce counting event
In above you mistyped 'which' as 'whic' or so, and here reference.
Perhaps go thru spell checker?
...
+ * registered, or ``ERR_PTR(-ENOMEM)`` if the entry could not be allocated.
Better to spell out "error pointer" instead of cryptic ERR_PTR().
...
+ * Executa registered callbacks in order of their priority until either no
+ * callback is left or a callback returned a value with the %SSAM_NOTIF_STOP
returns
+ * bit set. Note that this bit is set automatically when converting non.zero
+ * error values via ssam_notifier_from_errno() to notifier values.
...
+ for (i = i - 1; i >= 0; i--)
while (i--)
+ ssam_nf_head_destroy(&nf->head[i]);
...
+ // limit number of processed events to avoid livelocking
+ for (i = 0; i < 10; i++) {
Magic number! Also, this will be better to read in a form of
unsigned int iterations = 10;
do {
...
} while (--iterations);
+ item = ssam_event_queue_pop(queue);
+ if (item == NULL)
+ return;
+
+ ssam_nf_call(nf, dev, item->rqid, &item->event);
+ kfree(item);
+ }
...
+static const guid_t SSAM_SSH_DSM_GUID = GUID_INIT(0xd5e383e1, 0xd892, 0x4a76,
+ 0x89, 0xfc, 0xf6, 0xaa, 0xae, 0x7e, 0xd5, 0xb5);
Can you use usual pattern for these UIDs, like
static const guid_t SSAM_SSH_DSM_GUID =
GUID_INIT(0xd5e383e1, 0xd892, 0x4a76,
0x89, 0xfc, 0xf6, 0xaa, 0xae, 0x7e, 0xd5, 0xb5);
?
Also put a comment how this UID will look like in a string representation.
...
+ if (!acpi_has_method(handle, "_DSM"))
+ return 0;
Hmm... What's the expectation?
+ obj = acpi_evaluate_dsm_typed(handle, &SSAM_SSH_DSM_GUID,
+ SSAM_SSH_DSM_REVISION, 0, NULL,
+ ACPI_TYPE_BUFFER);
+ if (!obj)
+ return -EFAULT;
EFAULT?! Perhaps you can simply return 0 here, no?
+ for (i = 0; i < obj->buffer.length && i < 8; i++)
+ mask |= (((u64)obj->buffer.pointer[i]) << (i * 8));
Don't we have some helpers for this? At least I remember similar code
went to one of PDx86 drivers like intel-vbtn or so.
+ if (mask & 0x01)
BIT(0) ?
+ *funcs = mask;
...
+ caps->ssh_power_profile = (u32)-1;
+ caps->screen_on_sleep_idle_timeout = (u32)-1;
+ caps->screen_off_sleep_idle_timeout = (u32)-1;
+ caps->d3_closes_handle = false;
+ caps->ssh_buffer_size = (u32)-1;
Use proper types and their limits (limits.h missed?).
...
+ // initialize request and packet transport layers
Inconsistent style of comments.
...
+ * In the course of this shutdown procedure, all currently registered
+ * notifiers will be unregistered. It is, however, strongly recommended to not
+ * rely on this behavior, and instead the party registring the notifier should
registering
+ * unregister it before the controller gets shut down, e.g. via the SSAM bus
+ * which guarantees client devices to be removed before a shutdown.
+ * Note that events may still be pending after this call, but due to the
+ * notifiers being unregistered, the will be dropped when the controller is
the?!
+ * subsequently being destroyed via ssam_controller_destroy().
...
+ * Ensures that all resources associated with the controller get freed. This
+ * function should only be called after the controller has been stopped via
+ * ssam_controller_shutdown(). In general, this function should not be called
+ * directly. The only valid place to call this function direclty is during
directly
+ * initialization, before the controller has been fully initialized and passed
+ * to other processes. This function is called automatically when the
+ * reference count of the controller reaches zero.
...
+ * ssam_request_sync_free() - Free a synchronous request.
+ * @rqst: The request to free.
to be freed?
...
+ * Allocates a synchronous request struct on the stack, fully initializes it
+ * using the provided buffer as message data buffer, submits it, and then
+ * waits for its completion before returning its staus. The
status
+ * SSH_COMMAND_MESSAGE_LENGTH() macro can be used to compute the required
+ * message buffer size.
...
+ * This is a wrapper for the raw SAM request to enable an event, thus it does
+ * not handle referecnce counting for enable/disable of events. If an event
+ * has already been enabled, the EC will ignore this request.
Grammar and English language style somehow feels not okay.
...
+ u8 buf[1] = { 0x00 };
Can't be simply buf ?
...
+ * This function will only send the display-off notification command if
+ * display noticications are supported by the EC. Currently all known devices
+ * support these notification.
Spell check!
...
+ * This function will only send the display-on notification command if display
+ * noticications are supported by the EC. Currently all known devices support
+ * these notification.
Ditto.
...
+ ssam_err(ctrl, "unexpected response from D0-exit notification:"
+ " 0x%02x\n", response);
Don't split string literals. Had you run a checkpatch?
Please do and use strict mode.
...
Overall impression of this submission:
- it's quite huge as for a single patch
- it feels like quite an overengineered solution: READ_ONCE, RCU,
list + spin_lock, RB tree of notifiers, my head!
- where is the architectural document of all these?