summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPixelBot AutoMerger <android-nexus-securitybot@system.gserviceaccount.com>2024-01-28 18:39:37 -0800
committerSecurityBot <android-nexus-securitybot@system.gserviceaccount.com>2024-01-28 18:39:37 -0800
commit7b5aed64401d3a4a1031472b0f0a59664a13c19e (patch)
treeca493f838d1f64cf26f033a6519055e517f2adc8
parent3f52eff0bec3116236b26feee0fe4ff255d652a1 (diff)
parentbfc9969208ad4923c9f59e9ebd0d8b7cf0227c5e (diff)
downloadlwis-7b5aed64401d3a4a1031472b0f0a59664a13c19e.tar.gz
Merge android13-gs-pixel-5.10-24Q2 into android13-gs-pixel-5.10
SBMerger: 571992243 Change-Id: I8c7b4baec06007652cf2a75ea0c8b99b3540cf74 Signed-off-by: SecurityBot <android-nexus-securitybot@system.gserviceaccount.com>
-rw-r--r--lwis_device.c35
-rw-r--r--lwis_device.h19
-rw-r--r--lwis_device_i2c.c1
-rw-r--r--lwis_device_i2c.h1
-rw-r--r--lwis_dt.c10
-rw-r--r--lwis_i2c_bus_manager.c470
-rw-r--r--lwis_i2c_bus_manager.h28
-rw-r--r--lwis_i2c_sched.c17
-rw-r--r--lwis_i2c_sched.h10
-rw-r--r--lwis_ioctl.c2
-rw-r--r--lwis_periodic_io.c30
-rw-r--r--lwis_transaction.c352
-rw-r--r--lwis_transaction.h34
13 files changed, 503 insertions, 506 deletions
diff --git a/lwis_device.c b/lwis_device.c
index 309584d..84815d8 100644
--- a/lwis_device.c
+++ b/lwis_device.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Google LWIS Base Device Driver
*
- * Copyright (c) 2018 Google, LLC
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Copyright 2018 Google LLC.
*/
#define pr_fmt(fmt) KBUILD_MODNAME "-dev: " fmt
@@ -16,10 +13,12 @@
#include <linux/device.h>
#include <linux/hashtable.h>
#include <linux/init.h>
+#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
+#include <linux/workqueue.h>
#include "lwis_buffer.h"
#include "lwis_clock.h"
@@ -583,6 +582,31 @@ static struct lwis_device *get_power_down_dev(struct lwis_device *lwis_dev)
return lwis_dev;
}
+void lwis_queue_device_worker(struct lwis_client *client)
+{
+ struct lwis_i2c_bus_manager *i2c_bus_manager = lwis_i2c_bus_manager_get(client->lwis_dev);
+ if (i2c_bus_manager) {
+ kthread_queue_work(&i2c_bus_manager->i2c_bus_worker, &client->i2c_work);
+ } else {
+ if (client->lwis_dev->transaction_worker_thread) {
+ kthread_queue_work(&client->lwis_dev->transaction_worker,
+ &client->transaction_work);
+ }
+ }
+}
+
+void lwis_flush_device_worker(struct lwis_client *client)
+{
+ struct lwis_i2c_bus_manager *i2c_bus_manager = lwis_i2c_bus_manager_get(client->lwis_dev);
+ if (i2c_bus_manager) {
+ lwis_i2c_bus_manager_flush_i2c_worker(client->lwis_dev);
+ } else {
+ if (client->lwis_dev->transaction_worker_thread) {
+ kthread_flush_worker(&client->lwis_dev->transaction_worker);
+ }
+ }
+}
+
int lwis_dev_process_power_sequence(struct lwis_device *lwis_dev,
struct lwis_device_power_sequence_list *list, bool set_active,
bool skip_error)
@@ -1613,7 +1637,6 @@ void lwis_base_unprobe(struct lwis_device *unprobe_lwis_dev)
lwis_dev->irq_gpios_info.gpios = NULL;
}
- /* Disconnect from the bus manager */
lwis_i2c_bus_manager_disconnect(lwis_dev);
/* Destroy device */
diff --git a/lwis_device.h b/lwis_device.h
index c70b98d..e70a42b 100644
--- a/lwis_device.h
+++ b/lwis_device.h
@@ -55,10 +55,7 @@
* Once the flush is complete, the client will transition back
* to NOT_FLUSHING state.
*/
-enum lwis_client_flush_state {
- NOT_FLUSHING = 0,
- FLUSHING
-};
+enum lwis_client_flush_state { NOT_FLUSHING, FLUSHING };
/* Forward declaration for lwis_device. This is needed for the declaration for
lwis_device_subclass_operations data struct. */
@@ -451,4 +448,18 @@ void lwis_save_register_io_info(struct lwis_device *lwis_dev, struct lwis_io_ent
*/
void lwis_process_worker_queue(struct lwis_client *client);
+/*
+ * lwis_queue_device_worker:
+ * Function to queue periodic or transaction work on the device
+ * worker.
+ */
+void lwis_queue_device_worker(struct lwis_client *client);
+
+/*
+ * lwis_flush_device_worker:
+ * Function to flush periodic or transaction work from the device
+ * worker.
+ */
+void lwis_flush_device_worker(struct lwis_client *client);
+
#endif /* LWIS_DEVICE_H_ */
diff --git a/lwis_device_i2c.c b/lwis_device_i2c.c
index 877719f..ba7b14a 100644
--- a/lwis_device_i2c.c
+++ b/lwis_device_i2c.c
@@ -273,7 +273,6 @@ static int lwis_i2c_device_probe(struct platform_device *plat_dev)
goto error_probe;
}
- /* Create I2C Bus Manager */
ret = lwis_i2c_bus_manager_create(i2c_dev);
if (ret) {
dev_err(i2c_dev->base_dev.dev, "Error in i2c bus manager creation\n");
diff --git a/lwis_device_i2c.h b/lwis_device_i2c.h
index 393bd32..3f43e1a 100644
--- a/lwis_device_i2c.h
+++ b/lwis_device_i2c.h
@@ -34,7 +34,6 @@ struct lwis_i2c_device {
u32 i2c_lock_group_id;
/* Mutex shared by the same group id's I2C devices */
struct mutex *group_i2c_lock;
- /* Pointer to the I2C bus manager for this device */
struct lwis_i2c_bus_manager *i2c_bus_manager;
int device_priority;
};
diff --git a/lwis_dt.c b/lwis_dt.c
index c844ce9..41e1878 100644
--- a/lwis_dt.c
+++ b/lwis_dt.c
@@ -1181,12 +1181,13 @@ static int parse_i2c_device_priority(struct lwis_i2c_device *i2c_dev)
return 0;
}
if (ret) {
- pr_err("invalid i2c-device-priority value\n");
+ dev_err(i2c_dev->base_dev.dev, "invalid i2c-device-priority value\n");
return ret;
}
if ((i2c_dev->device_priority < I2C_DEVICE_HIGH_PRIORITY) ||
(i2c_dev->device_priority > I2C_DEVICE_LOW_PRIORITY)) {
- pr_err("invalid i2c-device-priority value %d\n", i2c_dev->device_priority);
+ dev_err(i2c_dev->base_dev.dev, "invalid i2c-device-priority value %d\n",
+ i2c_dev->device_priority);
return -EINVAL;
}
@@ -1219,7 +1220,7 @@ static int parse_i2c_lock_group_id(struct lwis_i2c_device *i2c_dev)
return 0;
}
-static int parse_transaction_process_limit(struct lwis_device *lwis_dev)
+static void parse_transaction_process_limit(struct lwis_device *lwis_dev)
{
struct device_node *dev_node;
@@ -1228,8 +1229,6 @@ static int parse_transaction_process_limit(struct lwis_device *lwis_dev)
of_property_read_u32(dev_node, "transaction-process-limit",
&lwis_dev->transaction_process_limit);
-
- return 0;
}
int lwis_base_parse_dt(struct lwis_device *lwis_dev)
@@ -1408,7 +1407,6 @@ int lwis_i2c_device_parse_dt(struct lwis_i2c_device *i2c_dev)
ret = parse_i2c_device_priority(i2c_dev);
if (ret) {
- dev_err(i2c_dev->base_dev.dev, "Error parsing i2c device priority\n");
return ret;
}
diff --git a/lwis_i2c_bus_manager.c b/lwis_i2c_bus_manager.c
index c030f27..ce9f235 100644
--- a/lwis_i2c_bus_manager.c
+++ b/lwis_i2c_bus_manager.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * Google LWIS I2C BUS Manager
+ * Google LWIS I2C Bus Manager
*
- * Copyright (c) 2023 Google, LLC
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Copyright 2023 Google LLC.
*/
#define pr_fmt(fmt) KBUILD_MODNAME "-i2c-bus-manager: " fmt
@@ -18,23 +15,22 @@
bool lwis_i2c_bus_manager_debug;
module_param(lwis_i2c_bus_manager_debug, bool, 0644);
-/* Defines the global list of bus managers shared among various I2C devices
- * Each manager would control the transfers on a single I2C bus */
+/*
+ * Defines the global list of bus managers shared among various I2C devices
+ * Each manager would control the transfers on a single I2C bus
+ */
static struct mutex i2c_bus_manager_list_lock;
static struct lwis_i2c_bus_manager_list i2c_bus_manager_list;
/*
* insert_bus_manager_id_in_list:
* Inserts the newly created instance of I2C bus manager in the list
-*/
+ */
static int insert_bus_manager_id_in_list(struct lwis_i2c_bus_manager *i2c_bus_manager,
int i2c_bus_handle)
{
struct lwis_i2c_bus_manager_identifier *i2c_bus_manager_identifier_node = NULL;
- if (!i2c_bus_manager)
- return -EINVAL;
-
i2c_bus_manager_identifier_node =
kzalloc(sizeof(struct lwis_i2c_bus_manager_identifier), GFP_KERNEL);
if (!i2c_bus_manager_identifier_node) {
@@ -57,12 +53,12 @@ static int insert_bus_manager_id_in_list(struct lwis_i2c_bus_manager *i2c_bus_ma
/*
* delete_bus_manager_id_in_list:
* Deletes the newly created instance of I2C bus manager in the list
-*/
+ */
static void delete_bus_manager_id_in_list(int i2c_bus_handle)
{
- struct lwis_i2c_bus_manager_identifier *i2c_bus_manager_identifier_node = NULL;
- struct list_head *i2c_bus_manager_list_node = NULL;
- struct list_head *i2c_bus_manager_list_tmp_node = NULL;
+ struct lwis_i2c_bus_manager_identifier *i2c_bus_manager_identifier_node;
+ struct list_head *i2c_bus_manager_list_node;
+ struct list_head *i2c_bus_manager_list_tmp_node;
mutex_lock(&i2c_bus_manager_list_lock);
list_for_each_safe (i2c_bus_manager_list_node, i2c_bus_manager_list_tmp_node,
@@ -84,13 +80,13 @@ static void delete_bus_manager_id_in_list(int i2c_bus_handle)
* find_i2c_bus_manager:
* Returns a valid I2C Bus Manager for a valid i2c_bus_handle.
* Returns NULL if the bus manager hasn't been created for this handle.
-*/
+ */
static struct lwis_i2c_bus_manager *find_i2c_bus_manager(int i2c_bus_handle)
{
struct lwis_i2c_bus_manager *i2c_bus_manager = NULL;
- struct list_head *i2c_bus_manager_list_node = NULL;
- struct list_head *i2c_bus_manager_list_tmp_node = NULL;
- struct lwis_i2c_bus_manager_identifier *i2c_bus_manager_identifier = NULL;
+ struct list_head *i2c_bus_manager_list_node;
+ struct list_head *i2c_bus_manager_list_tmp_node;
+ struct lwis_i2c_bus_manager_identifier *i2c_bus_manager_identifier;
mutex_lock(&i2c_bus_manager_list_lock);
list_for_each_safe (i2c_bus_manager_list_node, i2c_bus_manager_list_tmp_node,
@@ -109,17 +105,32 @@ static struct lwis_i2c_bus_manager *find_i2c_bus_manager(int i2c_bus_handle)
}
/*
+ * stop_i2c_kthread_workers:
+ * Stop I2C worker thread, one per bus
+ */
+static void stop_i2c_kthread_workers(struct lwis_i2c_bus_manager *i2c_bus_manager,
+ struct lwis_device *lwis_dev)
+{
+ if (!i2c_bus_manager)
+ return;
+
+ if (i2c_bus_manager->i2c_bus_worker_thread) {
+ if (lwis_i2c_bus_manager_debug) {
+ dev_err(lwis_dev->dev,
+ "stop_i2c_kthread_workers: destroying I2C Bus Manager thread\n");
+ }
+ kthread_stop(i2c_bus_manager->i2c_bus_worker_thread);
+ }
+}
+
+/*
* create_i2c_kthread_workers:
* Creates I2C worker threads, one per bus
-*/
+ */
static int create_i2c_kthread_workers(struct lwis_i2c_bus_manager *i2c_bus_manager,
struct lwis_device *lwis_dev)
{
char i2c_bus_thread_name[LWIS_MAX_NAME_STRING_LEN];
- if (!i2c_bus_manager) {
- dev_err(lwis_dev->dev, "lwis_create_kthread_workers: I2C Bus Manager is NULL\n");
- return -ENODEV;
- }
scnprintf(i2c_bus_thread_name, LWIS_MAX_NAME_STRING_LEN, "lwis_%s",
i2c_bus_manager->i2c_bus_name);
kthread_init_worker(&i2c_bus_manager->i2c_bus_worker);
@@ -137,7 +148,7 @@ static int create_i2c_kthread_workers(struct lwis_i2c_bus_manager *i2c_bus_manag
* check_i2c_thread_priority:
* Checks if the lwis device being connected has the same priority as other I2C threads
* Prints a warning message if there is a difference between the priorities
-*/
+ */
static void check_i2c_thread_priority(struct lwis_i2c_bus_manager *i2c_bus_manager,
struct lwis_device *lwis_dev)
{
@@ -153,7 +164,7 @@ static void check_i2c_thread_priority(struct lwis_i2c_bus_manager *i2c_bus_manag
/*
* set_i2c_thread_priority:
* Sets the priority for I2C threads
-*/
+ */
static int set_i2c_thread_priority(struct lwis_i2c_bus_manager *i2c_bus_manager,
struct lwis_device *lwis_dev)
{
@@ -176,10 +187,6 @@ static bool is_valid_connected_device(struct lwis_device *lwis_dev,
struct lwis_i2c_connected_device *connected_i2c_device;
struct list_head *i2c_connected_device_node, *i2c_connected_device_tmp_node;
- if ((lwis_dev == NULL) || (i2c_bus_manager == NULL)) {
- return false;
- }
-
list_for_each_safe (i2c_connected_device_node, i2c_connected_device_tmp_node,
&i2c_bus_manager->i2c_connected_devices) {
connected_i2c_device =
@@ -196,7 +203,7 @@ static bool is_valid_connected_device(struct lwis_device *lwis_dev,
/*
* set_i2c_bus_manager_name:
* Builds and sets the I2C Bus manager name
-*/
+ */
static void set_i2c_bus_manager_name(struct lwis_i2c_bus_manager *i2c_bus_manager)
{
scnprintf(i2c_bus_manager->i2c_bus_name, LWIS_MAX_NAME_STRING_LEN, "I2C_Bus_%d",
@@ -215,36 +222,28 @@ static void destroy_i2c_bus_manager(struct lwis_i2c_bus_manager *i2c_bus_manager
return;
}
- dev_info(lwis_dev->dev, "Destroying I2C Bus Manager: %s\n", i2c_bus_manager->i2c_bus_name);
+ dev_dbg(lwis_dev->dev, "Destroying I2C Bus Manager: %s\n", i2c_bus_manager->i2c_bus_name);
mutex_lock(&i2c_bus_manager->i2c_process_queue_lock);
for (i = 0; i < I2C_MAX_PRIORITY_LEVELS; i++) {
lwis_i2c_process_request_queue_destroy(&i2c_bus_manager->i2c_bus_process_queue[i]);
}
mutex_unlock(&i2c_bus_manager->i2c_process_queue_lock);
- /* Delete the bus manager instance from the list */
delete_bus_manager_id_in_list(i2c_bus_manager->i2c_bus_id);
- /* Free the bus manager */
kfree(i2c_bus_manager);
- i2c_bus_manager = NULL;
}
/*
* connect_i2c_bus_manager:
* Connects a lwis device to this instance of the I2C bus manager.
-*/
+ */
static int connect_i2c_bus_manager(struct lwis_i2c_bus_manager *i2c_bus_manager,
struct lwis_device *lwis_dev)
{
int ret = 0;
struct lwis_i2c_connected_device *connected_i2c_device;
- if ((!lwis_dev) || (!i2c_bus_manager)) {
- pr_err("Null lwis device or bus manager\n");
- return -EINVAL;
- }
-
if (!lwis_check_device_type(lwis_dev, DEVICE_TYPE_I2C)) {
dev_err(lwis_dev->dev,
"Failed trying to connect non I2C device to a I2C bus manager\n");
@@ -267,11 +266,8 @@ static int connect_i2c_bus_manager(struct lwis_i2c_bus_manager *i2c_bus_manager,
static bool i2c_device_priority_is_valid(int device_priority)
{
- if ((device_priority >= I2C_DEVICE_HIGH_PRIORITY) &&
- (device_priority <= I2C_DEVICE_LOW_PRIORITY)) {
- return true;
- }
- return false;
+ return ((device_priority >= I2C_DEVICE_HIGH_PRIORITY) &&
+ (device_priority <= I2C_DEVICE_LOW_PRIORITY));
}
/*
@@ -283,30 +279,24 @@ static bool i2c_device_priority_is_valid(int device_priority)
*/
void lwis_i2c_bus_manager_process_worker_queue(struct lwis_client *client)
{
- /* Get the correct I2C Bus manager to process it's queue */
- struct lwis_device *lwis_dev = NULL;
- struct lwis_i2c_bus_manager *i2c_bus_manager = NULL;
- int i = 0;
+ struct lwis_device *lwis_dev;
+ struct lwis_i2c_bus_manager *i2c_bus_manager;
+ int i;
/* The transfers will be processed in fifo order */
- struct lwis_client *client_to_process = NULL;
- struct lwis_device *lwis_dev_to_process = NULL;
- struct lwis_i2c_process_queue *process_queue = NULL;
- struct lwis_i2c_process_request *process_request = NULL;
+ struct lwis_client *client_to_process;
+ struct lwis_device *lwis_dev_to_process;
+ struct lwis_i2c_process_queue *process_queue;
+ struct lwis_i2c_process_request *process_request;
struct list_head *i2c_client_node, *i2c_client_tmp_node;
lwis_dev = client->lwis_dev;
- i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
+ i2c_bus_manager = lwis_i2c_bus_manager_get(lwis_dev);
if (lwis_i2c_bus_manager_debug) {
dev_info(lwis_dev->dev, "%s scheduled by %s\n", i2c_bus_manager->i2c_bus_name,
- lwis_dev->name);
- }
-
- if (!i2c_bus_manager) {
- dev_err(lwis_dev->dev, "I2C Bus Manager is null\n");
- return;
+ lwis_dev->name);
}
mutex_lock(&i2c_bus_manager->i2c_process_queue_lock);
@@ -315,9 +305,9 @@ void lwis_i2c_bus_manager_process_worker_queue(struct lwis_client *client)
list_for_each_safe (i2c_client_node, i2c_client_tmp_node, &process_queue->head) {
if (lwis_i2c_bus_manager_debug) {
dev_info(lwis_dev->dev,
- "Process request nodes for %s: cur %p tmp %p\n",
- i2c_bus_manager->i2c_bus_name, i2c_client_node,
- i2c_client_tmp_node);
+ "Process request nodes for %s: cur %p tmp %p\n",
+ i2c_bus_manager->i2c_bus_name, i2c_client_node,
+ i2c_client_tmp_node);
}
process_request = list_entry(i2c_client_node,
struct lwis_i2c_process_request, request_node);
@@ -342,7 +332,7 @@ void lwis_i2c_bus_manager_process_worker_queue(struct lwis_client *client)
if (lwis_i2c_bus_manager_debug) {
dev_info(lwis_dev_to_process->dev, "Processing client start %s\n",
- lwis_dev_to_process->name);
+ lwis_dev_to_process->name);
}
if (is_valid_connected_device(lwis_dev_to_process, i2c_bus_manager)) {
@@ -352,7 +342,7 @@ void lwis_i2c_bus_manager_process_worker_queue(struct lwis_client *client)
if (lwis_i2c_bus_manager_debug) {
dev_info(lwis_dev_to_process->dev, "Processing client end %s\n",
- lwis_dev_to_process->name);
+ lwis_dev_to_process->name);
}
}
}
@@ -365,9 +355,9 @@ void lwis_i2c_bus_manager_process_worker_queue(struct lwis_client *client)
*/
int lwis_i2c_bus_manager_create(struct lwis_i2c_device *i2c_dev)
{
- int ret = 0;
- int i = 0;
- struct lwis_i2c_bus_manager *i2c_bus_manager = NULL;
+ int ret;
+ int i;
+ struct lwis_i2c_bus_manager *i2c_bus_manager;
struct lwis_device *i2c_base_device = &i2c_dev->base_dev;
if (!lwis_check_device_type(i2c_base_device, DEVICE_TYPE_I2C)) {
@@ -376,7 +366,6 @@ int lwis_i2c_bus_manager_create(struct lwis_i2c_device *i2c_dev)
i2c_bus_manager = find_i2c_bus_manager(i2c_dev->adapter->nr);
if (!i2c_bus_manager) {
- /* Allocate memory for I2C Bus Manager */
i2c_bus_manager = kzalloc(sizeof(struct lwis_i2c_bus_manager), GFP_KERNEL);
if (!i2c_bus_manager) {
dev_err(i2c_base_device->dev, "Failed to allocate lwis i2c bus manager\n");
@@ -424,6 +413,7 @@ int lwis_i2c_bus_manager_create(struct lwis_i2c_device *i2c_dev)
/* Connect this lwis device to the I2C Bus manager found/created */
ret = connect_i2c_bus_manager(i2c_bus_manager, i2c_base_device);
if (ret < 0) {
+ dev_err(i2c_base_device->dev, "Failed to connect device to I2C Bus Manager\n");
goto error_creating_i2c_bus_manager;
}
@@ -437,9 +427,10 @@ int lwis_i2c_bus_manager_create(struct lwis_i2c_device *i2c_dev)
error_creating_i2c_bus_manager:
dev_err(i2c_base_device->dev, "Error creating I2C Bus Manager\n");
+ delete_bus_manager_id_in_list(i2c_dev->adapter->nr);
+ stop_i2c_kthread_workers(i2c_bus_manager, i2c_base_device);
if (i2c_bus_manager) {
kfree(i2c_bus_manager);
- i2c_bus_manager = NULL;
}
return -EINVAL;
}
@@ -448,15 +439,15 @@ error_creating_i2c_bus_manager:
* lwis_i2c_bus_manager_disconnect:
* Disconnects a lwis device from this instance of the I2C bus manager.
* Doesn't destroy the instance of I2C bus manager
-*/
+ */
void lwis_i2c_bus_manager_disconnect(struct lwis_device *lwis_dev)
{
struct lwis_i2c_bus_manager *i2c_bus_manager;
struct lwis_i2c_connected_device *connected_i2c_device;
struct list_head *i2c_connected_device_node, *i2c_connected_device_tmp_node;
- struct lwis_i2c_device *i2c_dev = NULL;
+ struct lwis_i2c_device *i2c_dev;
- i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
+ i2c_bus_manager = lwis_i2c_bus_manager_get(lwis_dev);
if (!i2c_bus_manager) {
return;
}
@@ -473,10 +464,10 @@ void lwis_i2c_bus_manager_disconnect(struct lwis_device *lwis_dev)
if (connected_i2c_device->connected_device == lwis_dev) {
list_del(&connected_i2c_device->connected_device_node);
kfree(connected_i2c_device);
- connected_i2c_device = NULL;
- --i2c_bus_manager->number_of_connected_devices;
+ i2c_bus_manager->number_of_connected_devices--;
- /* Destroy the bus manager instance if there
+ /*
+ * Destroy the bus manager instance if there
* are no more I2C devices connected to it
*/
if (i2c_bus_manager->number_of_connected_devices == 0) {
@@ -487,13 +478,13 @@ void lwis_i2c_bus_manager_disconnect(struct lwis_device *lwis_dev)
}
}
-/* lwis_i2c_bus_manager_lock_i2c_bus:
+/*
+ * lwis_i2c_bus_manager_lock_i2c_bus:
* Locks the I2C bus for a given I2C Lwis Device
*/
void lwis_i2c_bus_manager_lock_i2c_bus(struct lwis_device *lwis_dev)
{
- struct lwis_i2c_bus_manager *i2c_bus_manager = NULL;
- i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
+ struct lwis_i2c_bus_manager *i2c_bus_manager = lwis_i2c_bus_manager_get(lwis_dev);
if (i2c_bus_manager) {
mutex_lock(&i2c_bus_manager->i2c_bus_lock);
if (lwis_i2c_bus_manager_debug) {
@@ -502,13 +493,13 @@ void lwis_i2c_bus_manager_lock_i2c_bus(struct lwis_device *lwis_dev)
}
}
-/* lwis_i2c_bus_manager_unlock_i2c_bus:
+/*
+ * lwis_i2c_bus_manager_unlock_i2c_bus:
* Unlocks the I2C bus for a given I2C Lwis Device
*/
void lwis_i2c_bus_manager_unlock_i2c_bus(struct lwis_device *lwis_dev)
{
- struct lwis_i2c_bus_manager *i2c_bus_manager = NULL;
- i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
+ struct lwis_i2c_bus_manager *i2c_bus_manager = lwis_i2c_bus_manager_get(lwis_dev);
if (i2c_bus_manager) {
if (lwis_i2c_bus_manager_debug) {
dev_info(lwis_dev->dev, "%s unlock\n", i2c_bus_manager->i2c_bus_name);
@@ -517,12 +508,13 @@ void lwis_i2c_bus_manager_unlock_i2c_bus(struct lwis_device *lwis_dev)
}
}
-/* lwis_i2c_bus_managlwis_i2c_bus_manager_get_managerr_get:
+/*
+ * lwis_i2c_bus_managlwis_i2c_bus_manager_getr_get:
* Gets I2C Bus Manager for a given lwis device
*/
-struct lwis_i2c_bus_manager *lwis_i2c_bus_manager_get_manager(struct lwis_device *lwis_dev)
+struct lwis_i2c_bus_manager *lwis_i2c_bus_manager_get(struct lwis_device *lwis_dev)
{
- struct lwis_i2c_device *i2c_dev = NULL;
+ struct lwis_i2c_device *i2c_dev;
if (lwis_check_device_type(lwis_dev, DEVICE_TYPE_I2C)) {
i2c_dev = container_of(lwis_dev, struct lwis_i2c_device, base_dev);
if (i2c_dev) {
@@ -537,26 +529,26 @@ struct lwis_i2c_bus_manager *lwis_i2c_bus_manager_get_manager(struct lwis_device
*/
void lwis_i2c_bus_manager_flush_i2c_worker(struct lwis_device *lwis_dev)
{
- struct lwis_i2c_bus_manager *i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
-
- if (i2c_bus_manager == NULL)
- return;
+ struct lwis_i2c_bus_manager *i2c_bus_manager = lwis_i2c_bus_manager_get(lwis_dev);
- kthread_flush_worker(&i2c_bus_manager->i2c_bus_worker);
+ if (i2c_bus_manager) {
+ kthread_flush_worker(&i2c_bus_manager->i2c_bus_worker);
+ }
}
-/* lwis_i2c_bus_manager_list_initialize:
+/*
+ * lwis_i2c_bus_manager_list_initialize:
* Initializes bus manager global list. This is the list that holds
* actual bus manager pointers for a given physical I2C Bus connection
*/
void lwis_i2c_bus_manager_list_initialize(void)
{
- /* initialize_i2c_bus_manager_list */
mutex_init(&i2c_bus_manager_list_lock);
INIT_LIST_HEAD(&i2c_bus_manager_list.i2c_bus_manager_list_head);
}
-/* lwis_i2c_bus_manager_list_deinitialize:
+/*
+ * lwis_i2c_bus_manager_list_deinitialize:
* Deinitializes bus manager global list
*/
void lwis_i2c_bus_manager_list_deinitialize(void)
@@ -564,7 +556,6 @@ void lwis_i2c_bus_manager_list_deinitialize(void)
struct list_head *i2c_bus_manager_list_node, *i2c_bus_manager_list_tmp_node;
struct lwis_i2c_bus_manager_identifier *i2c_bus_manager_identifier;
- /* deinitialize_i2c_bus_manager_list */
mutex_lock(&i2c_bus_manager_list_lock);
list_for_each_safe (i2c_bus_manager_list_node, i2c_bus_manager_list_tmp_node,
&i2c_bus_manager_list.i2c_bus_manager_list_head) {
@@ -574,108 +565,191 @@ void lwis_i2c_bus_manager_list_deinitialize(void)
i2c_bus_manager_identifier->i2c_bus_manager = NULL;
list_del(&i2c_bus_manager_identifier->i2c_bus_manager_list_node);
kfree(i2c_bus_manager_identifier);
- i2c_bus_manager_identifier = NULL;
}
mutex_unlock(&i2c_bus_manager_list_lock);
}
-/* lwis_i2c_bus_manager_connect_client:
- * Connects a lwis client to the bus manager to be processed by the worker.
- * The client will be connected to the appropriate priority queue based
- * on the I2C device priority specified in the dts for the I2C device node.
- * I2C lwis client is always connected when a new instance of client is
- * created.
+/*
+ * do_client_connect:
+ * Connect client to the bus manager processing node list.
*/
-int lwis_i2c_bus_manager_connect_client(struct lwis_client *connecting_client)
+static int do_client_connect(struct lwis_client *connecting_client,
+ struct lwis_i2c_bus_manager *i2c_bus_manager,
+ struct lwis_i2c_process_request *client_node, int device_priority)
{
- int ret = 0;
- int device_priority = I2C_MAX_PRIORITY_LEVELS;
- bool create_client_node = true;
+ struct lwis_i2c_process_queue *process_queue;
struct lwis_i2c_process_request *i2c_connecting_client_node;
- struct lwis_device *lwis_dev = NULL;
- struct lwis_i2c_process_queue *process_queue = NULL;
- struct lwis_i2c_device *i2c_dev = NULL;
- struct lwis_i2c_bus_manager *i2c_bus_manager = NULL;
- struct list_head *request, *request_tmp;
- struct lwis_i2c_process_request *search_node;
+ process_queue = &i2c_bus_manager->i2c_bus_process_queue[device_priority];
- if (!connecting_client) {
- pr_err("Connecting client pointer for I2C Bus Manager is NULL\n");
- return -EINVAL;
+ if ((client_node) && (client_node->requesting_client == connecting_client)) {
+ dev_info(connecting_client->lwis_dev->dev,
+ "I2C client already connected %s(%p) to bus %s \n",
+ connecting_client->lwis_dev->name, connecting_client,
+ i2c_bus_manager->i2c_bus_name);
+ return 0;
}
- lwis_dev = connecting_client->lwis_dev;
- if (!lwis_dev) {
- pr_err("Connecting device for I2C Bus Manager is NULL\n");
- return -EINVAL;
+ i2c_connecting_client_node = kzalloc(sizeof(struct lwis_i2c_process_request), GFP_KERNEL);
+ if (!i2c_connecting_client_node) {
+ return -ENOMEM;
}
+ i2c_connecting_client_node->requesting_client = connecting_client;
+ INIT_LIST_HEAD(&i2c_connecting_client_node->request_node);
+ list_add_tail(&i2c_connecting_client_node->request_node, &process_queue->head);
+ process_queue->number_of_nodes++;
+ dev_info(connecting_client->lwis_dev->dev, "Connecting client %s(%p) to bus %s\n",
+ connecting_client->lwis_dev->name, connecting_client,
+ i2c_bus_manager->i2c_bus_name);
+ return 0;
+}
- if (!lwis_check_device_type(lwis_dev, DEVICE_TYPE_I2C)) {
- return ret;
+/*
+ * do_client_disconnect:
+ * Disconnect client from the bus manager processing node list.
+ */
+static int do_client_disconnect(struct lwis_client *disconnecting_client,
+ struct lwis_i2c_bus_manager *i2c_bus_manager,
+ struct lwis_i2c_process_request *i2c_disconnecting_client_node,
+ int device_priority)
+{
+ struct lwis_i2c_process_queue *process_queue =
+ &i2c_bus_manager->i2c_bus_process_queue[device_priority];
+ dev_info(disconnecting_client->lwis_dev->dev,
+ "Disconnecting I2C client %s(%p) from bus %s\n",
+ disconnecting_client->lwis_dev->name, disconnecting_client,
+ i2c_bus_manager->i2c_bus_name);
+ list_del(&i2c_disconnecting_client_node->request_node);
+ i2c_disconnecting_client_node->requesting_client = NULL;
+ kfree(i2c_disconnecting_client_node);
+ process_queue->number_of_nodes--;
+ return 0;
+}
+
+/*
+ * find_client:
+ * Find the client on the bus manager to connect/disconnect from the processing
+ * node list.
+ */
+static int find_client(int device_priority, struct lwis_i2c_bus_manager *i2c_bus_manager,
+ struct lwis_client *client,
+ enum lwis_i2c_client_connection connection_status)
+{
+ struct list_head *request, *request_tmp;
+ struct lwis_i2c_process_queue *process_queue;
+ struct lwis_i2c_process_request *client_node;
+
+ process_queue = &i2c_bus_manager->i2c_bus_process_queue[device_priority];
+ if (!lwis_i2c_process_request_queue_is_empty(process_queue)) {
+ list_for_each_safe (request, request_tmp, &process_queue->head) {
+ client_node =
+ list_entry(request, struct lwis_i2c_process_request, request_node);
+ if (client_node->requesting_client != client) {
+ continue;
+ }
+ if (connection_status == I2C_CLIENT_CONNECT) {
+ return do_client_connect(client, i2c_bus_manager, client_node,
+ device_priority);
+ } else if (connection_status == I2C_CLIENT_DISCONNECT) {
+ return do_client_disconnect(client, i2c_bus_manager, client_node,
+ device_priority);
+ } else {
+ dev_err(client->lwis_dev->dev,
+ "Invalid client connection status %d", connection_status);
+ return -EINVAL;
+ }
+ }
}
- i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
- if (!i2c_bus_manager) {
- dev_err(lwis_dev->dev, "I2C bus manager is NULL\n");
- return -EINVAL;
+ /*
+ * Connect the client if:
+ * 1. The process queue is empty.
+ * 2. If there is no matching client found durnig the search in the exiting queue.
+ */
+ if (connection_status == I2C_CLIENT_CONNECT) {
+ return do_client_connect(client, i2c_bus_manager, NULL, device_priority);
}
- i2c_dev = container_of(lwis_dev, struct lwis_i2c_device, base_dev);
- if (!i2c_dev) {
- dev_err(lwis_dev->dev, "I2C device is NULL\n");
- return -EINVAL;
+ return 0;
+}
+
+/*
+ * get_device_priority_and_bus_manager:
+ * Get the device priority and I2C Bus Manager handle for the client.
+ */
+static int get_device_priority_and_bus_manager(struct lwis_client *client, int *device_priority,
+ struct lwis_i2c_bus_manager **i2c_bus_manager)
+{
+ struct lwis_i2c_device *i2c_dev;
+
+ /*
+ * This device type check ensures that the non-I2C devices do
+ * not get a failure due to bus manager being null when trying
+ * to open the lwis client.
+ */
+ if (!lwis_check_device_type(client->lwis_dev, DEVICE_TYPE_I2C)) {
+ return 0;
}
- device_priority = i2c_dev->device_priority;
- if (!i2c_device_priority_is_valid(device_priority)) {
- dev_err(lwis_dev->dev, "Invalid I2C device priority %d\n", device_priority);
+ /*
+ * This check ensures that the I2C devices have a valid
+ * bus manager to associate the lwis clients.
+ */
+ *i2c_bus_manager = lwis_i2c_bus_manager_get(client->lwis_dev);
+ if (!(*i2c_bus_manager)) {
+ dev_err(client->lwis_dev->dev, "I2C bus manager is NULL\n");
return -EINVAL;
}
- mutex_lock(&i2c_bus_manager->i2c_process_queue_lock);
+ /*
+ * Since i2c_dev validity is checked in lwis_i2c_bus_manager_get
+ * there is no need to check whether i2c_dev is null and we can proceed
+ * with processing device_priority directly.
+ */
+ i2c_dev = container_of(client->lwis_dev, struct lwis_i2c_device, base_dev);
- // Search for existing client node in the queue, if client is already connected
- // to this bus then don't create a new client node
- process_queue = &i2c_bus_manager->i2c_bus_process_queue[device_priority];
- if (!lwis_i2c_process_request_queue_is_empty(process_queue)) {
- list_for_each_safe (request, request_tmp, &process_queue->head) {
- search_node =
- list_entry(request, struct lwis_i2c_process_request, request_node);
- if (search_node->requesting_client == connecting_client) {
- dev_info(lwis_dev->dev,
- "I2C client already connected %s(%p) to bus %s \n",
- lwis_dev->name, connecting_client,
- i2c_bus_manager->i2c_bus_name);
- create_client_node = false;
- break;
- }
- }
+ *device_priority = i2c_dev->device_priority;
+ if (!i2c_device_priority_is_valid(*device_priority)) {
+ dev_err(client->lwis_dev->dev, "Invalid I2C device priority %d\n",
+ *device_priority);
+ return -EINVAL;
}
- if (create_client_node) {
- i2c_connecting_client_node =
- kzalloc(sizeof(struct lwis_i2c_process_request), GFP_KERNEL);
- if (!i2c_connecting_client_node) {
- dev_err(lwis_dev->dev, "Failed to connect client to I2C Bus Manager\n");
- return -ENOMEM;
- }
- i2c_connecting_client_node->requesting_client = connecting_client;
- INIT_LIST_HEAD(&i2c_connecting_client_node->request_node);
- list_add_tail(&i2c_connecting_client_node->request_node, &process_queue->head);
- ++process_queue->number_of_nodes;
- dev_info(lwis_dev->dev, "Connecting client %s(%p) to bus %s\n", lwis_dev->name,
- connecting_client, i2c_bus_manager->i2c_bus_name);
- if (lwis_i2c_bus_manager_debug) {
- dev_info(lwis_dev->dev, "Adding process request %p\n",
- i2c_connecting_client_node);
- }
+ return 0;
+}
+
+/*
+ * lwis_i2c_bus_manager_connect_client:
+ * Connects a lwis client to the bus manager to be processed by the worker.
+ * The client will be connected to the appropriate priority queue based
+ * on the I2C device priority specified in the dts for the I2C device node.
+ * I2C lwis client is always connected when a new instance of client is
+ * created.
+ */
+int lwis_i2c_bus_manager_connect_client(struct lwis_client *connecting_client)
+{
+ int ret;
+ int device_priority = I2C_MAX_PRIORITY_LEVELS;
+ struct lwis_i2c_bus_manager *i2c_bus_manager = NULL;
+
+ ret = get_device_priority_and_bus_manager(connecting_client, &device_priority,
+ &i2c_bus_manager);
+ if (ret || !i2c_bus_manager) {
+ return ret;
}
+ /*
+ * Search for existing client node in the queue, if client is already connected
+ * to this bus then don't create a new client node
+ */
+ mutex_lock(&i2c_bus_manager->i2c_process_queue_lock);
+ ret = find_client(device_priority, i2c_bus_manager, connecting_client, I2C_CLIENT_CONNECT);
mutex_unlock(&i2c_bus_manager->i2c_process_queue_lock);
+
return ret;
}
-/* lwis_i2c_bus_manager_disconnect_client:
+/*
+ * lwis_i2c_bus_manager_disconnect_client:
* Disconnects a lwis client to the bus manager. This will make sure that
* the released client is not processed further by the I2C worker.
* The client will be disconnected from the appropriate priority queue based
@@ -685,67 +759,17 @@ int lwis_i2c_bus_manager_connect_client(struct lwis_client *connecting_client)
*/
void lwis_i2c_bus_manager_disconnect_client(struct lwis_client *disconnecting_client)
{
+ int ret;
int device_priority = I2C_MAX_PRIORITY_LEVELS;
- struct lwis_i2c_process_request *i2c_disconnecting_client_node;
- struct lwis_device *lwis_dev = NULL;
- struct lwis_i2c_process_queue *process_queue = NULL;
- struct lwis_i2c_device *i2c_dev = NULL;
- struct list_head *request, *request_tmp;
struct lwis_i2c_bus_manager *i2c_bus_manager = NULL;
- if (!disconnecting_client) {
- pr_err("Disconnecting client pointer for I2C Bus Manager is NULL\n");
- return;
- }
-
- lwis_dev = disconnecting_client->lwis_dev;
- if (!lwis_dev) {
- pr_err("Disconnecting device for I2C Bus Manager is NULL\n");
- return;
- }
-
- if (!lwis_check_device_type(lwis_dev, DEVICE_TYPE_I2C)) {
- return;
- }
-
- i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
- if (!i2c_bus_manager) {
- dev_err(lwis_dev->dev, "I2C bus manager is NULL\n");
- return;
- }
-
- i2c_dev = container_of(lwis_dev, struct lwis_i2c_device, base_dev);
- if (!i2c_dev) {
- dev_err(lwis_dev->dev, "I2C device is NULL\n");
- return;
- }
-
- device_priority = i2c_dev->device_priority;
- if (!i2c_device_priority_is_valid(device_priority)) {
- dev_err(lwis_dev->dev, "Invalid I2C device priority %d\n", device_priority);
+ ret = get_device_priority_and_bus_manager(disconnecting_client, &device_priority,
+ &i2c_bus_manager);
+ if (ret || !i2c_bus_manager) {
return;
}
mutex_lock(&i2c_bus_manager->i2c_process_queue_lock);
- process_queue = &i2c_bus_manager->i2c_bus_process_queue[device_priority];
- list_for_each_safe (request, request_tmp, &process_queue->head) {
- i2c_disconnecting_client_node =
- list_entry(request, struct lwis_i2c_process_request, request_node);
- if (i2c_disconnecting_client_node->requesting_client == disconnecting_client) {
- dev_info(lwis_dev->dev, "Disconnecting I2C client %s(%p) from bus %s\n",
- lwis_dev->name, disconnecting_client,
- i2c_bus_manager->i2c_bus_name);
- list_del(&i2c_disconnecting_client_node->request_node);
- i2c_disconnecting_client_node->requesting_client = NULL;
- if (lwis_i2c_bus_manager_debug) {
- dev_info(lwis_dev->dev, "Freeing process request %p\n",
- i2c_disconnecting_client_node);
- }
- kfree(i2c_disconnecting_client_node);
- i2c_disconnecting_client_node = NULL;
- --process_queue->number_of_nodes;
- break;
- }
- }
+ find_client(device_priority, i2c_bus_manager, disconnecting_client, I2C_CLIENT_DISCONNECT);
mutex_unlock(&i2c_bus_manager->i2c_process_queue_lock);
} \ No newline at end of file
diff --git a/lwis_i2c_bus_manager.h b/lwis_i2c_bus_manager.h
index b278124..364e786 100644
--- a/lwis_i2c_bus_manager.h
+++ b/lwis_i2c_bus_manager.h
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Google LWIS I2C Bus Manager
*
- * Copyright (c) 2023 Google, LLC
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Copyright 2023 Google LLC.
*/
#ifndef LWIS_I2C_BUS_MANAGER_H_
@@ -22,13 +19,18 @@
* in which the requests will be executed
*/
enum lwis_i2c_device_priority_level {
- I2C_DEVICE_HIGH_PRIORITY = 0,
- I2C_DEVICE_MEDIUM_PRIORITY = 1,
- I2C_DEVICE_LOW_PRIORITY = 2,
- I2C_MAX_PRIORITY_LEVELS = 3
+ I2C_DEVICE_HIGH_PRIORITY,
+ I2C_DEVICE_MEDIUM_PRIORITY,
+ I2C_DEVICE_LOW_PRIORITY,
+ I2C_MAX_PRIORITY_LEVELS
};
-// Forward declaration
+/* enum lwis_i2c_client_connection:
+ * Defines the I2C client connection status
+ * being requested
+ */
+enum lwis_i2c_client_connection { I2C_CLIENT_CONNECT, I2C_CLIENT_DISCONNECT };
+
struct lwis_i2c_device;
/* struct lwis_i2c_bus_manager_list:
@@ -50,7 +52,7 @@ struct lwis_i2c_bus_manager_identifier {
* This is a collection of process request nodes that identify
* the lwis device requests in order they were queued.
* The scheduler is set to operate requests in a
- * first in-first out manner, starting and updating the head
+ * first in-first out manner, starting and updating the head
* and working towards the tail end. */
struct lwis_i2c_process_queue {
/* Head node for the process queue */
@@ -66,7 +68,7 @@ struct lwis_i2c_process_queue {
struct lwis_i2c_bus_manager {
/* Unique identifier for this I2C bus manager */
int i2c_bus_id;
- /* Name of I2C Bus manager corresponds to the name of the I2C Bus*/
+ /* Name of I2C Bus manager corresponds to the name of the I2C Bus */
char i2c_bus_name[LWIS_MAX_NAME_STRING_LEN];
/* Lock to control access to bus transfers */
struct mutex i2c_bus_lock;
@@ -97,7 +99,7 @@ void lwis_i2c_bus_manager_lock_i2c_bus(struct lwis_device *lwis_dev);
void lwis_i2c_bus_manager_unlock_i2c_bus(struct lwis_device *lwis_dev);
-struct lwis_i2c_bus_manager *lwis_i2c_bus_manager_get_manager(struct lwis_device *lwis_dev);
+struct lwis_i2c_bus_manager *lwis_i2c_bus_manager_get(struct lwis_device *lwis_dev);
int lwis_i2c_bus_manager_create(struct lwis_i2c_device *i2c_dev);
diff --git a/lwis_i2c_sched.c b/lwis_i2c_sched.c
index 1ca802f..dd167e4 100644
--- a/lwis_i2c_sched.c
+++ b/lwis_i2c_sched.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * Google LWIS I2C Bus Manager
+ * Google LWIS I2C Bus Manager Scheduler
*
- * Copyright (c) 2023 Google, LLC
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Copyright 2023 Google LLC.
*/
#define pr_fmt(fmt) KBUILD_MODNAME "-i2c-sched: " fmt
@@ -18,10 +15,7 @@
*/
bool lwis_i2c_process_request_queue_is_empty(struct lwis_i2c_process_queue *process_queue)
{
- if ((!process_queue) || ((process_queue) && (process_queue->number_of_nodes == 0))) {
- return true;
- }
- return false;
+ return (!process_queue || (process_queue && (process_queue->number_of_nodes == 0)));
}
/*
@@ -56,7 +50,6 @@ void lwis_i2c_process_request_queue_destroy(struct lwis_i2c_process_queue *proce
list_del(&process_request->request_node);
process_request->requesting_client = NULL;
kfree(process_request);
- process_request = NULL;
- --process_queue->number_of_nodes;
+ process_queue->number_of_nodes--;
}
} \ No newline at end of file
diff --git a/lwis_i2c_sched.h b/lwis_i2c_sched.h
index 22073af..3ab4862 100644
--- a/lwis_i2c_sched.h
+++ b/lwis_i2c_sched.h
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Google LWIS I2C Bus Manager
+ * Google LWIS I2C Bus Manager Scheduler
*
- * Copyright (c) 2023 Google, LLC
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * Copyright 2023 Google LLC.
*/
#ifndef LWIS_I2C_SCHED_H_
@@ -13,7 +10,6 @@
#include "lwis_device.h"
-// Forward declaration
struct lwis_i2c_process_queue;
/* lwis_i2c_process_request:
diff --git a/lwis_ioctl.c b/lwis_ioctl.c
index b2fbe1f..cf32a89 100644
--- a/lwis_ioctl.c
+++ b/lwis_ioctl.c
@@ -1146,7 +1146,7 @@ static int construct_transaction_from_cmd(struct lwis_client *client, uint32_t c
struct lwis_transaction *k_transaction;
struct lwis_device *lwis_dev = client->lwis_dev;
- k_transaction = kmalloc(sizeof(*k_transaction), GFP_KERNEL);
+ k_transaction = kzalloc(sizeof(struct lwis_transaction), GFP_KERNEL);
if (!k_transaction) {
dev_err(lwis_dev->dev, "Failed to allocate transaction info\n");
return -ENOMEM;
diff --git a/lwis_periodic_io.c b/lwis_periodic_io.c
index 39145ab..cac5f57 100644
--- a/lwis_periodic_io.c
+++ b/lwis_periodic_io.c
@@ -13,9 +13,7 @@
#include "lwis_periodic_io.h"
#include <linux/completion.h>
-#include <linux/kthread.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#include "lwis_allocator.h"
#include "lwis_event.h"
@@ -35,15 +33,10 @@ static enum hrtimer_restart periodic_io_timer_func(struct hrtimer *timer)
struct lwis_periodic_io_proxy *periodic_io_proxy;
struct lwis_client *client;
bool active_periodic_io_present = false;
- struct lwis_device *lwis_dev;
- struct lwis_i2c_bus_manager *i2c_bus_manager = NULL;
periodic_io_list = container_of(timer, struct lwis_periodic_io_list, hr_timer);
client = periodic_io_list->client;
- lwis_dev = client->lwis_dev;
- i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
-
/* Go through all periodic io under the chosen periodic list */
spin_lock_irqsave(&client->periodic_io_lock, flags);
list_for_each_safe (it_period, it_period_tmp, &periodic_io_list->list) {
@@ -53,7 +46,8 @@ static enum hrtimer_restart periodic_io_timer_func(struct hrtimer *timer)
client->lwis_dev, sizeof(*periodic_io_proxy), GFP_ATOMIC);
if (!periodic_io_proxy) {
/* Non-fatal, skip this period */
- dev_warn(lwis_dev->dev, "Cannot allocate new periodic io proxy.\n");
+ dev_warn(client->lwis_dev->dev,
+ "Cannot allocate new periodic io proxy.\n");
} else {
periodic_io_proxy->periodic_io = periodic_io;
list_add_tail(&periodic_io_proxy->process_queue_node,
@@ -63,12 +57,7 @@ static enum hrtimer_restart periodic_io_timer_func(struct hrtimer *timer)
}
}
if (active_periodic_io_present) {
- if (i2c_bus_manager) {
- kthread_queue_work(&i2c_bus_manager->i2c_bus_worker, &client->i2c_work);
- } else {
- kthread_queue_work(&client->lwis_dev->transaction_worker,
- &client->transaction_work);
- }
+ lwis_queue_device_worker(client);
}
spin_unlock_irqrestore(&client->periodic_io_lock, flags);
if (!active_periodic_io_present) {
@@ -523,15 +512,10 @@ int lwis_periodic_io_client_flush(struct lwis_client *client)
struct lwis_periodic_io_list *it_periodic_io_list;
unsigned long flags;
- struct lwis_device *lwis_dev = client->lwis_dev;
- struct lwis_i2c_bus_manager *i2c_bus_manager = NULL;
-
struct lwis_periodic_io *periodic_cleanup_io;
struct lwis_periodic_io_proxy *periodic_cleanup_io_proxy;
struct list_head *it_cleanup_period, *it_cleanup_period_tmp;
- i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
-
/* First, cancel all timers */
hash_for_each_safe (client->timer_list, i, tmp, it_periodic_io_list, node) {
spin_lock_irqsave(&client->periodic_io_lock, flags);
@@ -546,13 +530,7 @@ int lwis_periodic_io_client_flush(struct lwis_client *client)
}
/* Wait until all workload in process queue are processed */
- if (i2c_bus_manager) {
- lwis_i2c_bus_manager_flush_i2c_worker(lwis_dev);
- } else {
- if (client->lwis_dev->transaction_worker_thread) {
- kthread_flush_worker(&client->lwis_dev->transaction_worker);
- }
- }
+ lwis_flush_device_worker(client);
spin_lock_irqsave(&client->periodic_io_lock, flags);
/* Cleanup any stale entries remaining after the flush */
diff --git a/lwis_transaction.c b/lwis_transaction.c
index 89fa685..823de12 100644
--- a/lwis_transaction.c
+++ b/lwis_transaction.c
@@ -13,11 +13,9 @@
#include "lwis_transaction.h"
#include <linux/delay.h>
-#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/preempt.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#include "lwis_allocator.h"
#include "lwis_commands.h"
@@ -114,16 +112,16 @@ static void save_transaction_to_history(struct lwis_client *client,
}
}
-void lwis_transaction_free(struct lwis_device *lwis_dev, struct lwis_transaction **ptransaction)
+void lwis_transaction_free(struct lwis_device *lwis_dev, struct lwis_transaction **lwis_tx)
{
int i;
struct lwis_fence_pending_signal *pending_fence;
struct list_head *it_fence, *it_fence_tmp;
- struct lwis_transaction *transaction = *ptransaction;
+ struct lwis_transaction *transaction = *lwis_tx;
if (transaction->is_weak_transaction) {
+ *lwis_tx = NULL;
kfree(transaction);
- transaction = NULL;
return;
}
@@ -155,11 +153,11 @@ void lwis_transaction_free(struct lwis_device *lwis_dev, struct lwis_transaction
if (transaction->resp) {
kfree(transaction->resp);
}
+ *lwis_tx = NULL;
kfree(transaction);
- *ptransaction = NULL;
}
-static int process_transaction(struct lwis_client *client, struct lwis_transaction **ptransaction,
+static int process_transaction(struct lwis_client *client, struct lwis_transaction **lwis_tx,
struct list_head *pending_events, struct list_head *pending_fences,
bool skip_err, bool check_transaction_limit)
{
@@ -168,7 +166,7 @@ static int process_transaction(struct lwis_client *client, struct lwis_transacti
int pending_status;
struct lwis_io_entry *entry = NULL;
struct lwis_device *lwis_dev = client->lwis_dev;
- struct lwis_transaction *transaction = *ptransaction;
+ struct lwis_transaction *transaction = *lwis_tx;
struct lwis_transaction_info_v2 *info = &transaction->info;
struct lwis_transaction_response_header *resp = transaction->resp;
size_t resp_size;
@@ -179,35 +177,32 @@ static int process_transaction(struct lwis_client *client, struct lwis_transacti
int64_t process_timestamp = -1;
unsigned long flags;
- int total_number_of_entries = info->num_io_entries;
- int max_transaction_entry_limit = lwis_dev->transaction_process_limit;
- int remaining_entries_to_be_processed = transaction->remaining_entries_to_process;
- int number_of_entries_to_process_in_current_run = 0;
- int processing_start_index = 0;
- int processing_end_index = 0;
+ const int total_entries = info->num_io_entries;
+ int max_limit = lwis_dev->transaction_process_limit;
+ int remaining_entries = transaction->remaining_entries_to_process;
+ int current_run_entries;
+ int start_idx;
+ int end_idx;
/*
* Process all the transactions at once if:
- * 1. the processing device has no limitation on the number of entries to process per transaction
- * 2. the transaction is running in event context
- * 3. the transaction is being called as a part of cleanup
- * Note: For #2 and #3, this transaction will not be queued for further processing by any worker thread
- * later and therefore all entries need to be processed in the same run
- */
+ * 1. the processing device has no limitation on the number of entries
+ * to process per transaction.
+ * 2. the transaction is running in event context.
+ * 3. the transaction is being called as a part of cleanup.
+ * Note: For #2 and #3, this transaction will not be queued for further
+ * processing by any worker thread later and therefore all entries need
+ * to be processed in the same run.
+ */
if ((lwis_dev->transaction_process_limit <= 0) ||
- (transaction->info.run_in_event_context) || (skip_err == true) ||
- (check_transaction_limit == false)) {
- max_transaction_entry_limit = total_number_of_entries;
+ (transaction->info.run_in_event_context || skip_err || !check_transaction_limit)) {
+ max_limit = total_entries;
}
- number_of_entries_to_process_in_current_run =
- (remaining_entries_to_be_processed > max_transaction_entry_limit) ?
- max_transaction_entry_limit :
- remaining_entries_to_be_processed;
- processing_start_index = total_number_of_entries - remaining_entries_to_be_processed;
- processing_end_index = processing_start_index + number_of_entries_to_process_in_current_run;
- remaining_entries_to_be_processed =
- remaining_entries_to_be_processed - number_of_entries_to_process_in_current_run;
+ current_run_entries = (remaining_entries > max_limit) ? max_limit : remaining_entries;
+ start_idx = total_entries - remaining_entries;
+ end_idx = start_idx + current_run_entries;
+ remaining_entries = remaining_entries - current_run_entries;
if (lwis_transaction_debug) {
process_timestamp = ktime_to_ns(lwis_get_time());
@@ -219,22 +214,25 @@ static int process_transaction(struct lwis_client *client, struct lwis_transacti
resp->completion_index = -1;
/*
- * If the starting read buffer pointer is not null then use this cached location to correctly
+ * If the starting read buffer pointer is not null then
+ * use this cached location to correctly
* set the read buffer for the current transaction processing run.
*/
if (transaction->starting_read_buf) {
read_buf = transaction->starting_read_buf;
}
- /* Use write memory barrier at the beginning of I/O entries if the access protocol
- * allows it */
+ /*
+ * Use write memory barrier at the beginning of I/O entries if the access protocol
+ * allows it.
+ */
if (lwis_dev->vops.register_io_barrier != NULL) {
lwis_dev->vops.register_io_barrier(lwis_dev,
/*use_read_barrier=*/false,
/*use_write_barrier=*/true);
}
lwis_i2c_bus_manager_lock_i2c_bus(lwis_dev);
- for (i = processing_start_index; i < processing_end_index; ++i) {
+ for (i = start_idx; i < end_idx; i++) {
entry = &info->io_entries[i];
if (entry->type == LWIS_IO_ENTRY_WRITE ||
entry->type == LWIS_IO_ENTRY_WRITE_BATCH ||
@@ -364,14 +362,16 @@ static int process_transaction(struct lwis_client *client, struct lwis_transacti
process_duration_ns = ktime_to_ns(lwis_get_time() - process_timestamp);
}
- /* Use read memory barrier at the end of I/O entries if the access protocol
- * allows it */
+ /*
+ * Use read memory barrier at the end of I/O entries if the access protocol
+ * allows it.
+ */
if (lwis_dev->vops.register_io_barrier != NULL) {
lwis_dev->vops.register_io_barrier(lwis_dev, /*use_read_barrier=*/true,
/*use_write_barrier=*/false);
}
- if ((remaining_entries_to_be_processed > 0) && (ret == 0)) {
+ if (remaining_entries > 0 && ret == 0) {
/*
* If there are remaining entries to be processed in this transaction,
* don't delete this transaction and update the current remaining
@@ -381,7 +381,7 @@ static int process_transaction(struct lwis_client *client, struct lwis_transacti
*/
spin_lock_irqsave(&client->transaction_lock, flags);
transaction->starting_read_buf = read_buf;
- transaction->remaining_entries_to_process = remaining_entries_to_be_processed;
+ transaction->remaining_entries_to_process = remaining_entries;
spin_unlock_irqrestore(&client->transaction_lock, flags);
return ret;
}
@@ -401,10 +401,10 @@ static int process_transaction(struct lwis_client *client, struct lwis_transacti
}
spin_lock_irqsave(&client->transaction_lock, flags);
- transaction->remaining_entries_to_process = remaining_entries_to_be_processed;
+ transaction->remaining_entries_to_process = remaining_entries;
if (pending_fences) {
- /* Convert -ECANCELED error code to userspace Cancellation error code */
+ /* Convert -ECANCELED error code to userspace Cancellation error code. */
pending_status = resp->error_code == -ECANCELED ? 1 : resp->error_code;
lwis_pending_fences_move_all(lwis_dev, transaction, pending_fences, pending_status);
}
@@ -412,42 +412,43 @@ static int process_transaction(struct lwis_client *client, struct lwis_transacti
/*
* This check needs to be handled only for cases where we are processing
- * the transaction based on the limit specified in the dts
+ * the transaction based on the limit specified in the dts.
* When the transactions are cancelled or executed in event context
- * the limit doesn't dictate the number of entries that will be processed
+ * the limit doesn't dictate the number of entries that will be processed.
*/
if (check_transaction_limit) {
- /* 1. If all of the entries are processed for a given transaction then
+ /*
+ * 1. If all of the entries are processed for a given transaction then
* delete the transaction from the queue and enable emit signals for
- * pending events and fences
+ * pending events and fences.
* 2. Delete transaction from the process queue after the limit is fulfilled
- * or there is an error while processing
+ * or there is an error while processing.
*/
list_del(&transaction->process_queue_node);
}
if (info->trigger_event_counter == LWIS_EVENT_COUNTER_EVERY_TIME) {
/*
- *Only clean the transaction struct for this iteration. The
+ * Only clean the transaction struct for this iteration. The
* I/O entries are not being freed.
*/
kfree(transaction->resp);
+ *lwis_tx = NULL;
kfree(transaction);
- transaction = NULL;
} else {
- lwis_transaction_free(lwis_dev, ptransaction);
+ lwis_transaction_free(lwis_dev, lwis_tx);
}
spin_unlock_irqrestore(&client->transaction_lock, flags);
return ret;
}
-static void cancel_transaction(struct lwis_device *lwis_dev, struct lwis_transaction **ptransaction,
+static void cancel_transaction(struct lwis_device *lwis_dev, struct lwis_transaction **lwis_tx,
int error_code, struct list_head *pending_events,
struct list_head *pending_fences, bool delete_pending_map_node)
{
int pending_status;
- struct lwis_transaction *transaction = *ptransaction;
+ struct lwis_transaction *transaction = *lwis_tx;
struct lwis_transaction_info_v2 *info = &transaction->info;
struct lwis_transaction_response_header resp;
resp.id = info->id;
@@ -457,7 +458,7 @@ static void cancel_transaction(struct lwis_device *lwis_dev, struct lwis_transac
resp.completion_index = -1;
if (transaction->is_weak_transaction) {
- lwis_transaction_free(lwis_dev, ptransaction);
+ lwis_transaction_free(lwis_dev, lwis_tx);
return;
}
@@ -466,7 +467,9 @@ static void cancel_transaction(struct lwis_device *lwis_dev, struct lwis_transac
sizeof(resp));
}
if (pending_fences) {
- /* Convert -ECANCELED error code to userspace Cancellation error code */
+ /*
+ * Convert -ECANCELED error code to userspace Cancellation error code.
+ */
pending_status = error_code == -ECANCELED ? 1 : error_code;
lwis_pending_fences_move_all(lwis_dev, transaction, pending_fences, pending_status);
}
@@ -475,7 +478,61 @@ static void cancel_transaction(struct lwis_device *lwis_dev, struct lwis_transac
hash_del(&transaction->pending_map_node);
}
- lwis_transaction_free(lwis_dev, ptransaction);
+ lwis_transaction_free(lwis_dev, lwis_tx);
+}
+
+static bool process_broken_transaction(struct lwis_client *client, struct list_head *pending_events,
+ struct list_head *pending_fences,
+ struct lwis_transaction *transaction)
+{
+ unsigned long flush_flags;
+ struct device *dev = client->lwis_dev->dev;
+
+ /*
+ * Continue the loop if the transaction is complete and deleted or
+ * if the transaction exists but all the entries are processed
+ */
+ if (transaction && transaction->remaining_entries_to_process > 0) {
+ /*
+ * If the transaction exists and there are entries
+ * remaning to be processed, that would indicate the
+ * transaction processing limit has reached for this
+ * device and we stop processing its queue further.
+ */
+ if (lwis_transaction_debug) {
+ dev_info(
+ dev,
+ "Transaction processing limit reached, remaining entries to process %d\n",
+ transaction->remaining_entries_to_process);
+ }
+
+ /*
+ * Queue the remaining transaction again on the transaction
+ * worker/bus manager worker to be processed again later if
+ * the client is not flushing.
+ * If the client is flushing, cancel the remaining transaction
+ * and delete from the process queue node.
+ */
+ spin_lock_irqsave(&client->flush_lock, flush_flags);
+ if (client->flush_state == NOT_FLUSHING) {
+ if (lwis_transaction_debug) {
+ dev_info(dev, "Client: NOT_FLUSHING, schedule remaining work");
+ }
+
+ lwis_queue_device_worker(client);
+ } else {
+ if (lwis_transaction_debug) {
+ dev_info(dev, "Client: FLUSHING, abort remaining transaction");
+ }
+ list_del(&transaction->process_queue_node);
+ cancel_transaction(client->lwis_dev, &transaction,
+ transaction->resp->error_code, pending_events,
+ pending_fences, false);
+ }
+ spin_unlock_irqrestore(&client->flush_lock, flush_flags);
+ return true;
+ }
+ return false;
}
void lwis_process_transactions_in_queue(struct lwis_client *client)
@@ -486,20 +543,19 @@ void lwis_process_transactions_in_queue(struct lwis_client *client)
struct list_head pending_events;
struct list_head pending_fences;
struct lwis_transaction *transaction;
- struct lwis_device *lwis_dev = client->lwis_dev;
- struct lwis_i2c_bus_manager *i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
INIT_LIST_HEAD(&pending_events);
INIT_LIST_HEAD(&pending_fences);
spin_lock_irqsave(&client->transaction_lock, flags);
list_for_each_safe (it_tran, it_tran_tmp, &client->transaction_process_queue) {
- if (!client->is_enabled) {
+ if (!client->is_enabled && client->lwis_dev->type != DEVICE_TYPE_TOP) {
/*
* If client is not enabled, then we just need to requeue
* the transaction until the client is enabled. This will
* ensure that we don't loose the submitted transactions.
- */
+ * Top device does not require enabling.
+ */
if (lwis_transaction_debug) {
dev_info(client->lwis_dev->dev,
"Client is not ready to process transactions");
@@ -507,13 +563,7 @@ void lwis_process_transactions_in_queue(struct lwis_client *client)
spin_unlock_irqrestore(&client->transaction_lock, flags);
spin_lock_irqsave(&client->flush_lock, flush_flags);
if (client->flush_state == NOT_FLUSHING) {
- if (i2c_bus_manager) {
- kthread_queue_work(&i2c_bus_manager->i2c_bus_worker,
- &client->i2c_work);
- } else {
- kthread_queue_work(&client->lwis_dev->transaction_worker,
- &client->transaction_work);
- }
+ lwis_queue_device_worker(client);
}
spin_unlock_irqrestore(&client->flush_lock, flush_flags);
return;
@@ -532,56 +582,12 @@ void lwis_process_transactions_in_queue(struct lwis_client *client)
spin_lock_irqsave(&client->transaction_lock, flags);
/*
- * Continue the loop if the transaction is complete and deleted or
- * if the transaction exists but all the entries are processed
- */
- if ((transaction != NULL) &&
- (transaction->remaining_entries_to_process > 0)) {
- /*
- * If the transaction exists and there are entries remaning to be processed,
- * that would indicate the transaction processing limit has reached for this
- * device and we stop processing its queue further
- */
- if (lwis_transaction_debug) {
- dev_info(
- client->lwis_dev->dev,
- "Transaction processing limit reached, remaining entries to process %d\n",
- transaction->remaining_entries_to_process);
- }
-
- /*
- * Queue the remaining transaction again on the transaction worker/bus maanger worker
- * to be processed again later if the client is not flushing
- * If the client is flushing, cancel the remaining transaction
- * and delete from the process queue node.
- */
- spin_lock_irqsave(&client->flush_lock, flush_flags);
- if (client->flush_state == NOT_FLUSHING) {
- if (lwis_transaction_debug) {
- dev_info(
- client->lwis_dev->dev,
- "Client is not flushing, schedule the remaining work");
- }
-
- if (i2c_bus_manager) {
- kthread_queue_work(&i2c_bus_manager->i2c_bus_worker,
- &client->i2c_work);
- } else {
- kthread_queue_work(&client->lwis_dev->transaction_worker,
- &client->transaction_work);
- }
- } else {
- if (lwis_transaction_debug) {
- dev_info(
- client->lwis_dev->dev,
- "Client is flushing, aborting the remaining transaction");
- }
- list_del(&transaction->process_queue_node);
- cancel_transaction(client->lwis_dev, &transaction,
- transaction->resp->error_code, &pending_events,
- &pending_fences, false);
- }
- spin_unlock_irqrestore(&client->flush_lock, flush_flags);
+ * If LWIS is processing a broken transaction,
+ * then it needs to stop processing the client's transaction queue further
+ * until the broken transaction is completely processed.
+ */
+ if (process_broken_transaction(client, &pending_events, &pending_fences,
+ transaction)) {
break;
}
}
@@ -640,17 +646,12 @@ int lwis_transaction_client_flush(struct lwis_client *client)
int i;
struct hlist_node *tmp;
struct lwis_transaction_event_list *it_evt_list;
- struct lwis_device *lwis_dev = NULL;
- struct lwis_i2c_bus_manager *i2c_bus_manager = NULL;
if (!client) {
pr_err("Client pointer cannot be NULL while flushing transactions.\n");
return -ENODEV;
}
- lwis_dev = client->lwis_dev;
- i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
-
spin_lock_irqsave(&client->transaction_lock, flags);
hash_for_each_safe (client->transaction_list, i, tmp, it_evt_list, node) {
if ((it_evt_list->event_id & 0xFFFF0000FFFFFFFFll) ==
@@ -675,21 +676,17 @@ int lwis_transaction_client_flush(struct lwis_client *client)
client->flush_state = FLUSHING;
spin_unlock_irqrestore(&client->flush_lock, flags);
- if (i2c_bus_manager) {
- lwis_i2c_bus_manager_flush_i2c_worker(lwis_dev);
- } else {
- if (client->lwis_dev->transaction_worker_thread) {
- kthread_flush_worker(&client->lwis_dev->transaction_worker);
- }
- }
+ lwis_flush_device_worker(client);
spin_lock_irqsave(&client->flush_lock, flags);
client->flush_state = NOT_FLUSHING;
spin_unlock_irqrestore(&client->flush_lock, flags);
spin_lock_irqsave(&client->transaction_lock, flags);
- /* The transaction queue should be empty after canceling all transactions,
- * but check anyway. */
+ /*
+ * The transaction queue should be empty after canceling all transactions,
+ * but check anyway.
+ */
cancel_all_transactions_in_queue_locked(client, &client->transaction_process_queue);
spin_unlock_irqrestore(&client->transaction_lock, flags);
@@ -704,7 +701,6 @@ int lwis_transaction_client_cleanup(struct lwis_client *client)
struct lwis_transaction_event_list *it_evt_list;
spin_lock_irqsave(&client->transaction_lock, flags);
- /* Perform client defined clean-up routine. */
it_evt_list = event_list_find(client, LWIS_EVENT_ID_CLIENT_CLEANUP |
(int64_t)client->lwis_dev->id
<< LWIS_EVENT_ID_EVENT_CODE_LEN);
@@ -800,35 +796,32 @@ static int check_transaction_param_locked(struct lwis_client *client,
return -ENODEV;
}
- /* Assign the transaction id and increment transaction counter */
info->id = client->transaction_counter++;
- /* Initialize event counter return value */
+
info->current_trigger_event_counter = -1LL;
- /* Look for the trigger event state, if specified */
+ /* Look for the trigger event state, if specified. */
if (info->trigger_event_id != LWIS_EVENT_ID_NONE) {
event_state = lwis_device_event_state_find(lwis_dev, info->trigger_event_id);
if (event_state == NULL) {
- /* Event has not been encountered, setting event counter
- * to zero */
+ /* Event has not been encountered, setting event counter to zero. */
info->current_trigger_event_counter = 0;
} else {
- /* Event found, return current counter to userspace */
+ /* Event found, return current counter to userspace. */
info->current_trigger_event_counter = event_state->event_counter;
}
} else if (!lwis_triggered_by_condition(transaction)) {
- /* Otherwise it's an immediate transaction */
+ /* Otherwise it's an immediate transaction. */
transaction->queue_immediately = true;
}
- /* Both trigger event ID and counter are defined */
+ /* Both trigger event ID and counter are defined. */
if (info->trigger_event_id != LWIS_EVENT_ID_NONE &&
EXPLICIT_EVENT_COUNTER(info->trigger_event_counter)) {
- /* Check if event has happened already */
+ /* Check if event has happened already. */
if (info->trigger_event_counter == info->current_trigger_event_counter) {
if (is_level_triggered) {
- /* Convert this transaction into an immediate
- * one */
+ /* Convert this transaction into an immediate one. */
transaction->queue_immediately = true;
} else {
return -ENOENT;
@@ -838,7 +831,7 @@ static int check_transaction_param_locked(struct lwis_client *client,
}
}
- /* Make sure sw events exist in event table */
+ /* Make sure sw events exist in event table. */
if (IS_ERR_OR_NULL(lwis_device_event_state_find_or_create(lwis_dev,
info->emit_success_event_id)) ||
IS_ERR_OR_NULL(
@@ -859,7 +852,6 @@ static int prepare_transaction_fences_locked(struct lwis_client *client,
{
int ret = 0;
- /* If triggered by trigger_condition */
if (lwis_triggered_by_condition(transaction)) {
ret = lwis_parse_trigger_condition(client, transaction);
if (ret) {
@@ -867,7 +859,7 @@ static int prepare_transaction_fences_locked(struct lwis_client *client,
}
}
- /* If transaction contains completion fences, add them to the transaction */
+ /* If transaction contains completion fences, add them to the transaction. */
ret = lwis_add_completion_fence(client, transaction);
return ret;
@@ -893,13 +885,14 @@ static int prepare_response_locked(struct lwis_client *client, struct lwis_trans
}
}
- // Event response payload consists of header, and address and
- // offset pairs.
+ /* Event response payload consists of header, and address and offset pairs. */
resp_size = sizeof(struct lwis_transaction_response_header) +
read_entries * sizeof(struct lwis_io_result) + read_buf_size;
- /* Revisit the use of GFP_ATOMIC here. Reason for this to be atomic is
+ /*
+ * Revisit the use of GFP_ATOMIC here. Reason for this to be atomic is
* because this function can be called by transaction_replace while
- * holding onto a spinlock. */
+ * holding onto a spinlock.
+ */
transaction->resp = kmalloc(resp_size, GFP_ATOMIC);
if (!transaction->resp) {
dev_err(client->lwis_dev->dev, "Cannot allocate transaction response\n");
@@ -914,29 +907,21 @@ static int prepare_response_locked(struct lwis_client *client, struct lwis_trans
return 0;
}
-/* Calling this function requires holding the client's transaction_lock. */
+/*
+ * Calling this function requires holding the client's transaction_lock.
+ */
static int queue_transaction_locked(struct lwis_client *client,
struct lwis_transaction *transaction)
{
struct lwis_transaction_event_list *event_list;
struct lwis_transaction_info_v2 *info = &transaction->info;
- struct lwis_device *lwis_dev = client->lwis_dev;
- struct lwis_i2c_bus_manager *i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
if (transaction->queue_immediately) {
- /* Immediate trigger. */
list_add_tail(&transaction->process_queue_node, &client->transaction_process_queue);
- if (i2c_bus_manager) {
- kthread_queue_work(&i2c_bus_manager->i2c_bus_worker, &client->i2c_work);
- } else {
- kthread_queue_work(&client->lwis_dev->transaction_worker,
- &client->transaction_work);
- }
+ lwis_queue_device_worker(client);
} else if (lwis_triggered_by_condition(transaction)) {
- /* Trigger by trigger conditions. */
add_pending_transaction(client, transaction);
} else {
- /* Trigger by event. */
event_list = event_list_find_or_create(client, info->trigger_event_id);
if (!event_list) {
dev_err(client->lwis_dev->dev, "Cannot create transaction event list\n");
@@ -981,7 +966,6 @@ new_repeating_transaction_iteration(struct lwis_client *client,
struct lwis_transaction *new_instance;
uint8_t *resp_buf;
- /* Construct a new instance for repeating transactions */
new_instance = kmalloc(sizeof(struct lwis_transaction), GFP_ATOMIC);
if (!new_instance) {
dev_err(client->lwis_dev->dev,
@@ -990,7 +974,6 @@ new_repeating_transaction_iteration(struct lwis_client *client,
}
memcpy(&new_instance->info, &transaction->info, sizeof(transaction->info));
- /* Allocate response buffer */
resp_buf = kmalloc(sizeof(struct lwis_transaction_response_header) +
transaction->resp->results_size_bytes,
GFP_ATOMIC);
@@ -1018,7 +1001,7 @@ static void defer_transaction_locked(struct lwis_client *client,
struct lwis_transaction *transaction,
struct list_head *pending_events,
struct list_head *pending_fences, bool del_event_list_node,
- unsigned long* flags)
+ unsigned long *flags)
{
if (del_event_list_node) {
list_del(&transaction->event_list_node);
@@ -1051,8 +1034,6 @@ int lwis_transaction_event_trigger(struct lwis_client *client, int64_t event_id,
struct lwis_transaction *new_instance;
int64_t trigger_counter = 0;
struct list_head pending_fences;
- struct lwis_device *lwis_dev = client->lwis_dev;
- struct lwis_i2c_bus_manager *i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
INIT_LIST_HEAD(&pending_fences);
@@ -1062,20 +1043,18 @@ int lwis_transaction_event_trigger(struct lwis_client *client, int64_t event_id,
event_id = event_id ^ LWIS_OVERFLOW_IRQ_EVENT_FLAG;
}
event_list = event_list_find(client, event_id);
- /* No event found, just return. */
if (event_list == NULL || list_empty(&event_list->list)) {
spin_unlock_irqrestore(&client->transaction_lock, flags);
return 0;
}
- /* Go through all transactions under the chosen event list. */
list_for_each_safe (it_tran, it_tran_tmp, &event_list->list) {
transaction = list_entry(it_tran, struct lwis_transaction, event_list_node);
if (transaction->is_weak_transaction) {
weak_transaction = transaction;
transaction = pending_transaction_peek(client, weak_transaction->id);
if (transaction == NULL) {
- /* It means the transaction is already executed or is canceled */
+ /* It means the transaction is already executed or is canceled. */
list_del(&weak_transaction->event_list_node);
kfree(weak_transaction);
continue;
@@ -1092,8 +1071,7 @@ int lwis_transaction_event_trigger(struct lwis_client *client, int64_t event_id,
hash_del(&transaction->pending_map_node);
defer_transaction_locked(client, transaction, pending_events,
&pending_fences,
- /* del_event_list_node */ false,
- &flags);
+ /* del_event_list_node */ false, &flags);
}
continue;
}
@@ -1105,8 +1083,10 @@ int lwis_transaction_event_trigger(struct lwis_client *client, int64_t event_id,
continue;
}
- /* Compare current event with trigger event counter to make
- * sure this transaction needs to be executed now. */
+ /*
+ * Compare current event with trigger event counter to make
+ * sure this transaction needs to be executed now.
+ */
trigger_counter = transaction->info.trigger_event_counter;
if (trigger_counter == LWIS_EVENT_COUNTER_ON_NEXT_OCCURRENCE ||
trigger_counter == event_counter) {
@@ -1128,14 +1108,8 @@ int lwis_transaction_event_trigger(struct lwis_client *client, int64_t event_id,
}
}
- /* Schedule deferred transactions */
if (!list_empty(&client->transaction_process_queue)) {
- if (i2c_bus_manager) {
- kthread_queue_work(&i2c_bus_manager->i2c_bus_worker, &client->i2c_work);
- } else {
- kthread_queue_work(&client->lwis_dev->transaction_worker,
- &client->transaction_work);
- }
+ lwis_queue_device_worker(client);
}
spin_unlock_irqrestore(&client->transaction_lock, flags);
@@ -1154,8 +1128,6 @@ void lwis_transaction_fence_trigger(struct lwis_client *client, struct lwis_fenc
struct list_head *it_tran, *it_tran_tmp;
struct list_head pending_events;
struct list_head pending_fences;
- struct lwis_device *lwis_dev = client->lwis_dev;
- struct lwis_i2c_bus_manager *i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
if (list_empty(transaction_list)) {
return;
@@ -1171,7 +1143,7 @@ void lwis_transaction_fence_trigger(struct lwis_client *client, struct lwis_fenc
transaction = pending_transaction_peek(client, transaction_id->id);
if (transaction == NULL) {
- /* It means the transaction is already executed or is canceled */
+ /* It means the transaction is already executed or is canceled. */
if (lwis_fence_debug) {
dev_info(
client->lwis_dev->dev,
@@ -1201,14 +1173,8 @@ void lwis_transaction_fence_trigger(struct lwis_client *client, struct lwis_fenc
kfree(transaction_id);
}
- /* Schedule deferred transactions */
if (!list_empty(&client->transaction_process_queue)) {
- if (i2c_bus_manager) {
- kthread_queue_work(&i2c_bus_manager->i2c_bus_worker, &client->i2c_work);
- } else {
- kthread_queue_work(&client->lwis_dev->transaction_worker,
- &client->transaction_work);
- }
+ lwis_queue_device_worker(client);
}
spin_unlock_irqrestore(&client->transaction_lock, flags);
@@ -1217,7 +1183,9 @@ void lwis_transaction_fence_trigger(struct lwis_client *client, struct lwis_fenc
lwis_fences_pending_signal_emit(client->lwis_dev, &pending_fences);
}
-/* Calling this function requires holding the client's transaction_lock. */
+/*
+ * Calling this function requires holding the client's transaction_lock.
+ */
static int cancel_waiting_transaction_locked(struct lwis_client *client, int64_t id)
{
int i;
@@ -1226,7 +1194,7 @@ static int cancel_waiting_transaction_locked(struct lwis_client *client, int64_t
struct lwis_transaction_event_list *it_evt_list;
struct lwis_transaction *transaction;
- /* Search transactions triggered by events */
+ /* Search transactions triggered by events. */
hash_for_each_safe (client->transaction_list, i, tmp, it_evt_list, node) {
list_for_each_safe (it_tran, it_tran_tmp, &it_evt_list->list) {
transaction = list_entry(it_tran, struct lwis_transaction, event_list_node);
@@ -1237,7 +1205,7 @@ static int cancel_waiting_transaction_locked(struct lwis_client *client, int64_t
}
}
- /* Search transactions triggered by trigger_condition */
+ /* Search transactions triggered by trigger_condition. */
hash_for_each_possible_safe (client->pending_transactions, transaction, tmp,
pending_map_node, id) {
if (transaction->info.id == id) {
diff --git a/lwis_transaction.h b/lwis_transaction.h
index 9f91b2f..78767a5 100644
--- a/lwis_transaction.h
+++ b/lwis_transaction.h
@@ -32,12 +32,14 @@ struct lwis_transaction {
struct list_head process_queue_node;
struct hlist_node pending_map_node;
int signaled_count;
- /* Flag used for level trigger conditions, indicating the transaction
+ /*
+ * Flag used for level trigger conditions, indicating the transaction
* should be queued right after creation
*/
bool queue_immediately;
- /* temporary variables to add supports for mixing events and fences in
- * trigger_condition. Will be removed and refacter into an union soon.
+ /*
+ * temporary variables to add support for mixing events and fences in
+ * trigger_condition. Will be removed and refactor into an union soon.
*/
bool is_weak_transaction;
int64_t id;
@@ -48,21 +50,24 @@ struct lwis_transaction {
struct list_head completion_fence_list;
/* Precondition fence file pointer */
struct file *precondition_fence_fp;
- /* If the transaction has more entries to process than the transaction_process_limit
- for the processing device, then this will save the number of entries that are
- remaining to be processed after a given transaction process cycle
- */
+ /*
+ * If the transaction has more entries to process than the transaction_process_limit
+ * for the processing device, then this will save the number of entries that are
+ * remaining to be processed after a given transaction process cycle
+ */
int remaining_entries_to_process;
- /* Starting read buffer pointer is set to the last read location when the transaction
- process limit has reached. During the next run for the transaction, this pointer
- will be referred to correctly point to the read buffer for the run.
- */
+ /*
+ * Starting read buffer pointer is set to the last read location when the transaction
+ * process limit has reached. During the next run for the transaction, this pointer
+ * will be referred to correctly point to the read buffer for the run.
+ */
uint8_t *starting_read_buf;
};
-/* For debugging purposes, keeps track of the transaction information, as
+/*
+ * For debugging purposes, keeps track of the transaction information, as
* well as the time it executes and the time it took to execute.
-*/
+ */
struct lwis_transaction_history {
struct lwis_transaction_info_v2 info;
int64_t process_timestamp;
@@ -94,7 +99,8 @@ int lwis_transaction_cancel(struct lwis_client *client, int64_t id);
void lwis_transaction_free(struct lwis_device *lwis_dev, struct lwis_transaction **ptransaction);
-/* Expects lwis_client->transaction_lock to be acquired before calling
+/*
+ * Expects lwis_client->transaction_lock to be acquired before calling
* the following functions. */
int lwis_transaction_submit_locked(struct lwis_client *client,
struct lwis_transaction *transaction);