Commit 65b5b0e1 authored by Mikhail Karpenko's avatar Mikhail Karpenko

Update locking for queue pointers

parent 0564ebaf
...@@ -1185,22 +1185,31 @@ static void finish_rec(struct elphel_ahci_priv *dpriv) ...@@ -1185,22 +1185,31 @@ static void finish_rec(struct elphel_ahci_priv *dpriv)
/** Move a pointer to free command slot one step forward. This function holds spin lock #elphel_ahci_priv::flags_lock */ /** Move a pointer to free command slot one step forward. This function holds spin lock #elphel_ahci_priv::flags_lock */
static int move_tail(struct elphel_ahci_priv *dpriv) static int move_tail(struct elphel_ahci_priv *dpriv)
{ {
int ret;
unsigned long irq_flags;
size_t slot = (dpriv->tail_ptr + 1) % MAX_CMD_SLOTS; size_t slot = (dpriv->tail_ptr + 1) % MAX_CMD_SLOTS;
spin_lock_irqsave(&dpriv->flags_lock, irq_flags);
if (slot != dpriv->head_ptr) { if (slot != dpriv->head_ptr) {
set_flag(dpriv, LOCK_TAIL); dpriv->flags |= LOCK_TAIL;
dpriv->tail_ptr = slot; dpriv->tail_ptr = slot;
dev_dbg(dpriv->dev, "move tail pointer to slot: %u\n", slot); ret = 0;
return 0;
} else { } else {
/* no more free command slots */ /* no more free command slots */
return -1; ret = -1;
} }
spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags);
if (ret == 0)
dev_dbg(dpriv->dev, "move tail pointer to slot: %u\n", slot);
return ret;
} }
/** Move a pointer to next ready command. This function holds spin lock #elphel_ahci_priv::flags_lock*/ /** Move a pointer to next ready command. This function holds spin lock #elphel_ahci_priv::flags_lock*/
static int move_head(struct elphel_ahci_priv *dpriv) static int move_head(struct elphel_ahci_priv *dpriv)
{ {
int ret;
size_t use_tail; size_t use_tail;
unsigned long irq_flags; unsigned long irq_flags;
size_t slot = (dpriv->head_ptr + 1) % MAX_CMD_SLOTS; size_t slot = (dpriv->head_ptr + 1) % MAX_CMD_SLOTS;
...@@ -1212,17 +1221,19 @@ static int move_head(struct elphel_ahci_priv *dpriv) ...@@ -1212,17 +1221,19 @@ static int move_head(struct elphel_ahci_priv *dpriv)
} else { } else {
use_tail = dpriv->tail_ptr; use_tail = dpriv->tail_ptr;
} }
spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags);
if (dpriv->head_ptr != use_tail) { if (dpriv->head_ptr != use_tail) {
dpriv->head_ptr = slot; dpriv->head_ptr = slot;
dev_dbg(dpriv->dev, "move head pointer to slot: %u\n", slot); ret = 0;
return 0;
} else { } else {
/* no more commands in queue */ /* no more commands in queue */
return -1; ret = -1;
} }
spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags);
if (ret == 0)
dev_dbg(dpriv->dev, "move head pointer to slot: %u\n", slot);
return ret;
} }
/** Check if command queue is empty */ /** Check if command queue is empty */
...@@ -1382,6 +1393,7 @@ static ssize_t rawdev_write(struct device *dev, ///< device structure associate ...@@ -1382,6 +1393,7 @@ static ssize_t rawdev_write(struct device *dev, ///< device structure associate
} else { } else {
dpriv->flags |= DELAYED_FINISH; dpriv->flags |= DELAYED_FINISH;
} }
dpriv->datascope.reg_stat[CMD_RCVD] = dpriv->datascope.reg_stat[CMD_RCVD] + 1;
return buff_sz; return buff_sz;
} }
...@@ -1440,6 +1452,8 @@ static ssize_t rawdev_write(struct device *dev, ///< device structure associate ...@@ -1440,6 +1452,8 @@ static ssize_t rawdev_write(struct device *dev, ///< device structure associate
/* new command slot is ready now and can be unlocked */ /* new command slot is ready now and can be unlocked */
reset_flag(dpriv, LOCK_TAIL); reset_flag(dpriv, LOCK_TAIL);
dpriv->datascope.reg_stat[CMD_RCVD] = dpriv->datascope.reg_stat[CMD_RCVD] + 1;
if (!proceed) { if (!proceed) {
/* disk may be free by the moment, try to grab it */ /* disk may be free by the moment, try to grab it */
spin_lock_irqsave(&dpriv->flags_lock, irq_flags); spin_lock_irqsave(&dpriv->flags_lock, irq_flags);
......
...@@ -83,7 +83,8 @@ enum { ...@@ -83,7 +83,8 @@ enum {
REG_PxSERR, ///< value of PxSERR in data buffer REG_PxSERR, ///< value of PxSERR in data buffer
IRQ_COUNTER, ///< interrupts counter for internal commands IRQ_COUNTER, ///< interrupts counter for internal commands
IRQ_COUNTER_SYS, ///< interrupts counter for system commands IRQ_COUNTER_SYS, ///< interrupts counter for system commands
CMD_SENT ///< number of commands sent CMD_SENT, ///< number of commands sent
CMD_RCVD ///< number of commands received
}; };
struct datascope { struct datascope {
void __iomem *timestamp_reg; ///< register in vendor specific address range (PxVS) where timestamp can be written void __iomem *timestamp_reg; ///< register in vendor specific address range (PxVS) where timestamp can be written
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment