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

Update locking for queue pointers

parent 0564ebaf
Loading
Loading
Loading
Loading
+23 −9
Original line number Original line Diff line number Diff line
@@ -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)
	} 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
		} 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
	/* 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);
+2 −1
Original line number Original line Diff line number Diff line
@@ -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