Commit 2c9168ed authored by Oleg Dzhimiev's avatar Oleg Dzhimiev

Merge branch 'master' of https://github.com/Elphel/linux-elphel

parents bee02963 fa5d6aea
......@@ -111,6 +111,36 @@ static int elphel_check_load(struct device *dev)
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)
{
unsigned long irq_flags;
......@@ -154,9 +184,22 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance)
/** Command queue processing tasklet */
void process_queue(unsigned long data)
{
int i;
size_t total_sz = 0;
unsigned long irq_flags;
unsigned long time_usec;
sec_usec_t end_time = {0};
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) {
finish_cmd(dpriv);
if (move_head(dpriv) != -1) {
......@@ -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 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)
dpriv->lba_ptr.lba_write += dpriv->lba_ptr.wr_count;
dpriv->flags |= PROC_CMD;
......@@ -1389,17 +1434,45 @@ static ssize_t lba_current_write(struct device *dev, struct device_attribute *at
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(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_END, S_IRUSR | S_IRGRP | 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_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_IROTH | S_IWUSR | S_IWGRP, lba_end_read, lba_end_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[] = {
&dev_attr_load_module.attr,
&dev_attr_SYSFS_AHCI_FNAME_WRITE.attr,
&dev_attr_SYSFS_AHCI_FNAME_START.attr,
&dev_attr_SYSFS_AHCI_FNAME_END.attr,
&dev_attr_SYSFS_AHCI_FNAME_CURR.attr,
&dev_attr_SYSFS_AHCI_FNAME_WRSPEED.attr,
NULL
};
static const struct attribute_group dev_attr_root_group = {
......
......@@ -20,7 +20,9 @@
*/
#include <uapi/elphel/ahci_cmd.h>
#include <uapi/elphel/c313a.h>
#include "../elphel/circbuf.h"
#include "../elphel/x393_fpga_functions.h"
#ifndef _AHCI_ELPHEL_EXT
#define _AHCI_ELPHEL_EXT
......@@ -55,6 +57,15 @@
#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
#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 */
struct drv_pointers {
......@@ -111,6 +122,7 @@ struct elphel_ahci_priv {
///< because this flag is accessed from interrupt context
struct tasklet_struct bh; ///< command processing tasklet
struct device *dev; ///< pointer to parent device structure
struct rec_stat stat; ///< recording statistics
};
#endif /* _AHCI_ELPHEL_EXT */
......@@ -1462,7 +1462,7 @@ void trigSlaveUpdate(int sensor_port) ///< sensor port number (0..3)
while (common_pars->updated[sensor_port]) {
dev_dbg(g_devfp_ptr,"port= %d, thisFrameNumber[%d] = %d\n", sensor_port, sensor_port, (int) thisFrameNumber(sensor_port));
common_pars->updated[sensor_port] = 0;
if (pars_to_update[nupdate ].num != P_TRIG_PERIOD){ //???
if (pars_to_update[nupdate ].num != P_TRIG_PERIOD){ // updated any other parameter - treat as period is updated (make sure it will not trigger)
updated_period = FRAMEPAIR_FORCE_PROC;
}
pars_to_update[nupdate ].num= P_TRIG_MASTER ; pars_to_update[nupdate++].val = common_pars->master_chn;
......
......@@ -1095,7 +1095,18 @@ int multisensor_pgm_detectsensor (int sensor_port, ///< sensor p
x393_sensio_ctrl(sensio_ctl,sensor_port);
camsync_mode.trig = 0;
camsync_mode.trig_set = 1;
// Maybe it should be set to triggered mode first
x393_camsync_mode (camsync_mode);
// Trying with the sequencer
// X393_SEQ_SEND1 (sensor_port, frame16, x393_camsync_mode, camsync_mode);
// dev_dbg(g_dev_ptr,"{%d} X3X3_SEQ_SEND1(0x%x, 0x%x, x393_camsync_mode, 0x%x)\n",
// sensor_port, sensor_port, frame16, (int) camsync_mode.d32);
udelay (100);
GLOBALPARS(sensor_port,G_SENS_AVAIL) |= 1<< (GLOBALPARS(sensor_port,G_SENS_AVAIL)); // temporary to indicate sensor detection functions that they need to initialize multisensor registers
......
......@@ -169,6 +169,8 @@ const unsigned long param_depend_tab[]=
P_SENSOR_PHASE, ONCHANGE_SENSORPHASE | ONCHANGE_EXPOSURE | ONCHANGE_LIMITFPS | \
ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
P_FPGA_XTRA, ONCHANGE_LIMITFPS ,
//TODO NC393: Check - maybe no-need to stop/restart the compressor when changing trigger modes?
P_TRIG, ONCHANGE_RECALCSEQ | ONCHANGE_TRIGGERMODE | ONCHANGE_TRIGSEQ | ONCHANGE_LIMITFPS | /// Next to call with afterinit
ONCHANGE_MULTISENS |
ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
......
This diff is collapsed.
......@@ -41,7 +41,7 @@ unsigned long sensor_to_camsync(unsigned long pixel_time, unsigned long sensor_c
#define X393_SEQ_SEND1S(port,frame,func,data,subchn) {if ((frame) < 0) seqr_##func (0, (data), (port), (subchn)); \
else seqa_##func ((frame), (data), (port), (subchn)); }
/** Tells if parameter is modifies
/** Tells if parameter is modified
* @param x parameter index to test
* @return nonzero if modified */
#define FRAMEPAR_MODIFIED(x) (thispars->mod[(x) >> 5] & (1<<((x) & 0x1f)))
......
......@@ -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);
return ts;
}
EXPORT_SYMBOL_GPL(get_fpga_rtc);
/** Set FPGA RTC to specified time */
int set_fpga_rtc (sec_usec_t ts) ///< timestamp providing seconds and microseconds
......
......@@ -38,6 +38,8 @@
#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 */
#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). */
#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). */
......@@ -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
* [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)
/** This file shows avarage write speed */
#define SYSFS_AHCI_WR_SPEED SYSFS_AHCI_ENTRY_NAME_TO_STR(SYSFS_AHCI_FNAME_WRSPEED)
struct frame_data {
unsigned int sensor_port;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment