diff options
Diffstat (limited to 'drivers/edgetpu/edgetpu-kci.c')
-rw-r--r-- | drivers/edgetpu/edgetpu-kci.c | 75 |
1 files changed, 63 insertions, 12 deletions
diff --git a/drivers/edgetpu/edgetpu-kci.c b/drivers/edgetpu/edgetpu-kci.c index f506a04..e467fac 100644 --- a/drivers/edgetpu/edgetpu-kci.c +++ b/drivers/edgetpu/edgetpu-kci.c @@ -432,6 +432,14 @@ static void edgetpu_kci_handle_irq(struct edgetpu_mailbox *mailbox) schedule_work(&kci->work); } +static void edgetpu_kci_update_usage_work(struct work_struct *work) +{ + struct edgetpu_kci *kci = + container_of(work, struct edgetpu_kci, usage_work); + + edgetpu_kci_update_usage(kci->mailbox->etdev); +} + int edgetpu_kci_init(struct edgetpu_mailbox_manager *mgr, struct edgetpu_kci *kci) { @@ -478,6 +486,7 @@ int edgetpu_kci_init(struct edgetpu_mailbox_manager *mgr, init_waitqueue_head(&kci->wait_list_waitq); INIT_WORK(&kci->work, edgetpu_kci_consume_responses_work); edgetpu_reverse_kci_init(&kci->rkci); + INIT_WORK(&kci->usage_work, edgetpu_kci_update_usage_work); EDGETPU_MAILBOX_CONTEXT_WRITE(mailbox, context_enable, 1); return 0; } @@ -507,7 +516,9 @@ int edgetpu_kci_reinit(struct edgetpu_kci *kci) void edgetpu_kci_cancel_work_queues(struct edgetpu_kci *kci) { - /* Cancel KCI and reverse KCI workers */ + /* Cancel workers that may send KCIs. */ + cancel_work_sync(&kci->usage_work); + /* Cancel KCI and reverse KCI workers. */ cancel_work_sync(&kci->work); cancel_work_sync(&kci->rkci.work); } @@ -516,10 +527,6 @@ void edgetpu_kci_release(struct edgetpu_dev *etdev, struct edgetpu_kci *kci) { if (!kci) return; - /* - * Command/Response queues are managed (dmam_alloc_coherent()), we don't - * need to free them. - */ edgetpu_kci_cancel_work_queues(kci); @@ -853,19 +860,42 @@ enum edgetpu_fw_flavor edgetpu_kci_fw_info(struct edgetpu_kci *kci, return flavor; } +void edgetpu_kci_update_usage_async(struct edgetpu_dev *etdev) +{ + schedule_work(&etdev->kci->usage_work); +} + int edgetpu_kci_update_usage(struct edgetpu_dev *etdev) { - int ret; + int ret = -EAGAIN; - /* Quick return if device already powered down, else get PM ref. */ + /* Quick return if device is already powered down. */ if (!edgetpu_is_powered(etdev)) return -EAGAIN; - ret = edgetpu_pm_get(etdev->pm); - if (ret) - return ret; - ret = edgetpu_kci_update_usage_locked(etdev); + /* + * Lockout change in f/w load/unload status during usage update. + * Skip usage update if the firmware is being updated now or is not + * valid. + */ + if (!edgetpu_firmware_trylock(etdev)) + return -EAGAIN; - edgetpu_pm_put(etdev->pm); + if (edgetpu_firmware_status_locked(etdev) != FW_VALID) + goto fw_unlock; + /* + * This function may run in a worker that is being canceled when the + * device is powering down, and the power down code holds the PM lock. + * Using trylock to prevent cancel_work_sync() waiting forever. + */ + if (!edgetpu_pm_trylock(etdev->pm)) + goto fw_unlock; + + if (edgetpu_is_powered(etdev)) + ret = edgetpu_kci_update_usage_locked(etdev); + edgetpu_pm_unlock(etdev->pm); + +fw_unlock: + edgetpu_firmware_unlock(etdev); return ret; } @@ -986,3 +1016,24 @@ int edgetpu_kci_close_device(struct edgetpu_kci *kci, u32 mailbox_ids) return -ENODEV; return edgetpu_kci_send_cmd(kci, &cmd); } + +int edgetpu_kci_notify_throttling(struct edgetpu_dev *etdev, u32 level) +{ + struct edgetpu_command_element cmd = { + .code = KCI_CODE_NOTIFY_THROTTLING, + .dma = { + .flags = level, + }, + }; + int ret; + + if (!etdev->kci) + return -ENODEV; + if (!edgetpu_pm_get_if_powered(etdev->pm)) + return -EAGAIN; + + ret = edgetpu_kci_send_cmd(etdev->kci, &cmd); + edgetpu_pm_put(etdev->pm); + return ret; +} + |