diff options
Diffstat (limited to 'drivers/block/rsxx/cregs.c')
-rw-r--r-- | drivers/block/rsxx/cregs.c | 59 |
1 files changed, 37 insertions, 22 deletions
diff --git a/drivers/block/rsxx/cregs.c b/drivers/block/rsxx/cregs.c index a31fd727e804..80bbe639fccd 100644 --- a/drivers/block/rsxx/cregs.c +++ b/drivers/block/rsxx/cregs.c @@ -107,10 +107,10 @@ static struct creg_cmd *pop_active_cmd(struct rsxx_cardinfo *card) * Spin lock is needed because this can be called in atomic/interrupt * context. */ - spin_lock_bh(&card->creg_ctrl.pop_lock); + spin_lock_bh(&card->creg_ctrl.lock); cmd = card->creg_ctrl.active_cmd; card->creg_ctrl.active_cmd = NULL; - spin_unlock_bh(&card->creg_ctrl.pop_lock); + spin_unlock_bh(&card->creg_ctrl.lock); return cmd; } @@ -126,7 +126,11 @@ static void creg_issue_cmd(struct rsxx_cardinfo *card, struct creg_cmd *cmd) cmd->buf, cmd->stream); } - /* Data copy must complete before initiating the command. */ + /* + * Data copy must complete before initiating the command. This is + * needed for weakly ordered processors (i.e. PowerPC), so that all + * neccessary registers are written before we kick the hardware. + */ wmb(); /* Setting the valid bit will kick off the command. */ @@ -192,11 +196,11 @@ static int creg_queue_cmd(struct rsxx_cardinfo *card, cmd->cb_private = cb_private; cmd->status = 0; - mutex_lock(&card->creg_ctrl.lock); + spin_lock(&card->creg_ctrl.lock); list_add_tail(&cmd->list, &card->creg_ctrl.queue); card->creg_ctrl.q_depth++; creg_kick_queue(card); - mutex_unlock(&card->creg_ctrl.lock); + spin_unlock(&card->creg_ctrl.lock); return 0; } @@ -219,10 +223,11 @@ static void creg_cmd_timed_out(unsigned long data) kmem_cache_free(creg_cmd_pool, cmd); - spin_lock(&card->creg_ctrl.pop_lock); + + spin_lock(&card->creg_ctrl.lock); card->creg_ctrl.active = 0; creg_kick_queue(card); - spin_unlock(&card->creg_ctrl.pop_lock); + spin_unlock(&card->creg_ctrl.lock); } @@ -291,10 +296,10 @@ creg_done: kmem_cache_free(creg_cmd_pool, cmd); - mutex_lock(&card->creg_ctrl.lock); + spin_lock(&card->creg_ctrl.lock); card->creg_ctrl.active = 0; creg_kick_queue(card); - mutex_unlock(&card->creg_ctrl.lock); + spin_unlock(&card->creg_ctrl.lock); } static void creg_reset(struct rsxx_cardinfo *card) @@ -303,6 +308,10 @@ static void creg_reset(struct rsxx_cardinfo *card) struct creg_cmd *tmp; unsigned long flags; + /* + * mutex_trylock is used here because if reset_lock is taken then a + * reset is already happening. So, we can just go ahead and return. + */ if (!mutex_trylock(&card->creg_ctrl.reset_lock)) return; @@ -315,7 +324,7 @@ static void creg_reset(struct rsxx_cardinfo *card) "Resetting creg interface for recovery\n"); /* Cancel outstanding commands */ - mutex_lock(&card->creg_ctrl.lock); + spin_lock(&card->creg_ctrl.lock); list_for_each_entry_safe(cmd, tmp, &card->creg_ctrl.queue, list) { list_del(&cmd->list); card->creg_ctrl.q_depth--; @@ -336,7 +345,7 @@ static void creg_reset(struct rsxx_cardinfo *card) card->creg_ctrl.active = 0; } - mutex_unlock(&card->creg_ctrl.lock); + spin_unlock(&card->creg_ctrl.lock); card->creg_ctrl.reset = 0; spin_lock_irqsave(&card->irq_lock, flags); @@ -359,7 +368,7 @@ static void creg_cmd_done_cb(struct rsxx_cardinfo *card, { struct creg_completion *cmd_completion; - cmd_completion = (struct creg_completion *)cmd->cb_private; + cmd_completion = cmd->cb_private; BUG_ON(!cmd_completion); cmd_completion->st = st; @@ -380,7 +389,6 @@ static int __issue_creg_rw(struct rsxx_cardinfo *card, unsigned long timeout; int st; - INIT_COMPLETION(cmd_done); completion.cmd_done = &cmd_done; completion.st = 0; completion.creg_status = 0; @@ -390,8 +398,13 @@ static int __issue_creg_rw(struct rsxx_cardinfo *card, if (st) return st; + /* + * This timeout is neccessary for unresponsive hardware. The additional + * 20 seconds to used to guarantee that each cregs requests has time to + * complete. + */ timeout = msecs_to_jiffies((CREG_TIMEOUT_MSEC * - card->creg_ctrl.q_depth) + 20000); + card->creg_ctrl.q_depth) + 20000); /* * The creg interface is guaranteed to complete. It has a timeout @@ -443,7 +456,7 @@ static int issue_creg_rw(struct rsxx_cardinfo *card, if (st) return st; - data = (void *)((char *)data + xfer); + data = (char *)data + xfer; addr += xfer; size8 -= xfer; } while (size8); @@ -558,9 +571,9 @@ static void hw_log_msg(struct rsxx_cardinfo *card, const char *str, int len) } /* - * The substrncpy() function copies to string(up to count bytes) point to by src - * (including the terminating '\0' character) to dest. Returns the number of - * bytes copied to dest. + * The substrncpy function copies the src string (which includes the + * terminating '\0' character), up to the count into the dest pointer. + * Returns the number of bytes copied to dest. */ static int substrncpy(char *dest, const char *src, int count) { @@ -657,6 +670,9 @@ int rsxx_reg_access(struct rsxx_cardinfo *card, if (st) return -EFAULT; + if (cmd.cnt > RSXX_MAX_REG_CNT) + return -EFAULT; + st = issue_reg_cmd(card, &cmd, read); if (st) return st; @@ -682,8 +698,7 @@ int rsxx_creg_setup(struct rsxx_cardinfo *card) INIT_WORK(&card->creg_ctrl.done_work, creg_cmd_done); mutex_init(&card->creg_ctrl.reset_lock); INIT_LIST_HEAD(&card->creg_ctrl.queue); - mutex_init(&card->creg_ctrl.lock); - spin_lock_init(&card->creg_ctrl.pop_lock); + spin_lock_init(&card->creg_ctrl.lock); setup_timer(&card->creg_ctrl.cmd_timer, creg_cmd_timed_out, (unsigned long) card); @@ -697,7 +712,7 @@ void rsxx_creg_destroy(struct rsxx_cardinfo *card) int cnt = 0; /* Cancel outstanding commands */ - mutex_lock(&card->creg_ctrl.lock); + spin_lock(&card->creg_ctrl.lock); list_for_each_entry_safe(cmd, tmp, &card->creg_ctrl.queue, list) { list_del(&cmd->list); if (cmd->cb) @@ -722,7 +737,7 @@ void rsxx_creg_destroy(struct rsxx_cardinfo *card) "Canceled active creg command\n"); kmem_cache_free(creg_cmd_pool, cmd); } - mutex_unlock(&card->creg_ctrl.lock); + spin_unlock(&card->creg_ctrl.lock); cancel_work_sync(&card->creg_ctrl.done_work); } |