diff options
author | Meghana Barkalle <mbarkalle@google.com> | 2023-05-05 21:01:27 +0000 |
---|---|---|
committer | Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> | 2023-12-13 16:36:31 +0000 |
commit | ef0b81e3ed914748c271989a120a628678a1905a (patch) | |
tree | e8c225ce37a3cd0007fcd67454d61b1690433e3e | |
parent | 61d154cf6e0ce8ee91000c5ea8aab389a113107e (diff) | |
download | lwis-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.h | 2 | ||||
-rw-r--r-- | lwis_dt.c | 14 | ||||
-rw-r--r-- | lwis_ioctl.c | 1 | ||||
-rw-r--r-- | lwis_transaction.c | 105 | ||||
-rw-r--r-- | lwis_transaction.h | 8 |
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; }; /* @@ -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 |