Loading drivers/input/touchscreen/focaltech_touch/focaltech_core.c +16 −3 Original line number Diff line number Diff line Loading @@ -296,7 +296,9 @@ static int fts_ts_vm_handle_vm_hardware(struct fts_ts_data *fts_data) return rc; } static void fts_ts_vm_irq_on_lend_callback(void *data, enum hh_irq_label label) static void fts_ts_vm_irq_on_lend_callback(void *data, unsigned long notif_type, enum hh_irq_label label) { struct fts_ts_data *fts_data = data; struct irq_data *irq_data; Loading Loading @@ -472,6 +474,10 @@ static void fts_ts_trusted_touch_vm_mode_disable(struct fts_ts_data *fts_data) pr_err("Failed to release irq rc:%d\n", rc); else atomic_set(&fts_data->vm_info->tvm_owns_irq, 0); rc = hh_irq_release_notify(fts_data->vm_info->irq_label); if (rc) pr_err("Failed to notify release irq rc:%d\n", rc); } atomic_set(&fts_data->trusted_touch_enabled, 0); reinit_completion(&fts_data->resource_checkpoint); Loading Loading @@ -600,6 +606,7 @@ static void fts_ts_trusted_touch_complete(struct fts_ts_data *fts_data) } static void fts_ts_vm_irq_on_release_callback(void *data, unsigned long notif_type, enum hh_irq_label label) { struct fts_ts_data *fts_data = data; Loading Loading @@ -730,7 +737,7 @@ static int fts_ts_trusted_touch_vm_mode_enable(struct fts_ts_data *fts_data) } atomic_set(&vm_info->pvm_owns_iomem, 0); rc = hh_irq_lend(vm_info->irq_label, vm_info->vm_name, rc = hh_irq_lend_v2(vm_info->irq_label, vm_info->vm_name, fts_data->irq, &fts_ts_vm_irq_on_release_callback, fts_data); if (rc) { pr_err("Failed to lend irq\n"); Loading @@ -738,6 +745,12 @@ static int fts_ts_trusted_touch_vm_mode_enable(struct fts_ts_data *fts_data) } atomic_set(&vm_info->pvm_owns_irq, 0); rc = hh_irq_lend_notify(vm_info->irq_label); if (rc) { pr_err("Failed to notify irq\n"); return -EINVAL; } reinit_completion(&fts_data->trusted_touch_powerdown); atomic_set(&fts_data->trusted_touch_enabled, 1); pr_debug("trusted touch enabled\n"); Loading Loading @@ -809,7 +822,7 @@ static int fts_ts_vm_init(struct fts_ts_data *fts_data) goto init_fail; } vm_info->mem_cookie = mem_cookie; rc = hh_irq_wait_for_lend(vm_info->irq_label, HH_PRIMARY_VM, rc = hh_irq_wait_for_lend_v2(vm_info->irq_label, HH_PRIMARY_VM, &fts_ts_vm_irq_on_lend_callback, fts_data); atomic_set(&vm_info->tvm_owns_irq, 0); atomic_set(&vm_info->tvm_owns_iomem, 0); Loading drivers/input/touchscreen/st/fts.c +18 −4 Original line number Diff line number Diff line Loading @@ -321,7 +321,9 @@ static int fts_vm_handle_vm_hardware(struct fts_ts_info *info) return rc; } static void fts_vm_irq_on_lend_callback(void *data, enum hh_irq_label label) static void fts_vm_irq_on_lend_callback(void *data, unsigned long notif_type, enum hh_irq_label label) { struct fts_ts_info *info = data; struct irq_data *irq_data; Loading Loading @@ -497,6 +499,10 @@ static void fts_trusted_touch_vm_mode_disable(struct fts_ts_info *info) pr_err("Failed to release irq rc:%d\n", rc); else atomic_set(&info->vm_info->tvm_owns_irq, 0); rc = hh_irq_release_notify(info->vm_info->irq_label); if (rc) pr_err("Failed to notify release irq rc:%d\n", rc); } atomic_set(&info->trusted_touch_enabled, 0); reinit_completion(&info->resource_checkpoint); Loading Loading @@ -624,7 +630,9 @@ static void fts_trusted_touch_complete(struct fts_ts_info *info) } } static void fts_vm_irq_on_release_callback(void *data, enum hh_irq_label label) static void fts_vm_irq_on_release_callback(void *data, unsigned long notif_type, enum hh_irq_label label) { struct fts_ts_info *info = data; int rc = 0; Loading Loading @@ -755,7 +763,7 @@ static int fts_trusted_touch_vm_mode_enable(struct fts_ts_info *info) } atomic_set(&vm_info->pvm_owns_iomem, 0); rc = hh_irq_lend(vm_info->irq_label, vm_info->vm_name, rc = hh_irq_lend_v2(vm_info->irq_label, vm_info->vm_name, info->client->irq, &fts_vm_irq_on_release_callback, info); if (rc) { pr_err("Failed to lend irq\n"); Loading @@ -763,6 +771,12 @@ static int fts_trusted_touch_vm_mode_enable(struct fts_ts_info *info) } atomic_set(&vm_info->pvm_owns_irq, 0); rc = hh_irq_lend_notify(vm_info->irq_label); if (rc) { pr_err("Failed to notify irq\n"); return -EINVAL; } reinit_completion(&info->trusted_touch_powerdown); atomic_set(&info->trusted_touch_enabled, 1); pr_debug("trusted touch enabled\n"); Loading Loading @@ -833,7 +847,7 @@ static int fts_vm_init(struct fts_ts_info *info) goto init_fail; } vm_info->mem_cookie = mem_cookie; rc = hh_irq_wait_for_lend(vm_info->irq_label, HH_PRIMARY_VM, rc = hh_irq_wait_for_lend_v2(vm_info->irq_label, HH_PRIMARY_VM, &fts_vm_irq_on_lend_callback, info); atomic_set(&vm_info->tvm_owns_irq, 0); atomic_set(&vm_info->tvm_owns_iomem, 0); Loading drivers/virt/haven/hh_irq_lend.c +172 −47 Original line number Diff line number Diff line Loading @@ -17,22 +17,20 @@ struct hh_irq_entry { hh_vmid_t vmid; enum hh_vm_names vm_name; hh_irq_handle_fn_v2 v2_handle; hh_irq_handle_fn handle; void *data; enum { /* start state */ HH_IRQ_STATE_NONE, /* NONE -> WAIT_RELEASE by hh_irq_lend */ HH_IRQ_STATE_WAIT_RELEASE, /* NONE -> WAIT_LEND by hh_irq_wait_lend */ HH_IRQ_STATE_WAIT_RELEASE_OR_ACCEPT, HH_IRQ_STATE_WAIT_LEND, /* WAIT_RELEASE -> RELEASED by notifier */ /* RELEASED -> NONE by hh_irq_reclaim */ HH_IRQ_STATE_RELEASED, /* WAIT_LEND -> LENT by notifier */ /* LENT -> NONE by hh_irq_release */ HH_IRQ_STATE_LENT, /* notification states */ HH_IRQ_STATE_RELEASED, /* svm -> pvm */ HH_IRQ_STATE_ACCEPTED, /* svm -> pvm */ HH_IRQ_STATE_LENT, /* pvm -> svm */ } state; hh_virq_handle_t virq_handle; }; Loading @@ -40,40 +38,59 @@ struct hh_irq_entry { static struct hh_irq_entry hh_irq_entries[HH_IRQ_LABEL_MAX]; static DEFINE_SPINLOCK(hh_irq_lend_lock); static int hh_irq_released_nb_handler(struct notifier_block *this, static int hh_irq_released_accepted_nb_handler(struct notifier_block *this, unsigned long cmd, void *data) { unsigned long flags; enum hh_irq_label label; struct hh_irq_entry *entry; struct hh_rm_notif_vm_irq_released_payload *released = data; struct hh_rm_notif_vm_irq_released_payload *released; struct hh_rm_notif_vm_irq_accepted_payload *accepted; if (cmd != HH_RM_NOTIF_VM_IRQ_RELEASED) if (cmd != HH_RM_NOTIF_VM_IRQ_RELEASED && cmd != HH_RM_NOTIF_VM_IRQ_ACCEPTED) return NOTIFY_DONE; spin_lock_irqsave(&hh_irq_lend_lock, flags); for (label = 0; label < HH_IRQ_LABEL_MAX; label++) { entry = &hh_irq_entries[label]; if (entry->state != HH_IRQ_STATE_WAIT_RELEASE) if (entry->state != HH_IRQ_STATE_WAIT_RELEASE_OR_ACCEPT && entry->state != HH_IRQ_STATE_ACCEPTED) continue; switch (cmd) { case HH_RM_NOTIF_VM_IRQ_RELEASED: released = data; if (released->virq_handle == entry->virq_handle) { entry->state = HH_IRQ_STATE_RELEASED; spin_unlock_irqrestore(&hh_irq_lend_lock, flags); entry->v2_handle(entry->data, cmd, label); return NOTIFY_OK; } entry->handle(entry->data, label); break; case HH_RM_NOTIF_VM_IRQ_ACCEPTED: accepted = data; if (accepted->virq_handle == entry->virq_handle) { entry->state = HH_IRQ_STATE_ACCEPTED; spin_unlock_irqrestore(&hh_irq_lend_lock, flags); entry->v2_handle(entry->data, cmd, label); return NOTIFY_OK; } break; } } spin_unlock_irqrestore(&hh_irq_lend_lock, flags); return NOTIFY_DONE; } static struct notifier_block hh_irq_released_nb = { .notifier_call = hh_irq_released_nb_handler, static struct notifier_block hh_irq_released_accepted_nb = { .notifier_call = hh_irq_released_accepted_nb_handler, }; static int hh_irq_lent_nb_handler(struct notifier_block *this, Loading Loading @@ -112,7 +129,7 @@ static int hh_irq_lent_nb_handler(struct notifier_block *this, spin_unlock_irqrestore(&hh_irq_lend_lock, flags); entry->handle(entry->data, label); entry->v2_handle(entry->data, cmd, label); return NOTIFY_OK; } Loading @@ -127,22 +144,24 @@ static struct notifier_block hh_irq_lent_nb = { }; /** * hh_irq_lend: Lend a hardware interrupt to another VM * hh_irq_lend_v2: Lend a hardware interrupt to another VM * @label: vIRQ high-level label * @name: VM name to send interrupt to * @irq: Linux IRQ number to lend * @on_release: callback to invoke when other VM returns the * interrupt * @data: Argument to pass to on_release * @cb_handle: callback to invoke when other VM release or accept the interrupt * @data: Argument to pass to cb_handle * * Returns 0 on success also the handle corresponding to Linux IRQ#. * Returns < 0 on error */ int hh_irq_lend(enum hh_irq_label label, enum hh_vm_names name, int irq, hh_irq_handle_fn on_release, void *data) int hh_irq_lend_v2(enum hh_irq_label label, enum hh_vm_names name, int irq, hh_irq_handle_fn_v2 cb_handle, void *data) { int ret, virq; unsigned long flags; struct hh_irq_entry *entry; if (label >= HH_IRQ_LABEL_MAX || !on_release) if (label >= HH_IRQ_LABEL_MAX || !cb_handle) return -EINVAL; entry = &hh_irq_entries[label]; Loading @@ -163,16 +182,62 @@ int hh_irq_lend(enum hh_irq_label label, enum hh_vm_names name, return ret; } entry->handle = on_release; entry->v2_handle = cb_handle; entry->data = data; entry->state = HH_IRQ_STATE_WAIT_RELEASE; entry->state = HH_IRQ_STATE_WAIT_RELEASE_OR_ACCEPT; spin_unlock_irqrestore(&hh_irq_lend_lock, flags); return hh_rm_vm_irq_lend_notify(entry->vmid, virq, label, &entry->virq_handle); return hh_rm_vm_irq_lend(entry->vmid, virq, label, &entry->virq_handle); } EXPORT_SYMBOL(hh_irq_lend_v2); /** * hh_irq_lend: Lend a hardware interrupt to another VM * @label: vIRQ high-level label * @name: VM name to send interrupt to * @irq: Linux IRQ number to lend * @cb_handle: callback to invoke when other VM release or accept the interrupt * @data: Argument to pass to cb_handle * * Returns 0 on success also the handle corresponding to Linux IRQ#. * Returns < 0 on error */ int hh_irq_lend(enum hh_irq_label label, enum hh_vm_names name, int irq, hh_irq_handle_fn cb_handle, void *data) { struct hh_irq_entry *entry; if (label >= HH_IRQ_LABEL_MAX || !cb_handle) return -EINVAL; entry = &hh_irq_entries[label]; entry->handle = cb_handle; return 0; } EXPORT_SYMBOL(hh_irq_lend); /** * hh_irq_lend_notify: Pass the irq handle to other VM for accept * @label: vIRQ high-level label * * Returns 0 on success, < 0 on error */ int hh_irq_lend_notify(enum hh_irq_label label) { struct hh_irq_entry *entry; if (label >= HH_IRQ_LABEL_MAX) return -EINVAL; entry = &hh_irq_entries[label]; if (entry->state == HH_IRQ_STATE_NONE) return -EINVAL; return hh_rm_vm_irq_lend_notify(entry->vmid, entry->virq_handle); } EXPORT_SYMBOL(hh_irq_lend_notify); /** * hh_irq_reclaim: Reclaim a hardware interrupt after other VM * has released. Loading @@ -193,7 +258,8 @@ int hh_irq_reclaim(enum hh_irq_label label) entry = &hh_irq_entries[label]; if (entry->state != HH_IRQ_STATE_RELEASED) if (entry->state != HH_IRQ_STATE_WAIT_RELEASE_OR_ACCEPT && (entry->state != HH_IRQ_STATE_RELEASED)) return -EINVAL; ret = hh_rm_vm_irq_reclaim(entry->virq_handle); Loading @@ -204,15 +270,14 @@ int hh_irq_reclaim(enum hh_irq_label label) EXPORT_SYMBOL(hh_irq_reclaim); /** * hh_irq_wait_lend: Register to claim a lent interrupt from another * VM * hh_irq_wait_for_lend_v2: Register to claim a lent interrupt from another VM * @label: vIRQ high-level label * @name: Lender's VM name. If don't care, then use HH_VM_MAX * @on_lend: callback to invoke when other VM lends the interrupt * @data: Argument to pass to on_lend */ int hh_irq_wait_for_lend(enum hh_irq_label label, enum hh_vm_names name, hh_irq_handle_fn on_lend, void *data) int hh_irq_wait_for_lend_v2(enum hh_irq_label label, enum hh_vm_names name, hh_irq_handle_fn_v2 on_lend, void *data) { unsigned long flags; struct hh_irq_entry *entry; Loading @@ -229,13 +294,27 @@ int hh_irq_wait_for_lend(enum hh_irq_label label, enum hh_vm_names name, } entry->vm_name = name; entry->handle = on_lend; entry->v2_handle = on_lend; entry->data = data; entry->state = HH_IRQ_STATE_WAIT_LEND; spin_unlock_irqrestore(&hh_irq_lend_lock, flags); return 0; } EXPORT_SYMBOL(hh_irq_wait_for_lend_v2); /** * hh_irq_wait_lend: Register to claim a lent interrupt from another VM * @label: vIRQ high-level label * @name: Lender's VM name. If don't care, then use HH_VM_MAX * @on_lend: callback to invoke when other VM lends the interrupt * @data: Argument to pass to on_lend */ int hh_irq_wait_for_lend(enum hh_irq_label label, enum hh_vm_names name, hh_irq_handle_fn on_lend, void *data) { return 0; } EXPORT_SYMBOL(hh_irq_wait_for_lend); /** Loading Loading @@ -276,10 +355,38 @@ int hh_irq_accept(enum hh_irq_label label, int irq, int type) if (irq == -1) irq = hh_rm_virq_to_irq(virq, type); entry->state = HH_IRQ_STATE_ACCEPTED; return irq; } EXPORT_SYMBOL(hh_irq_accept); /** * hh_irq_accept_notify: Notify the lend vm (pvm) that IRQ is accepted * @label: vIRQ high-level label * @irq: Linux IRQ# to associate vIRQ with. If don't care, use -1 * * Returns the Linux IRQ# that vIRQ was registered to on success. * Returns <0 on error * This function is not thread-safe w.r.t. IRQ lend state. Do not race with * hh_irq_release or another hh_irq_accept with same label. */ int hh_irq_accept_notify(enum hh_irq_label label) { struct hh_irq_entry *entry; if (label >= HH_IRQ_LABEL_MAX) return -EINVAL; entry = &hh_irq_entries[label]; if (entry->state != HH_IRQ_STATE_ACCEPTED) return -EINVAL; return hh_rm_vm_irq_accept_notify(entry->vmid, entry->virq_handle); } EXPORT_SYMBOL(hh_irq_accept_notify); /** * hh_irq_release: Release a lent interrupt * @label: vIRQ high-level label Loading @@ -296,17 +403,34 @@ int hh_irq_release(enum hh_irq_label label) entry = &hh_irq_entries[label]; if (entry->state != HH_IRQ_STATE_LENT) if (entry->state != HH_IRQ_STATE_ACCEPTED) return -EINVAL; ret = hh_rm_vm_irq_release_notify(entry->vmid, entry->virq_handle); ret = hh_rm_vm_irq_release(entry->virq_handle); if (!ret) entry->state = HH_IRQ_STATE_WAIT_LEND; return ret; } EXPORT_SYMBOL(hh_irq_release); int hh_irq_release_notify(enum hh_irq_label label) { struct hh_irq_entry *entry; if (label >= HH_IRQ_LABEL_MAX) return -EINVAL; entry = &hh_irq_entries[label]; if (entry->state != HH_IRQ_STATE_ACCEPTED && entry->state != HH_IRQ_STATE_WAIT_LEND) return -EINVAL; return hh_rm_vm_irq_release_notify(entry->vmid, entry->virq_handle); } EXPORT_SYMBOL(hh_irq_release_notify); static int __init hh_irq_lend_init(void) { int ret; Loading @@ -314,14 +438,15 @@ static int __init hh_irq_lend_init(void) ret = hh_rm_register_notifier(&hh_irq_lent_nb); if (ret) return ret; return hh_rm_register_notifier(&hh_irq_released_nb); return hh_rm_register_notifier(&hh_irq_released_accepted_nb); } module_init(hh_irq_lend_init); static void hh_irq_lend_exit(void) { hh_rm_unregister_notifier(&hh_irq_lent_nb); hh_rm_unregister_notifier(&hh_irq_released_nb); hh_rm_unregister_notifier(&hh_irq_released_accepted_nb); } module_exit(hh_irq_lend_exit); Loading drivers/virt/haven/hh_rm_core.c +9 −0 Original line number Diff line number Diff line Loading @@ -218,6 +218,15 @@ static int hh_rm_process_notif(void *recv_buff, size_t recv_buff_size) goto err; } break; case HH_RM_NOTIF_VM_IRQ_ACCEPTED: if (recv_buff_size != sizeof(*hdr) + sizeof(struct hh_rm_notif_vm_irq_accepted_payload)) { pr_err("%s: Invalid size for VM_IRQ_ACCEPTED notif: %u\n", __func__, recv_buff_size - sizeof(*hdr)); ret = -EINVAL; goto err; } break; case HH_RM_NOTIF_MEM_SHARED: if (recv_buff_size < sizeof(*hdr) + sizeof(struct hh_rm_notif_mem_shared_payload)) { Loading drivers/virt/haven/hh_rm_drv_private.h +1 −0 Original line number Diff line number Diff line Loading @@ -181,6 +181,7 @@ struct hh_vm_irq_lend_resp_payload { /* Call: VM_IRQ_NOTIFY */ #define HH_VM_IRQ_NOTIFY_FLAGS_LENT BIT(0) #define HH_VM_IRQ_NOTIFY_FLAGS_RELEASED BIT(1) #define HH_VM_IRQ_NOTIFY_FLAGS_ACCEPTED BIT(2) /* Call: VM_IRQ_RELEASE */ struct hh_vm_irq_release_req_payload { Loading Loading
drivers/input/touchscreen/focaltech_touch/focaltech_core.c +16 −3 Original line number Diff line number Diff line Loading @@ -296,7 +296,9 @@ static int fts_ts_vm_handle_vm_hardware(struct fts_ts_data *fts_data) return rc; } static void fts_ts_vm_irq_on_lend_callback(void *data, enum hh_irq_label label) static void fts_ts_vm_irq_on_lend_callback(void *data, unsigned long notif_type, enum hh_irq_label label) { struct fts_ts_data *fts_data = data; struct irq_data *irq_data; Loading Loading @@ -472,6 +474,10 @@ static void fts_ts_trusted_touch_vm_mode_disable(struct fts_ts_data *fts_data) pr_err("Failed to release irq rc:%d\n", rc); else atomic_set(&fts_data->vm_info->tvm_owns_irq, 0); rc = hh_irq_release_notify(fts_data->vm_info->irq_label); if (rc) pr_err("Failed to notify release irq rc:%d\n", rc); } atomic_set(&fts_data->trusted_touch_enabled, 0); reinit_completion(&fts_data->resource_checkpoint); Loading Loading @@ -600,6 +606,7 @@ static void fts_ts_trusted_touch_complete(struct fts_ts_data *fts_data) } static void fts_ts_vm_irq_on_release_callback(void *data, unsigned long notif_type, enum hh_irq_label label) { struct fts_ts_data *fts_data = data; Loading Loading @@ -730,7 +737,7 @@ static int fts_ts_trusted_touch_vm_mode_enable(struct fts_ts_data *fts_data) } atomic_set(&vm_info->pvm_owns_iomem, 0); rc = hh_irq_lend(vm_info->irq_label, vm_info->vm_name, rc = hh_irq_lend_v2(vm_info->irq_label, vm_info->vm_name, fts_data->irq, &fts_ts_vm_irq_on_release_callback, fts_data); if (rc) { pr_err("Failed to lend irq\n"); Loading @@ -738,6 +745,12 @@ static int fts_ts_trusted_touch_vm_mode_enable(struct fts_ts_data *fts_data) } atomic_set(&vm_info->pvm_owns_irq, 0); rc = hh_irq_lend_notify(vm_info->irq_label); if (rc) { pr_err("Failed to notify irq\n"); return -EINVAL; } reinit_completion(&fts_data->trusted_touch_powerdown); atomic_set(&fts_data->trusted_touch_enabled, 1); pr_debug("trusted touch enabled\n"); Loading Loading @@ -809,7 +822,7 @@ static int fts_ts_vm_init(struct fts_ts_data *fts_data) goto init_fail; } vm_info->mem_cookie = mem_cookie; rc = hh_irq_wait_for_lend(vm_info->irq_label, HH_PRIMARY_VM, rc = hh_irq_wait_for_lend_v2(vm_info->irq_label, HH_PRIMARY_VM, &fts_ts_vm_irq_on_lend_callback, fts_data); atomic_set(&vm_info->tvm_owns_irq, 0); atomic_set(&vm_info->tvm_owns_iomem, 0); Loading
drivers/input/touchscreen/st/fts.c +18 −4 Original line number Diff line number Diff line Loading @@ -321,7 +321,9 @@ static int fts_vm_handle_vm_hardware(struct fts_ts_info *info) return rc; } static void fts_vm_irq_on_lend_callback(void *data, enum hh_irq_label label) static void fts_vm_irq_on_lend_callback(void *data, unsigned long notif_type, enum hh_irq_label label) { struct fts_ts_info *info = data; struct irq_data *irq_data; Loading Loading @@ -497,6 +499,10 @@ static void fts_trusted_touch_vm_mode_disable(struct fts_ts_info *info) pr_err("Failed to release irq rc:%d\n", rc); else atomic_set(&info->vm_info->tvm_owns_irq, 0); rc = hh_irq_release_notify(info->vm_info->irq_label); if (rc) pr_err("Failed to notify release irq rc:%d\n", rc); } atomic_set(&info->trusted_touch_enabled, 0); reinit_completion(&info->resource_checkpoint); Loading Loading @@ -624,7 +630,9 @@ static void fts_trusted_touch_complete(struct fts_ts_info *info) } } static void fts_vm_irq_on_release_callback(void *data, enum hh_irq_label label) static void fts_vm_irq_on_release_callback(void *data, unsigned long notif_type, enum hh_irq_label label) { struct fts_ts_info *info = data; int rc = 0; Loading Loading @@ -755,7 +763,7 @@ static int fts_trusted_touch_vm_mode_enable(struct fts_ts_info *info) } atomic_set(&vm_info->pvm_owns_iomem, 0); rc = hh_irq_lend(vm_info->irq_label, vm_info->vm_name, rc = hh_irq_lend_v2(vm_info->irq_label, vm_info->vm_name, info->client->irq, &fts_vm_irq_on_release_callback, info); if (rc) { pr_err("Failed to lend irq\n"); Loading @@ -763,6 +771,12 @@ static int fts_trusted_touch_vm_mode_enable(struct fts_ts_info *info) } atomic_set(&vm_info->pvm_owns_irq, 0); rc = hh_irq_lend_notify(vm_info->irq_label); if (rc) { pr_err("Failed to notify irq\n"); return -EINVAL; } reinit_completion(&info->trusted_touch_powerdown); atomic_set(&info->trusted_touch_enabled, 1); pr_debug("trusted touch enabled\n"); Loading Loading @@ -833,7 +847,7 @@ static int fts_vm_init(struct fts_ts_info *info) goto init_fail; } vm_info->mem_cookie = mem_cookie; rc = hh_irq_wait_for_lend(vm_info->irq_label, HH_PRIMARY_VM, rc = hh_irq_wait_for_lend_v2(vm_info->irq_label, HH_PRIMARY_VM, &fts_vm_irq_on_lend_callback, info); atomic_set(&vm_info->tvm_owns_irq, 0); atomic_set(&vm_info->tvm_owns_iomem, 0); Loading
drivers/virt/haven/hh_irq_lend.c +172 −47 Original line number Diff line number Diff line Loading @@ -17,22 +17,20 @@ struct hh_irq_entry { hh_vmid_t vmid; enum hh_vm_names vm_name; hh_irq_handle_fn_v2 v2_handle; hh_irq_handle_fn handle; void *data; enum { /* start state */ HH_IRQ_STATE_NONE, /* NONE -> WAIT_RELEASE by hh_irq_lend */ HH_IRQ_STATE_WAIT_RELEASE, /* NONE -> WAIT_LEND by hh_irq_wait_lend */ HH_IRQ_STATE_WAIT_RELEASE_OR_ACCEPT, HH_IRQ_STATE_WAIT_LEND, /* WAIT_RELEASE -> RELEASED by notifier */ /* RELEASED -> NONE by hh_irq_reclaim */ HH_IRQ_STATE_RELEASED, /* WAIT_LEND -> LENT by notifier */ /* LENT -> NONE by hh_irq_release */ HH_IRQ_STATE_LENT, /* notification states */ HH_IRQ_STATE_RELEASED, /* svm -> pvm */ HH_IRQ_STATE_ACCEPTED, /* svm -> pvm */ HH_IRQ_STATE_LENT, /* pvm -> svm */ } state; hh_virq_handle_t virq_handle; }; Loading @@ -40,40 +38,59 @@ struct hh_irq_entry { static struct hh_irq_entry hh_irq_entries[HH_IRQ_LABEL_MAX]; static DEFINE_SPINLOCK(hh_irq_lend_lock); static int hh_irq_released_nb_handler(struct notifier_block *this, static int hh_irq_released_accepted_nb_handler(struct notifier_block *this, unsigned long cmd, void *data) { unsigned long flags; enum hh_irq_label label; struct hh_irq_entry *entry; struct hh_rm_notif_vm_irq_released_payload *released = data; struct hh_rm_notif_vm_irq_released_payload *released; struct hh_rm_notif_vm_irq_accepted_payload *accepted; if (cmd != HH_RM_NOTIF_VM_IRQ_RELEASED) if (cmd != HH_RM_NOTIF_VM_IRQ_RELEASED && cmd != HH_RM_NOTIF_VM_IRQ_ACCEPTED) return NOTIFY_DONE; spin_lock_irqsave(&hh_irq_lend_lock, flags); for (label = 0; label < HH_IRQ_LABEL_MAX; label++) { entry = &hh_irq_entries[label]; if (entry->state != HH_IRQ_STATE_WAIT_RELEASE) if (entry->state != HH_IRQ_STATE_WAIT_RELEASE_OR_ACCEPT && entry->state != HH_IRQ_STATE_ACCEPTED) continue; switch (cmd) { case HH_RM_NOTIF_VM_IRQ_RELEASED: released = data; if (released->virq_handle == entry->virq_handle) { entry->state = HH_IRQ_STATE_RELEASED; spin_unlock_irqrestore(&hh_irq_lend_lock, flags); entry->v2_handle(entry->data, cmd, label); return NOTIFY_OK; } entry->handle(entry->data, label); break; case HH_RM_NOTIF_VM_IRQ_ACCEPTED: accepted = data; if (accepted->virq_handle == entry->virq_handle) { entry->state = HH_IRQ_STATE_ACCEPTED; spin_unlock_irqrestore(&hh_irq_lend_lock, flags); entry->v2_handle(entry->data, cmd, label); return NOTIFY_OK; } break; } } spin_unlock_irqrestore(&hh_irq_lend_lock, flags); return NOTIFY_DONE; } static struct notifier_block hh_irq_released_nb = { .notifier_call = hh_irq_released_nb_handler, static struct notifier_block hh_irq_released_accepted_nb = { .notifier_call = hh_irq_released_accepted_nb_handler, }; static int hh_irq_lent_nb_handler(struct notifier_block *this, Loading Loading @@ -112,7 +129,7 @@ static int hh_irq_lent_nb_handler(struct notifier_block *this, spin_unlock_irqrestore(&hh_irq_lend_lock, flags); entry->handle(entry->data, label); entry->v2_handle(entry->data, cmd, label); return NOTIFY_OK; } Loading @@ -127,22 +144,24 @@ static struct notifier_block hh_irq_lent_nb = { }; /** * hh_irq_lend: Lend a hardware interrupt to another VM * hh_irq_lend_v2: Lend a hardware interrupt to another VM * @label: vIRQ high-level label * @name: VM name to send interrupt to * @irq: Linux IRQ number to lend * @on_release: callback to invoke when other VM returns the * interrupt * @data: Argument to pass to on_release * @cb_handle: callback to invoke when other VM release or accept the interrupt * @data: Argument to pass to cb_handle * * Returns 0 on success also the handle corresponding to Linux IRQ#. * Returns < 0 on error */ int hh_irq_lend(enum hh_irq_label label, enum hh_vm_names name, int irq, hh_irq_handle_fn on_release, void *data) int hh_irq_lend_v2(enum hh_irq_label label, enum hh_vm_names name, int irq, hh_irq_handle_fn_v2 cb_handle, void *data) { int ret, virq; unsigned long flags; struct hh_irq_entry *entry; if (label >= HH_IRQ_LABEL_MAX || !on_release) if (label >= HH_IRQ_LABEL_MAX || !cb_handle) return -EINVAL; entry = &hh_irq_entries[label]; Loading @@ -163,16 +182,62 @@ int hh_irq_lend(enum hh_irq_label label, enum hh_vm_names name, return ret; } entry->handle = on_release; entry->v2_handle = cb_handle; entry->data = data; entry->state = HH_IRQ_STATE_WAIT_RELEASE; entry->state = HH_IRQ_STATE_WAIT_RELEASE_OR_ACCEPT; spin_unlock_irqrestore(&hh_irq_lend_lock, flags); return hh_rm_vm_irq_lend_notify(entry->vmid, virq, label, &entry->virq_handle); return hh_rm_vm_irq_lend(entry->vmid, virq, label, &entry->virq_handle); } EXPORT_SYMBOL(hh_irq_lend_v2); /** * hh_irq_lend: Lend a hardware interrupt to another VM * @label: vIRQ high-level label * @name: VM name to send interrupt to * @irq: Linux IRQ number to lend * @cb_handle: callback to invoke when other VM release or accept the interrupt * @data: Argument to pass to cb_handle * * Returns 0 on success also the handle corresponding to Linux IRQ#. * Returns < 0 on error */ int hh_irq_lend(enum hh_irq_label label, enum hh_vm_names name, int irq, hh_irq_handle_fn cb_handle, void *data) { struct hh_irq_entry *entry; if (label >= HH_IRQ_LABEL_MAX || !cb_handle) return -EINVAL; entry = &hh_irq_entries[label]; entry->handle = cb_handle; return 0; } EXPORT_SYMBOL(hh_irq_lend); /** * hh_irq_lend_notify: Pass the irq handle to other VM for accept * @label: vIRQ high-level label * * Returns 0 on success, < 0 on error */ int hh_irq_lend_notify(enum hh_irq_label label) { struct hh_irq_entry *entry; if (label >= HH_IRQ_LABEL_MAX) return -EINVAL; entry = &hh_irq_entries[label]; if (entry->state == HH_IRQ_STATE_NONE) return -EINVAL; return hh_rm_vm_irq_lend_notify(entry->vmid, entry->virq_handle); } EXPORT_SYMBOL(hh_irq_lend_notify); /** * hh_irq_reclaim: Reclaim a hardware interrupt after other VM * has released. Loading @@ -193,7 +258,8 @@ int hh_irq_reclaim(enum hh_irq_label label) entry = &hh_irq_entries[label]; if (entry->state != HH_IRQ_STATE_RELEASED) if (entry->state != HH_IRQ_STATE_WAIT_RELEASE_OR_ACCEPT && (entry->state != HH_IRQ_STATE_RELEASED)) return -EINVAL; ret = hh_rm_vm_irq_reclaim(entry->virq_handle); Loading @@ -204,15 +270,14 @@ int hh_irq_reclaim(enum hh_irq_label label) EXPORT_SYMBOL(hh_irq_reclaim); /** * hh_irq_wait_lend: Register to claim a lent interrupt from another * VM * hh_irq_wait_for_lend_v2: Register to claim a lent interrupt from another VM * @label: vIRQ high-level label * @name: Lender's VM name. If don't care, then use HH_VM_MAX * @on_lend: callback to invoke when other VM lends the interrupt * @data: Argument to pass to on_lend */ int hh_irq_wait_for_lend(enum hh_irq_label label, enum hh_vm_names name, hh_irq_handle_fn on_lend, void *data) int hh_irq_wait_for_lend_v2(enum hh_irq_label label, enum hh_vm_names name, hh_irq_handle_fn_v2 on_lend, void *data) { unsigned long flags; struct hh_irq_entry *entry; Loading @@ -229,13 +294,27 @@ int hh_irq_wait_for_lend(enum hh_irq_label label, enum hh_vm_names name, } entry->vm_name = name; entry->handle = on_lend; entry->v2_handle = on_lend; entry->data = data; entry->state = HH_IRQ_STATE_WAIT_LEND; spin_unlock_irqrestore(&hh_irq_lend_lock, flags); return 0; } EXPORT_SYMBOL(hh_irq_wait_for_lend_v2); /** * hh_irq_wait_lend: Register to claim a lent interrupt from another VM * @label: vIRQ high-level label * @name: Lender's VM name. If don't care, then use HH_VM_MAX * @on_lend: callback to invoke when other VM lends the interrupt * @data: Argument to pass to on_lend */ int hh_irq_wait_for_lend(enum hh_irq_label label, enum hh_vm_names name, hh_irq_handle_fn on_lend, void *data) { return 0; } EXPORT_SYMBOL(hh_irq_wait_for_lend); /** Loading Loading @@ -276,10 +355,38 @@ int hh_irq_accept(enum hh_irq_label label, int irq, int type) if (irq == -1) irq = hh_rm_virq_to_irq(virq, type); entry->state = HH_IRQ_STATE_ACCEPTED; return irq; } EXPORT_SYMBOL(hh_irq_accept); /** * hh_irq_accept_notify: Notify the lend vm (pvm) that IRQ is accepted * @label: vIRQ high-level label * @irq: Linux IRQ# to associate vIRQ with. If don't care, use -1 * * Returns the Linux IRQ# that vIRQ was registered to on success. * Returns <0 on error * This function is not thread-safe w.r.t. IRQ lend state. Do not race with * hh_irq_release or another hh_irq_accept with same label. */ int hh_irq_accept_notify(enum hh_irq_label label) { struct hh_irq_entry *entry; if (label >= HH_IRQ_LABEL_MAX) return -EINVAL; entry = &hh_irq_entries[label]; if (entry->state != HH_IRQ_STATE_ACCEPTED) return -EINVAL; return hh_rm_vm_irq_accept_notify(entry->vmid, entry->virq_handle); } EXPORT_SYMBOL(hh_irq_accept_notify); /** * hh_irq_release: Release a lent interrupt * @label: vIRQ high-level label Loading @@ -296,17 +403,34 @@ int hh_irq_release(enum hh_irq_label label) entry = &hh_irq_entries[label]; if (entry->state != HH_IRQ_STATE_LENT) if (entry->state != HH_IRQ_STATE_ACCEPTED) return -EINVAL; ret = hh_rm_vm_irq_release_notify(entry->vmid, entry->virq_handle); ret = hh_rm_vm_irq_release(entry->virq_handle); if (!ret) entry->state = HH_IRQ_STATE_WAIT_LEND; return ret; } EXPORT_SYMBOL(hh_irq_release); int hh_irq_release_notify(enum hh_irq_label label) { struct hh_irq_entry *entry; if (label >= HH_IRQ_LABEL_MAX) return -EINVAL; entry = &hh_irq_entries[label]; if (entry->state != HH_IRQ_STATE_ACCEPTED && entry->state != HH_IRQ_STATE_WAIT_LEND) return -EINVAL; return hh_rm_vm_irq_release_notify(entry->vmid, entry->virq_handle); } EXPORT_SYMBOL(hh_irq_release_notify); static int __init hh_irq_lend_init(void) { int ret; Loading @@ -314,14 +438,15 @@ static int __init hh_irq_lend_init(void) ret = hh_rm_register_notifier(&hh_irq_lent_nb); if (ret) return ret; return hh_rm_register_notifier(&hh_irq_released_nb); return hh_rm_register_notifier(&hh_irq_released_accepted_nb); } module_init(hh_irq_lend_init); static void hh_irq_lend_exit(void) { hh_rm_unregister_notifier(&hh_irq_lent_nb); hh_rm_unregister_notifier(&hh_irq_released_nb); hh_rm_unregister_notifier(&hh_irq_released_accepted_nb); } module_exit(hh_irq_lend_exit); Loading
drivers/virt/haven/hh_rm_core.c +9 −0 Original line number Diff line number Diff line Loading @@ -218,6 +218,15 @@ static int hh_rm_process_notif(void *recv_buff, size_t recv_buff_size) goto err; } break; case HH_RM_NOTIF_VM_IRQ_ACCEPTED: if (recv_buff_size != sizeof(*hdr) + sizeof(struct hh_rm_notif_vm_irq_accepted_payload)) { pr_err("%s: Invalid size for VM_IRQ_ACCEPTED notif: %u\n", __func__, recv_buff_size - sizeof(*hdr)); ret = -EINVAL; goto err; } break; case HH_RM_NOTIF_MEM_SHARED: if (recv_buff_size < sizeof(*hdr) + sizeof(struct hh_rm_notif_mem_shared_payload)) { Loading
drivers/virt/haven/hh_rm_drv_private.h +1 −0 Original line number Diff line number Diff line Loading @@ -181,6 +181,7 @@ struct hh_vm_irq_lend_resp_payload { /* Call: VM_IRQ_NOTIFY */ #define HH_VM_IRQ_NOTIFY_FLAGS_LENT BIT(0) #define HH_VM_IRQ_NOTIFY_FLAGS_RELEASED BIT(1) #define HH_VM_IRQ_NOTIFY_FLAGS_ACCEPTED BIT(2) /* Call: VM_IRQ_RELEASE */ struct hh_vm_irq_release_req_payload { Loading