Kernel Driver: module timeout issue when switching streaming channels. caused due to waiting to a timeout on the previous channel. That

stream stopped thus the buffer never filled up. solved by aboting the waiting semaphore on channel switch
SMI: fixed low sample rate timeouts and a function for timeout calculation on read
Radio: FPGA soft reset on start caused faulty operation. needs investigation.
Radio: removed redundant sleeps
Various bug fixes.
pull/146/head
David Michaeli 2023-09-26 17:29:23 +00:00
rodzic 774f1862d1
commit a698dcf02a
7 zmienionych plików z 825 dodań i 789 usunięć

Wyświetl plik

@ -92,6 +92,10 @@ struct bcm2835_smi_dev_instance
wait_queue_head_t poll_event;
bool readable;
bool writeable;
bool reader_thread_running;
bool writer_thread_running;
bool reader_waiting_sema;
bool writer_waiting_sema;
};
@ -211,6 +215,12 @@ static void set_state(smi_stream_state_en state)
{
dev_info(inst->dev, "Set STREAMING_STATUS = %d, cur_addr = %d", state, inst->cur_address);
inst->address_changed = 1;
// abort the current timed out waiting on the current channel
if (inst->smi_inst != NULL && inst->reader_waiting_sema)
{
up(&inst->smi_inst->bounce.callback_sem);
}
}
inst->state = state;
@ -629,17 +639,14 @@ int reader_thread_stream_function(void *pv)
s64 t1, t2, t3;
dev_info(inst->dev, "Enterred reader thread");
inst->reader_thread_running = true;
while(!kthread_should_stop())
{
// check if the streaming state is on, if not, sleep and check again
if (inst->state != smi_stream_rx_channel_0 && inst->state != smi_stream_rx_channel_1)
{
//mutex_lock(&inst->read_lock);
//kfifo_reset(&inst->rx_fifo);
//mutex_unlock(&inst->read_lock);
msleep(5);
msleep(1);
continue;
}
@ -647,7 +654,7 @@ int reader_thread_stream_function(void *pv)
// sync smi address
if (inst->address_changed)
{
bcm2835_smi_set_address(inst->smi_inst, inst->cur_address);
bcm2835_smi_set_address(inst->smi_inst, inst->cur_address);
inst->address_changed = 0;
}
@ -657,7 +664,7 @@ int reader_thread_stream_function(void *pv)
count = stream_smi_user_dma(inst->smi_inst, DMA_DEV_TO_MEM, &bounce, current_dma_buffer);
if (count != DMA_BOUNCE_BUFFER_SIZE || bounce == NULL)
{
dev_err(inst->dev, "stream_smi_user_dma returned illegal count = %d", count);
dev_err(inst->dev, "stream_smi_user_dma returned illegal count = %d, buff_num = %d", count, current_dma_buffer);
spin_lock(&inst->smi_inst->transaction_lock);
dmaengine_terminate_sync(inst->smi_inst->dma_chan);
spin_unlock(&inst->smi_inst->transaction_lock);
@ -692,41 +699,31 @@ int reader_thread_stream_function(void *pv)
// timeout. This means that we didn't get enough data into the buffer during this period. we shall
// "continue" and try again
start = ktime_get();
while (1)
// wait for completion
inst->reader_waiting_sema = true;
if (down_timeout(&bounce->callback_sem, msecs_to_jiffies(1000)))
{
// wait for completion, but if not complete (timeout) - nevermind,
// try to wait more, unless someone tells us to stop
if (down_timeout(&bounce->callback_sem, msecs_to_jiffies(1000)))
{
dev_info(inst->dev, "Reader DMA bounce timed out");
spin_lock(&inst->smi_inst->transaction_lock);
dmaengine_terminate_sync(inst->smi_inst->dma_chan);
spin_unlock(&inst->smi_inst->transaction_lock);
}
else
{
//--------------------------------------------------------
// Switch the buffers
current_dma_buffer = 1-current_dma_buffer;
break;
}
// after each timeout check if we are still entitled to keep trying
// if not, shut down the DMA transaction and continue empty loop
if (inst->state != smi_stream_rx_channel_0 && inst->state != smi_stream_rx_channel_1)
{
spin_lock(&inst->smi_inst->transaction_lock);
dmaengine_terminate_sync(inst->smi_inst->dma_chan);
spin_unlock(&inst->smi_inst->transaction_lock);
break;
}
dev_info(inst->dev, "Reader DMA bounce timed out");
spin_lock(&inst->smi_inst->transaction_lock);
dmaengine_terminate_sync(inst->smi_inst->dma_chan);
spin_unlock(&inst->smi_inst->transaction_lock);
}
else
{
//--------------------------------------------------------
// Switch the buffers
current_dma_buffer = 1-current_dma_buffer;
}
inst->reader_waiting_sema = false;
t3 = ktime_to_ns(ktime_sub(ktime_get(), start));
//dev_info(inst->dev, "TIMING (1,2,3): %lld %lld %lld %d", (long long)t1, (long long)t2, (long long)t3, current_dma_buffer);
}
dev_info(inst->dev, "Left reader thread");
inst->reader_thread_running = false;
inst->reader_waiting_sema = false;
return 0;
}
@ -739,6 +736,7 @@ int writer_thread_stream_function(void *pv)
int num_bytes = 0;
int num_copied = 0;
dev_info(inst->dev, "Enterred writer thread");
inst->writer_thread_running = true;
while(!kthread_should_stop())
{
@ -752,7 +750,7 @@ int writer_thread_stream_function(void *pv)
// sync smi address
if (inst->address_changed)
{
bcm2835_smi_set_address(inst->smi_inst, inst->cur_address);
bcm2835_smi_set_address(inst->smi_inst, inst->cur_address);
inst->address_changed = 0;
}
@ -794,6 +792,7 @@ int writer_thread_stream_function(void *pv)
}
// Wait for current chunk to complete
inst->writer_waiting_sema = true;
if (down_timeout(&bounce->callback_sem, msecs_to_jiffies(1000)))
{
dev_err(inst->dev, "Writer DMA bounce timed out");
@ -801,6 +800,7 @@ int writer_thread_stream_function(void *pv)
dmaengine_terminate_sync(inst->smi_inst->dma_chan);
spin_unlock(&inst->smi_inst->transaction_lock);
}
inst->writer_waiting_sema = false;
}
else
{
@ -811,6 +811,8 @@ int writer_thread_stream_function(void *pv)
}
dev_info(inst->dev, "Left writer thread");
inst->writer_thread_running = false;
inst->writer_waiting_sema = false;
return 0;
}
@ -1191,6 +1193,10 @@ static int smi_stream_dev_probe(struct platform_device *pdev)
init_waitqueue_head(&inst->poll_event);
inst->readable = false;
inst->writeable = false;
inst->reader_thread_running = false;
inst->writer_thread_running = false;
inst->reader_waiting_sema = false;
inst->writer_waiting_sema = false;
mutex_init(&inst->read_lock);
mutex_init(&inst->write_lock);

Wyświetl plik

@ -184,26 +184,25 @@ int caribou_fpga_program_to_fpga(caribou_fpga_st* dev, unsigned char *buffer, si
while (prog_retries--)
{
if (caribou_prog_configure_from_buffer(&dev->prog_dev, buffer, len) == 0)
if (caribou_prog_configure_from_buffer(&dev->prog_dev, buffer, len) != 0)
{
continue;
}
//caribou_fpga_soft_reset(dev);
io_utils_usleep(100000);
caribou_fpga_get_status(dev, NULL);
if (dev->status == caribou_fpga_status_operational)
{
break;
}
}
}
if (prog_retries == 0)
{
ZF_LOGE("Programming failed");
return -1;
}
caribou_fpga_soft_reset(dev);
io_utils_usleep(100000);
caribou_fpga_get_status(dev, NULL);
if (dev->status == caribou_fpga_status_not_programmed)
{
ZF_LOGE("Programming failed");
return -1;
}
}
else
{

Wyświetl plik

@ -569,6 +569,7 @@ int caribou_smi_init(caribou_smi_st* dev,
dev->debug_mode = caribou_smi_none;
dev->invert_iq = false;
dev->sample_rate = CARIBOU_SMI_SAMPLE_RATE;
dev->initialized = 1;
return 0;
@ -585,6 +586,23 @@ int caribou_smi_close (caribou_smi_st* dev)
return close (dev->filedesc);
}
//=========================================================================
void caribou_smi_set_sample_rate(caribou_smi_st* dev, uint32_t sample_rate)
{
if (sample_rate < 100000)
{
dev->sample_rate = 100000;
}
else if (sample_rate > CARIBOU_SMI_SAMPLE_RATE)
{
dev->sample_rate = CARIBOU_SMI_SAMPLE_RATE;
}
else
{
dev->sample_rate = sample_rate;
}
}
//=========================================================================
void caribou_smi_set_debug_mode(caribou_smi_st* dev, caribou_smi_debug_mode_en mode)
{
@ -597,6 +615,14 @@ void caribou_smi_invert_iq(caribou_smi_st* dev, bool invert)
dev->invert_iq = invert;
}
//=========================================================================
static int caribou_smi_calc_read_timeout(uint32_t sample_rate, size_t len)
{
uint32_t to_millisec = (2 * len * 1000) / sample_rate;
if (to_millisec < 1) to_millisec = 1;
return to_millisec;
}
//=========================================================================
int caribou_smi_read(caribou_smi_st* dev, caribou_smi_channel_en channel,
caribou_smi_sample_complex_int16* samples,
@ -607,9 +633,8 @@ int caribou_smi_read(caribou_smi_st* dev, caribou_smi_channel_en channel,
caribou_smi_sample_meta* meta_offset = metadata;
size_t left_to_read = length_samples * CARIBOU_SMI_BYTES_PER_SAMPLE; // in bytes
size_t read_so_far = 0; // in samples
uint32_t to_millisec = (2 * dev->native_batch_len * 1000) / CARIBOU_SMI_SAMPLE_RATE;
if (to_millisec < 2) to_millisec = 2;
uint32_t to_millisec = caribou_smi_calc_read_timeout(dev->sample_rate, dev->native_batch_len);
while (left_to_read)
{
if (sample_offset) sample_offset = samples + read_so_far;
@ -617,6 +642,8 @@ int caribou_smi_read(caribou_smi_st* dev, caribou_smi_channel_en channel,
// current_read_len in bytes
size_t current_read_len = ((left_to_read > dev->native_batch_len) ? dev->native_batch_len : left_to_read);
to_millisec = caribou_smi_calc_read_timeout(dev->sample_rate, current_read_len);
int ret = caribou_smi_timeout_read(dev, dev->read_temp_buffer, current_read_len, to_millisec);
if (ret < 0)
{

Wyświetl plik

@ -63,6 +63,7 @@ typedef struct
int initialized;
int filedesc;
size_t native_batch_len;
uint32_t sample_rate;
smi_stream_state_en state;
uint8_t *read_temp_buffer;
@ -95,6 +96,7 @@ int caribou_smi_write(caribou_smi_st* dev, caribou_smi_channel_en channel,
size_t caribou_smi_get_native_batch_samples(caribou_smi_st* dev);
void caribou_smi_setup_ios(caribou_smi_st* dev);
void caribou_smi_set_sample_rate(caribou_smi_st* dev, uint32_t sample_rate);
#ifdef __cplusplus
}

Wyświetl plik

@ -36,14 +36,11 @@ int cariboulite_radio_init(cariboulite_radio_state_st* radio, sys_st *sys, carib
radio->smi_channel_id = GET_SMI_CH(type);
// activation of the channel
if (cariboulite_radio_activate_channel(radio, cariboulite_channel_dir_rx, true) != 0)
{
return -1;
}
usleep(10000);
cariboulite_radio_activate_channel(radio, cariboulite_channel_dir_rx, true);
usleep(1000);
cariboulite_radio_activate_channel(radio, cariboulite_channel_dir_rx, false);
return cariboulite_radio_activate_channel(radio, cariboulite_channel_dir_rx, false);
return 0;
}
//=========================================================================
@ -245,6 +242,22 @@ int cariboulite_radio_set_rx_samp_cutoff(cariboulite_radio_state_st* radio,
at86rf215_radio_set_rx_bandwidth_sampling(&radio->sys->modem, GET_MODEM_CH(radio->type), &cfg);
radio->rx_fs = rx_sample_rate;
radio->rx_fcut = rx_cutoff;
// setup the smi sample rate for timeout
uint32_t sample_rate = 4000000;
switch(rx_sample_rate)
{
at86rf215_radio_rx_sample_rate_4000khz: sample_rate = 4000000; break;
at86rf215_radio_rx_sample_rate_2000khz: sample_rate = 2000000; break;
at86rf215_radio_rx_sample_rate_1333khz: sample_rate = 1333000; break;
at86rf215_radio_rx_sample_rate_1000khz: sample_rate = 1000000; break;
at86rf215_radio_rx_sample_rate_800khz: sample_rate = 800000; break;
at86rf215_radio_rx_sample_rate_666khz: sample_rate = 666000; break;
at86rf215_radio_rx_sample_rate_500khz: sample_rate = 500000; break;
at86rf215_radio_rx_sample_rate_400khz: sample_rate = 400000; break;
}
caribou_smi_set_sample_rate(&radio->sys->smi, sample_rate);
return 0;
}
@ -864,13 +877,12 @@ int cariboulite_radio_activate_channel(cariboulite_radio_state_st* radio,
// then deactivate the modem's stream
cariboulite_radio_set_modem_state(radio, at86rf215_radio_state_cmd_trx_off);
// if we deactivate, first shut off the smi stream
ret = caribou_smi_set_driver_streaming_state(&radio->sys->smi, smi_stream_idle);
// DEACTIVATION
if (activate == false)
if (!activate)
{
// if we deactivate, first shut off the smi stream
ret = caribou_smi_set_driver_streaming_state(&radio->sys->smi, smi_stream_idle);
return ret;
}
@ -901,7 +913,7 @@ int cariboulite_radio_activate_channel(cariboulite_radio_state_st* radio,
// RX on both channels looks the same
if (radio->channel_direction == cariboulite_channel_dir_rx)
{
// after modem is activated turn on the the smi stream
// Setup the IQ stream properties
smi_stream_state_en smi_state = smi_stream_idle;
if (radio->smi_channel_id == caribou_smi_channel_900)
smi_state = smi_stream_rx_channel_0;
@ -918,15 +930,15 @@ int cariboulite_radio_activate_channel(cariboulite_radio_state_st* radio,
.clock_skew = at86rf215_iq_clock_data_skew_4_906ns,
};
at86rf215_setup_iq_if(&radio->sys->modem, &modem_iq_config);
// configure FPGA with the correct rx channel
caribou_fpga_set_smi_channel (&radio->sys->fpga, radio->type == cariboulite_channel_s1g? caribou_fpga_smi_channel_0 : caribou_fpga_smi_channel_1);
caribou_fpga_set_io_ctrl_dig (&radio->sys->fpga, radio->type == cariboulite_channel_s1g? 0 : 1, 0);
//caribou_fpga_set_io_ctrl_dig (&radio->sys->fpga, radio->type == cariboulite_channel_s1g? 0 : 1, 0);
//usleep(5000);
// turn on the modem RX
cariboulite_radio_set_modem_state(radio, at86rf215_radio_state_cmd_rx);
usleep(20000);
// apply the state
// turn on the SMI stream
if (caribou_smi_set_driver_streaming_state(&radio->sys->smi, smi_state) != 0)
{
ZF_LOGD("Failed to configure modem with cmd_rx");

Wyświetl plik

@ -387,9 +387,9 @@ int cariboulite_init_submodules (sys_st* sys)
// Print the SPI information
//io_utils_spi_print_setup(&sys->spi_dev);
// Initialize the two Radio High-Level devices
cariboulite_radio_init(&sys->radio_low, sys, cariboulite_channel_s1g);
cariboulite_radio_init(&sys->radio_high, sys, cariboulite_channel_6g);
// Initialize the two Radio High-Level devices
cariboulite_radio_init(&sys->radio_low, sys, cariboulite_channel_s1g);
cariboulite_radio_init(&sys->radio_high, sys, cariboulite_channel_6g);
cariboulite_radio_set_rx_samp_cutoff(&sys->radio_low, at86rf215_radio_rx_sample_rate_4000khz, at86rf215_radio_rx_f_cut_half_fs);
cariboulite_radio_set_tx_samp_cutoff(&sys->radio_low, at86rf215_radio_rx_sample_rate_4000khz, at86rf215_radio_rx_f_cut_half_fs);
@ -632,7 +632,7 @@ int cariboulite_init_driver_minimal(sys_st *sys, hat_board_info_st *info, bool p
}
if (sys->reset_fpga_on_startup)
{
caribou_fpga_soft_reset(&sys->fpga);
//caribou_fpga_soft_reset(&sys->fpga);
}
// Reading the configuration from the FPGA (resistor set)