Commit c9b13370 authored by Mikhail Karpenko's avatar Mikhail Karpenko
Browse files

Set spin locks for LOCK_TAIL flag

parent 72aebf77
Loading
Loading
Loading
Loading
+40 −16
Original line number Original line Diff line number Diff line
@@ -34,7 +34,6 @@
#include "ahci_elphel.h"
#include "ahci_elphel.h"
#include "../elphel/exif393.h"
#include "../elphel/exif393.h"
#include "../elphel/jpeghead.h"
#include "../elphel/jpeghead.h"
#include "../elphel/x393_helpers.h"


#define DRV_NAME "elphel-ahci"
#define DRV_NAME "elphel-ahci"
/*
/*
@@ -68,11 +67,13 @@ static int process_cmd(struct elphel_ahci_priv *dpriv);
static inline size_t get_size_from(const struct fvec *vects, int index, size_t offset, int all);
static inline size_t get_size_from(const struct fvec *vects, int index, size_t offset, int all);
static inline void vectmov(struct fvec *vec, size_t len);
static inline void vectmov(struct fvec *vec, size_t len);
static inline void vectsplit(struct fvec *vect, struct fvec *parts, size_t *n_elem);
static inline void vectsplit(struct fvec *vect, struct fvec *parts, size_t *n_elem);
int move_tail(struct elphel_ahci_priv *dpriv);
static int move_tail(struct elphel_ahci_priv *dpriv);
int move_head(struct elphel_ahci_priv *dpriv);
static int move_head(struct elphel_ahci_priv *dpriv);
size_t get_prev_slot(const struct elphel_ahci_priv *dpriv);
static size_t get_prev_slot(const struct elphel_ahci_priv *dpriv);
int is_cmdq_empty(const struct elphel_ahci_priv *dpriv);
static int is_cmdq_empty(const struct elphel_ahci_priv *dpriv);
void process_queue(unsigned long data);
void process_queue(unsigned long data);
static void set_flag(struct elphel_ahci_priv *drpiv, uint32_t flag);
static void reset_flag(struct elphel_ahci_priv *dpriv, uint32_t flag);
/* debug functions */
/* debug functions */
static int check_chunks(struct fvec *vects);
static int check_chunks(struct fvec *vects);
static void dump_sg_list(const struct device *dev, const struct fvec *sgl, size_t elems);
static void dump_sg_list(const struct device *dev, const struct fvec *sgl, size_t elems);
@@ -139,7 +140,7 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance)
		dpriv->flags &= ~IRQ_SIMPLE;
		dpriv->flags &= ~IRQ_SIMPLE;
		irq_stat = readl(port_mmio + PORT_IRQ_STAT);
		irq_stat = readl(port_mmio + PORT_IRQ_STAT);


		dev_dbg(host->dev, "irq_stat = 0x%x, host irq_stat = 0x%x, time stamp: %u\n", irq_stat, host_irq_stat, get_rtc_usec());
		dev_dbg(host->dev, "irq_stat = 0x%x, host irq_stat = 0x%x\n", irq_stat, host_irq_stat);


		writel(irq_stat, port_mmio + PORT_IRQ_STAT);
		writel(irq_stat, port_mmio + PORT_IRQ_STAT);
		writel(host_irq_stat, hpriv->mmio + HOST_IRQ_STAT);
		writel(host_irq_stat, hpriv->mmio + HOST_IRQ_STAT);
@@ -407,6 +408,26 @@ static void elphel_qc_prep(struct ata_queued_cmd *qc)
			AHCI_CMD_TBL_AR_SZ, DMA_TO_DEVICE);
			AHCI_CMD_TBL_AR_SZ, DMA_TO_DEVICE);
}
}


/** Set flag @e flag in driver private structure. This function uses spin lock to access the flags variable. */
static void set_flag(struct elphel_ahci_priv *dpriv, uint32_t flag)
{
	unsigned long irq_flags;

	spin_lock_irqsave(&dpriv->flags_lock, irq_flags);
	dpriv->flags |= flag;
	spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags);
}

/** Reset flag @e flag in driver private structure. This function uses spin lock to access the flags variable. */
static void reset_flag(struct elphel_ahci_priv *dpriv, uint32_t flag)
{
	unsigned long irq_flags;

	spin_lock_irqsave(&dpriv->flags_lock, irq_flags);
	dpriv->flags &= ~flag;
	spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags);
}

/** Map buffer vectors to S/G list and return the number of vectors mapped */
/** Map buffer vectors to S/G list and return the number of vectors mapped */
static int map_vectors(struct elphel_ahci_priv *dpriv)
static int map_vectors(struct elphel_ahci_priv *dpriv)
{
{
@@ -976,13 +997,13 @@ static void finish_rec(struct elphel_ahci_priv *dpriv)
	process_cmd(dpriv);
	process_cmd(dpriv);
}
}


/** Move a pointer to free command slot one step forward */
/** Move a pointer to free command slot one step forward. This function holds spin lock #elphel_ahci_priv::flags_lock */
int move_tail(struct elphel_ahci_priv *dpriv)
static int move_tail(struct elphel_ahci_priv *dpriv)
{
{
	size_t slot = (dpriv->tail_ptr + 1) % MAX_CMD_SLOTS;
	size_t slot = (dpriv->tail_ptr + 1) % MAX_CMD_SLOTS;


	if (slot != dpriv->head_ptr) {
	if (slot != dpriv->head_ptr) {
		dpriv->flags |= LOCK_TAIL;
		set_flag(dpriv, LOCK_TAIL);
		dpriv->tail_ptr = slot;
		dpriv->tail_ptr = slot;
		dev_dbg(dpriv->dev, "move tail pointer to slot: %u\n", slot);
		dev_dbg(dpriv->dev, "move tail pointer to slot: %u\n", slot);
		return 0;
		return 0;
@@ -992,18 +1013,21 @@ int move_tail(struct elphel_ahci_priv *dpriv)
	}
	}
}
}


/** Move a pointer to next ready command */
/** Move a pointer to next ready command. This function holds spin lock #elphel_ahci_priv::flags_lock*/
int move_head(struct elphel_ahci_priv *dpriv)
static int move_head(struct elphel_ahci_priv *dpriv)
{
{
	size_t use_tail;
	size_t use_tail;
	unsigned long irq_flags;
	size_t slot = (dpriv->head_ptr + 1) % MAX_CMD_SLOTS;
	size_t slot = (dpriv->head_ptr + 1) % MAX_CMD_SLOTS;


	spin_lock_irqsave(&dpriv->flags_lock, irq_flags);
	if (dpriv->flags & LOCK_TAIL) {
	if (dpriv->flags & LOCK_TAIL) {
		/* current command slot is not ready yet, use previous */
		/* current command slot is not ready yet, use previous */
		use_tail = get_prev_slot(dpriv);
		use_tail = get_prev_slot(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;
@@ -1017,7 +1041,7 @@ int move_head(struct elphel_ahci_priv *dpriv)
}
}


/** Check if command queue is empty */
/** Check if command queue is empty */
int is_cmdq_empty(const struct elphel_ahci_priv *dpriv)
static int is_cmdq_empty(const struct elphel_ahci_priv *dpriv)
{
{
	size_t use_tail;
	size_t use_tail;


@@ -1034,7 +1058,7 @@ int is_cmdq_empty(const struct elphel_ahci_priv *dpriv)
}
}


/** Get command slot before the last one filled in */
/** Get command slot before the last one filled in */
size_t get_prev_slot(const struct elphel_ahci_priv *dpriv)
static size_t get_prev_slot(const struct elphel_ahci_priv *dpriv)
{
{
	size_t slot;
	size_t slot;


@@ -1089,13 +1113,13 @@ static ssize_t rawdev_write(struct device *dev, ///< device structure associate


	if (move_tail(dpriv) == -1) {
	if (move_tail(dpriv) == -1) {
		/* we are not ready yet because command queue is full */
		/* we are not ready yet because command queue is full */
		printk_ratelimited(KERN_DEBUG "command queue is full\n");
		printk_ratelimited(KERN_DEBUG "command queue is full, flags = %u, proceed = %d\n", dpriv->flags, proceed);
		return -EAGAIN;
		return -EAGAIN;
	}
	}
	chunks = dpriv->data_chunks[dpriv->tail_ptr];
	chunks = dpriv->data_chunks[dpriv->tail_ptr];
	buffs = &dpriv->fbuffs[dpriv->tail_ptr];
	buffs = &dpriv->fbuffs[dpriv->tail_ptr];


	dev_dbg(dev, "process frame from sensor port: %u, command = %d\n", fdata.sensor_port, fdata.cmd);
	dev_dbg(dev, "process frame from sensor port: %u, command = %d, flags = %u\n", fdata.sensor_port, fdata.cmd, dpriv->flags);
	if (fdata.cmd & DRV_CMD_EXIF) {
	if (fdata.cmd & DRV_CMD_EXIF) {
		rcvd = exif_get_data(fdata.sensor_port, fdata.meta_index, buffs->exif_buff.iov_base, buffs->exif_buff.iov_len);
		rcvd = exif_get_data(fdata.sensor_port, fdata.meta_index, buffs->exif_buff.iov_base, buffs->exif_buff.iov_len);
		chunks[CHUNK_EXIF].iov_len = rcvd;
		chunks[CHUNK_EXIF].iov_len = rcvd;
@@ -1135,7 +1159,7 @@ static ssize_t rawdev_write(struct device *dev, ///< device structure associate
	}
	}
	align_frame(dpriv);
	align_frame(dpriv);
	/* new command slot is ready now and can be unlocked */
	/* new command slot is ready now and can be unlocked */
	dpriv->flags &= ~LOCK_TAIL;
	reset_flag(dpriv, LOCK_TAIL);


	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 */