diff --git a/drivers/virt/haven/hh_dbl.c b/drivers/virt/haven/hh_dbl.c index e1491b18e22b..d08a27340482 100644 --- a/drivers/virt/haven/hh_dbl.c +++ b/drivers/virt/haven/hh_dbl.c @@ -34,6 +34,7 @@ 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; @@ -43,11 +44,11 @@ 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 */ @@ -68,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 == HH_CAPID_INVAL) || - !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 == HH_CAPID_INVAL) || - !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; @@ -94,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 @@ -102,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; @@ -112,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; @@ -138,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 @@ -147,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; @@ -177,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, @@ -186,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; @@ -196,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; @@ -219,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. @@ -226,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; @@ -518,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; @@ -543,6 +569,8 @@ int hh_dbl_populate_cap_info(enum hh_dbl_label label, u64 cap_id, 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; @@ -581,6 +609,7 @@ 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); diff --git a/include/linux/haven/hh_dbl.h b/include/linux/haven/hh_dbl.h index 3c092bdea129..ab5c4ca40536 100644 --- a/include/linux/haven/hh_dbl.h +++ b/include/linux/haven/hh_dbl.h @@ -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, @@ -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 @@ -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; } diff --git a/net/neuron/channel/ch_haven_recv.c b/net/neuron/channel/ch_haven_recv.c index 5f9375c857a7..47f0a6568436 100644 --- a/net/neuron/channel/ch_haven_recv.c +++ b/net/neuron/channel/ch_haven_recv.c @@ -94,7 +94,7 @@ static inline int channel_hh_kick(struct neuron_mq_data_priv *priv) hh_dbl_flags_t dbl_mask = CH_DBL_MASK; int ret; - ret = hh_dbl_send(priv->tx_dbl, &dbl_mask); + ret = hh_dbl_send(priv->tx_dbl, &dbl_mask, 0); if (ret) pr_err("failed to raise virq to the sender %d\n", ret); diff --git a/net/neuron/channel/ch_haven_send.c b/net/neuron/channel/ch_haven_send.c index 7a4f5d322615..43ceb3387c16 100644 --- a/net/neuron/channel/ch_haven_send.c +++ b/net/neuron/channel/ch_haven_send.c @@ -68,7 +68,7 @@ static inline int channel_hh_kick(struct neuron_mq_data_priv *priv) hh_dbl_flags_t dbl_mask = CH_DBL_MASK; int ret; - ret = hh_dbl_send(priv->tx_dbl, &dbl_mask); + ret = hh_dbl_send(priv->tx_dbl, &dbl_mask, 0); if (ret) pr_err("failed to raise virq to the sender %d\n", ret); diff --git a/net/qrtr/haven.c b/net/qrtr/haven.c index 446d42dd85ec..fc39f96c6b01 100644 --- a/net/qrtr/haven.c +++ b/net/qrtr/haven.c @@ -68,7 +68,7 @@ static void qrtr_haven_kick(struct qrtr_haven_dev *qdev) hh_dbl_flags_t dbl_mask = QRTR_DBL_MASK; int ret; - ret = hh_dbl_send(qdev->tx_dbl, &dbl_mask); + ret = hh_dbl_send(qdev->tx_dbl, &dbl_mask, HH_DBL_NONBLOCK); if (ret) dev_err(qdev->dev, "failed to raise doorbell %d\n", ret); }