kopia lustrzana https://github.com/cariboulabs/cariboulite
keeping multiple dma transaction in queue instead of single shot
rodzic
c6c1fd8c69
commit
b2b003642d
|
@ -243,10 +243,11 @@ static void set_state(smi_stream_state_en state)
|
||||||
inst->address_changed = 1;
|
inst->address_changed = 1;
|
||||||
|
|
||||||
// abort the current waiting on the current channel
|
// abort the current waiting on the current channel
|
||||||
if (inst->smi_inst != NULL && inst->reader_waiting_sema && state == smi_stream_idle)
|
/*if (inst->smi_inst != NULL && inst->reader_waiting_sema && state == smi_stream_idle)
|
||||||
{
|
{
|
||||||
up(&inst->smi_inst->bounce.callback_sem);
|
up(&inst->smi_inst->bounce.callback_sem);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
inst->state = state;
|
inst->state = state;
|
||||||
|
@ -332,19 +333,20 @@ static int smi_init_programmed_read(struct bcm2835_smi_instance *smi_inst, int n
|
||||||
int smics_temp;
|
int smics_temp;
|
||||||
int success = 0;
|
int success = 0;
|
||||||
|
|
||||||
/* Disable the peripheral: */
|
if(smi_is_active(smi_inst))
|
||||||
smics_temp = read_smi_reg(smi_inst, SMICS) & ~(SMICS_ENABLE | SMICS_WRITE);
|
|
||||||
write_smi_reg(smi_inst, smics_temp, SMICS);
|
|
||||||
|
|
||||||
// wait for the ENABLE to go low
|
|
||||||
BUSY_WAIT_WHILE_TIMEOUT(smi_enabled(smi_inst), 1000000U, success);
|
|
||||||
if (!success)
|
|
||||||
{
|
{
|
||||||
return -1;
|
|
||||||
|
write_smi_reg(smi_inst, 4*num_transfers, SMIL);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
write_smi_reg(inst->smi_inst, 0, SMIL);
|
||||||
|
|
||||||
|
|
||||||
|
smics_temp = read_smi_reg(smi_inst, SMICS);
|
||||||
/* Program the transfer count: */
|
/* Program the transfer count: */
|
||||||
write_smi_reg(smi_inst, num_transfers, SMIL);
|
write_smi_reg(smi_inst, 4*num_transfers, SMIL);
|
||||||
|
|
||||||
/* re-enable and start: */
|
/* re-enable and start: */
|
||||||
smics_temp |= SMICS_ENABLE;
|
smics_temp |= SMICS_ENABLE;
|
||||||
|
@ -819,11 +821,15 @@ ssize_t stream_smi_user_dma( struct bcm2835_smi_instance *inst,
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
int reader_thread_stream_function(void *pv)
|
int reader_thread_stream_function(void *pv)
|
||||||
{
|
{
|
||||||
int count = 0;
|
|
||||||
int current_dma_buffer = 0;
|
int current_dma_buffer = 0;
|
||||||
|
int current_dma_user = 0;
|
||||||
int buffer_ready[2] = {0, 0}; // does a certain buffer contain actual data
|
int buffer_ready[2] = {0, 0}; // does a certain buffer contain actual data
|
||||||
struct bcm2835_smi_bounce_info *bounce = NULL;
|
uint32_t dma_buffer_idx_wr = 0;
|
||||||
|
uint32_t dma_buffer_idx_rd = 0;
|
||||||
unsigned int errors = 0;
|
unsigned int errors = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ktime_t start;
|
ktime_t start;
|
||||||
s64 t1, t2, t3;
|
s64 t1, t2, t3;
|
||||||
|
@ -831,63 +837,87 @@ int reader_thread_stream_function(void *pv)
|
||||||
dev_info(inst->dev, "Enterred reader thread");
|
dev_info(inst->dev, "Enterred reader thread");
|
||||||
inst->reader_thread_running = true;
|
inst->reader_thread_running = true;
|
||||||
|
|
||||||
|
/* Disable the peripheral: */
|
||||||
|
if(smi_disable_sync(inst->smi_inst))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
write_smi_reg(inst->smi_inst, 0, SMIL);
|
||||||
|
|
||||||
|
sema_init(&inst->smi_inst->bounce.callback_sem, 0);
|
||||||
|
|
||||||
while(!kthread_should_stop() && !(inst->address_changed) && !errors)
|
while(!kthread_should_stop() && !(inst->address_changed) && !errors)
|
||||||
{
|
{
|
||||||
// check if the streaming state is on, if not, sleep and check again
|
struct bcm2835_smi_instance *smi_inst = inst->smi_inst;
|
||||||
if ((inst->state != smi_stream_rx_channel_0 && inst->state != smi_stream_rx_channel_1) || inst->invalidate_rx_buffers)
|
uint32_t used_buffers = dma_buffer_idx_wr - dma_buffer_idx_rd;
|
||||||
|
while(used_buffers < DMA_BOUNCE_BUFFER_COUNT)
|
||||||
{
|
{
|
||||||
msleep(2);
|
|
||||||
// invalidate both buffers integrity
|
struct scatterlist *sgl = NULL;
|
||||||
inst->invalidate_rx_buffers = 0;
|
|
||||||
buffer_ready[0] = 0;
|
spin_lock(&smi_inst->transaction_lock);
|
||||||
buffer_ready[1] = 0;
|
|
||||||
current_dma_buffer = 0;
|
|
||||||
continue;
|
sgl = &(smi_inst->bounce.sgl[current_dma_buffer]);
|
||||||
|
if (sgl == NULL)
|
||||||
|
{
|
||||||
|
dev_err(smi_inst->dev, "sgl is NULL");
|
||||||
|
spin_unlock(&smi_inst->transaction_lock);
|
||||||
|
errors = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start = ktime_get();
|
if (!stream_smi_dma_submit_sgl(smi_inst, sgl, 1, DMA_DEV_TO_MEM, stream_smi_dma_callback_user_copy))
|
||||||
// sync smi address
|
|
||||||
if (inst->address_changed)
|
|
||||||
{
|
{
|
||||||
bcm2835_smi_set_address(inst->smi_inst, inst->cur_address);
|
dev_err(smi_inst->dev, "sgl submit failed");
|
||||||
inst->address_changed = 0;
|
spin_unlock(&smi_inst->transaction_lock);
|
||||||
// invalidate the buffers
|
errors = 1;
|
||||||
buffer_ready[0] = 0;
|
break;
|
||||||
buffer_ready[1] = 0;
|
|
||||||
current_dma_buffer = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------
|
dma_async_issue_pending(smi_inst->dma_chan);
|
||||||
// try setup a new DMA transfer into dma bounce buffer
|
spin_unlock(&smi_inst->transaction_lock);
|
||||||
// bounce will hold the current transfers state
|
|
||||||
buffer_ready[current_dma_buffer] = 0;
|
|
||||||
count = stream_smi_user_dma(inst->smi_inst, DMA_DEV_TO_MEM, &bounce, current_dma_buffer);
|
|
||||||
if (count != DMA_BOUNCE_BUFFER_SIZE || bounce == NULL)
|
current_dma_buffer = (current_dma_buffer + 1) % DMA_BOUNCE_BUFFER_COUNT;
|
||||||
{
|
dma_buffer_idx_wr++;
|
||||||
dev_err(inst->dev, "stream_smi_user_dma returned illegal count = %d, buff_num = %d", count, current_dma_buffer);
|
used_buffers = dma_buffer_idx_wr - dma_buffer_idx_rd;
|
||||||
spin_lock(&inst->smi_inst->transaction_lock);
|
|
||||||
dmaengine_terminate_sync(inst->smi_inst->dma_chan);
|
|
||||||
spin_unlock(&inst->smi_inst->transaction_lock);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t1 = ktime_to_ns(ktime_sub(ktime_get(), start));
|
t1 = ktime_to_ns(ktime_sub(ktime_get(), start));
|
||||||
|
|
||||||
//--------------------------------------------------------
|
spin_lock(&smi_inst->transaction_lock);
|
||||||
// Don't wait for the buffer to fill in, copy the "other"
|
if(!(dma_buffer_idx_rd % 100 ))
|
||||||
// previously filled up buffer into the kfifo - only if
|
printk("init programmed read %u %u\n",dma_buffer_idx_wr ,dma_buffer_idx_rd);
|
||||||
// buffer is valid
|
ret = smi_init_programmed_read(smi_inst, DMA_BOUNCE_BUFFER_SIZE);
|
||||||
start = ktime_get();
|
if (ret != 0)
|
||||||
|
|
||||||
if (buffer_ready[1-current_dma_buffer] && !inst->invalidate_rx_buffers)
|
|
||||||
{
|
{
|
||||||
if (mutex_lock_interruptible(&inst->read_lock))
|
spin_unlock(&smi_inst->transaction_lock);
|
||||||
{
|
dev_err(smi_inst->dev, "smi_init_programmed_read returned %d", ret);
|
||||||
//return -EINTR;
|
errors = 1;
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
|
spin_unlock(&smi_inst->transaction_lock);
|
||||||
|
|
||||||
kfifo_in(&inst->rx_fifo, bounce->buffer[1-current_dma_buffer], DMA_BOUNCE_BUFFER_SIZE);
|
// wait for completion
|
||||||
|
inst->reader_waiting_sema = true;
|
||||||
|
if (down_timeout(&smi_inst->bounce.callback_sem, msecs_to_jiffies(200)))
|
||||||
|
{
|
||||||
|
dev_info(inst->dev, "Reader DMA bounce timed out");
|
||||||
|
errors = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
inst->reader_waiting_sema = false;
|
||||||
|
|
||||||
|
current_dma_user = (current_dma_user + 1) % DMA_BOUNCE_BUFFER_COUNT;
|
||||||
|
dma_buffer_idx_rd++;
|
||||||
|
|
||||||
|
|
||||||
|
if (!mutex_lock_interruptible(&inst->read_lock))
|
||||||
|
{
|
||||||
|
kfifo_in(&inst->rx_fifo, smi_inst->bounce.buffer[current_dma_user], DMA_BOUNCE_BUFFER_SIZE);
|
||||||
mutex_unlock(&inst->read_lock);
|
mutex_unlock(&inst->read_lock);
|
||||||
|
|
||||||
// for the polling mechanism
|
// for the polling mechanism
|
||||||
|
@ -895,47 +925,23 @@ int reader_thread_stream_function(void *pv)
|
||||||
wake_up_interruptible(&inst->poll_event);
|
wake_up_interruptible(&inst->poll_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
t2 = ktime_to_ns(ktime_sub(ktime_get(), start));
|
|
||||||
|
|
||||||
//--------------------------------------------------------
|
|
||||||
// Wait for current chunk to complete
|
|
||||||
// the semaphore will go up when "stream_smi_dma_callback_user_copy" interrupt is trigerred
|
|
||||||
// indicating that the dma transfer finished. If doesn't happen in 1000 jiffies, we have a
|
|
||||||
// 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();
|
|
||||||
// wait for completion
|
|
||||||
inst->reader_waiting_sema = true;
|
|
||||||
if (down_timeout(&bounce->callback_sem, msecs_to_jiffies(200)))
|
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
|
||||||
// if state has become idle
|
|
||||||
if (inst->state == smi_stream_idle)
|
|
||||||
{
|
|
||||||
dev_info(inst->dev, "Reader state became idle, terminating dma");
|
|
||||||
spin_lock(&inst->smi_inst->transaction_lock);
|
|
||||||
dmaengine_terminate_sync(inst->smi_inst->dma_chan);
|
|
||||||
spin_unlock(&inst->smi_inst->transaction_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------
|
|
||||||
// Switch the buffers
|
|
||||||
buffer_ready[current_dma_buffer] = 1;
|
|
||||||
current_dma_buffer = 1-current_dma_buffer;
|
|
||||||
}
|
|
||||||
inst->reader_waiting_sema = false;
|
|
||||||
|
|
||||||
t3 = ktime_to_ns(ktime_sub(ktime_get(), start));
|
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, "TIMING (1,2,3): %lld %lld %lld %d", (long long)t1, (long long)t2, (long long)t3, current_dma_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev_info(inst->dev, "Reader state became idle, terminating dma");
|
||||||
|
spin_lock(&inst->smi_inst->transaction_lock);
|
||||||
|
dmaengine_terminate_sync(inst->smi_inst->dma_chan);
|
||||||
|
spin_unlock(&inst->smi_inst->transaction_lock);
|
||||||
|
|
||||||
|
dev_info(inst->dev, "Reader state became idle, terminating smi transaction");
|
||||||
|
smi_disable_sync(inst->smi_inst);
|
||||||
|
|
||||||
dev_info(inst->dev, "Left reader thread");
|
dev_info(inst->dev, "Left reader thread");
|
||||||
inst->reader_thread_running = false;
|
inst->reader_thread_running = false;
|
||||||
inst->reader_waiting_sema = false;
|
inst->reader_waiting_sema = false;
|
||||||
|
|
Ładowanie…
Reference in New Issue