Commit 72aebf77 authored by Mikhail Karpenko's avatar Mikhail Karpenko
Browse files

Add doxygen documentation

parent 5850bdf6
Loading
Loading
Loading
Loading
+37 −6
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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) {
@@ -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;
@@ -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;
@@ -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;
@@ -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);
@@ -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;
@@ -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);
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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;
@@ -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;
+59 −74
Original line number Diff line number Diff line
@@ -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 {
@@ -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