summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMeghana Barkalle <mbarkalle@google.com>2023-04-20 08:34:46 +0000
committerTreehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com>2023-12-13 16:36:31 +0000
commitb64156b9d2e33a005d07f004f3e9967db2aa6a0c (patch)
tree30f28c6fe283e74841f46e98b5dd2e0be40ba85f
parenta835b156e0347ce33d1b2040569cffa54ff041d7 (diff)
downloadlwis-b64156b9d2e33a005d07f004f3e9967db2aa6a0c.tar.gz
Optimize I2C Bus manager scheduling
1. Add I2C device priority to dts device node to facilitate better scheduling. Default I2C priority is set to HIGH for all device. The levels that can be specified are: HIGH = 0 MEDIUM = 1 LOW = 2 2. Update the I2C bus manager process queue to handle requests from clients in the device priority order. 3. Remove enquiing individual requests from I2C devices on the bus manager process queue directly. This optimization would result in locking the Bus Manager process queue spinlock less times and thereby reduce the thread waittime as well. Test: GCA Smoke Test Bug: 299130975 Change-Id: I74e5fa9e11b80636d9afa23a81f9ed33cb3b1fdf (cherry picked from commit 377dba45d501ac1a27134c371bb17cda4ab4b839) Signed-off-by: Meghana Barkalle <mbarkalle@google.com>
-rw-r--r--lwis_device.c7
-rw-r--r--lwis_device_i2c.c1
-rw-r--r--lwis_device_i2c.h1
-rw-r--r--lwis_dt.c34
-rw-r--r--lwis_i2c_bus_manager.c293
-rw-r--r--lwis_i2c_bus_manager.h22
-rw-r--r--lwis_i2c_sched.c67
-rw-r--r--lwis_i2c_sched.h10
-rw-r--r--lwis_periodic_io.c8
-rw-r--r--lwis_transaction.c24
10 files changed, 313 insertions, 154 deletions
diff --git a/lwis_device.c b/lwis_device.c
index 60b5dc4..4735f62 100644
--- a/lwis_device.c
+++ b/lwis_device.c
@@ -160,6 +160,11 @@ static int lwis_open(struct inode *node, struct file *fp)
/* Storing the client handle in fp private_data for easy access */
fp->private_data = lwis_client;
+ if (lwis_i2c_bus_manager_connect_client(lwis_client)) {
+ dev_err(lwis_dev->dev, "Failed to connect lwis client to I2C bus manager\n");
+ return -EINVAL;
+ }
+
lwis_client->is_enabled = false;
return 0;
}
@@ -234,6 +239,8 @@ static int lwis_release_client(struct lwis_client *lwis_client)
}
spin_unlock_irqrestore(&lwis_dev->lock, flags);
+ lwis_i2c_bus_manager_disconnect_client(lwis_client);
+
kfree(lwis_client);
return 0;
diff --git a/lwis_device_i2c.c b/lwis_device_i2c.c
index ad513b8..877719f 100644
--- a/lwis_device_i2c.c
+++ b/lwis_device_i2c.c
@@ -7,7 +7,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
#define pr_fmt(fmt) KBUILD_MODNAME "-i2c-dev: " fmt
#include "lwis_device_i2c.h"
diff --git a/lwis_device_i2c.h b/lwis_device_i2c.h
index 03c393f..393bd32 100644
--- a/lwis_device_i2c.h
+++ b/lwis_device_i2c.h
@@ -36,6 +36,7 @@ struct lwis_i2c_device {
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;
};
int lwis_i2c_device_deinit(void);
diff --git a/lwis_dt.c b/lwis_dt.c
index d6c4559..d2e1c3a 100644
--- a/lwis_dt.c
+++ b/lwis_dt.c
@@ -25,6 +25,7 @@
#include "lwis_i2c.h"
#include "lwis_ioreg.h"
#include "lwis_regulator.h"
+#include "lwis_i2c_bus_manager.h"
#define SHARED_STRING "shared-"
#define PULSE_STRING "pulse-"
@@ -1165,6 +1166,33 @@ static int parse_thread_priority(struct lwis_device *lwis_dev)
return 0;
}
+static int parse_i2c_device_priority(struct lwis_i2c_device *i2c_dev)
+{
+ struct device_node *dev_node;
+ int ret = 0;
+
+ dev_node = i2c_dev->base_dev.plat_dev->dev.of_node;
+ /* Set i2c device_priority value to default */
+ i2c_dev->device_priority = I2C_DEVICE_HIGH_PRIORITY;
+
+ ret = of_property_read_u32(dev_node, "i2c-device-priority", &i2c_dev->device_priority);
+ /* If no property in device tree, just return to use default */
+ if (ret == -EINVAL) {
+ return 0;
+ }
+ if (ret) {
+ pr_err("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);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int parse_i2c_lock_group_id(struct lwis_i2c_device *i2c_dev)
{
struct device_node *dev_node;
@@ -1364,6 +1392,12 @@ int lwis_i2c_device_parse_dt(struct lwis_i2c_device *i2c_dev)
return ret;
}
+ ret = parse_i2c_device_priority(i2c_dev);
+ if (ret) {
+ dev_err(i2c_dev->base_dev.dev, "Error parsing i2c device priority\n");
+ return ret;
+ }
+
return 0;
}
diff --git a/lwis_i2c_bus_manager.c b/lwis_i2c_bus_manager.c
index 1b3525e..04711f7 100644
--- a/lwis_i2c_bus_manager.c
+++ b/lwis_i2c_bus_manager.c
@@ -208,20 +208,24 @@ static void destroy_i2c_bus_manager(struct lwis_i2c_bus_manager *i2c_bus_manager
struct lwis_device *lwis_dev)
{
unsigned long flags;
- if (i2c_bus_manager) {
- dev_info(lwis_dev->dev, "Destroying I2C Bus Manager: %s\n",
- i2c_bus_manager->i2c_bus_name);
- spin_lock_irqsave(&i2c_bus_manager->i2c_process_queue_lock, flags);
- lwis_i2c_process_request_queue_destroy(&i2c_bus_manager->i2c_bus_process_queue);
- spin_unlock_irqrestore(&i2c_bus_manager->i2c_process_queue_lock, flags);
-
- /* Delete the bus manager instance from the list */
- delete_bus_manager_id_in_list(i2c_bus_manager->i2c_bus_id);
+ int i = 0;
+ if (!i2c_bus_manager) {
+ return;
+ }
- /* Free the bus manager */
- kfree(i2c_bus_manager);
- i2c_bus_manager = NULL;
+ dev_info(lwis_dev->dev, "Destroying I2C Bus Manager: %s\n", i2c_bus_manager->i2c_bus_name);
+ spin_lock_irqsave(&i2c_bus_manager->i2c_process_queue_lock, flags);
+ for (i = 0; i < I2C_MAX_PRIORITY_LEVELS; i++) {
+ lwis_i2c_process_request_queue_destroy(&i2c_bus_manager->i2c_bus_process_queue[i]);
}
+ spin_unlock_irqrestore(&i2c_bus_manager->i2c_process_queue_lock, flags);
+
+ /* 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;
}
/*
@@ -259,42 +263,76 @@ static int connect_i2c_bus_manager(struct lwis_i2c_bus_manager *i2c_bus_manager,
return ret;
}
+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;
+}
+
/*
* lwis_i2c_bus_manager_process_worker_queue:
* Function to be called by i2c bus manager worker thread to
- * pick the next I2C device that is scheduled for transfer
+ * pick the next I2C client that is scheduled for transfer.
+ * The process queue will be processed in order of I2C
+ * 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;
/* The transfers will be processed in fifo order */
- struct lwis_device **dequeuing_dev = NULL;
struct lwis_client *client_to_process = NULL;
struct lwis_device *lwis_dev_to_process = NULL;
unsigned long flags;
+ struct lwis_i2c_process_queue *process_queue = NULL;
+ struct lwis_i2c_process_request *process_request = NULL;
+
+ 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);
- if (i2c_bus_manager) {
- spin_lock_irqsave(&i2c_bus_manager->i2c_process_queue_lock, flags);
- dequeuing_dev = lwis_i2c_process_request_queue_dequeue_request(
- &i2c_bus_manager->i2c_bus_process_queue);
- spin_unlock_irqrestore(&i2c_bus_manager->i2c_process_queue_lock, flags);
-
- if (dequeuing_dev) {
- lwis_dev_to_process = *dequeuing_dev;
+ if (!i2c_bus_manager) {
+ dev_err(lwis_dev->dev, "I2C Bus Manager is null\n");
+ return;
+ }
+ spin_lock_irqsave(&i2c_bus_manager->i2c_process_queue_lock, flags);
+ for (i = 0; i < I2C_MAX_PRIORITY_LEVELS; i++) {
+ process_queue = &i2c_bus_manager->i2c_bus_process_queue[i];
+ list_for_each_safe (i2c_client_node, i2c_client_tmp_node, &process_queue->head) {
+ process_request = list_entry(i2c_client_node,
+ struct lwis_i2c_process_request, request_node);
+ if (!process_request) {
+ dev_err(lwis_dev->dev, "I2C Bus Worker process_request is null\n");
+ break;
+ }
+ client_to_process = process_request->requesting_client;
+ if (!client_to_process) {
+ dev_err(lwis_dev->dev,
+ "I2C Bus Worker client_to_process is null\n");
+ break;
+ }
+ lwis_dev_to_process = client_to_process->lwis_dev;
+ if (!lwis_dev_to_process) {
+ dev_err(lwis_dev->dev,
+ "I2C Bus Worker lwis_dev_to_process is null\n");
+ break;
+ }
+ spin_unlock_irqrestore(&i2c_bus_manager->i2c_process_queue_lock, flags);
if (is_valid_connected_device(lwis_dev_to_process, i2c_bus_manager)) {
- client_to_process =
- container_of(dequeuing_dev, struct lwis_client, lwis_dev);
lwis_process_transactions_in_queue(client_to_process);
lwis_process_periodic_io_in_queue(client_to_process);
}
+ spin_lock_irqsave(&i2c_bus_manager->i2c_process_queue_lock, flags);
}
}
+ spin_unlock_irqrestore(&i2c_bus_manager->i2c_process_queue_lock, flags);
}
/*
@@ -304,6 +342,7 @@ 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;
struct lwis_device *i2c_base_device = &i2c_dev->base_dev;
@@ -331,7 +370,10 @@ int lwis_i2c_bus_manager_create(struct lwis_i2c_device *i2c_dev)
INIT_LIST_HEAD(&i2c_bus_manager->i2c_connected_devices);
/* Create a I2C transfer process queue */
- lwis_i2c_process_request_queue_initialize(&i2c_bus_manager->i2c_bus_process_queue);
+ for (i = 0; i < I2C_MAX_PRIORITY_LEVELS; i++) {
+ lwis_i2c_process_request_queue_initialize(
+ &i2c_bus_manager->i2c_bus_process_queue[i]);
+ }
/* Insert this instance of bus manager in the bus manager list */
ret = insert_bus_manager_id_in_list(i2c_bus_manager, i2c_dev->adapter->nr);
@@ -421,25 +463,6 @@ void lwis_i2c_bus_manager_disconnect(struct lwis_device *lwis_dev)
}
}
-/* lwis_i2c_bus_manager_enqueue_transfer_request:
- * Enqueues I2C transfer request from a requesting device on the I2C Scheduler
- */
-int lwis_i2c_bus_manager_enqueue_transfer_request(struct lwis_i2c_bus_manager *i2c_bus_manager,
- struct lwis_device **lwis_dev)
-{
- int ret = 0;
- struct lwis_device *enqueuing_dev = *lwis_dev;
- unsigned long flags;
-
- if (lwis_check_device_type(enqueuing_dev, DEVICE_TYPE_I2C)) {
- spin_lock_irqsave(&i2c_bus_manager->i2c_process_queue_lock, flags);
- ret = lwis_i2c_process_request_queue_enqueue_request(
- &i2c_bus_manager->i2c_bus_process_queue, lwis_dev);
- spin_unlock_irqrestore(&i2c_bus_manager->i2c_process_queue_lock, flags);
- }
- return ret;
-}
-
/* lwis_i2c_bus_manager_lock_i2c_bus:
* Locks the I2C bus for a given I2C Lwis Device
*/
@@ -479,23 +502,23 @@ struct lwis_i2c_bus_manager *lwis_i2c_bus_manager_get_manager(struct lwis_device
return NULL;
}
+/* lwis_i2c_bus_manager_flush_i2c_worker:
+ * Flushes the I2C Bus Manager worker
+ */
void lwis_i2c_bus_manager_flush_i2c_worker(struct lwis_device *lwis_dev)
{
- unsigned long process_queue_flags;
struct lwis_i2c_bus_manager *i2c_bus_manager = lwis_i2c_bus_manager_get_manager(lwis_dev);
if (i2c_bus_manager == NULL)
return;
kthread_flush_worker(&i2c_bus_manager->i2c_bus_worker);
-
- /* After flushing the worker the process queue should be empty.
- * This destroy is to make sure there are no more requests to be handled. */
- spin_lock_irqsave(&i2c_bus_manager->i2c_process_queue_lock, process_queue_flags);
- lwis_i2c_process_request_queue_destroy(&i2c_bus_manager->i2c_bus_process_queue);
- spin_unlock_irqrestore(&i2c_bus_manager->i2c_process_queue_lock, process_queue_flags);
}
+/* 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 */
@@ -503,6 +526,9 @@ void lwis_i2c_bus_manager_list_initialize(void)
INIT_LIST_HEAD(&i2c_bus_manager_list.i2c_bus_manager_list_head);
}
+/* lwis_i2c_bus_manager_list_deinitialize:
+ * Deinitializes bus manager global list
+ */
void lwis_i2c_bus_manager_list_deinitialize(void)
{
struct list_head *i2c_bus_manager_list_node, *i2c_bus_manager_list_tmp_node;
@@ -521,4 +547,169 @@ void lwis_i2c_bus_manager_list_deinitialize(void)
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.
+ */
+int lwis_i2c_bus_manager_connect_client(struct lwis_client *connecting_client)
+{
+ int ret = 0;
+ int device_priority = I2C_MAX_PRIORITY_LEVELS;
+ unsigned long flags;
+ bool create_client_node = true;
+ 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;
+
+ if (!connecting_client) {
+ pr_err("Connecting client pointer for I2C Bus Manager is NULL\n");
+ return -EINVAL;
+ }
+
+ lwis_dev = connecting_client->lwis_dev;
+ if (!lwis_dev) {
+ pr_err("Connecting device for I2C Bus Manager is NULL\n");
+ return -EINVAL;
+ }
+
+ if (!lwis_check_device_type(lwis_dev, DEVICE_TYPE_I2C)) {
+ return ret;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&i2c_bus_manager->i2c_process_queue_lock, flags);
+
+ // 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;
+ }
+ }
+ }
+
+ if (create_client_node) {
+ i2c_connecting_client_node =
+ kzalloc(sizeof(struct lwis_i2c_process_request), GFP_ATOMIC);
+ 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);
+ }
+
+ spin_unlock_irqrestore(&i2c_bus_manager->i2c_process_queue_lock, flags);
+ return ret;
+}
+
+/* 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
+ * on the I2C device priority specified in the dts for the I2C device node.
+ * I2C lwis client is always disconnected when the instance of client is
+ * released/destroyed.
+ */
+void lwis_i2c_bus_manager_disconnect_client(struct lwis_client *disconnecting_client)
+{
+ int device_priority = I2C_MAX_PRIORITY_LEVELS;
+ unsigned long flags;
+ 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);
+ return;
+ }
+
+ spin_lock_irqsave(&i2c_bus_manager->i2c_process_queue_lock, flags);
+ 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;
+ kfree(i2c_disconnecting_client_node);
+ i2c_disconnecting_client_node = NULL;
+ --process_queue->number_of_nodes;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&i2c_bus_manager->i2c_process_queue_lock, flags);
} \ No newline at end of file
diff --git a/lwis_i2c_bus_manager.h b/lwis_i2c_bus_manager.h
index ca40ae8..5e236e1 100644
--- a/lwis_i2c_bus_manager.h
+++ b/lwis_i2c_bus_manager.h
@@ -17,6 +17,17 @@
#include "lwis_periodic_io.h"
#include "lwis_transaction.h"
+/* enum lwis_i2c_device_priority_level:
+ * Defines the I2C device priority level
+ * 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
+};
+
// Forward declaration
struct lwis_i2c_device;
@@ -45,7 +56,7 @@ struct lwis_i2c_process_queue {
/* Head node for the process queue */
struct list_head head;
/* Total number of devices that are queued to be processed */
- int number_of_requests;
+ int number_of_nodes;
};
/*
@@ -67,7 +78,7 @@ struct lwis_i2c_bus_manager {
struct kthread_worker i2c_bus_worker;
struct task_struct *i2c_bus_worker_thread;
/* Queue of all I2C devices that have data to transfer in their process queues */
- struct lwis_i2c_process_queue i2c_bus_process_queue;
+ struct lwis_i2c_process_queue i2c_bus_process_queue[I2C_MAX_PRIORITY_LEVELS];
/* List of I2C devices using this bus */
struct list_head i2c_connected_devices;
/* Total number of physically connected devices to the bus
@@ -94,13 +105,14 @@ void lwis_i2c_bus_manager_disconnect(struct lwis_device *lwis_dev);
void lwis_i2c_bus_manager_process_worker_queue(struct lwis_client *client);
-int lwis_i2c_bus_manager_enqueue_transfer_request(struct lwis_i2c_bus_manager *i2c_bus_manager,
- struct lwis_device **lwis_dev);
-
void lwis_i2c_bus_manager_flush_i2c_worker(struct lwis_device *lwis_dev);
void lwis_i2c_bus_manager_list_initialize(void);
void lwis_i2c_bus_manager_list_deinitialize(void);
+int lwis_i2c_bus_manager_connect_client(struct lwis_client *connecting_client);
+
+void lwis_i2c_bus_manager_disconnect_client(struct lwis_client *disconnecting_client);
+
#endif /* LWIS_I2C_BUS_MANAGER_H */
diff --git a/lwis_i2c_sched.c b/lwis_i2c_sched.c
index 3c61fcf..1ca802f 100644
--- a/lwis_i2c_sched.c
+++ b/lwis_i2c_sched.c
@@ -16,9 +16,9 @@
* lwis_i2c_process_request_queue_is_empty:
* Checks if the I2C process request queue is empty
*/
-static bool lwis_i2c_process_request_queue_is_empty(struct lwis_i2c_process_queue *process_queue)
+bool lwis_i2c_process_request_queue_is_empty(struct lwis_i2c_process_queue *process_queue)
{
- if ((!process_queue) || ((process_queue) && (process_queue->number_of_requests == 0))) {
+ if ((!process_queue) || ((process_queue) && (process_queue->number_of_nodes == 0))) {
return true;
}
return false;
@@ -30,7 +30,7 @@ static bool lwis_i2c_process_request_queue_is_empty(struct lwis_i2c_process_queu
*/
void lwis_i2c_process_request_queue_initialize(struct lwis_i2c_process_queue *process_queue)
{
- process_queue->number_of_requests = 0;
+ process_queue->number_of_nodes = 0;
INIT_LIST_HEAD(&process_queue->head);
}
@@ -54,66 +54,9 @@ void lwis_i2c_process_request_queue_destroy(struct lwis_i2c_process_queue *proce
process_request =
list_entry(request, struct lwis_i2c_process_request, request_node);
list_del(&process_request->request_node);
- process_request->requesting_device = NULL;
+ process_request->requesting_client = NULL;
kfree(process_request);
process_request = NULL;
- --process_queue->number_of_requests;
+ --process_queue->number_of_nodes;
}
-}
-
-/*
- * lwis_i2c_process_request_queue_enqueue_request:
- * Enqueues a requesting device on tail of the I2C Scheduler
-*/
-int lwis_i2c_process_request_queue_enqueue_request(struct lwis_i2c_process_queue *process_queue,
- struct lwis_device **requesting_device)
-{
- int ret = 0;
- struct lwis_i2c_process_request *request;
- struct lwis_device *lwis_dev = *requesting_device;
-
- if ((!process_queue) || (!requesting_device) || (!lwis_dev)) {
- pr_err("Invalid pointer\n");
- return -EINVAL;
- }
-
- // Atomic allocation needed here since this memory is allocated within
- // transition and periodic io locks of various I2C devices
- request = kzalloc(sizeof(struct lwis_i2c_process_request), GFP_ATOMIC);
- if (!request) {
- dev_err(lwis_dev->dev, "Failed to allocate I2C Process Request Node memory\n");
- return -ENOMEM;
- }
- request->requesting_device = requesting_device;
- INIT_LIST_HEAD(&request->request_node);
- list_add_tail(&request->request_node, &process_queue->head);
- process_queue->number_of_requests++;
-
- return ret;
-}
-
-/*
- * lwis_i2c_process_request_queue_dequeue_request:
- * Dequeues a lwis device from head of the I2C Scheduler
-*/
-struct lwis_device **
-lwis_i2c_process_request_queue_dequeue_request(struct lwis_i2c_process_queue *process_queue)
-{
- struct lwis_i2c_process_request *request;
- struct lwis_device **requested_device = NULL;
-
- if (lwis_i2c_process_request_queue_is_empty(process_queue)) {
- return requested_device;
- }
-
- request = list_first_entry_or_null(&process_queue->head, struct lwis_i2c_process_request,
- request_node);
- if (request) {
- requested_device = request->requesting_device;
- list_del(&request->request_node);
- kfree(request);
- request = NULL;
- process_queue->number_of_requests--;
- }
- return requested_device;
} \ No newline at end of file
diff --git a/lwis_i2c_sched.h b/lwis_i2c_sched.h
index de3390d..22073af 100644
--- a/lwis_i2c_sched.h
+++ b/lwis_i2c_sched.h
@@ -20,18 +20,14 @@ struct lwis_i2c_process_queue;
* This maintains the node to identify the devices that
* have a request to be processed on a given I2C bus */
struct lwis_i2c_process_request {
- struct lwis_device **requesting_device;
+ struct lwis_client *requesting_client;
struct list_head request_node;
};
+bool lwis_i2c_process_request_queue_is_empty(struct lwis_i2c_process_queue *process_queue);
+
void lwis_i2c_process_request_queue_initialize(struct lwis_i2c_process_queue *process_queue);
void lwis_i2c_process_request_queue_destroy(struct lwis_i2c_process_queue *process_queue);
-int lwis_i2c_process_request_queue_enqueue_request(struct lwis_i2c_process_queue *process_queue,
- struct lwis_device **requesting_device);
-
-struct lwis_device **
-lwis_i2c_process_request_queue_dequeue_request(struct lwis_i2c_process_queue *process_queue);
-
#endif /* LWIS_I2C_SCHED_H_ */ \ No newline at end of file
diff --git a/lwis_periodic_io.c b/lwis_periodic_io.c
index bdd86e5..ad5ef83 100644
--- a/lwis_periodic_io.c
+++ b/lwis_periodic_io.c
@@ -37,7 +37,6 @@ static enum hrtimer_restart periodic_io_timer_func(struct hrtimer *timer)
bool active_periodic_io_present = false;
struct lwis_device *lwis_dev;
struct lwis_i2c_bus_manager *i2c_bus_manager = NULL;
- int ret = 0;
periodic_io_list = container_of(timer, struct lwis_periodic_io_list, hr_timer);
client = periodic_io_list->client;
@@ -65,12 +64,7 @@ static enum hrtimer_restart periodic_io_timer_func(struct hrtimer *timer)
}
if (active_periodic_io_present) {
if (i2c_bus_manager) {
- ret = lwis_i2c_bus_manager_enqueue_transfer_request(i2c_bus_manager,
- &client->lwis_dev);
- if (!ret) {
- kthread_queue_work(&i2c_bus_manager->i2c_bus_worker,
- &client->i2c_work);
- }
+ kthread_queue_work(&i2c_bus_manager->i2c_bus_worker, &client->i2c_work);
} else {
kthread_queue_work(&client->lwis_dev->transaction_worker,
&client->transaction_work);
diff --git a/lwis_transaction.c b/lwis_transaction.c
index 983cd5c..db3c094 100644
--- a/lwis_transaction.c
+++ b/lwis_transaction.c
@@ -744,13 +744,7 @@ static int queue_transaction_locked(struct lwis_client *client,
/* Immediate trigger. */
list_add_tail(&transaction->process_queue_node, &client->transaction_process_queue);
if (i2c_bus_manager) {
- if (!lwis_i2c_bus_manager_enqueue_transfer_request(i2c_bus_manager,
- &client->lwis_dev)) {
- kthread_queue_work(&i2c_bus_manager->i2c_bus_worker,
- &client->i2c_work);
- } else {
- dev_err(client->lwis_dev->dev, "Cannot queue I2C transfer\n");
- }
+ kthread_queue_work(&i2c_bus_manager->i2c_bus_worker, &client->i2c_work);
} else {
kthread_queue_work(&client->lwis_dev->transaction_worker,
&client->transaction_work);
@@ -947,13 +941,7 @@ 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) {
- if (!lwis_i2c_bus_manager_enqueue_transfer_request(i2c_bus_manager,
- &client->lwis_dev)) {
- kthread_queue_work(&i2c_bus_manager->i2c_bus_worker,
- &client->i2c_work);
- } else {
- dev_err(client->lwis_dev->dev, "Cannot queue I2C transfer\n");
- }
+ kthread_queue_work(&i2c_bus_manager->i2c_bus_worker, &client->i2c_work);
} else {
kthread_queue_work(&client->lwis_dev->transaction_worker,
&client->transaction_work);
@@ -1026,13 +1014,7 @@ void lwis_transaction_fence_trigger(struct lwis_client *client, struct lwis_fenc
/* Schedule deferred transactions */
if (!list_empty(&client->transaction_process_queue)) {
if (i2c_bus_manager) {
- if (!lwis_i2c_bus_manager_enqueue_transfer_request(i2c_bus_manager,
- &client->lwis_dev)) {
- kthread_queue_work(&i2c_bus_manager->i2c_bus_worker,
- &client->i2c_work);
- } else {
- dev_err(client->lwis_dev->dev, "Cannot queue I2C transfer\n");
- }
+ kthread_queue_work(&i2c_bus_manager->i2c_bus_worker, &client->i2c_work);
} else {
kthread_queue_work(&client->lwis_dev->transaction_worker,
&client->transaction_work);