summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMeghana Barkalle <mbarkalle@google.com>2023-05-05 21:01:27 +0000
committerTreehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com>2023-12-13 16:36:31 +0000
commitef0b81e3ed914748c271989a120a628678a1905a (patch)
treee8c225ce37a3cd0007fcd67454d61b1690433e3e
parent61d154cf6e0ce8ee91000c5ea8aab389a113107e (diff)
downloadlwis-ef0b81e3ed914748c271989a120a628678a1905a.tar.gz
Add entry processing limit for queued transactions
When the numbers of processing entries need to be controlled then user could specify the following tag in the I2C device dt entry: transaction-process-limit When this entry is not specified, the default system behaviour is to process all the entries Test: GCA Smoke Test Bug: 299130975 Change-Id: I7c5979c84560e5b505a481b15889a782bb154062 (cherry picked from commit bb0bf434d0c5614c5b664b44f57e223fc1084d4e) Signed-off-by: Meghana Barkalle <mbarkalle@google.com>
-rw-r--r--lwis_device.h2
-rw-r--r--lwis_dt.c14
-rw-r--r--lwis_ioctl.c1
-rw-r--r--lwis_transaction.c105
-rw-r--r--lwis_transaction.h8
5 files changed, 120 insertions, 10 deletions
diff --git a/lwis_device.h b/lwis_device.h
index 75881fa..97d865a 100644
--- a/lwis_device.h
+++ b/lwis_device.h
@@ -294,6 +294,8 @@ struct lwis_device {
/* Worker thread */
struct kthread_worker transaction_worker;
struct task_struct *transaction_worker_thread;
+ /* Limit on number of transactions to be processed at a time */
+ int transaction_process_limit;
};
/*
diff --git a/lwis_dt.c b/lwis_dt.c
index d2e1c3a..c844ce9 100644
--- a/lwis_dt.c
+++ b/lwis_dt.c
@@ -1219,6 +1219,19 @@ 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)
+{
+ struct device_node *dev_node;
+
+ lwis_dev->transaction_process_limit = 0;
+ dev_node = lwis_dev->plat_dev->dev.of_node;
+
+ 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)
{
struct device *dev;
@@ -1349,6 +1362,7 @@ int lwis_base_parse_dt(struct lwis_device *lwis_dev)
parse_access_mode(lwis_dev);
parse_thread_priority(lwis_dev);
parse_bitwidths(lwis_dev);
+ parse_transaction_process_limit(lwis_dev);
lwis_dev->bts_scenario_name = NULL;
of_property_read_string(dev_node, "bts-scenario", &lwis_dev->bts_scenario_name);
diff --git a/lwis_ioctl.c b/lwis_ioctl.c
index 1599149..4a2ebe4 100644
--- a/lwis_ioctl.c
+++ b/lwis_ioctl.c
@@ -1202,6 +1202,7 @@ static int construct_transaction_from_cmd(struct lwis_client *client, uint32_t c
k_transaction->resp = NULL;
k_transaction->is_weak_transaction = false;
+ k_transaction->remaining_entries_to_process = k_transaction->info.num_io_entries;
INIT_LIST_HEAD(&k_transaction->event_list_node);
INIT_LIST_HEAD(&k_transaction->process_queue_node);
INIT_LIST_HEAD(&k_transaction->completion_fence_list);
diff --git a/lwis_transaction.c b/lwis_transaction.c
index db3c094..5e55582 100644
--- a/lwis_transaction.c
+++ b/lwis_transaction.c
@@ -122,6 +122,7 @@ void lwis_transaction_free(struct lwis_device *lwis_dev, struct lwis_transaction
if (transaction->is_weak_transaction) {
kfree(transaction);
+ transaction = NULL;
return;
}
@@ -151,11 +152,12 @@ void lwis_transaction_free(struct lwis_device *lwis_dev, struct lwis_transaction
kfree(transaction->resp);
}
kfree(transaction);
+ transaction = NULL;
}
static int process_transaction(struct lwis_client *client, struct lwis_transaction *transaction,
struct list_head *pending_events, struct list_head *pending_fences,
- bool skip_err)
+ bool skip_err, bool check_transaction_limit)
{
int i;
int ret = 0;
@@ -172,6 +174,33 @@ 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;
+
+ /*
+ * 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
+ */
+ if ((lwis_dev->transaction_process_limit <= 0) ||
+ (transaction->info.run_in_event_context) || (skip_err == true)) {
+ max_transaction_entry_limit = total_number_of_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;
+ remaining_entries_to_be_processed =
+ remaining_entries_to_be_processed - max_transaction_entry_limit;
+
if (lwis_transaction_debug) {
process_timestamp = ktime_to_ns(lwis_get_time());
}
@@ -188,7 +217,7 @@ static int process_transaction(struct lwis_client *client, struct lwis_transacti
/*use_write_barrier=*/true);
}
lwis_i2c_bus_manager_lock_i2c_bus(lwis_dev);
- for (i = 0; i < info->num_io_entries; ++i) {
+ for (i = processing_start_index; i < number_of_entries_to_process_in_current_run; ++i) {
entry = &info->io_entries[i];
if (entry->type == LWIS_IO_ENTRY_WRITE ||
entry->type == LWIS_IO_ENTRY_WRITE_BATCH ||
@@ -324,6 +353,21 @@ static int process_transaction(struct lwis_client *client, struct lwis_transacti
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 there are remaining entries to be processed in this transaction,
+ * don't delete this transaction and update the current remaining
+ * count of entries in the transaction. Stop processing further
+ * until there are no more remaining entries to be processed
+ * in the transaction.
+ */
+ spin_lock_irqsave(&client->transaction_lock, flags);
+ transaction->remaining_entries_to_process = remaining_entries_to_be_processed;
+ spin_unlock_irqrestore(&client->transaction_lock, flags);
+ return ret;
+ }
+
if (pending_events) {
lwis_pending_event_push(pending_events,
resp->error_code ? info->emit_error_event_id :
@@ -339,17 +383,39 @@ 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;
+
if (pending_fences) {
/* 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);
}
save_transaction_to_history(client, info, process_timestamp, process_duration_ns);
+
+ /*
+ * This check needs to be handled only for cases where we are processing
+ * 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
+ */
+ if (check_transaction_limit) {
+ /* 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
+ * 2. Delete transaction from the process queue after the limit is fulfilled
+ * 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
- * I/O entries are not being freed. */
+ /*
+ *Only clean the transaction struct for this iteration. The
+ * I/O entries are not being freed.
+ */
kfree(transaction->resp);
kfree(transaction);
+ transaction = NULL;
} else {
lwis_transaction_free(lwis_dev, transaction);
}
@@ -402,16 +468,34 @@ void lwis_process_transactions_in_queue(struct lwis_client *client)
spin_lock_irqsave(&client->transaction_lock, flags);
list_for_each_safe (it_tran, it_tran_tmp, &client->transaction_process_queue) {
transaction = list_entry(it_tran, struct lwis_transaction, process_queue_node);
- list_del(&transaction->process_queue_node);
if (transaction->resp->error_code) {
+ list_del(&transaction->process_queue_node);
cancel_transaction(client->lwis_dev, transaction,
transaction->resp->error_code, &pending_events,
&pending_fences);
} else {
spin_unlock_irqrestore(&client->transaction_lock, flags);
process_transaction(client, transaction, &pending_events, &pending_fences,
- /*skip_err=*/false);
+ /*skip_err=*/false, /*check_transaction_limit=*/true);
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
+ */
+ dev_info(
+ client->lwis_dev->dev,
+ "Transaction processing limit reached, remaining entries to process %d\n",
+ transaction->remaining_entries_to_process);
+ break;
+ }
}
}
spin_unlock_irqrestore(&client->transaction_lock, flags);
@@ -548,7 +632,8 @@ int lwis_transaction_client_cleanup(struct lwis_client *client)
process_transaction(client, transaction,
/*pending_events=*/NULL,
/*pending_fences=*/NULL,
- /*skip_err=*/true);
+ /*skip_err=*/true,
+ /*check_transaction_limit=*/false);
spin_lock_irqsave(&client->transaction_lock, flags);
}
}
@@ -820,6 +905,9 @@ new_repeating_transaction_iteration(struct lwis_client *client,
memcpy(resp_buf, transaction->resp, sizeof(struct lwis_transaction_response_header));
new_instance->resp = (struct lwis_transaction_response_header *)resp_buf;
+ new_instance->is_weak_transaction = transaction->is_weak_transaction;
+ new_instance->remaining_entries_to_process = transaction->info.num_io_entries;
+
INIT_LIST_HEAD(&new_instance->event_list_node);
INIT_LIST_HEAD(&new_instance->process_queue_node);
INIT_LIST_HEAD(&new_instance->completion_fence_list);
@@ -846,7 +934,7 @@ static void defer_transaction_locked(struct lwis_client *client,
if (transaction->info.run_in_event_context) {
spin_unlock_irqrestore(&client->transaction_lock, flags);
process_transaction(client, transaction, pending_events, pending_fences,
- /*skip_err=*/false);
+ /*skip_err=*/false, /*check_transaction_limit=*/false);
spin_lock_irqsave(&client->transaction_lock, flags);
} else {
list_add_tail(&transaction->process_queue_node, &client->transaction_process_queue);
@@ -883,7 +971,6 @@ int lwis_transaction_event_trigger(struct lwis_client *client, int64_t event_id,
/* 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);
diff --git a/lwis_transaction.h b/lwis_transaction.h
index 340257a..5f61f75 100644
--- a/lwis_transaction.h
+++ b/lwis_transaction.h
@@ -18,7 +18,8 @@ struct lwis_device;
struct lwis_client;
struct lwis_fence;
-/* Transaction entry. Each entry belongs to two queues:
+/*
+ * Transaction entry. Each entry belongs to two queues:
* 1) Event list: Transactions are sorted by event IDs. This is to search for
* the appropriate transactions to trigger.
* 2) Process queue: When it's time to process, the transaction will be put
@@ -47,6 +48,11 @@ 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
+ */
+ int remaining_entries_to_process;
};
/* For debugging purposes, keeps track of the transaction information, as