diff options
author | PixelBot AutoMerger <android-nexus-securitybot@system.gserviceaccount.com> | 2024-01-28 18:39:37 -0800 |
---|---|---|
committer | SecurityBot <android-nexus-securitybot@system.gserviceaccount.com> | 2024-01-28 18:39:37 -0800 |
commit | 7b5aed64401d3a4a1031472b0f0a59664a13c19e (patch) | |
tree | ca493f838d1f64cf26f033a6519055e517f2adc8 | |
parent | 3f52eff0bec3116236b26feee0fe4ff255d652a1 (diff) | |
parent | bfc9969208ad4923c9f59e9ebd0d8b7cf0227c5e (diff) | |
download | lwis-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.c | 35 | ||||
-rw-r--r-- | lwis_device.h | 19 | ||||
-rw-r--r-- | lwis_device_i2c.c | 1 | ||||
-rw-r--r-- | lwis_device_i2c.h | 1 | ||||
-rw-r--r-- | lwis_dt.c | 10 | ||||
-rw-r--r-- | lwis_i2c_bus_manager.c | 470 | ||||
-rw-r--r-- | lwis_i2c_bus_manager.h | 28 | ||||
-rw-r--r-- | lwis_i2c_sched.c | 17 | ||||
-rw-r--r-- | lwis_i2c_sched.h | 10 | ||||
-rw-r--r-- | lwis_ioctl.c | 2 | ||||
-rw-r--r-- | lwis_periodic_io.c | 30 | ||||
-rw-r--r-- | lwis_transaction.c | 352 | ||||
-rw-r--r-- | lwis_transaction.h | 34 |
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; }; @@ -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); |