diff options
-rw-r--r-- | drivers/target/target_core_user.c | 31 |
1 files changed, 16 insertions, 15 deletions
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index ac37ce6be15c..9a1b314f6482 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -236,16 +236,26 @@ static inline size_t head_to_end(size_t head, size_t size) * * Called with ring lock held. */ -static bool is_ring_space_avail(struct tcmu_dev *udev, size_t cmd_needed, size_t data_needed) +static bool is_ring_space_avail(struct tcmu_dev *udev, size_t cmd_size, size_t data_needed) { struct tcmu_mailbox *mb = udev->mb_addr; size_t space; u32 cmd_head; + size_t cmd_needed; tcmu_flush_dcache_range(mb, sizeof(*mb)); cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */ + /* + * If cmd end-of-ring space is too small then we need space for a NOP plus + * original cmd - cmds are internally contiguous. + */ + if (head_to_end(cmd_head, udev->cmdr_size) >= cmd_size) + cmd_needed = cmd_size; + else + cmd_needed = cmd_size + head_to_end(cmd_head, udev->cmdr_size); + space = spc_free(cmd_head, udev->cmdr_last_cleaned, udev->cmdr_size); if (space < cmd_needed) { pr_debug("no cmd space: %u %u %u\n", cmd_head, @@ -268,9 +278,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) struct tcmu_dev *udev = tcmu_cmd->tcmu_dev; struct se_cmd *se_cmd = tcmu_cmd->se_cmd; size_t base_command_size, command_size; - size_t cmdr_space_needed; struct tcmu_mailbox *mb; - size_t pad_size; struct tcmu_cmd_entry *entry; int i; struct scatterlist *sg; @@ -307,17 +315,7 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) "cmd/data ring buffers\n", command_size, tcmu_cmd->data_length, udev->cmdr_size, udev->data_size); - /* - * Cmd end-of-ring space is too small so we need space for a NOP plus - * original cmd - cmds are internally contiguous. - */ - if (head_to_end(cmd_head, udev->cmdr_size) >= command_size) - pad_size = 0; - else - pad_size = head_to_end(cmd_head, udev->cmdr_size); - cmdr_space_needed = command_size + pad_size; - - while (!is_ring_space_avail(udev, cmdr_space_needed, tcmu_cmd->data_length)) { + while (!is_ring_space_avail(udev, command_size, tcmu_cmd->data_length)) { int ret; DEFINE_WAIT(__wait); @@ -338,7 +336,10 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */ } - if (pad_size) { + /* Insert a PAD if end-of-ring space is too small */ + if (head_to_end(cmd_head, udev->cmdr_size) < command_size) { + size_t pad_size = head_to_end(cmd_head, udev->cmdr_size); + entry = (void *) mb + CMDR_OFF + cmd_head; tcmu_flush_dcache_range(entry, sizeof(*entry)); tcmu_hdr_set_op(&entry->hdr, TCMU_OP_PAD); |