Loading src/drivers/ata/ahci_elphel.c +40 −16 Original line number Original line Diff line number Diff line Loading @@ -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" /* /* Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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) { { Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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 */ Loading Loading
src/drivers/ata/ahci_elphel.c +40 −16 Original line number Original line Diff line number Diff line Loading @@ -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" /* /* Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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) { { Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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 */ Loading