Loading src/drivers/ata/ahci_elphel.c +76 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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; Loading Loading @@ -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 = { Loading src/drivers/ata/ahci_elphel.h +12 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 { Loading Loading @@ -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 */ src/drivers/elphel/framepars.c +1 −1 Original line number Diff line number Diff line Loading @@ -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; Loading src/drivers/elphel/multi10359.c +11 −0 Original line number Diff line number Diff line Loading @@ -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 Loading src/drivers/elphel/param_depend.h +2 −0 Original line number Diff line number Diff line Loading @@ -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 | \ Loading Loading
src/drivers/ata/ahci_elphel.c +76 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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; Loading Loading @@ -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 = { Loading
src/drivers/ata/ahci_elphel.h +12 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 { Loading Loading @@ -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 */
src/drivers/elphel/framepars.c +1 −1 Original line number Diff line number Diff line Loading @@ -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; Loading
src/drivers/elphel/multi10359.c +11 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
src/drivers/elphel/param_depend.h +2 −0 Original line number Diff line number Diff line Loading @@ -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 | \ Loading