summaryrefslogtreecommitdiffstats
path: root/drivers/block/rsxx/cregs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block/rsxx/cregs.c')
-rw-r--r--drivers/block/rsxx/cregs.c59
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);
}