Loading drivers/soc/qcom/guestvm_loader.c +61 −19 Original line number Diff line number Diff line Loading @@ -10,7 +10,6 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/haven/hh_common.h> #include <linux/haven/hh_rm_drv.h> #include <soc/qcom/subsystem_notif.h> Loading @@ -31,12 +30,13 @@ static struct kobj_type guestvm_kobj_type = { }; struct guestvm_loader_private { struct work_struct vm_loader_work; struct notifier_block guestvm_nb; struct kobject vm_loader_kobj; struct device *dev; char vm_name[MAX_LEN]; void *vm_loaded; int vmid; u8 vm_status; }; static inline enum hh_vm_names get_hh_vm_name(const char *str) Loading @@ -50,24 +50,50 @@ static inline enum hh_vm_names get_hh_vm_name(const char *str) return HH_VM_MAX; } static void guestvm_loader_rm_notifier(struct work_struct *vm_loader_work) static int guestvm_loader_nb_handler(struct notifier_block *this, unsigned long cmd, void *data) { struct guestvm_loader_private *priv; int ret = 0; struct hh_rm_notif_vm_status_payload *vm_status_payload = data; u8 vm_status = vm_status_payload->vm_status; int ret; priv = container_of(vm_loader_work, struct guestvm_loader_private, vm_loader_work); priv->vmid = hh_rm_vm_alloc_vmid(get_hh_vm_name(priv->vm_name)); if (priv->vmid == HH_VM_MAX) { dev_err(priv->dev, "Couldn't get vmid.\n"); return; priv = container_of(this, struct guestvm_loader_private, guestvm_nb); if (cmd != HH_RM_NOTIF_VM_STATUS) return NOTIFY_DONE; if (priv->vmid != vm_status_payload->vmid) dev_warn(priv->dev, "Expected a notification from vmid = %d, but received one from vmid = %d\n", priv->vmid, vm_status_payload->vmid); /* * Listen to STATUS_READY or STATUS_RUNNING notifications from RM. * These notifications come from RM after PIL loading the VM images. * Query GET_HYP_RESOURCES to populate other entities such as MessageQ * and DBL. */ switch (vm_status) { case HH_RM_VM_STATUS_READY: priv->vm_status = HH_RM_VM_STATUS_READY; ret = hh_rm_populate_hyp_res(vm_status_payload->vmid); if (ret < 0) { dev_err(priv->dev, "Failed to get hyp resources for vmid = %d ret = %d\n", vm_status_payload->vmid, ret); return NOTIFY_DONE; } ret = hh_rm_vm_start(priv->vmid); if (ret) dev_err(priv->dev, "VM start has failed with %d.\n", ret); break; case HH_RM_VM_STATUS_RUNNING: break; default: dev_err(priv->dev, "Unknown notification receieved for vmid = %d vm_status = %d\n", vm_status_payload->vmid, vm_status); } return NOTIFY_DONE; } static ssize_t guestvm_load_start(struct kobject *kobj, static ssize_t guestvm_loader_start(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) Loading @@ -88,6 +114,13 @@ static ssize_t guestvm_load_start(struct kobject *kobj, } if (boot) { priv->vm_status = HH_RM_VM_STATUS_INIT; priv->vmid = hh_rm_vm_alloc_vmid(get_hh_vm_name(priv->vm_name)); if (priv->vmid < 0) { dev_err(priv->dev, "Couldn't allocate VMID.\n"); return count; } priv->vm_loaded = subsystem_get(priv->vm_name); if (IS_ERR(priv->vm_loaded)) { ret = (int)(PTR_ERR(priv->vm_loaded)); Loading @@ -96,13 +129,18 @@ static ssize_t guestvm_load_start(struct kobject *kobj, priv->vm_loaded = NULL; return ret; } schedule_work(&priv->vm_loader_work); priv->vm_status = HH_RM_VM_STATUS_RUNNING; ret = hh_rm_vm_start(priv->vmid); if (ret) dev_err(priv->dev, "VM start has failed for vmid = %d ret = %d\n", priv->vmid, ret); } return count; } static struct kobj_attribute guestvm_loader_attribute = __ATTR(boot_guestvm, 0220, NULL, guestvm_load_start); __ATTR(boot_guestvm, 0220, NULL, guestvm_loader_start); static struct attribute *attrs[] = { &guestvm_loader_attribute.attr, Loading Loading @@ -132,8 +170,6 @@ static int guestvm_loader_probe(struct platform_device *pdev) return -EINVAL; strlcpy(priv->vm_name, sub_sys, sizeof(priv->vm_name)); INIT_WORK(&priv->vm_loader_work, guestvm_loader_rm_notifier); ret = kobject_init_and_add(&priv->vm_loader_kobj, &guestvm_kobj_type, kernel_kobj, "load_guestvm"); if (ret) { Loading @@ -148,6 +184,12 @@ static int guestvm_loader_probe(struct platform_device *pdev) goto error_return; } priv->guestvm_nb.notifier_call = guestvm_loader_nb_handler; ret = hh_rm_register_notifier(&priv->guestvm_nb); if (ret) return ret; priv->vm_status = HH_RM_VM_STATUS_NO_STATE; return 0; error_return: Loading drivers/virt/haven/hh_dbl.c +79 −40 Original line number Diff line number Diff line Loading @@ -34,19 +34,21 @@ struct hh_dbl_cap_table { const char *rx_irq_name; dbl_rx_cb_t rx_callback; void *rx_priv_data; wait_queue_head_t cap_wq; }; static bool hh_dbl_initialized; static struct hh_dbl_cap_table hh_dbl_cap_table[HH_DBL_LABEL_MAX]; /** * hh_dbl_validate_params - Validate doorbell common parameters */ static int hh_dbl_validate_params(struct hh_dbl_desc *client_desc, enum hh_dbl_dir dir) enum hh_dbl_dir dir, const unsigned long flags) { struct hh_dbl_cap_table *cap_table_entry; if (!client_desc) if (IS_ERR_OR_NULL(client_desc)) return -EINVAL; /* Check if the client has manipulated the label */ Loading @@ -67,23 +69,35 @@ static int hh_dbl_validate_params(struct hh_dbl_desc *client_desc, * There are no doorbell setup for Tx or Rx */ if (dir == HH_DBL_DIRECTION_RX) { if (!cap_table_entry->rx_cap_id || !cap_table_entry->rx_reg_done) { pr_err("%s: label: %d; rx_cap_id: %llu; dir: %d rx_done: %d\n", __func__, client_desc->label, cap_table_entry->rx_cap_id, dir, cap_table_entry->rx_reg_done); if (!cap_table_entry->rx_reg_done) return -EINVAL; if (cap_table_entry->rx_cap_id != HH_CAPID_INVAL) return 0; if (flags & HH_DBL_NONBLOCK) return -EAGAIN; } if (wait_event_interruptible(cap_table_entry->cap_wq, cap_table_entry->rx_cap_id != HH_CAPID_INVAL)) return -ERESTARTSYS; return 0; } else { if (!cap_table_entry->tx_cap_id || !cap_table_entry->tx_reg_done) { pr_err("%s: label: %d; tx_cap_id: %llu; dir: %d tx_done: %d\n", __func__, client_desc->label, cap_table_entry->tx_cap_id, dir, cap_table_entry->tx_reg_done); if (!cap_table_entry->tx_reg_done) return -EINVAL; if (cap_table_entry->tx_cap_id != HH_CAPID_INVAL) return 0; if (flags & HH_DBL_NONBLOCK) return -EAGAIN; } if (wait_event_interruptible(cap_table_entry->cap_wq, cap_table_entry->tx_cap_id != HH_CAPID_INVAL)) return -ERESTARTSYS; return 0; } return 0; Loading @@ -93,6 +107,8 @@ static int hh_dbl_validate_params(struct hh_dbl_desc *client_desc, * hh_dbl_read_and_clean - Automatically read and clear the flags in doorbell * @client_desc: client handle to indetify the doorbell object * @clear_flags: clear the bits mentioned in the clear_flags * @flags: Optional flags to pass to send the data. For the list of flags, * see linux/haven/hh_dbl.h * * Reads and clears the flags of the Doorbell object. If there is a pending * bound virtual interrupt, it will be de-asserted Loading @@ -101,7 +117,8 @@ static int hh_dbl_validate_params(struct hh_dbl_desc *client_desc, * 0 on success, @clear_flags contains the doorbell’s previous unmasked flags * before the @clear_flags were removed. */ int hh_dbl_read_and_clean(void *dbl_client_desc, hh_dbl_flags_t *clear_flags) int hh_dbl_read_and_clean(void *dbl_client_desc, hh_dbl_flags_t *clear_flags, const unsigned long flags) { struct hh_dbl_cap_table *cap_table_entry; struct hh_hcall_dbl_recv_resp recv_resp; Loading @@ -111,7 +128,7 @@ int hh_dbl_read_and_clean(void *dbl_client_desc, hh_dbl_flags_t *clear_flags) if (!clear_flags) return -EINVAL; ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_RX); ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_RX, flags); if (ret) return ret; Loading @@ -137,6 +154,8 @@ EXPORT_SYMBOL(hh_dbl_read_and_clean); * the doorbell's bound virtual interrupt * @ack_mask: Controls which flags should be automatically cleared * when the interrupt is asserted * @flags: Optional flags to pass to send the data. For the list of flags, * see linux/haven/hh_dbl.h * * Sets the Doorbell object’s masks. A doorbell object has two masks * which are configured by the receiver to control which flags it is Loading @@ -146,13 +165,13 @@ EXPORT_SYMBOL(hh_dbl_read_and_clean); * 0 on success */ int hh_dbl_set_mask(void *dbl_client_desc, hh_dbl_flags_t enable_mask, hh_dbl_flags_t ack_mask) hh_dbl_flags_t ack_mask, const unsigned long flags) { struct hh_dbl_cap_table *cap_table_entry; struct hh_dbl_desc *client_desc = dbl_client_desc; int ret, hh_ret; ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_RX); ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_RX, flags); if (ret) return ret; Loading @@ -176,6 +195,8 @@ EXPORT_SYMBOL(hh_dbl_set_mask); * @client_desc: client handle to indetify the doorbell object * @newflags: flags to set in the doorbell. This flag along with enable_mask * in the doorbell decide whehter to raise vIRQ are not. * @flags: Optional flags to pass to send the data. For the list of flags, * see linux/haven/hh_dbl.h * * Set flags in the doorbell. If following the send, the set of enabled flags * as defined by the bitwise-AND of the doorbell flags with the EnableMask, Loading @@ -185,7 +206,8 @@ EXPORT_SYMBOL(hh_dbl_set_mask); * 0 on success, @newflags contains the doorbell’s previous unmasked flags * before the @newflags were added. */ int hh_dbl_send(void *dbl_client_desc, hh_dbl_flags_t *newflags) int hh_dbl_send(void *dbl_client_desc, hh_dbl_flags_t *newflags, unsigned long flags) { struct hh_dbl_cap_table *cap_table_entry; struct hh_hcall_dbl_send_resp send_resp; Loading @@ -195,7 +217,7 @@ int hh_dbl_send(void *dbl_client_desc, hh_dbl_flags_t *newflags) if (!newflags) return -EINVAL; ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_TX); ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_TX, flags); if (ret) return ret; Loading @@ -218,6 +240,8 @@ EXPORT_SYMBOL(hh_dbl_send); * hh_dbl_reset - clear all the flags of the doorbell and sets all bits in * the Doorbell’s mask. * @client_desc: client handle to indetify the doorbell object * @flags: Optional flags to pass to send the data. For the list of flags, * see linux/haven/hh_dbl.h * * Clears all the flags of the doorbell and sets all bits in the doorbell’s * mask. If there is a pending bound virtual interrupt, it will be de-asserted. Loading @@ -225,13 +249,13 @@ EXPORT_SYMBOL(hh_dbl_send); * Returns: * 0 on success */ int hh_dbl_reset(void *dbl_client_desc) int hh_dbl_reset(void *dbl_client_desc, const unsigned long flags) { struct hh_dbl_cap_table *cap_table_entry; struct hh_dbl_desc *client_desc = dbl_client_desc; int ret, hh_ret; ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_RX); ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_RX, flags); if (ret) return ret; Loading Loading @@ -278,6 +302,9 @@ void *hh_dbl_tx_register(enum hh_dbl_label label) if (label < 0 || label >= HH_DBL_LABEL_MAX) return ERR_PTR(-EINVAL); if (!hh_dbl_initialized) return ERR_PTR(-EPROBE_DEFER); cap_table_entry = &hh_dbl_cap_table[label]; if (mutex_lock_interruptible(&cap_table_entry->cap_entry_lock)) Loading Loading @@ -338,6 +365,9 @@ void *hh_dbl_rx_register(enum hh_dbl_label label, dbl_rx_cb_t rx_cb, void *priv) if (label < 0 || label >= HH_DBL_LABEL_MAX) return ERR_PTR(-EINVAL); if (!hh_dbl_initialized) return ERR_PTR(-EPROBE_DEFER); cap_table_entry = &hh_dbl_cap_table[label]; if (mutex_lock_interruptible(&cap_table_entry->cap_entry_lock)) Loading Loading @@ -365,20 +395,6 @@ void *hh_dbl_rx_register(enum hh_dbl_label label, dbl_rx_cb_t rx_cb, void *priv) cap_table_entry->rx_callback = rx_cb; cap_table_entry->rx_priv_data = priv; ret = request_threaded_irq(cap_table_entry->rx_irq, NULL, hh_dbl_rx_callback_thread, IRQF_ONESHOT, cap_table_entry->rx_irq_name, cap_table_entry); if (ret < 0) { pr_err("%s: IRQ registration failed\n", __func__); cap_table_entry->rx_callback = NULL; cap_table_entry->rx_priv_data = NULL; goto err; } cap_table_entry->rx_reg_done = 1; pr_debug("%s: Registered Rx client for label: %d\n", __func__, label); Loading Loading @@ -407,7 +423,7 @@ int hh_dbl_tx_unregister(void *dbl_client_desc) struct hh_dbl_desc *client_desc = dbl_client_desc; struct hh_dbl_cap_table *cap_table_entry; if (!client_desc) if (IS_ERR_OR_NULL(client_desc)) return -EINVAL; /* Check if the client has manipulated the label */ Loading Loading @@ -458,7 +474,7 @@ int hh_dbl_rx_unregister(void *dbl_client_desc) struct hh_dbl_desc *client_desc = dbl_client_desc; struct hh_dbl_cap_table *cap_table_entry; if (!client_desc) if (IS_ERR_OR_NULL(client_desc)) return -EINVAL; /* Check if the client has manipulated the label */ Loading Loading @@ -525,6 +541,9 @@ int hh_dbl_populate_cap_info(enum hh_dbl_label label, u64 cap_id, goto err; } cap_table_entry->tx_cap_id = cap_id; wake_up_interruptible(&cap_table_entry->cap_wq); pr_debug("%s: label: %d; tx_cap_id: %llu; dir: %d; rx_irq: %d\n", __func__, label, cap_id, direction, rx_irq); break; Loading @@ -537,6 +556,21 @@ int hh_dbl_populate_cap_info(enum hh_dbl_label label, u64 cap_id, } cap_table_entry->rx_cap_id = cap_id; cap_table_entry->rx_irq = rx_irq; ret = request_threaded_irq(cap_table_entry->rx_irq, NULL, hh_dbl_rx_callback_thread, IRQF_ONESHOT | IRQF_TRIGGER_RISING, cap_table_entry->rx_irq_name, cap_table_entry); if (ret < 0) { pr_err("%s: IRQ registration failed\n", __func__); goto err; } wake_up_interruptible(&cap_table_entry->cap_wq); pr_debug("%s: label: %d; rx_cap_id: %llu; dir: %d; rx_irq: %d\n", __func__, label, cap_id, direction, rx_irq); break; Loading Loading @@ -575,6 +609,9 @@ static int __init hh_dbl_init(void) for (i = 0; i < HH_DBL_LABEL_MAX; i++) { entry = &hh_dbl_cap_table[i]; mutex_init(&entry->cap_entry_lock); init_waitqueue_head(&entry->cap_wq); entry->tx_cap_id = HH_CAPID_INVAL; entry->rx_cap_id = HH_CAPID_INVAL; entry->rx_irq_name = kasprintf(GFP_KERNEL, "hh_dbl_rx_%d", i); if (!entry->rx_irq_name) { ret = -ENOMEM; Loading @@ -582,6 +619,8 @@ static int __init hh_dbl_init(void) } } hh_dbl_initialized = true; return 0; err: Loading drivers/virt/haven/hh_rm_core.c +10 −20 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <linux/haven/hh_msgq.h> #include <linux/haven/hh_errno.h> #include <linux/haven/hh_common.h> #include <linux/haven/hh_rm_drv.h> #include "hh_rm_drv_private.h" Loading Loading @@ -66,8 +67,6 @@ SRCU_NOTIFIER_HEAD_STATIC(hh_rm_notifier); static void hh_rm_get_svm_res_work_fn(struct work_struct *work); static DECLARE_WORK(hh_rm_get_svm_res_work, hh_rm_get_svm_res_work_fn); static int hh_rm_populate_hyp_res(hh_vmid_t vmid); static struct hh_rm_connection *hh_rm_alloc_connection(u32 msg_id) { struct hh_rm_connection *connection; Loading Loading @@ -124,21 +123,6 @@ int hh_rm_unregister_notifier(struct notifier_block *nb) } EXPORT_SYMBOL(hh_rm_unregister_notifier); static int hh_rm_process_notif_vm_status(void *recv_buff, size_t recv_buff_size) { struct hh_rm_notif_vm_status_payload *vm_status_payload; vm_status_payload = recv_buff + sizeof(struct hh_rm_rpc_hdr); /* The VM is now booting. Collect it's info and * populate to other entities such as MessageQ and DBL */ if (vm_status_payload->vm_status == HH_RM_OS_STATUS_BOOT) return hh_rm_populate_hyp_res(vm_status_payload->vmid); return 0; } static struct hh_rm_connection * hh_rm_wait_for_notif_fragments(void *recv_buff, size_t recv_buff_size) { Loading Loading @@ -214,8 +198,6 @@ static int hh_rm_process_notif(void *recv_buff, size_t recv_buff_size) ret = -EINVAL; goto err; } ret = hh_rm_process_notif_vm_status(recv_buff, recv_buff_size); break; case HH_RM_NOTIF_VM_IRQ_LENT: if (recv_buff_size != sizeof(*hdr) + Loading Loading @@ -699,7 +681,14 @@ static int hh_rm_get_irq(struct hh_vm_get_hyp_res_resp_entry *res_entry) return ret; } static int hh_rm_populate_hyp_res(hh_vmid_t vmid) /** * hh_rm_populate_hyp_res: Query Resource Manager VM to get hyp resources. * @vmid: The vmid of resources to be queried. * * The function encodes the error codes via ERR_PTR. Hence, the caller is * responsible to check it with IS_ERR_OR_NULL(). */ int hh_rm_populate_hyp_res(hh_vmid_t vmid) { struct hh_vm_get_hyp_res_resp_entry *res_entries = NULL; int linux_irq, ret = 0; Loading Loading @@ -769,6 +758,7 @@ static int hh_rm_populate_hyp_res(hh_vmid_t vmid) kfree(res_entries); return ret; } EXPORT_SYMBOL(hh_rm_populate_hyp_res); static void hh_rm_get_svm_res_work_fn(struct work_struct *work) { Loading drivers/virt/haven/hh_rm_iface.c +2 −2 Original line number Diff line number Diff line Loading @@ -506,13 +506,13 @@ int hh_rm_vm_start(int vmid) &resp_payload_size, &reply_err_code); if (reply_err_code || IS_ERR_OR_NULL(resp_payload)) { err = PTR_ERR(resp_payload); pr_err("%s: VM_ALLOCATE failed with err: %d\n", pr_err("%s: VM_START failed with err: %d\n", __func__, err); return err; } if (resp_payload_size != sizeof(*resp_payload)) { pr_err("%s: Invalid size received for VM_IRQ_ACCEPT: %u\n", pr_err("%s: Invalid size received for VM_START: %u\n", __func__, resp_payload_size); kfree(resp_payload); return -EINVAL; Loading include/linux/haven/hh_dbl.h +16 −8 Original line number Diff line number Diff line Loading @@ -19,6 +19,9 @@ enum hh_dbl_label { HH_DBL_LABEL_MAX }; /* Possible flags to pass for send, set_mask, read, reset */ #define HH_DBL_NONBLOCK BIT(32) #if IS_ENABLED(CONFIG_HH_DBL) void *hh_dbl_tx_register(enum hh_dbl_label label); void *hh_dbl_rx_register(enum hh_dbl_label label, dbl_rx_cb_t rx_cb, Loading @@ -27,11 +30,13 @@ void *hh_dbl_rx_register(enum hh_dbl_label label, dbl_rx_cb_t rx_cb, int hh_dbl_tx_unregister(void *dbl_client_desc); int hh_dbl_rx_unregister(void *dbl_client_desc); int hh_dbl_send(void *dbl_client_desc, uint64_t *newflags); int hh_dbl_send(void *dbl_client_desc, uint64_t *newflags, const unsigned long flags); int hh_dbl_set_mask(void *dbl_client_desc, hh_dbl_flags_t enable_mask, hh_dbl_flags_t ack_mask); int hh_dbl_read_and_clean(void *dbl_client_desc, hh_dbl_flags_t *clear_flags); int hh_dbl_reset(void *dbl_client_desc); hh_dbl_flags_t ack_mask, const unsigned long flags); int hh_dbl_read_and_clean(void *dbl_client_desc, hh_dbl_flags_t *clear_flags, const unsigned long flags); int hh_dbl_reset(void *dbl_client_desc, const unsigned long flags); int hh_dbl_populate_cap_info(enum hh_dbl_label label, u64 cap_id, int direction, int rx_irq); #else Loading @@ -57,25 +62,28 @@ static inline int hh_dbl_rx_unregister(void *dbl_client_desc) return ERR_PTR(-ENODEV); } static inline int hh_dbl_send(void *dbl_client_desc, uint64_t *newflags) static inline int hh_dbl_send(void *dbl_client_desc, uint64_t *newflags, const unsigned long flags) { return -EINVAL; } static inline int hh_dbl_set_mask(void *dbl_client_desc, hh_dbl_flags_t enable_mask, hh_dbl_flags_t ack_mask) hh_dbl_flags_t ack_mask, const unsigned long flags) { return -EINVAL; } static inline int hh_dbl_read_and_clean(void *dbl_client_desc, hh_dbl_flags_t *clear_flags) hh_dbl_flags_t *clear_flags, const unsigned long flags) { return -EINVAL; } static inline int hh_dbl_reset(void *dbl_client_desc) static inline int hh_dbl_reset(void *dbl_client_desc, const unsigned long flags) { return -EINVAL; } Loading Loading
drivers/soc/qcom/guestvm_loader.c +61 −19 Original line number Diff line number Diff line Loading @@ -10,7 +10,6 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/haven/hh_common.h> #include <linux/haven/hh_rm_drv.h> #include <soc/qcom/subsystem_notif.h> Loading @@ -31,12 +30,13 @@ static struct kobj_type guestvm_kobj_type = { }; struct guestvm_loader_private { struct work_struct vm_loader_work; struct notifier_block guestvm_nb; struct kobject vm_loader_kobj; struct device *dev; char vm_name[MAX_LEN]; void *vm_loaded; int vmid; u8 vm_status; }; static inline enum hh_vm_names get_hh_vm_name(const char *str) Loading @@ -50,24 +50,50 @@ static inline enum hh_vm_names get_hh_vm_name(const char *str) return HH_VM_MAX; } static void guestvm_loader_rm_notifier(struct work_struct *vm_loader_work) static int guestvm_loader_nb_handler(struct notifier_block *this, unsigned long cmd, void *data) { struct guestvm_loader_private *priv; int ret = 0; struct hh_rm_notif_vm_status_payload *vm_status_payload = data; u8 vm_status = vm_status_payload->vm_status; int ret; priv = container_of(vm_loader_work, struct guestvm_loader_private, vm_loader_work); priv->vmid = hh_rm_vm_alloc_vmid(get_hh_vm_name(priv->vm_name)); if (priv->vmid == HH_VM_MAX) { dev_err(priv->dev, "Couldn't get vmid.\n"); return; priv = container_of(this, struct guestvm_loader_private, guestvm_nb); if (cmd != HH_RM_NOTIF_VM_STATUS) return NOTIFY_DONE; if (priv->vmid != vm_status_payload->vmid) dev_warn(priv->dev, "Expected a notification from vmid = %d, but received one from vmid = %d\n", priv->vmid, vm_status_payload->vmid); /* * Listen to STATUS_READY or STATUS_RUNNING notifications from RM. * These notifications come from RM after PIL loading the VM images. * Query GET_HYP_RESOURCES to populate other entities such as MessageQ * and DBL. */ switch (vm_status) { case HH_RM_VM_STATUS_READY: priv->vm_status = HH_RM_VM_STATUS_READY; ret = hh_rm_populate_hyp_res(vm_status_payload->vmid); if (ret < 0) { dev_err(priv->dev, "Failed to get hyp resources for vmid = %d ret = %d\n", vm_status_payload->vmid, ret); return NOTIFY_DONE; } ret = hh_rm_vm_start(priv->vmid); if (ret) dev_err(priv->dev, "VM start has failed with %d.\n", ret); break; case HH_RM_VM_STATUS_RUNNING: break; default: dev_err(priv->dev, "Unknown notification receieved for vmid = %d vm_status = %d\n", vm_status_payload->vmid, vm_status); } return NOTIFY_DONE; } static ssize_t guestvm_load_start(struct kobject *kobj, static ssize_t guestvm_loader_start(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) Loading @@ -88,6 +114,13 @@ static ssize_t guestvm_load_start(struct kobject *kobj, } if (boot) { priv->vm_status = HH_RM_VM_STATUS_INIT; priv->vmid = hh_rm_vm_alloc_vmid(get_hh_vm_name(priv->vm_name)); if (priv->vmid < 0) { dev_err(priv->dev, "Couldn't allocate VMID.\n"); return count; } priv->vm_loaded = subsystem_get(priv->vm_name); if (IS_ERR(priv->vm_loaded)) { ret = (int)(PTR_ERR(priv->vm_loaded)); Loading @@ -96,13 +129,18 @@ static ssize_t guestvm_load_start(struct kobject *kobj, priv->vm_loaded = NULL; return ret; } schedule_work(&priv->vm_loader_work); priv->vm_status = HH_RM_VM_STATUS_RUNNING; ret = hh_rm_vm_start(priv->vmid); if (ret) dev_err(priv->dev, "VM start has failed for vmid = %d ret = %d\n", priv->vmid, ret); } return count; } static struct kobj_attribute guestvm_loader_attribute = __ATTR(boot_guestvm, 0220, NULL, guestvm_load_start); __ATTR(boot_guestvm, 0220, NULL, guestvm_loader_start); static struct attribute *attrs[] = { &guestvm_loader_attribute.attr, Loading Loading @@ -132,8 +170,6 @@ static int guestvm_loader_probe(struct platform_device *pdev) return -EINVAL; strlcpy(priv->vm_name, sub_sys, sizeof(priv->vm_name)); INIT_WORK(&priv->vm_loader_work, guestvm_loader_rm_notifier); ret = kobject_init_and_add(&priv->vm_loader_kobj, &guestvm_kobj_type, kernel_kobj, "load_guestvm"); if (ret) { Loading @@ -148,6 +184,12 @@ static int guestvm_loader_probe(struct platform_device *pdev) goto error_return; } priv->guestvm_nb.notifier_call = guestvm_loader_nb_handler; ret = hh_rm_register_notifier(&priv->guestvm_nb); if (ret) return ret; priv->vm_status = HH_RM_VM_STATUS_NO_STATE; return 0; error_return: Loading
drivers/virt/haven/hh_dbl.c +79 −40 Original line number Diff line number Diff line Loading @@ -34,19 +34,21 @@ struct hh_dbl_cap_table { const char *rx_irq_name; dbl_rx_cb_t rx_callback; void *rx_priv_data; wait_queue_head_t cap_wq; }; static bool hh_dbl_initialized; static struct hh_dbl_cap_table hh_dbl_cap_table[HH_DBL_LABEL_MAX]; /** * hh_dbl_validate_params - Validate doorbell common parameters */ static int hh_dbl_validate_params(struct hh_dbl_desc *client_desc, enum hh_dbl_dir dir) enum hh_dbl_dir dir, const unsigned long flags) { struct hh_dbl_cap_table *cap_table_entry; if (!client_desc) if (IS_ERR_OR_NULL(client_desc)) return -EINVAL; /* Check if the client has manipulated the label */ Loading @@ -67,23 +69,35 @@ static int hh_dbl_validate_params(struct hh_dbl_desc *client_desc, * There are no doorbell setup for Tx or Rx */ if (dir == HH_DBL_DIRECTION_RX) { if (!cap_table_entry->rx_cap_id || !cap_table_entry->rx_reg_done) { pr_err("%s: label: %d; rx_cap_id: %llu; dir: %d rx_done: %d\n", __func__, client_desc->label, cap_table_entry->rx_cap_id, dir, cap_table_entry->rx_reg_done); if (!cap_table_entry->rx_reg_done) return -EINVAL; if (cap_table_entry->rx_cap_id != HH_CAPID_INVAL) return 0; if (flags & HH_DBL_NONBLOCK) return -EAGAIN; } if (wait_event_interruptible(cap_table_entry->cap_wq, cap_table_entry->rx_cap_id != HH_CAPID_INVAL)) return -ERESTARTSYS; return 0; } else { if (!cap_table_entry->tx_cap_id || !cap_table_entry->tx_reg_done) { pr_err("%s: label: %d; tx_cap_id: %llu; dir: %d tx_done: %d\n", __func__, client_desc->label, cap_table_entry->tx_cap_id, dir, cap_table_entry->tx_reg_done); if (!cap_table_entry->tx_reg_done) return -EINVAL; if (cap_table_entry->tx_cap_id != HH_CAPID_INVAL) return 0; if (flags & HH_DBL_NONBLOCK) return -EAGAIN; } if (wait_event_interruptible(cap_table_entry->cap_wq, cap_table_entry->tx_cap_id != HH_CAPID_INVAL)) return -ERESTARTSYS; return 0; } return 0; Loading @@ -93,6 +107,8 @@ static int hh_dbl_validate_params(struct hh_dbl_desc *client_desc, * hh_dbl_read_and_clean - Automatically read and clear the flags in doorbell * @client_desc: client handle to indetify the doorbell object * @clear_flags: clear the bits mentioned in the clear_flags * @flags: Optional flags to pass to send the data. For the list of flags, * see linux/haven/hh_dbl.h * * Reads and clears the flags of the Doorbell object. If there is a pending * bound virtual interrupt, it will be de-asserted Loading @@ -101,7 +117,8 @@ static int hh_dbl_validate_params(struct hh_dbl_desc *client_desc, * 0 on success, @clear_flags contains the doorbell’s previous unmasked flags * before the @clear_flags were removed. */ int hh_dbl_read_and_clean(void *dbl_client_desc, hh_dbl_flags_t *clear_flags) int hh_dbl_read_and_clean(void *dbl_client_desc, hh_dbl_flags_t *clear_flags, const unsigned long flags) { struct hh_dbl_cap_table *cap_table_entry; struct hh_hcall_dbl_recv_resp recv_resp; Loading @@ -111,7 +128,7 @@ int hh_dbl_read_and_clean(void *dbl_client_desc, hh_dbl_flags_t *clear_flags) if (!clear_flags) return -EINVAL; ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_RX); ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_RX, flags); if (ret) return ret; Loading @@ -137,6 +154,8 @@ EXPORT_SYMBOL(hh_dbl_read_and_clean); * the doorbell's bound virtual interrupt * @ack_mask: Controls which flags should be automatically cleared * when the interrupt is asserted * @flags: Optional flags to pass to send the data. For the list of flags, * see linux/haven/hh_dbl.h * * Sets the Doorbell object’s masks. A doorbell object has two masks * which are configured by the receiver to control which flags it is Loading @@ -146,13 +165,13 @@ EXPORT_SYMBOL(hh_dbl_read_and_clean); * 0 on success */ int hh_dbl_set_mask(void *dbl_client_desc, hh_dbl_flags_t enable_mask, hh_dbl_flags_t ack_mask) hh_dbl_flags_t ack_mask, const unsigned long flags) { struct hh_dbl_cap_table *cap_table_entry; struct hh_dbl_desc *client_desc = dbl_client_desc; int ret, hh_ret; ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_RX); ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_RX, flags); if (ret) return ret; Loading @@ -176,6 +195,8 @@ EXPORT_SYMBOL(hh_dbl_set_mask); * @client_desc: client handle to indetify the doorbell object * @newflags: flags to set in the doorbell. This flag along with enable_mask * in the doorbell decide whehter to raise vIRQ are not. * @flags: Optional flags to pass to send the data. For the list of flags, * see linux/haven/hh_dbl.h * * Set flags in the doorbell. If following the send, the set of enabled flags * as defined by the bitwise-AND of the doorbell flags with the EnableMask, Loading @@ -185,7 +206,8 @@ EXPORT_SYMBOL(hh_dbl_set_mask); * 0 on success, @newflags contains the doorbell’s previous unmasked flags * before the @newflags were added. */ int hh_dbl_send(void *dbl_client_desc, hh_dbl_flags_t *newflags) int hh_dbl_send(void *dbl_client_desc, hh_dbl_flags_t *newflags, unsigned long flags) { struct hh_dbl_cap_table *cap_table_entry; struct hh_hcall_dbl_send_resp send_resp; Loading @@ -195,7 +217,7 @@ int hh_dbl_send(void *dbl_client_desc, hh_dbl_flags_t *newflags) if (!newflags) return -EINVAL; ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_TX); ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_TX, flags); if (ret) return ret; Loading @@ -218,6 +240,8 @@ EXPORT_SYMBOL(hh_dbl_send); * hh_dbl_reset - clear all the flags of the doorbell and sets all bits in * the Doorbell’s mask. * @client_desc: client handle to indetify the doorbell object * @flags: Optional flags to pass to send the data. For the list of flags, * see linux/haven/hh_dbl.h * * Clears all the flags of the doorbell and sets all bits in the doorbell’s * mask. If there is a pending bound virtual interrupt, it will be de-asserted. Loading @@ -225,13 +249,13 @@ EXPORT_SYMBOL(hh_dbl_send); * Returns: * 0 on success */ int hh_dbl_reset(void *dbl_client_desc) int hh_dbl_reset(void *dbl_client_desc, const unsigned long flags) { struct hh_dbl_cap_table *cap_table_entry; struct hh_dbl_desc *client_desc = dbl_client_desc; int ret, hh_ret; ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_RX); ret = hh_dbl_validate_params(client_desc, HH_DBL_DIRECTION_RX, flags); if (ret) return ret; Loading Loading @@ -278,6 +302,9 @@ void *hh_dbl_tx_register(enum hh_dbl_label label) if (label < 0 || label >= HH_DBL_LABEL_MAX) return ERR_PTR(-EINVAL); if (!hh_dbl_initialized) return ERR_PTR(-EPROBE_DEFER); cap_table_entry = &hh_dbl_cap_table[label]; if (mutex_lock_interruptible(&cap_table_entry->cap_entry_lock)) Loading Loading @@ -338,6 +365,9 @@ void *hh_dbl_rx_register(enum hh_dbl_label label, dbl_rx_cb_t rx_cb, void *priv) if (label < 0 || label >= HH_DBL_LABEL_MAX) return ERR_PTR(-EINVAL); if (!hh_dbl_initialized) return ERR_PTR(-EPROBE_DEFER); cap_table_entry = &hh_dbl_cap_table[label]; if (mutex_lock_interruptible(&cap_table_entry->cap_entry_lock)) Loading Loading @@ -365,20 +395,6 @@ void *hh_dbl_rx_register(enum hh_dbl_label label, dbl_rx_cb_t rx_cb, void *priv) cap_table_entry->rx_callback = rx_cb; cap_table_entry->rx_priv_data = priv; ret = request_threaded_irq(cap_table_entry->rx_irq, NULL, hh_dbl_rx_callback_thread, IRQF_ONESHOT, cap_table_entry->rx_irq_name, cap_table_entry); if (ret < 0) { pr_err("%s: IRQ registration failed\n", __func__); cap_table_entry->rx_callback = NULL; cap_table_entry->rx_priv_data = NULL; goto err; } cap_table_entry->rx_reg_done = 1; pr_debug("%s: Registered Rx client for label: %d\n", __func__, label); Loading Loading @@ -407,7 +423,7 @@ int hh_dbl_tx_unregister(void *dbl_client_desc) struct hh_dbl_desc *client_desc = dbl_client_desc; struct hh_dbl_cap_table *cap_table_entry; if (!client_desc) if (IS_ERR_OR_NULL(client_desc)) return -EINVAL; /* Check if the client has manipulated the label */ Loading Loading @@ -458,7 +474,7 @@ int hh_dbl_rx_unregister(void *dbl_client_desc) struct hh_dbl_desc *client_desc = dbl_client_desc; struct hh_dbl_cap_table *cap_table_entry; if (!client_desc) if (IS_ERR_OR_NULL(client_desc)) return -EINVAL; /* Check if the client has manipulated the label */ Loading Loading @@ -525,6 +541,9 @@ int hh_dbl_populate_cap_info(enum hh_dbl_label label, u64 cap_id, goto err; } cap_table_entry->tx_cap_id = cap_id; wake_up_interruptible(&cap_table_entry->cap_wq); pr_debug("%s: label: %d; tx_cap_id: %llu; dir: %d; rx_irq: %d\n", __func__, label, cap_id, direction, rx_irq); break; Loading @@ -537,6 +556,21 @@ int hh_dbl_populate_cap_info(enum hh_dbl_label label, u64 cap_id, } cap_table_entry->rx_cap_id = cap_id; cap_table_entry->rx_irq = rx_irq; ret = request_threaded_irq(cap_table_entry->rx_irq, NULL, hh_dbl_rx_callback_thread, IRQF_ONESHOT | IRQF_TRIGGER_RISING, cap_table_entry->rx_irq_name, cap_table_entry); if (ret < 0) { pr_err("%s: IRQ registration failed\n", __func__); goto err; } wake_up_interruptible(&cap_table_entry->cap_wq); pr_debug("%s: label: %d; rx_cap_id: %llu; dir: %d; rx_irq: %d\n", __func__, label, cap_id, direction, rx_irq); break; Loading Loading @@ -575,6 +609,9 @@ static int __init hh_dbl_init(void) for (i = 0; i < HH_DBL_LABEL_MAX; i++) { entry = &hh_dbl_cap_table[i]; mutex_init(&entry->cap_entry_lock); init_waitqueue_head(&entry->cap_wq); entry->tx_cap_id = HH_CAPID_INVAL; entry->rx_cap_id = HH_CAPID_INVAL; entry->rx_irq_name = kasprintf(GFP_KERNEL, "hh_dbl_rx_%d", i); if (!entry->rx_irq_name) { ret = -ENOMEM; Loading @@ -582,6 +619,8 @@ static int __init hh_dbl_init(void) } } hh_dbl_initialized = true; return 0; err: Loading
drivers/virt/haven/hh_rm_core.c +10 −20 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <linux/haven/hh_msgq.h> #include <linux/haven/hh_errno.h> #include <linux/haven/hh_common.h> #include <linux/haven/hh_rm_drv.h> #include "hh_rm_drv_private.h" Loading Loading @@ -66,8 +67,6 @@ SRCU_NOTIFIER_HEAD_STATIC(hh_rm_notifier); static void hh_rm_get_svm_res_work_fn(struct work_struct *work); static DECLARE_WORK(hh_rm_get_svm_res_work, hh_rm_get_svm_res_work_fn); static int hh_rm_populate_hyp_res(hh_vmid_t vmid); static struct hh_rm_connection *hh_rm_alloc_connection(u32 msg_id) { struct hh_rm_connection *connection; Loading Loading @@ -124,21 +123,6 @@ int hh_rm_unregister_notifier(struct notifier_block *nb) } EXPORT_SYMBOL(hh_rm_unregister_notifier); static int hh_rm_process_notif_vm_status(void *recv_buff, size_t recv_buff_size) { struct hh_rm_notif_vm_status_payload *vm_status_payload; vm_status_payload = recv_buff + sizeof(struct hh_rm_rpc_hdr); /* The VM is now booting. Collect it's info and * populate to other entities such as MessageQ and DBL */ if (vm_status_payload->vm_status == HH_RM_OS_STATUS_BOOT) return hh_rm_populate_hyp_res(vm_status_payload->vmid); return 0; } static struct hh_rm_connection * hh_rm_wait_for_notif_fragments(void *recv_buff, size_t recv_buff_size) { Loading Loading @@ -214,8 +198,6 @@ static int hh_rm_process_notif(void *recv_buff, size_t recv_buff_size) ret = -EINVAL; goto err; } ret = hh_rm_process_notif_vm_status(recv_buff, recv_buff_size); break; case HH_RM_NOTIF_VM_IRQ_LENT: if (recv_buff_size != sizeof(*hdr) + Loading Loading @@ -699,7 +681,14 @@ static int hh_rm_get_irq(struct hh_vm_get_hyp_res_resp_entry *res_entry) return ret; } static int hh_rm_populate_hyp_res(hh_vmid_t vmid) /** * hh_rm_populate_hyp_res: Query Resource Manager VM to get hyp resources. * @vmid: The vmid of resources to be queried. * * The function encodes the error codes via ERR_PTR. Hence, the caller is * responsible to check it with IS_ERR_OR_NULL(). */ int hh_rm_populate_hyp_res(hh_vmid_t vmid) { struct hh_vm_get_hyp_res_resp_entry *res_entries = NULL; int linux_irq, ret = 0; Loading Loading @@ -769,6 +758,7 @@ static int hh_rm_populate_hyp_res(hh_vmid_t vmid) kfree(res_entries); return ret; } EXPORT_SYMBOL(hh_rm_populate_hyp_res); static void hh_rm_get_svm_res_work_fn(struct work_struct *work) { Loading
drivers/virt/haven/hh_rm_iface.c +2 −2 Original line number Diff line number Diff line Loading @@ -506,13 +506,13 @@ int hh_rm_vm_start(int vmid) &resp_payload_size, &reply_err_code); if (reply_err_code || IS_ERR_OR_NULL(resp_payload)) { err = PTR_ERR(resp_payload); pr_err("%s: VM_ALLOCATE failed with err: %d\n", pr_err("%s: VM_START failed with err: %d\n", __func__, err); return err; } if (resp_payload_size != sizeof(*resp_payload)) { pr_err("%s: Invalid size received for VM_IRQ_ACCEPT: %u\n", pr_err("%s: Invalid size received for VM_START: %u\n", __func__, resp_payload_size); kfree(resp_payload); return -EINVAL; Loading
include/linux/haven/hh_dbl.h +16 −8 Original line number Diff line number Diff line Loading @@ -19,6 +19,9 @@ enum hh_dbl_label { HH_DBL_LABEL_MAX }; /* Possible flags to pass for send, set_mask, read, reset */ #define HH_DBL_NONBLOCK BIT(32) #if IS_ENABLED(CONFIG_HH_DBL) void *hh_dbl_tx_register(enum hh_dbl_label label); void *hh_dbl_rx_register(enum hh_dbl_label label, dbl_rx_cb_t rx_cb, Loading @@ -27,11 +30,13 @@ void *hh_dbl_rx_register(enum hh_dbl_label label, dbl_rx_cb_t rx_cb, int hh_dbl_tx_unregister(void *dbl_client_desc); int hh_dbl_rx_unregister(void *dbl_client_desc); int hh_dbl_send(void *dbl_client_desc, uint64_t *newflags); int hh_dbl_send(void *dbl_client_desc, uint64_t *newflags, const unsigned long flags); int hh_dbl_set_mask(void *dbl_client_desc, hh_dbl_flags_t enable_mask, hh_dbl_flags_t ack_mask); int hh_dbl_read_and_clean(void *dbl_client_desc, hh_dbl_flags_t *clear_flags); int hh_dbl_reset(void *dbl_client_desc); hh_dbl_flags_t ack_mask, const unsigned long flags); int hh_dbl_read_and_clean(void *dbl_client_desc, hh_dbl_flags_t *clear_flags, const unsigned long flags); int hh_dbl_reset(void *dbl_client_desc, const unsigned long flags); int hh_dbl_populate_cap_info(enum hh_dbl_label label, u64 cap_id, int direction, int rx_irq); #else Loading @@ -57,25 +62,28 @@ static inline int hh_dbl_rx_unregister(void *dbl_client_desc) return ERR_PTR(-ENODEV); } static inline int hh_dbl_send(void *dbl_client_desc, uint64_t *newflags) static inline int hh_dbl_send(void *dbl_client_desc, uint64_t *newflags, const unsigned long flags) { return -EINVAL; } static inline int hh_dbl_set_mask(void *dbl_client_desc, hh_dbl_flags_t enable_mask, hh_dbl_flags_t ack_mask) hh_dbl_flags_t ack_mask, const unsigned long flags) { return -EINVAL; } static inline int hh_dbl_read_and_clean(void *dbl_client_desc, hh_dbl_flags_t *clear_flags) hh_dbl_flags_t *clear_flags, const unsigned long flags) { return -EINVAL; } static inline int hh_dbl_reset(void *dbl_client_desc) static inline int hh_dbl_reset(void *dbl_client_desc, const unsigned long flags) { return -EINVAL; } Loading