summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMeghana Barkalle <mbarkalle@google.com>2023-11-09 06:15:17 +0000
committerMeghana Barkalle <mbarkalle@google.com>2024-01-23 20:26:14 +0000
commitbfc9969208ad4923c9f59e9ebd0d8b7cf0227c5e (patch)
treeca493f838d1f64cf26f033a6519055e517f2adc8
parente549ebb8523848761335992076bfb4a9a721cafc (diff)
downloadlwis-bfc9969208ad4923c9f59e9ebd0d8b7cf0227c5e.tar.gz
This change addresses the comments for the I2C Bus Manager feature. 1. Stop I2C bus manager kthread worker if there is an error during I2C bus manager creation. 2. Fix setting transaction pointer to NULL after the transaction is freed. 3. Refactor functions to connect and disconnect the I2C clients from the bus manager. 4. Refactor processing broken transaction based on transaction limit. 5. Refactor lwis_i2c_bus_manager_get_manager to lwis_i2c_bus_manager_get. 6. Refactor ptransaction to a non-hungarian naming scheme. 7. Fix comment formatting and copyright headers in LWIS files. 8. Refactor functions to queue work on transaction and bus manager worker threads. Bug: 316016899 Test: GCA Smoke Test Change-Id: I3e6c36d048ffd4f8adc938578210f30e01d7dff5 Signed-off-by: Meghana Barkalle <mbarkalle@google.com> (cherry picked from commit 55b89edc912e9207793f51e0f9f9d0d89e2dd203)
-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.c351
-rw-r--r--lwis_transaction.h34
13 files changed, 502 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 1ee1a45..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,21 +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 && lwis_dev->type != DEVICE_TYPE_TOP) {
+ 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");
@@ -508,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;
@@ -533,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;
}
}
@@ -641,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) ==
@@ -676,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);
@@ -705,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);
@@ -801,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;
@@ -839,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(
@@ -860,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) {
@@ -868,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;
@@ -894,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");
@@ -915,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");
@@ -982,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,
@@ -991,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);
@@ -1019,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);
@@ -1052,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);
@@ -1063,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;
@@ -1093,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;
}
@@ -1106,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) {
@@ -1129,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);
@@ -1155,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;
@@ -1172,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,
@@ -1202,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);
@@ -1218,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;
@@ -1227,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);
@@ -1238,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);