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
74d07703
Commit
74d07703
authored
Nov 23, 2016
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Plain Diff
merged with master (ahci-related)
parents
9f769f4c
363177f0
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
93 additions
and
3 deletions
+93
-3
ahci_elphel.c
src/drivers/ata/ahci_elphel.c
+76
-3
ahci_elphel.h
src/drivers/ata/ahci_elphel.h
+12
-0
x393_fpga_functions.c
src/drivers/elphel/x393_fpga_functions.c
+1
-0
ahci_cmd.h
src/include/uapi/elphel/ahci_cmd.h
+4
-0
No files found.
src/drivers/ata/ahci_elphel.c
View file @
74d07703
...
@@ -111,6 +111,36 @@ static int elphel_check_load(struct device *dev)
...
@@ -111,6 +111,36 @@ static int elphel_check_load(struct device *dev)
return
ret
;
return
ret
;
}
}
/** Calculate the difference between two time stamps and return it in microseconds */
static
unsigned
long
time_diff_usec
(
sec_usec_t
*
start_time
,
sec_usec_t
*
end_time
)
{
unsigned
long
time_us
;
const
unsigned
long
scale
=
1000000
;
if
(
start_time
->
sec
<=
end_time
->
sec
)
{
time_us
=
(
end_time
->
sec
-
start_time
->
sec
)
*
scale
;
}
else
{
// time counter has rolled over
time_us
=
(
ULONG_MAX
-
start_time
->
sec
+
end_time
->
sec
)
*
scale
;
}
if
(
start_time
->
usec
<=
end_time
->
usec
)
time_us
+=
end_time
->
usec
-
start_time
->
usec
;
else
time_us
+=
scale
-
start_time
->
usec
+
end_time
->
usec
;
return
time_us
;
}
/** Add new recording speed sample to the list of samples */
static
void
add_sample
(
unsigned
int
sample
,
struct
rec_stat
*
stat
)
{
stat
->
samples
[
stat
->
samples_ptr
]
=
sample
;
stat
->
samples_ptr
++
;
if
(
stat
->
samples_ptr
>=
SPEED_SAMPLES_NUM
)
{
stat
->
samples_ptr
=
0
;
}
}
static
irqreturn_t
elphel_irq_handler
(
int
irq
,
void
*
dev_instance
)
static
irqreturn_t
elphel_irq_handler
(
int
irq
,
void
*
dev_instance
)
{
{
unsigned
long
irq_flags
;
unsigned
long
irq_flags
;
...
@@ -154,9 +184,22 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance)
...
@@ -154,9 +184,22 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance)
/** Command queue processing tasklet */
/** Command queue processing tasklet */
void
process_queue
(
unsigned
long
data
)
void
process_queue
(
unsigned
long
data
)
{
{
int
i
;
size_t
total_sz
=
0
;
unsigned
long
irq_flags
;
unsigned
long
irq_flags
;
unsigned
long
time_usec
;
sec_usec_t
end_time
=
{
0
};
struct
elphel_ahci_priv
*
dpriv
=
(
struct
elphel_ahci_priv
*
)
data
;
struct
elphel_ahci_priv
*
dpriv
=
(
struct
elphel_ahci_priv
*
)
data
;
// calculate the speed this frame has been written with
get_fpga_rtc
(
&
end_time
);
time_usec
=
time_diff_usec
(
&
dpriv
->
stat
.
start_time
,
&
end_time
);
if
(
time_usec
!=
0
)
{
for
(
i
=
0
;
i
<
dpriv
->
sg_elems
;
i
++
)
total_sz
+=
dpriv
->
sgl
[
i
].
iov_len
;
add_sample
(
total_sz
/
time_usec
,
&
dpriv
->
stat
);
}
if
(
process_cmd
(
dpriv
)
==
0
)
{
if
(
process_cmd
(
dpriv
)
==
0
)
{
finish_cmd
(
dpriv
);
finish_cmd
(
dpriv
);
if
(
move_head
(
dpriv
)
!=
-
1
)
{
if
(
move_head
(
dpriv
)
!=
-
1
)
{
...
@@ -919,6 +962,8 @@ static int process_cmd(struct elphel_ahci_priv *dpriv)
...
@@ -919,6 +962,8 @@ static int process_cmd(struct elphel_ahci_priv *dpriv)
size_t
max_sz
=
(
MAX_LBA_COUNT
+
1
)
*
PHY_BLOCK_SIZE
;
size_t
max_sz
=
(
MAX_LBA_COUNT
+
1
)
*
PHY_BLOCK_SIZE
;
size_t
rem_sz
=
get_size_from
(
dpriv
->
data_chunks
[
dpriv
->
head_ptr
],
dpriv
->
curr_data_chunk
,
dpriv
->
curr_data_offset
,
EXCLUDE_REM
);
size_t
rem_sz
=
get_size_from
(
dpriv
->
data_chunks
[
dpriv
->
head_ptr
],
dpriv
->
curr_data_chunk
,
dpriv
->
curr_data_offset
,
EXCLUDE_REM
);
get_fpga_rtc
(
&
dpriv
->
stat
.
start_time
);
if
(
dpriv
->
flags
&
PROC_CMD
)
if
(
dpriv
->
flags
&
PROC_CMD
)
dpriv
->
lba_ptr
.
lba_write
+=
dpriv
->
lba_ptr
.
wr_count
;
dpriv
->
lba_ptr
.
lba_write
+=
dpriv
->
lba_ptr
.
wr_count
;
dpriv
->
flags
|=
PROC_CMD
;
dpriv
->
flags
|=
PROC_CMD
;
...
@@ -1389,17 +1434,45 @@ static ssize_t lba_current_write(struct device *dev, struct device_attribute *at
...
@@ -1389,17 +1434,45 @@ static ssize_t lba_current_write(struct device *dev, struct device_attribute *at
return
buff_sz
;
return
buff_sz
;
}
}
/** Return the current disk write speed in MB/s */
static
ssize_t
wr_speed_read
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buff
)
{
int
i
;
unsigned
int
val
,
median
;
unsigned
int
*
l
,
*
r
;
unsigned
int
samples
[
SPEED_SAMPLES_NUM
];
struct
elphel_ahci_priv
*
dpriv
=
dev_get_dpriv
(
dev
);
// sort recording speed samples and get median
memcpy
(
samples
,
dpriv
->
stat
.
samples
,
SPEED_SAMPLES_NUM
*
sizeof
(
dpriv
->
stat
.
samples
[
0
]));
l
=
samples
;
for
(
i
=
1
;
i
<
SPEED_SAMPLES_NUM
;
i
++
)
{
val
=
samples
[
i
];
r
=
&
samples
[
i
-
1
];
while
(
r
>=
l
&&
*
r
>
val
)
{
*
(
r
+
1
)
=
*
r
;
r
--
;
}
*
(
r
+
1
)
=
val
;
}
median
=
samples
[
SPEED_SAMPLES_NUM
/
2
];
return
snprintf
(
buff
,
32
,
"Write speed: %u MB/s
\n
"
,
median
);
}
static
DEVICE_ATTR
(
load_module
,
S_IWUSR
|
S_IWGRP
,
NULL
,
set_load_flag
);
static
DEVICE_ATTR
(
load_module
,
S_IWUSR
|
S_IWGRP
,
NULL
,
set_load_flag
);
static
DEVICE_ATTR
(
SYSFS_AHCI_FNAME_WRITE
,
S_IWUSR
|
S_IWGRP
,
NULL
,
rawdev_write
);
static
DEVICE_ATTR
(
SYSFS_AHCI_FNAME_WRITE
,
S_IWUSR
|
S_IWGRP
,
NULL
,
rawdev_write
);
static
DEVICE_ATTR
(
SYSFS_AHCI_FNAME_START
,
S_IRUSR
|
S_IRGRP
|
S_IWUSR
|
S_IWGRP
,
lba_start_read
,
lba_start_write
);
static
DEVICE_ATTR
(
SYSFS_AHCI_FNAME_START
,
S_IRUSR
|
S_IRGRP
|
S_IROTH
|
S_IWUSR
|
S_IWGRP
,
lba_start_read
,
lba_start_write
);
static
DEVICE_ATTR
(
SYSFS_AHCI_FNAME_END
,
S_IRUSR
|
S_IRGRP
|
S_IWUSR
|
S_IWGRP
,
lba_end_read
,
lba_end_write
);
static
DEVICE_ATTR
(
SYSFS_AHCI_FNAME_END
,
S_IRUSR
|
S_IRGRP
|
S_IROTH
|
S_IWUSR
|
S_IWGRP
,
lba_end_read
,
lba_end_write
);
static
DEVICE_ATTR
(
SYSFS_AHCI_FNAME_CURR
,
S_IRUSR
|
S_IRGRP
|
S_IWUSR
|
S_IRGRP
,
lba_current_read
,
lba_current_write
);
static
DEVICE_ATTR
(
SYSFS_AHCI_FNAME_CURR
,
S_IRUSR
|
S_IRGRP
|
S_IROTH
|
S_IWUSR
|
S_IWGRP
,
lba_current_read
,
lba_current_write
);
static
DEVICE_ATTR
(
SYSFS_AHCI_FNAME_WRSPEED
,
S_IRUSR
|
S_IRGRP
|
S_IROTH
,
wr_speed_read
,
NULL
);
static
struct
attribute
*
root_dev_attrs
[]
=
{
static
struct
attribute
*
root_dev_attrs
[]
=
{
&
dev_attr_load_module
.
attr
,
&
dev_attr_load_module
.
attr
,
&
dev_attr_SYSFS_AHCI_FNAME_WRITE
.
attr
,
&
dev_attr_SYSFS_AHCI_FNAME_WRITE
.
attr
,
&
dev_attr_SYSFS_AHCI_FNAME_START
.
attr
,
&
dev_attr_SYSFS_AHCI_FNAME_START
.
attr
,
&
dev_attr_SYSFS_AHCI_FNAME_END
.
attr
,
&
dev_attr_SYSFS_AHCI_FNAME_END
.
attr
,
&
dev_attr_SYSFS_AHCI_FNAME_CURR
.
attr
,
&
dev_attr_SYSFS_AHCI_FNAME_CURR
.
attr
,
&
dev_attr_SYSFS_AHCI_FNAME_WRSPEED
.
attr
,
NULL
NULL
};
};
static
const
struct
attribute_group
dev_attr_root_group
=
{
static
const
struct
attribute_group
dev_attr_root_group
=
{
...
...
src/drivers/ata/ahci_elphel.h
View file @
74d07703
...
@@ -20,7 +20,9 @@
...
@@ -20,7 +20,9 @@
*/
*/
#include <uapi/elphel/ahci_cmd.h>
#include <uapi/elphel/ahci_cmd.h>
#include <uapi/elphel/c313a.h>
#include "../elphel/circbuf.h"
#include "../elphel/circbuf.h"
#include "../elphel/x393_fpga_functions.h"
#ifndef _AHCI_ELPHEL_EXT
#ifndef _AHCI_ELPHEL_EXT
#define _AHCI_ELPHEL_EXT
#define _AHCI_ELPHEL_EXT
...
@@ -55,6 +57,15 @@
...
@@ -55,6 +57,15 @@
#define JPEG_SIZE_LEN 2 ///< The size in bytes of JPEG marker length field
#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 INCLUDE_REM 1 ///< Include REM buffer to total size calculation
#define EXCLUDE_REM 0 ///< Exclude REM buffer from total size calculation
#define EXCLUDE_REM 0 ///< Exclude REM buffer from total size calculation
#define SPEED_SAMPLES_NUM 5 ///< Maximum number of samples for disk recording speed measurement
/** This structure is for collecting some recording statistics */
struct
rec_stat
{
unsigned
int
samples_ptr
;
///< pointer to next sample in rec_stat::samples
unsigned
int
samples
[
SPEED_SAMPLES_NUM
];
///< calculated recording speed samples, the value of recording speed
///< presented via sysfs is a median of this array
sec_usec_t
start_time
;
///< time when current command has been issued
};
/** This structure holds raw device buffer pointers */
/** This structure holds raw device buffer pointers */
struct
drv_pointers
{
struct
drv_pointers
{
...
@@ -111,6 +122,7 @@ struct elphel_ahci_priv {
...
@@ -111,6 +122,7 @@ struct elphel_ahci_priv {
///< because this flag is accessed from interrupt context
///< because this flag is accessed from interrupt context
struct
tasklet_struct
bh
;
///< command processing tasklet
struct
tasklet_struct
bh
;
///< command processing tasklet
struct
device
*
dev
;
///< pointer to parent device structure
struct
device
*
dev
;
///< pointer to parent device structure
struct
rec_stat
stat
;
///< recording statistics
};
};
#endif
/* _AHCI_ELPHEL_EXT */
#endif
/* _AHCI_ELPHEL_EXT */
src/drivers/elphel/x393_fpga_functions.c
View file @
74d07703
...
@@ -180,6 +180,7 @@ sec_usec_t * get_fpga_rtc(sec_usec_t * ts) ///< Pointer to a sec/usec structure
...
@@ -180,6 +180,7 @@ sec_usec_t * get_fpga_rtc(sec_usec_t * ts) ///< Pointer to a sec/usec structure
spin_unlock_bh
(
&
fpga_time_lock
);
spin_unlock_bh
(
&
fpga_time_lock
);
return
ts
;
return
ts
;
}
}
EXPORT_SYMBOL_GPL
(
get_fpga_rtc
);
/** Set FPGA RTC to specified time */
/** Set FPGA RTC to specified time */
int
set_fpga_rtc
(
sec_usec_t
ts
)
///< timestamp providing seconds and microseconds
int
set_fpga_rtc
(
sec_usec_t
ts
)
///< timestamp providing seconds and microseconds
...
...
src/include/uapi/elphel/ahci_cmd.h
View file @
74d07703
...
@@ -38,6 +38,8 @@
...
@@ -38,6 +38,8 @@
#define SYSFS_AHCI_FNAME_END lba_end
#define SYSFS_AHCI_FNAME_END lba_end
/** sysfs entry name, no double quotes. This macro is used to populate <em>struct attribute</em> in #ahci_elphel.c */
/** sysfs entry name, no double quotes. This macro is used to populate <em>struct attribute</em> in #ahci_elphel.c */
#define SYSFS_AHCI_FNAME_CURR lba_current
#define SYSFS_AHCI_FNAME_CURR lba_current
/** sysfs entry name, no double quotes. This macro is used to populate <em>struct attribute</em> in #ahci_elphel.c */
#define SYSFS_AHCI_FNAME_WRSPEED wr_speed
/** This file is used to send commands to AHCI driver from user space applications (camogm as for now). */
/** This file is used to send commands to AHCI driver from user space applications (camogm as for now). */
#define SYSFS_AHCI_WRITE SYSFS_AHCI_ENTRY NAME_TO_STR(SYSFS_AHCI_FNAME_WRITE)
#define SYSFS_AHCI_WRITE SYSFS_AHCI_ENTRY NAME_TO_STR(SYSFS_AHCI_FNAME_WRITE)
/** This file is used to control starting LBA of a disk buffer (R/W). */
/** This file is used to control starting LBA of a disk buffer (R/W). */
...
@@ -47,6 +49,8 @@
...
@@ -47,6 +49,8 @@
/** This file is used to control current LBA of a disk buffer (R/W). Use this file to set a pointer inside
/** This file is used to control current LBA of a disk buffer (R/W). Use this file to set a pointer inside
* [lba_start..lba_end] area where next write operation will begin. */
* [lba_start..lba_end] area where next write operation will begin. */
#define SYSFS_AHCI_LBA_CURRENT SYSFS_AHCI_ENTRY NAME_TO_STR(SYSFS_AHCI_FNAME_CURR)
#define SYSFS_AHCI_LBA_CURRENT SYSFS_AHCI_ENTRY NAME_TO_STR(SYSFS_AHCI_FNAME_CURR)
/** This file shows avarage write speed */
#define SYSFS_AHCI_WR_SPEED SYSFS_AHCI_ENTRY_NAME_TO_STR(SYSFS_AHCI_FNAME_WRSPEED)
struct
frame_data
{
struct
frame_data
{
unsigned
int
sensor_port
;
unsigned
int
sensor_port
;
...
...
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