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

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

parents bee02963 fa5d6aea
Loading
Loading
Loading
Loading
+76 −3
Original line number Original line Diff line number Diff line
@@ -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)
/** 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)
	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
	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 = {
+12 −0
Original line number Original line Diff line number Diff line
@@ -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 @@
#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 {
	                                             ///< 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 */
+1 −1
Original line number Original line Diff line number Diff line
@@ -1462,7 +1462,7 @@ void trigSlaveUpdate(int sensor_port) ///< sensor port number (0..3)
    while (common_pars->updated[sensor_port]) {
    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));
        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;
        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;
            updated_period = FRAMEPAIR_FORCE_PROC;
        }
        }
        pars_to_update[nupdate  ].num= P_TRIG_MASTER ;                  pars_to_update[nupdate++].val = common_pars->master_chn;
        pars_to_update[nupdate  ].num= P_TRIG_MASTER ;                  pars_to_update[nupdate++].val = common_pars->master_chn;
+11 −0
Original line number Original line Diff line number Diff line
@@ -1095,7 +1095,18 @@ int multisensor_pgm_detectsensor (int sensor_port, ///< sensor p
  x393_sensio_ctrl(sensio_ctl,sensor_port);
  x393_sensio_ctrl(sensio_ctl,sensor_port);
  camsync_mode.trig =     0;
  camsync_mode.trig =     0;
  camsync_mode.trig_set = 1;
  camsync_mode.trig_set = 1;

// Maybe it should be set to triggered mode first
  x393_camsync_mode (camsync_mode);
  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);
  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
  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
+2 −0
Original line number Original line Diff line number Diff line
@@ -169,6 +169,8 @@ const unsigned long param_depend_tab[]=
     P_SENSOR_PHASE,          ONCHANGE_SENSORPHASE | ONCHANGE_EXPOSURE | ONCHANGE_LIMITFPS | \
     P_SENSOR_PHASE,          ONCHANGE_SENSORPHASE | ONCHANGE_EXPOSURE | ONCHANGE_LIMITFPS | \
                              ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
                              ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
     P_FPGA_XTRA,             ONCHANGE_LIMITFPS ,
     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
     P_TRIG,                  ONCHANGE_RECALCSEQ | ONCHANGE_TRIGGERMODE | ONCHANGE_TRIGSEQ | ONCHANGE_LIMITFPS | /// Next to call with afterinit
                                   ONCHANGE_MULTISENS |
                                   ONCHANGE_MULTISENS |
                                   ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
                                   ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
Loading