Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-elphel
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
linux-elphel
Commits
72aebf77
Commit
72aebf77
authored
Sep 10, 2016
by
Mikhail Karpenko
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add doxygen documentation
parent
5850bdf6
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
96 additions
and
80 deletions
+96
-80
ahci_elphel.c
src/drivers/ata/ahci_elphel.c
+37
-6
ahci_elphel.h
src/drivers/ata/ahci_elphel.h
+59
-74
No files found.
src/drivers/ata/ahci_elphel.c
View file @
72aebf77
...
...
@@ -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 re
am
ing data chunk */
/** Fill free space in REM buffer with 0 and save the re
main
ing 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
;
...
...
src/drivers/ata/ahci_elphel.h
View file @
72aebf77
...
...
@@ -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
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment