Loading src/drivers/ata/ahci_elphel.c +37 −6 Original line number Diff line number Diff line Loading @@ -159,7 +159,7 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) return handled; } /** Command queue processing tasklet */ void process_queue(unsigned long data) { unsigned long irq_flags; Loading Loading @@ -474,6 +474,7 @@ static int map_vectors(struct elphel_ahci_priv *dpriv) return index; } /** Split buffer pointed by vector @e vect into several smaller buffer. Each part will be less than #MAX_PRDT_LEN bytes */ static inline void vectsplit(struct fvec *vect, struct fvec *parts, size_t *n_elem) { size_t len; Loading @@ -489,6 +490,8 @@ static inline void vectsplit(struct fvec *vect, struct fvec *parts, size_t *n_el *n_elem = *n_elem + 1; } } /** Copy @e len bytes from buffer pointed by @e src vector to buffer pointed by @e dest vector */ static inline void vectcpy(struct fvec *dest, void *src, size_t len) { unsigned char *d = (unsigned char *)dest->iov_base; Loading @@ -496,6 +499,8 @@ static inline void vectcpy(struct fvec *dest, void *src, size_t len) memcpy(d + dest->iov_len, src, len); dest->iov_len += len; } /** Move vector forward by @e len bytes decreasing its length */ static inline void vectmov(struct fvec *vec, size_t len) { if (vec->iov_len >= len) { Loading @@ -504,12 +509,16 @@ static inline void vectmov(struct fvec *vec, size_t len) vec->iov_len -= len; } } /** Shrink vector length by @len bytes */ static inline void vectshrink(struct fvec *vec, size_t len) { if (vec->iov_len >= len) { vec->iov_len -= len; } } /** Return the number of bytes needed to align @e data_len to @e align_len boundary */ static inline size_t align_bytes_num(size_t data_len, size_t align_len) { size_t rem = data_len % align_len; Loading @@ -518,12 +527,15 @@ static inline size_t align_bytes_num(size_t data_len, size_t align_len) else return align_len - rem; } /** This helper function is used to position a pointer @e offset bytes from the end * of a buffer. DMA handle is not updated intentionally as it is not needed during copying */ static inline unsigned char *vectrpos(struct fvec *vec, size_t offset) { return (unsigned char *)vec->iov_base + (vec->iov_len - offset); } /** Align current frame to disk sector boundary and each individual buffer to #ALIGNMENT_SIZE boundary */ static void align_frame(struct elphel_ahci_priv *dpriv) { unsigned char *src; Loading Loading @@ -784,6 +796,7 @@ static void init_vectors(struct frame_buffers *buffs, struct fvec *chunks) chunks[CHUNK_COMMON].iov_len = 0; } /** Allocate memory for frame buffers */ static int init_buffers(struct device *dev, struct frame_buffers *buffs) { int mult; Loading Loading @@ -846,6 +859,7 @@ err_header: return -ENOMEM; } /** Free allocated frame buffers */ static void deinit_buffers(struct device *dev, struct frame_buffers *buffs) { kfree(buffs->jpheader_buff.iov_base); Loading @@ -856,6 +870,7 @@ static void deinit_buffers(struct device *dev, struct frame_buffers *buffs) kfree(buffs->rem_buff.iov_base); } /** Discard buffer pointers which makes the command slot marked as empty */ static inline void reset_chunks(struct fvec *vects, int all) { int i; Loading @@ -869,6 +884,7 @@ static inline void reset_chunks(struct fvec *vects, int all) } } /** Get driver private structure from pointer to device structure */ static inline struct elphel_ahci_priv *dev_get_dpriv(struct device *dev) { struct ata_host *host = dev_get_drvdata(dev); Loading Loading @@ -916,6 +932,7 @@ static int process_cmd(struct elphel_ahci_priv *dpriv) return dpriv->sg_elems; } /** Finish currently running command */ static void finish_cmd(struct elphel_ahci_priv *dpriv) { int all; Loading @@ -935,7 +952,7 @@ static void finish_cmd(struct elphel_ahci_priv *dpriv) dpriv->flags &= ~PROC_CMD; } /** Fill free space in REM buffer with 0 and save the reaming data chunk */ /** Fill free space in REM buffer with 0 and save the remaining data chunk */ static void finish_rec(struct elphel_ahci_priv *dpriv) { size_t stuff_len; Loading @@ -959,6 +976,7 @@ static void finish_rec(struct elphel_ahci_priv *dpriv) process_cmd(dpriv); } /** Move a pointer to free command slot one step forward */ int move_tail(struct elphel_ahci_priv *dpriv) { size_t slot = (dpriv->tail_ptr + 1) % MAX_CMD_SLOTS; Loading @@ -974,6 +992,7 @@ int move_tail(struct elphel_ahci_priv *dpriv) } } /** Move a pointer to next ready command */ int move_head(struct elphel_ahci_priv *dpriv) { size_t use_tail; Loading @@ -997,6 +1016,7 @@ int move_head(struct elphel_ahci_priv *dpriv) } /** Check if command queue is empty */ int is_cmdq_empty(const struct elphel_ahci_priv *dpriv) { size_t use_tail; Loading @@ -1013,6 +1033,7 @@ int is_cmdq_empty(const struct elphel_ahci_priv *dpriv) return 1; } /** Get command slot before the last one filled in */ size_t get_prev_slot(const struct elphel_ahci_priv *dpriv) { size_t slot; Loading @@ -1028,10 +1049,11 @@ size_t get_prev_slot(const struct elphel_ahci_priv *dpriv) return slot; } static ssize_t rawdev_write(struct device *dev, ///< struct device_attribute *attr, ///< const char *buff, ///< size_t buff_sz) ///< /** Get and enqueue new command */ static ssize_t rawdev_write(struct device *dev, ///< device structure associated with the driver struct device_attribute *attr, ///< interface for device attributes const char *buff, ///< buffer containing new command size_t buff_sz) ///< the size of the command buffer { ssize_t rcvd = 0; bool proceed = false; Loading Loading @@ -1249,6 +1271,7 @@ static void elphel_cmd_issue(struct ata_port *ap,///< device port for which the writel(1 << slot_num, port_mmio + PORT_CMD_ISSUE); } /** Defer system command if internal command queue is not empty */ static int elphel_qc_defer(struct ata_queued_cmd *qc) { int ret; Loading @@ -1272,6 +1295,7 @@ static int elphel_qc_defer(struct ata_queued_cmd *qc) return ret; } /** Return the stating position of disk buffer (in LBA) */ static ssize_t lba_start_read(struct device *dev, struct device_attribute *attr, char *buff) { struct ata_host *host = dev_get_drvdata(dev); Loading @@ -1281,6 +1305,7 @@ static ssize_t lba_start_read(struct device *dev, struct device_attribute *attr, return snprintf(buff, 20, "%llu\n", dpriv->lba_ptr.lba_start); } /** Set the starting position of disk buffer (in LBA) */ static ssize_t lba_start_write(struct device *dev, struct device_attribute *attr, const char *buff, size_t buff_sz) { struct ata_host *host = dev_get_drvdata(dev); Loading @@ -1296,6 +1321,7 @@ static ssize_t lba_start_write(struct device *dev, struct device_attribute *attr return buff_sz; } /** Return the ending position of disk buffer (in LBA) */ static ssize_t lba_end_read(struct device *dev, struct device_attribute *attr, char *buff) { struct ata_host *host = dev_get_drvdata(dev); Loading @@ -1305,6 +1331,7 @@ static ssize_t lba_end_read(struct device *dev, struct device_attribute *attr, c return snprintf(buff, 20, "%llu\n", dpriv->lba_ptr.lba_end); } /** Set the ending position of disk buffer (in LBA) */ static ssize_t lba_end_write(struct device *dev, struct device_attribute *attr, const char *buff, size_t buff_sz) { struct ata_host *host = dev_get_drvdata(dev); Loading @@ -1320,6 +1347,7 @@ static ssize_t lba_end_write(struct device *dev, struct device_attribute *attr, return buff_sz; } /** Return the current position of write pointer (in LBA) */ static ssize_t lba_current_read(struct device *dev, struct device_attribute *attr, char *buff) { struct ata_host *host = dev_get_drvdata(dev); Loading @@ -1329,6 +1357,7 @@ static ssize_t lba_current_read(struct device *dev, struct device_attribute *att return snprintf(buff, 20, "%llu\n", dpriv->lba_ptr.lba_write); } /** Set the current position of write pointer (in LBA) */ static ssize_t lba_current_write(struct device *dev, struct device_attribute *attr, const char *buff, size_t buff_sz) { struct ata_host *host = dev_get_drvdata(dev); Loading Loading @@ -1400,6 +1429,7 @@ static struct platform_driver ahci_elphel_driver = { }; module_platform_driver(ahci_elphel_driver); /** Debug function, checks frame alignment */ static int check_chunks(struct fvec *vects) { int i; Loading @@ -1423,6 +1453,7 @@ static int check_chunks(struct fvec *vects) return ret; } /** Debug function, prints the S/G list of current command */ static void dump_sg_list(const struct device *dev, const struct fvec *sgl, size_t elems) { int i; Loading src/drivers/ata/ahci_elphel.h +59 −74 Original line number Diff line number Diff line Loading @@ -25,56 +25,36 @@ #ifndef _AHCI_ELPHEL_EXT #define _AHCI_ELPHEL_EXT /** Flag indicating that IRQ corresponds to internal command and should not be * processed in ahci_handle_port_interrupt */ #define IRQ_SIMPLE (1 << 0) /** Flag indicating that disk is currently busy. Access to this flag should be protected by * spin locks to prevent race conditions */ #define DISK_BUSY (1 << 1) /** Processing driver's internal command is in progress */ #define PROC_CMD (1 << 2) /** Flag indicating that the remaining chunk of data will be recorded */ #define LAST_BLOCK (1 << 3) /** Flag indicating that recording should be stopped right after the last chunk of data * is written */ #define DELAYED_FINISH (1 << 4) #define LOCK_TAIL (1 << 5) /** The length of a command FIS in double words */ #define CMD_FIS_LEN 5 /** This is used to get 28-bit address from 64-bit value */ #define ADDR_MASK_28_BIT ((u64)0xfffffff) /** A maximum of length of 4MB may exist for PRDT entry */ #define MAX_PRDT_LEN 0x3fffff /** An array or JPEG frame chunks contains pointers to JPEG leading marker, * JPEG header, Exif data if present, stuffing bytes chunk which aligns * the frame size to disk sector boundary, JPEG data which * can be split into two chunks, their corresponding align buffers, JPEG * trailing marker, and pointer to a buffer containing the remainder of a * frame. Ten chunks of data in total. * @todo Fix description */ #define MAX_DATA_CHUNKS 9 /** Default port number */ #define DEFAULT_PORT_NUM 0 /** Align buffers length to this amount of bytes */ #define ALIGNMENT_SIZE 32 /** Maximum number of entries in PRDT table. HW max is 64k. * Set this value the same as AHCI_MAX_SG in ahci.h */ #define MAX_SGL_LEN 168 /** Maximum number of frames which will be processed at the same time */ #define MAX_CMD_SLOTS 4 /** Maximum number of sectors for READ DMA or WRITE DMA commands */ #define MAX_LBA_COUNT 0xff /** Maximum number of sectors for READ DMA EXT or WRITE_DMA EXT commands */ #define MAX_LBA_COUNT_EXT 0xffff /** Physical disk block size */ #define PHY_BLOCK_SIZE 512 #define JPEG_MARKER_LEN 2 /** The size in bytes of JPEG marker length field */ #define JPEG_SIZE_LEN 2 /** Include REM buffer to total size calculation */ #define INCLUDE_REM 1 /** Exclude REM buffer from total size calculation */ #define EXCLUDE_REM 0 #define IRQ_SIMPLE (1 << 0) ///< Flag indicating that IRQ corresponds to internal command and should not be ///< processed in ahci_handle_port_interrupt #define DISK_BUSY (1 << 1) ///< Flag indicating that disk is currently busy. Access to this flag should be protected by ///< spin locks to prevent race conditions #define PROC_CMD (1 << 2) ///< Processing driver's internal command is in progress #define LAST_BLOCK (1 << 3) ///< Flag indicating that the remaining chunk of data will be recorded #define DELAYED_FINISH (1 << 4) ///< Flag indicating that recording should be stopped right after the last chunk of data is written #define LOCK_TAIL (1 << 5) ///< Lock current command slot until all data buffers are assigned and the frame is aligned #define CMD_FIS_LEN 5 ///< The length of a command FIS in double words #define ADDR_MASK_28_BIT ((u64)0xfffffff)///< This is used to get 28-bit address from 64-bit value #define MAX_PRDT_LEN 0x3fffff ///< A maximum of length of 4MB may exist for PRDT entry #define MAX_DATA_CHUNKS 9 ///< An array or JPEG frame chunks contains pointers to JPEG leading marker, ///< JPEG header, Exif data if present, stuffing bytes chunk which aligns ///< the frame size to disk sector boundary, JPEG data which ///< can be split into two chunks, align buffers, JPEG ///< trailing marker, and pointer to a buffer containing the remainder of a ///< frame. Nine chunks of data in total. #define DEFAULT_PORT_NUM 0 ///< Default port number #define ALIGNMENT_SIZE 32 ///< Align buffers length to this amount of bytes #define MAX_SGL_LEN 168 ///< Maximum number of entries in PRDT table. HW max is 64k. ///< Set this value the same as AHCI_MAX_SG in ahci.h #define MAX_CMD_SLOTS 4 ///< Maximum number of frames which will be processed at the same time #define MAX_LBA_COUNT 0xff ///< Maximum number of sectors for READ DMA or WRITE DMA commands #define MAX_LBA_COUNT_EXT 0xffff ///< Maximum number of sectors for READ DMA EXT or WRITE_DMA EXT commands #define PHY_BLOCK_SIZE 512 ///< Physical disk block size #define JPEG_MARKER_LEN 2 ///< The size in bytes of JPEG marker #define JPEG_SIZE_LEN 2 ///< The size in bytes of JPEG marker length field #define INCLUDE_REM 1 ///< Include REM buffer to total size calculation #define EXCLUDE_REM 0 ///< Exclude REM buffer from total size calculation /** This structure holds raw device buffer pointers */ struct drv_pointers { Loading @@ -84,38 +64,43 @@ struct drv_pointers { uint16_t wr_count; ///< the number of LBA to write next time }; /** Container structure for frame buffers */ struct frame_buffers { struct fvec exif_buff; struct fvec jpheader_buff; struct fvec trailer_buff; struct fvec common_buff; struct fvec exif_buff; ///< Exif buffer struct fvec jpheader_buff; ///< JPEG header buffer struct fvec trailer_buff; ///< buffer for trailing marker struct fvec common_buff; ///< common buffer where other parts are combined struct fvec rem_buff; ///< remainder from previous frame }; /** Symbolic names for slots in buffer pointers. Buffer alignment function relies on the order of these names, so * new names can be added but the overall order should not be changed */ enum { CHUNK_LEADER, CHUNK_EXIF, CHUNK_HEADER, CHUNK_COMMON, CHUNK_DATA_0, CHUNK_DATA_1, CHUNK_TRAILER, CHUNK_ALIGN, CHUNK_REM CHUNK_LEADER, ///< pointer to JPEG leading marker CHUNK_EXIF, ///< pointer to Exif buffer CHUNK_HEADER, ///< pointer to JPEG header data excluding leading marker CHUNK_COMMON, ///< pointer to common buffer CHUNK_DATA_0, ///< pointer to JPEG data CHUNK_DATA_1, ///< pointer to the second half of JPEG data if a frame crosses circbuf boundary CHUNK_TRAILER, ///< pointer to JPEG trailing marker CHUNK_ALIGN, ///< pointer to buffer where the second part of JPEG data should be aligned CHUNK_REM ///< pointer to buffer containing the remainder of current frame. It will be recorded during next transaction }; /** AHCI driver private structure */ struct elphel_ahci_priv { u32 clb_offs; u32 fb_offs; u32 base_addr; u32 flags; int curr_cmd; size_t max_data_sz; struct drv_pointers lba_ptr; struct frame_buffers fbuffs[MAX_CMD_SLOTS]; struct fvec data_chunks[MAX_CMD_SLOTS][MAX_DATA_CHUNKS]; struct fvec sgl[MAX_SGL_LEN]; int sg_elems; u32 clb_offs; ///< CLB offset, received from device tree u32 fb_offs; ///< FB offset, received from device tree u32 base_addr; ///< controller base address u32 flags; ///< flags indicating current state of the driver. Access to #DISK_BUSY flags is protected with ///< a spin lock int curr_cmd; ///< current ATA command size_t max_data_sz; ///< maximum data size (in bytes) which can be processed with current ATA command struct drv_pointers lba_ptr; ///< disk buffer pointers struct frame_buffers fbuffs[MAX_CMD_SLOTS]; ///< a set of buffers for each command struct fvec data_chunks[MAX_CMD_SLOTS][MAX_DATA_CHUNKS];///< a set of vectors pointing to data buffers for each command struct fvec sgl[MAX_SGL_LEN]; ///< an array of data buffers mapped for next transaction int sg_elems; ///< the number of S/G vectors mapped for next transaction in @e sgl array int curr_data_chunk; ///< index of a data chunk used during last transaction size_t curr_data_offset; ///< offset of the last byte in a data chunk pointed to by @e curr_data_chunk size_t head_ptr; ///< pointer to command slot which will be written next Loading Loading
src/drivers/ata/ahci_elphel.c +37 −6 Original line number Diff line number Diff line Loading @@ -159,7 +159,7 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) return handled; } /** Command queue processing tasklet */ void process_queue(unsigned long data) { unsigned long irq_flags; Loading Loading @@ -474,6 +474,7 @@ static int map_vectors(struct elphel_ahci_priv *dpriv) return index; } /** Split buffer pointed by vector @e vect into several smaller buffer. Each part will be less than #MAX_PRDT_LEN bytes */ static inline void vectsplit(struct fvec *vect, struct fvec *parts, size_t *n_elem) { size_t len; Loading @@ -489,6 +490,8 @@ static inline void vectsplit(struct fvec *vect, struct fvec *parts, size_t *n_el *n_elem = *n_elem + 1; } } /** Copy @e len bytes from buffer pointed by @e src vector to buffer pointed by @e dest vector */ static inline void vectcpy(struct fvec *dest, void *src, size_t len) { unsigned char *d = (unsigned char *)dest->iov_base; Loading @@ -496,6 +499,8 @@ static inline void vectcpy(struct fvec *dest, void *src, size_t len) memcpy(d + dest->iov_len, src, len); dest->iov_len += len; } /** Move vector forward by @e len bytes decreasing its length */ static inline void vectmov(struct fvec *vec, size_t len) { if (vec->iov_len >= len) { Loading @@ -504,12 +509,16 @@ static inline void vectmov(struct fvec *vec, size_t len) vec->iov_len -= len; } } /** Shrink vector length by @len bytes */ static inline void vectshrink(struct fvec *vec, size_t len) { if (vec->iov_len >= len) { vec->iov_len -= len; } } /** Return the number of bytes needed to align @e data_len to @e align_len boundary */ static inline size_t align_bytes_num(size_t data_len, size_t align_len) { size_t rem = data_len % align_len; Loading @@ -518,12 +527,15 @@ static inline size_t align_bytes_num(size_t data_len, size_t align_len) else return align_len - rem; } /** This helper function is used to position a pointer @e offset bytes from the end * of a buffer. DMA handle is not updated intentionally as it is not needed during copying */ static inline unsigned char *vectrpos(struct fvec *vec, size_t offset) { return (unsigned char *)vec->iov_base + (vec->iov_len - offset); } /** Align current frame to disk sector boundary and each individual buffer to #ALIGNMENT_SIZE boundary */ static void align_frame(struct elphel_ahci_priv *dpriv) { unsigned char *src; Loading Loading @@ -784,6 +796,7 @@ static void init_vectors(struct frame_buffers *buffs, struct fvec *chunks) chunks[CHUNK_COMMON].iov_len = 0; } /** Allocate memory for frame buffers */ static int init_buffers(struct device *dev, struct frame_buffers *buffs) { int mult; Loading Loading @@ -846,6 +859,7 @@ err_header: return -ENOMEM; } /** Free allocated frame buffers */ static void deinit_buffers(struct device *dev, struct frame_buffers *buffs) { kfree(buffs->jpheader_buff.iov_base); Loading @@ -856,6 +870,7 @@ static void deinit_buffers(struct device *dev, struct frame_buffers *buffs) kfree(buffs->rem_buff.iov_base); } /** Discard buffer pointers which makes the command slot marked as empty */ static inline void reset_chunks(struct fvec *vects, int all) { int i; Loading @@ -869,6 +884,7 @@ static inline void reset_chunks(struct fvec *vects, int all) } } /** Get driver private structure from pointer to device structure */ static inline struct elphel_ahci_priv *dev_get_dpriv(struct device *dev) { struct ata_host *host = dev_get_drvdata(dev); Loading Loading @@ -916,6 +932,7 @@ static int process_cmd(struct elphel_ahci_priv *dpriv) return dpriv->sg_elems; } /** Finish currently running command */ static void finish_cmd(struct elphel_ahci_priv *dpriv) { int all; Loading @@ -935,7 +952,7 @@ static void finish_cmd(struct elphel_ahci_priv *dpriv) dpriv->flags &= ~PROC_CMD; } /** Fill free space in REM buffer with 0 and save the reaming data chunk */ /** Fill free space in REM buffer with 0 and save the remaining data chunk */ static void finish_rec(struct elphel_ahci_priv *dpriv) { size_t stuff_len; Loading @@ -959,6 +976,7 @@ static void finish_rec(struct elphel_ahci_priv *dpriv) process_cmd(dpriv); } /** Move a pointer to free command slot one step forward */ int move_tail(struct elphel_ahci_priv *dpriv) { size_t slot = (dpriv->tail_ptr + 1) % MAX_CMD_SLOTS; Loading @@ -974,6 +992,7 @@ int move_tail(struct elphel_ahci_priv *dpriv) } } /** Move a pointer to next ready command */ int move_head(struct elphel_ahci_priv *dpriv) { size_t use_tail; Loading @@ -997,6 +1016,7 @@ int move_head(struct elphel_ahci_priv *dpriv) } /** Check if command queue is empty */ int is_cmdq_empty(const struct elphel_ahci_priv *dpriv) { size_t use_tail; Loading @@ -1013,6 +1033,7 @@ int is_cmdq_empty(const struct elphel_ahci_priv *dpriv) return 1; } /** Get command slot before the last one filled in */ size_t get_prev_slot(const struct elphel_ahci_priv *dpriv) { size_t slot; Loading @@ -1028,10 +1049,11 @@ size_t get_prev_slot(const struct elphel_ahci_priv *dpriv) return slot; } static ssize_t rawdev_write(struct device *dev, ///< struct device_attribute *attr, ///< const char *buff, ///< size_t buff_sz) ///< /** Get and enqueue new command */ static ssize_t rawdev_write(struct device *dev, ///< device structure associated with the driver struct device_attribute *attr, ///< interface for device attributes const char *buff, ///< buffer containing new command size_t buff_sz) ///< the size of the command buffer { ssize_t rcvd = 0; bool proceed = false; Loading Loading @@ -1249,6 +1271,7 @@ static void elphel_cmd_issue(struct ata_port *ap,///< device port for which the writel(1 << slot_num, port_mmio + PORT_CMD_ISSUE); } /** Defer system command if internal command queue is not empty */ static int elphel_qc_defer(struct ata_queued_cmd *qc) { int ret; Loading @@ -1272,6 +1295,7 @@ static int elphel_qc_defer(struct ata_queued_cmd *qc) return ret; } /** Return the stating position of disk buffer (in LBA) */ static ssize_t lba_start_read(struct device *dev, struct device_attribute *attr, char *buff) { struct ata_host *host = dev_get_drvdata(dev); Loading @@ -1281,6 +1305,7 @@ static ssize_t lba_start_read(struct device *dev, struct device_attribute *attr, return snprintf(buff, 20, "%llu\n", dpriv->lba_ptr.lba_start); } /** Set the starting position of disk buffer (in LBA) */ static ssize_t lba_start_write(struct device *dev, struct device_attribute *attr, const char *buff, size_t buff_sz) { struct ata_host *host = dev_get_drvdata(dev); Loading @@ -1296,6 +1321,7 @@ static ssize_t lba_start_write(struct device *dev, struct device_attribute *attr return buff_sz; } /** Return the ending position of disk buffer (in LBA) */ static ssize_t lba_end_read(struct device *dev, struct device_attribute *attr, char *buff) { struct ata_host *host = dev_get_drvdata(dev); Loading @@ -1305,6 +1331,7 @@ static ssize_t lba_end_read(struct device *dev, struct device_attribute *attr, c return snprintf(buff, 20, "%llu\n", dpriv->lba_ptr.lba_end); } /** Set the ending position of disk buffer (in LBA) */ static ssize_t lba_end_write(struct device *dev, struct device_attribute *attr, const char *buff, size_t buff_sz) { struct ata_host *host = dev_get_drvdata(dev); Loading @@ -1320,6 +1347,7 @@ static ssize_t lba_end_write(struct device *dev, struct device_attribute *attr, return buff_sz; } /** Return the current position of write pointer (in LBA) */ static ssize_t lba_current_read(struct device *dev, struct device_attribute *attr, char *buff) { struct ata_host *host = dev_get_drvdata(dev); Loading @@ -1329,6 +1357,7 @@ static ssize_t lba_current_read(struct device *dev, struct device_attribute *att return snprintf(buff, 20, "%llu\n", dpriv->lba_ptr.lba_write); } /** Set the current position of write pointer (in LBA) */ static ssize_t lba_current_write(struct device *dev, struct device_attribute *attr, const char *buff, size_t buff_sz) { struct ata_host *host = dev_get_drvdata(dev); Loading Loading @@ -1400,6 +1429,7 @@ static struct platform_driver ahci_elphel_driver = { }; module_platform_driver(ahci_elphel_driver); /** Debug function, checks frame alignment */ static int check_chunks(struct fvec *vects) { int i; Loading @@ -1423,6 +1453,7 @@ static int check_chunks(struct fvec *vects) return ret; } /** Debug function, prints the S/G list of current command */ static void dump_sg_list(const struct device *dev, const struct fvec *sgl, size_t elems) { int i; Loading
src/drivers/ata/ahci_elphel.h +59 −74 Original line number Diff line number Diff line Loading @@ -25,56 +25,36 @@ #ifndef _AHCI_ELPHEL_EXT #define _AHCI_ELPHEL_EXT /** Flag indicating that IRQ corresponds to internal command and should not be * processed in ahci_handle_port_interrupt */ #define IRQ_SIMPLE (1 << 0) /** Flag indicating that disk is currently busy. Access to this flag should be protected by * spin locks to prevent race conditions */ #define DISK_BUSY (1 << 1) /** Processing driver's internal command is in progress */ #define PROC_CMD (1 << 2) /** Flag indicating that the remaining chunk of data will be recorded */ #define LAST_BLOCK (1 << 3) /** Flag indicating that recording should be stopped right after the last chunk of data * is written */ #define DELAYED_FINISH (1 << 4) #define LOCK_TAIL (1 << 5) /** The length of a command FIS in double words */ #define CMD_FIS_LEN 5 /** This is used to get 28-bit address from 64-bit value */ #define ADDR_MASK_28_BIT ((u64)0xfffffff) /** A maximum of length of 4MB may exist for PRDT entry */ #define MAX_PRDT_LEN 0x3fffff /** An array or JPEG frame chunks contains pointers to JPEG leading marker, * JPEG header, Exif data if present, stuffing bytes chunk which aligns * the frame size to disk sector boundary, JPEG data which * can be split into two chunks, their corresponding align buffers, JPEG * trailing marker, and pointer to a buffer containing the remainder of a * frame. Ten chunks of data in total. * @todo Fix description */ #define MAX_DATA_CHUNKS 9 /** Default port number */ #define DEFAULT_PORT_NUM 0 /** Align buffers length to this amount of bytes */ #define ALIGNMENT_SIZE 32 /** Maximum number of entries in PRDT table. HW max is 64k. * Set this value the same as AHCI_MAX_SG in ahci.h */ #define MAX_SGL_LEN 168 /** Maximum number of frames which will be processed at the same time */ #define MAX_CMD_SLOTS 4 /** Maximum number of sectors for READ DMA or WRITE DMA commands */ #define MAX_LBA_COUNT 0xff /** Maximum number of sectors for READ DMA EXT or WRITE_DMA EXT commands */ #define MAX_LBA_COUNT_EXT 0xffff /** Physical disk block size */ #define PHY_BLOCK_SIZE 512 #define JPEG_MARKER_LEN 2 /** The size in bytes of JPEG marker length field */ #define JPEG_SIZE_LEN 2 /** Include REM buffer to total size calculation */ #define INCLUDE_REM 1 /** Exclude REM buffer from total size calculation */ #define EXCLUDE_REM 0 #define IRQ_SIMPLE (1 << 0) ///< Flag indicating that IRQ corresponds to internal command and should not be ///< processed in ahci_handle_port_interrupt #define DISK_BUSY (1 << 1) ///< Flag indicating that disk is currently busy. Access to this flag should be protected by ///< spin locks to prevent race conditions #define PROC_CMD (1 << 2) ///< Processing driver's internal command is in progress #define LAST_BLOCK (1 << 3) ///< Flag indicating that the remaining chunk of data will be recorded #define DELAYED_FINISH (1 << 4) ///< Flag indicating that recording should be stopped right after the last chunk of data is written #define LOCK_TAIL (1 << 5) ///< Lock current command slot until all data buffers are assigned and the frame is aligned #define CMD_FIS_LEN 5 ///< The length of a command FIS in double words #define ADDR_MASK_28_BIT ((u64)0xfffffff)///< This is used to get 28-bit address from 64-bit value #define MAX_PRDT_LEN 0x3fffff ///< A maximum of length of 4MB may exist for PRDT entry #define MAX_DATA_CHUNKS 9 ///< An array or JPEG frame chunks contains pointers to JPEG leading marker, ///< JPEG header, Exif data if present, stuffing bytes chunk which aligns ///< the frame size to disk sector boundary, JPEG data which ///< can be split into two chunks, align buffers, JPEG ///< trailing marker, and pointer to a buffer containing the remainder of a ///< frame. Nine chunks of data in total. #define DEFAULT_PORT_NUM 0 ///< Default port number #define ALIGNMENT_SIZE 32 ///< Align buffers length to this amount of bytes #define MAX_SGL_LEN 168 ///< Maximum number of entries in PRDT table. HW max is 64k. ///< Set this value the same as AHCI_MAX_SG in ahci.h #define MAX_CMD_SLOTS 4 ///< Maximum number of frames which will be processed at the same time #define MAX_LBA_COUNT 0xff ///< Maximum number of sectors for READ DMA or WRITE DMA commands #define MAX_LBA_COUNT_EXT 0xffff ///< Maximum number of sectors for READ DMA EXT or WRITE_DMA EXT commands #define PHY_BLOCK_SIZE 512 ///< Physical disk block size #define JPEG_MARKER_LEN 2 ///< The size in bytes of JPEG marker #define JPEG_SIZE_LEN 2 ///< The size in bytes of JPEG marker length field #define INCLUDE_REM 1 ///< Include REM buffer to total size calculation #define EXCLUDE_REM 0 ///< Exclude REM buffer from total size calculation /** This structure holds raw device buffer pointers */ struct drv_pointers { Loading @@ -84,38 +64,43 @@ struct drv_pointers { uint16_t wr_count; ///< the number of LBA to write next time }; /** Container structure for frame buffers */ struct frame_buffers { struct fvec exif_buff; struct fvec jpheader_buff; struct fvec trailer_buff; struct fvec common_buff; struct fvec exif_buff; ///< Exif buffer struct fvec jpheader_buff; ///< JPEG header buffer struct fvec trailer_buff; ///< buffer for trailing marker struct fvec common_buff; ///< common buffer where other parts are combined struct fvec rem_buff; ///< remainder from previous frame }; /** Symbolic names for slots in buffer pointers. Buffer alignment function relies on the order of these names, so * new names can be added but the overall order should not be changed */ enum { CHUNK_LEADER, CHUNK_EXIF, CHUNK_HEADER, CHUNK_COMMON, CHUNK_DATA_0, CHUNK_DATA_1, CHUNK_TRAILER, CHUNK_ALIGN, CHUNK_REM CHUNK_LEADER, ///< pointer to JPEG leading marker CHUNK_EXIF, ///< pointer to Exif buffer CHUNK_HEADER, ///< pointer to JPEG header data excluding leading marker CHUNK_COMMON, ///< pointer to common buffer CHUNK_DATA_0, ///< pointer to JPEG data CHUNK_DATA_1, ///< pointer to the second half of JPEG data if a frame crosses circbuf boundary CHUNK_TRAILER, ///< pointer to JPEG trailing marker CHUNK_ALIGN, ///< pointer to buffer where the second part of JPEG data should be aligned CHUNK_REM ///< pointer to buffer containing the remainder of current frame. It will be recorded during next transaction }; /** AHCI driver private structure */ struct elphel_ahci_priv { u32 clb_offs; u32 fb_offs; u32 base_addr; u32 flags; int curr_cmd; size_t max_data_sz; struct drv_pointers lba_ptr; struct frame_buffers fbuffs[MAX_CMD_SLOTS]; struct fvec data_chunks[MAX_CMD_SLOTS][MAX_DATA_CHUNKS]; struct fvec sgl[MAX_SGL_LEN]; int sg_elems; u32 clb_offs; ///< CLB offset, received from device tree u32 fb_offs; ///< FB offset, received from device tree u32 base_addr; ///< controller base address u32 flags; ///< flags indicating current state of the driver. Access to #DISK_BUSY flags is protected with ///< a spin lock int curr_cmd; ///< current ATA command size_t max_data_sz; ///< maximum data size (in bytes) which can be processed with current ATA command struct drv_pointers lba_ptr; ///< disk buffer pointers struct frame_buffers fbuffs[MAX_CMD_SLOTS]; ///< a set of buffers for each command struct fvec data_chunks[MAX_CMD_SLOTS][MAX_DATA_CHUNKS];///< a set of vectors pointing to data buffers for each command struct fvec sgl[MAX_SGL_LEN]; ///< an array of data buffers mapped for next transaction int sg_elems; ///< the number of S/G vectors mapped for next transaction in @e sgl array int curr_data_chunk; ///< index of a data chunk used during last transaction size_t curr_data_offset; ///< offset of the last byte in a data chunk pointed to by @e curr_data_chunk size_t head_ptr; ///< pointer to command slot which will be written next Loading