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
c6cc89b0
Commit
c6cc89b0
authored
Aug 31, 2016
by
Mikhail Karpenko
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Split long PRDT enries
Each PRDT entry is limited to 4Mb and this was fixed. Tests look fine.
parent
33ec5861
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
56 additions
and
23 deletions
+56
-23
ahci_elphel.c
src/drivers/ata/ahci_elphel.c
+50
-22
ahci_elphel.h
src/drivers/ata/ahci_elphel.h
+6
-1
No files found.
src/drivers/ata/ahci_elphel.c
View file @
c6cc89b0
...
...
@@ -71,6 +71,8 @@ static void finish_cmd(struct device *dev, struct elphel_ahci_priv *dpriv);
static
int
process_cmd
(
struct
device
*
dev
,
struct
elphel_ahci_priv
*
dpriv
,
struct
ata_port
*
port
);
//static void start_cmd(struct device *dev, struct elphel_ahci_priv *dpriv, struct ata_port *port);
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
vectsplit
(
struct
fvec
*
vect
,
struct
fvec
*
parts
,
size_t
*
n_elem
);
static
ssize_t
set_load_flag
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buff
,
size_t
buff_sz
)
...
...
@@ -141,8 +143,8 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance)
writel
(
host_irq_stat
,
hpriv
->
mmio
+
HOST_IRQ_STAT
);
handled
=
IRQ_HANDLED
;
//
if (process_cmd(host->dev, dpriv, host->ports[0]) == 0)
//
finish_cmd(host->dev, dpriv);
if
(
process_cmd
(
host
->
dev
,
dpriv
,
host
->
ports
[
0
])
==
0
)
finish_cmd
(
host
->
dev
,
dpriv
);
}
else
{
/* pass handling to AHCI level */
handled
=
ahci_single_irq_intr
(
irq
,
dev_instance
);
...
...
@@ -256,7 +258,6 @@ static int elphel_drv_probe(struct platform_device *pdev)
ret
=
init_buffers
(
dev
,
&
dpriv
->
fbuffs
);
if
(
ret
!=
0
)
return
ret
;
// sg_init_table(dpriv->sgl, MAX_DATA_CHUNKS);
init_vectors
(
dpriv
);
match
=
of_match_device
(
ahci_elphel_of_match
,
&
pdev
->
dev
);
...
...
@@ -640,7 +641,7 @@ static int map_vectors(struct elphel_ahci_priv *dpriv)
vect
=
chunks
[
i
];
}
if
(
total_sz
>
dpriv
->
max_data_sz
)
{
/
/ truncate current buffer and finish mapping
/
* truncate current buffer and finish mapping */
tail
=
total_sz
-
dpriv
->
max_data_sz
;
vect
.
iov_len
-=
tail
;
dpriv
->
curr_data_chunk
=
i
;
...
...
@@ -652,7 +653,20 @@ static int map_vectors(struct elphel_ahci_priv *dpriv)
finish
=
1
;
}
if
(
vect
.
iov_len
!=
0
)
{
if
(
vect
.
iov_len
<
MAX_PRDT_LEN
)
{
dpriv
->
sgl
[
index
++
]
=
vect
;
}
else
{
/* current vector is too long and can not be mapped to a single PRDT entry, split it */
vectsplit
(
&
vect
,
dpriv
->
sgl
,
&
index
);
if
(
vect
.
iov_len
<
MAX_PRDT_LEN
)
{
dpriv
->
sgl
[
index
++
]
=
vect
;
}
else
{
/* free slots in PRDT table have ended */
dpriv
->
curr_data_chunk
=
i
;
dpriv
->
curr_data_offset
=
(
unsigned
char
*
)
vect
.
iov_base
-
(
unsigned
char
*
)
chunks
[
i
].
iov_base
;
finish
=
1
;
}
}
}
if
(
finish
)
break
;
...
...
@@ -666,6 +680,21 @@ static int map_vectors(struct elphel_ahci_priv *dpriv)
return
index
;
}
static
inline
void
vectsplit
(
struct
fvec
*
vect
,
struct
fvec
*
parts
,
size_t
*
n_elem
)
{
size_t
len
;
struct
fvec
split
;
while
(
vect
->
iov_len
>
MAX_PRDT_LEN
&&
*
n_elem
<
MAX_SGL_LEN
)
{
len
=
MAX_PRDT_LEN
-
MAX_PRDT_LEN
%
PHY_BLOCK_SIZE
;
split
.
iov_base
=
vect
->
iov_base
;
split
.
iov_dma
=
vect
->
iov_dma
;
split
.
iov_len
=
len
;
vectmov
(
vect
,
len
);
parts
[
*
n_elem
]
=
split
;
*
n_elem
=
*
n_elem
+
1
;
}
}
static
inline
void
vectcpy
(
struct
fvec
*
dest
,
void
*
src
,
size_t
len
)
{
unsigned
char
*
d
=
(
unsigned
char
*
)
dest
->
iov_base
;
...
...
@@ -1236,7 +1265,6 @@ static ssize_t rawdev_write(struct device *dev, ///<
if
((
dpriv
->
flags
&
PROC_CMD
)
||
dont_process
)
{
// we are not ready yet
printk
(
KERN_DEBUG
">>> not ready: flags = %u
\n
"
,
dpriv
->
flags
);
return
-
EAGAIN
;
}
...
...
@@ -1315,24 +1343,24 @@ static ssize_t rawdev_write(struct device *dev, ///<
for
(
i
=
0
;
i
<
MAX_DATA_CHUNKS
;
i
++
)
{
printk
(
KERN_DEBUG
">>>
\t
slot: %i; len: %u
\n
"
,
i
,
dpriv
->
data_chunks
[
i
].
iov_len
);
}
if
(
check_chunks
(
dpriv
->
data_chunks
)
!=
0
)
{
dont_process
=
1
;
return
-
EINVAL
;
}
//
if (check_chunks(dpriv->data_chunks) != 0) {
//
dont_process = 1;
//
return -EINVAL;
//
}
process_cmd
(
dev
,
dpriv
,
port
);
while
(
dpriv
->
flags
&
PROC_CMD
)
{
#ifndef DEBUG_DONT_WRITE
while
(
dpriv
->
flags
&
IRQ_SIMPLE
)
{
printk_once
(
KERN_DEBUG
">>> waiting for interrupt
\n
"
);
msleep_interruptible
(
1
);
}
#endif
printk
(
KERN_DEBUG
">>> proceeding to next cmd chunk
\n
"
);
sg_elems
=
process_cmd
(
dev
,
dpriv
,
port
);
if
(
sg_elems
==
0
)
finish_cmd
(
dev
,
dpriv
);
}
//
while (dpriv->flags & PROC_CMD) {
//
#ifndef DEBUG_DONT_WRITE
//
while (dpriv->flags & IRQ_SIMPLE) {
//
printk_once(KERN_DEBUG ">>> waiting for interrupt\n");
//
msleep_interruptible(1);
//
}
//
#endif
//
printk(KERN_DEBUG ">>> proceeding to next cmd chunk\n");
//
sg_elems = process_cmd(dev, dpriv, port);
//
if (sg_elems == 0)
//
finish_cmd(dev, dpriv);
//
}
// if (chunks[CHUNK_DATA_0].iov_len != 0)
// dma_unmap_single(dev, chunks[CHUNK_DATA_0].iov_dma, chunks[CHUNK_DATA_0].iov_len, DMA_TO_DEVICE);
// if (chunks[CHUNK_DATA_1].iov_len != 0)
...
...
src/drivers/ata/ahci_elphel.h
View file @
c6cc89b0
...
...
@@ -34,6 +34,8 @@
#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
...
...
@@ -46,6 +48,9 @@
#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
/** This structure holds raw device buffer pointers */
struct
drv_pointers
{
...
...
@@ -102,7 +107,7 @@ struct elphel_ahci_priv {
struct
drv_pointers
lba_ptr
;
struct
frame_buffers
fbuffs
;
struct
fvec
data_chunks
[
MAX_DATA_CHUNKS
];
struct
fvec
sgl
[
MAX_
DATA_CHUNKS
];
struct
fvec
sgl
[
MAX_
SGL_LEN
];
int
sg_elems
;
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
...
...
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