kopia lustrzana https://github.com/cariboulabs/cariboulite
Kernel module SMI
integration of TX stream dma reader and writer corrections using mb() for memory boundarybug_fixes_integration_tx
rodzic
0595990c8d
commit
35d4a04295
|
@ -1,166 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include "../caribou_smi.h"
|
||||
#include "old/bcm2835_smi.h"
|
||||
|
||||
|
||||
#define SMI_STREAM_IOC_GET_NATIVE_BUF_SIZE _IO(BCM2835_SMI_IOC_MAGIC, 3)
|
||||
#define SMI_STREAM_IOC_SET_NON_BLOCK_READ _IO(BCM2835_SMI_IOC_MAGIC, 4)
|
||||
#define SMI_STREAM_IOC_SET_NON_BLOCK_WRITE _IO(BCM2835_SMI_IOC_MAGIC, 5)
|
||||
#define SMI_STREAM_IOC_SET_STREAM_STATUS _IO(BCM2835_SMI_IOC_MAGIC, 6)
|
||||
|
||||
static void setup_settings (struct smi_settings *settings)
|
||||
{
|
||||
settings->read_setup_time = 0;
|
||||
settings->read_strobe_time = 5;
|
||||
settings->read_hold_time = 0;
|
||||
settings->read_pace_time = 0;
|
||||
settings->write_setup_time = 0;
|
||||
settings->write_hold_time = 0;
|
||||
settings->write_pace_time = 0;
|
||||
settings->write_strobe_time = 4;
|
||||
settings->data_width = SMI_WIDTH_8BIT;
|
||||
settings->dma_enable = 1;
|
||||
settings->pack_data = 1;
|
||||
settings->dma_passthrough_enable = 1;
|
||||
}
|
||||
|
||||
pthread_t tid;
|
||||
int fd = -1;
|
||||
size_t native_batch_length_bytes = 0;
|
||||
int thread_running = 0;
|
||||
|
||||
void* read_thread(void *arg)
|
||||
{
|
||||
fd_set set;
|
||||
int rv;
|
||||
int timeout_num_millisec = 500;
|
||||
uint8_t *buffer = malloc(native_batch_length_bytes);
|
||||
int size_of_buf = native_batch_length_bytes;
|
||||
|
||||
while (thread_running)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
struct timeval timeout = {0};
|
||||
FD_ZERO(&set); // clear the set mask
|
||||
FD_SET(fd, &set); // add our file descriptor to the set - and only it
|
||||
int num_sec = timeout_num_millisec / 1000;
|
||||
timeout.tv_sec = num_sec;
|
||||
timeout.tv_usec = (timeout_num_millisec - num_sec*1000) * 1000;
|
||||
|
||||
rv = select(fd + 1, &set, NULL, NULL, &timeout);
|
||||
if(rv == -1)
|
||||
{
|
||||
int error = errno;
|
||||
switch(error)
|
||||
{
|
||||
case EINTR: // A signal was caught.
|
||||
continue;
|
||||
|
||||
case EBADF: // An invalid file descriptor was given in one of the sets.
|
||||
// (Perhaps a file descriptor that was already closed, or one on which an error has occurred.)
|
||||
case EINVAL: // nfds is negative or the value contained within timeout is invalid.
|
||||
case ENOMEM: // unable to allocate memory for internal tables.
|
||||
default: goto exit;
|
||||
};
|
||||
}
|
||||
else if (rv == 0)
|
||||
{
|
||||
printf("Read poll timeout\n");
|
||||
break;
|
||||
}
|
||||
else if (FD_ISSET(fd, &set))
|
||||
{
|
||||
int num_read = read(fd, buffer, size_of_buf);
|
||||
printf("Read %d bytes\n", num_read);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
char smi_file[] = "/dev/smi";
|
||||
struct smi_settings settings = {0};
|
||||
|
||||
fd = open(smi_file, O_RDWR);
|
||||
if (fd < 0)
|
||||
{
|
||||
printf("can't open smi driver file '%s'\n", smi_file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the current settings
|
||||
int ret = ioctl(fd, BCM2835_SMI_IOC_GET_SETTINGS, &settings);
|
||||
if (ret != 0)
|
||||
{
|
||||
printf("failed reading ioctl from smi fd (settings)\n");
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// apply the new settings
|
||||
setup_settings(&settings);
|
||||
ret = ioctl(fd, BCM2835_SMI_IOC_WRITE_SETTINGS, &settings);
|
||||
if (ret != 0)
|
||||
{
|
||||
printf("failed writing ioctl to the smi fd (settings)\n");
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// set the address to idle
|
||||
ret = ioctl(fd, BCM2835_SMI_IOC_ADDRESS, caribou_smi_address_idle);
|
||||
if (ret != 0)
|
||||
{
|
||||
printf("failed setting smi address (idle / %d) to device\n", caribou_smi_address_idle);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get the native batch length in bytes
|
||||
ret = ioctl(fd, SMI_STREAM_IOC_GET_NATIVE_BUF_SIZE, &native_batch_length_bytes);
|
||||
if (ret != 0)
|
||||
{
|
||||
printf("failed reading native batch length, setting default\n");
|
||||
native_batch_length_bytes = (1024)*(1024)/2;
|
||||
}
|
||||
printf("Native batch size: %u\n", native_batch_length_bytes);
|
||||
|
||||
// start streaming data
|
||||
ret = ioctl(fd, SMI_STREAM_IOC_SET_STREAM_STATUS, 1);
|
||||
|
||||
// start the reader thread
|
||||
thread_running = 1;
|
||||
int err = pthread_create(&tid, NULL, &read_thread, NULL);
|
||||
if (err != 0)
|
||||
{
|
||||
printf("\ncan't create thread :[%s]", strerror(err));
|
||||
}
|
||||
|
||||
getchar();
|
||||
thread_running = 0;
|
||||
|
||||
pthread_join(tid, NULL);
|
||||
|
||||
ret = ioctl(fd, SMI_STREAM_IOC_SET_STREAM_STATUS, 0);
|
||||
|
||||
close (fd);
|
||||
return 0;
|
||||
}
|
|
@ -176,7 +176,7 @@ static void set_state(smi_stream_state_en state)
|
|||
{
|
||||
inst->cur_address = (smi_stream_dir_device_to_smi<<ADDR_DIR_OFFSET) | (smi_stream_channel_1<<ADDR_CH_OFFSET);
|
||||
}
|
||||
else if (state == smi_stream_tx)
|
||||
else if (state == smi_stream_tx_channel)
|
||||
{
|
||||
inst->cur_address = smi_stream_dir_smi_to_device<<ADDR_DIR_OFFSET;
|
||||
}
|
||||
|
@ -250,17 +250,21 @@ static inline int smi_enabled(struct bcm2835_smi_instance *inst)
|
|||
}*/
|
||||
|
||||
/***************************************************************************/
|
||||
static void smi_init_programmed_read(struct bcm2835_smi_instance *smi_inst, int num_transfers)
|
||||
static int smi_init_programmed_read(struct bcm2835_smi_instance *smi_inst, int num_transfers)
|
||||
{
|
||||
int smics_temp;
|
||||
int success = 0;
|
||||
|
||||
/* Disable the peripheral: */
|
||||
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
|
||||
while (read_smi_reg(smi_inst, SMICS) & SMICS_ENABLE)
|
||||
;
|
||||
BUSY_WAIT_WHILE_TIMEOUT(smi_enabled(smi_inst), 100000U, success);
|
||||
if (!success)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Program the transfer count: */
|
||||
write_smi_reg(smi_inst, num_transfers, SMIL);
|
||||
|
@ -274,31 +278,38 @@ static void smi_init_programmed_read(struct bcm2835_smi_instance *smi_inst, int
|
|||
/* IO barrier - to be sure that the last request have
|
||||
been dispatched in the correct order
|
||||
*/
|
||||
smp_mb();
|
||||
mb();
|
||||
// busy wait as long as the transaction is active (taking place)
|
||||
while (read_smi_reg(smi_inst, SMICS) & SMICS_ACTIVE)
|
||||
;
|
||||
|
||||
BUSY_WAIT_WHILE_TIMEOUT(smi_is_active(smi_inst), 100000U, success);
|
||||
if (!success)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
// Clear the FIFO (reset it to zero contents)
|
||||
write_smi_reg(smi_inst, smics_temp, SMICS);
|
||||
|
||||
// Start the transaction
|
||||
smics_temp |= SMICS_START;
|
||||
write_smi_reg(smi_inst, smics_temp, SMICS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
static void smi_init_programmed_write(struct bcm2835_smi_instance *smi_inst, int num_transfers)
|
||||
static int smi_init_programmed_write(struct bcm2835_smi_instance *smi_inst, int num_transfers)
|
||||
{
|
||||
int smics_temp;
|
||||
int success = 0;
|
||||
|
||||
/* Disable the peripheral: */
|
||||
smics_temp = read_smi_reg(smi_inst, SMICS) & ~SMICS_ENABLE;
|
||||
write_smi_reg(smi_inst, smics_temp, SMICS);
|
||||
|
||||
// Wait as long as the SMI is still enabled
|
||||
while (read_smi_reg(smi_inst, SMICS) & SMICS_ENABLE)
|
||||
;
|
||||
BUSY_WAIT_WHILE_TIMEOUT(smi_enabled(smi_inst), 100000U, success);
|
||||
if (!success)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Program the transfer count: */
|
||||
write_smi_reg(smi_inst, num_transfers, SMIL);
|
||||
|
@ -309,6 +320,7 @@ static void smi_init_programmed_write(struct bcm2835_smi_instance *smi_inst, int
|
|||
|
||||
smics_temp |= SMICS_START;
|
||||
write_smi_reg(smi_inst, smics_temp, SMICS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -488,11 +500,23 @@ ssize_t stream_smi_user_dma( struct bcm2835_smi_instance *inst,
|
|||
// we have only 8 bit width
|
||||
if (dma_dir == DMA_DEV_TO_MEM)
|
||||
{
|
||||
smi_init_programmed_read(inst, DMA_BOUNCE_BUFFER_SIZE);
|
||||
int ret = smi_init_programmed_read(inst, DMA_BOUNCE_BUFFER_SIZE);
|
||||
if (ret != 0)
|
||||
{
|
||||
spin_unlock(&inst->transaction_lock);
|
||||
dev_err(inst->dev, "smi_init_programmed_read returned %d", ret);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
smi_init_programmed_write(inst, DMA_BOUNCE_BUFFER_SIZE);
|
||||
int ret = smi_init_programmed_write(inst, DMA_BOUNCE_BUFFER_SIZE);
|
||||
if (ret != 0)
|
||||
{
|
||||
spin_unlock(&inst->transaction_lock);
|
||||
dev_err(inst->dev, "smi_init_programmed_write returned %d", ret);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//printk(KERN_ERR DRIVER_NAME": SPIN-UNLOCK\n");
|
||||
|
@ -517,6 +541,10 @@ int reader_thread_stream_function(void *pv)
|
|||
// 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);
|
||||
continue;
|
||||
}
|
||||
|
@ -531,8 +559,10 @@ 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, "reader_thread return illegal count = %d", count);
|
||||
//current_dma_buffer = 1-current_dma_buffer;
|
||||
dev_err(inst->dev, "stream_smi_user_dma returned illegal count = %d", count);
|
||||
spin_lock(&inst->smi_inst->transaction_lock);
|
||||
dmaengine_terminate_sync(inst->smi_inst->dma_chan);
|
||||
spin_unlock(&inst->smi_inst->transaction_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -570,7 +600,10 @@ int reader_thread_stream_function(void *pv)
|
|||
// try to wait more, unless someone tells us to stop
|
||||
if (down_timeout(&bounce->callback_sem, msecs_to_jiffies(1000)))
|
||||
{
|
||||
dev_info(inst->dev, "DMA bounce timed out");
|
||||
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
|
||||
{
|
||||
|
@ -612,7 +645,7 @@ int writer_thread_stream_function(void *pv)
|
|||
while(!kthread_should_stop())
|
||||
{
|
||||
// check if the streaming state is on, if not, sleep and check again
|
||||
if (inst->state != smi_stream_tx)
|
||||
if (inst->state != smi_stream_tx_channel)
|
||||
{
|
||||
msleep(5);
|
||||
continue;
|
||||
|
@ -654,15 +687,25 @@ int writer_thread_stream_function(void *pv)
|
|||
if (count != DMA_BOUNCE_BUFFER_SIZE)
|
||||
{
|
||||
// error
|
||||
dev_err(inst->dev, "stream_smi_user_dma error");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wait for current chunk to complete
|
||||
if (down_timeout(&bounce->callback_sem, msecs_to_jiffies(1000)))
|
||||
{
|
||||
dev_err(inst->dev, "DMA bounce timed out");
|
||||
dev_err(inst->dev, "Writer 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 doen't have enough data, invoke poll
|
||||
inst->writeable = true;
|
||||
wake_up_interruptible(&inst->poll_event);
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(inst->dev, "Left writer thread");
|
||||
|
|
|
@ -69,7 +69,7 @@ typedef enum
|
|||
smi_stream_idle = 0,
|
||||
smi_stream_rx_channel_0 = 1,
|
||||
smi_stream_rx_channel_1 = 2,
|
||||
smi_stream_tx = 3,
|
||||
smi_stream_tx_channel = 3,
|
||||
} smi_stream_state_en;
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
|
Ładowanie…
Reference in New Issue