2008-08-13 14:42:49 Latency in SPI User Mode Drivers using irq_proc_handler.
Kiran Kumar B (INDIA)
Message: 60421
Greetings uClinux Team,
Configuration
Distribution Used : uClinux-dist-2008R1-RC8 , Board : BF527 Ezkit, Device Driver : SPI ( BlackFin as Master)
Description of Our Need
We have a need to read the SPI device from the user space , during occurrence of external hardware interrupt at rate of 1ms. We basically want to tie-up the IRQ ( GPIO Port G pin 5) in the kernel space, with the application's SPI read, with minimal kernel changes.
Method that we trying
The interrupts generated in kernel space is transmitted to user space through the proc interface. The main key is that the user mode process is allowed to block on a particular file descriptor and when an interrupt arrives the block is revoked and the process is put to schedule. The interrupts are registered through the function init_irq_proc where the irq’s inturn gets registered and the file /proc/irq/<nnn>/irq is created and the proc file operations of the file are linked with the irq_proc operations.
Problem Statement
We have done the modification in ezkit.c ( /arch / blackfin / mach-bf527 / boards ) by adding an extra structure member { BTN_2, GPIO_PG5, 1, " fpga-int : EXINT " } to the structure bfin_gpio_key_tables. With this change we are able to see a new directory in our target boards uClinux /proc / irq / 92 / < new file >
After going through the kernel code and the study material for drivers and interrupts , I was not able to find the "init_irq_proc" and " proc_irq_handler " in the kernel.
Please let us know if the present uClinux kernel supports this method of handling interrupts ?
Is this the right way to go about in accessing the /proc/irq/92 files ?
Kindly lets know if the latency involved in this proc interface method will be high ? We actually need to read the SPI, at max within 300us of the interrupt occurrence.
Thank you for your time, for reading through the text.
QuoteReplyEditDelete
2008-08-13 15:07:07 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Mike Frysinger (UNITED STATES)
Message: 60424
userspace spi drivers cannot handle irqs. i guess you could try and repurpose the gpio keys driver to serve as an interrupt source.
i dont know why you talk about init_irq_proc and /proc/irq/ as those are status-only directories. they do not get used by end applications that want to be woken up by an interrupt.
we've never tested the latency on any of these pieces though. i doubt you'd be able to reliably get 300us response time from userspace. if you need that kind of time, you'll most likely have to write a kernel driver. perhaps you'll even need to review the realtime adeos patch.
QuoteReplyEditDelete
2008-08-14 01:00:51 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Sonic Zhang (CHINA)
Message: 60431
Handler interrupt in user space directly is not supported.
If you want to read SPI device after a gpio interrupt occurs, you' d better write a kernel module to handler the gpio interrupt and export a ioctl function for an user application to wait and read the SPI device.
QuoteReplyEditDelete
2008-08-14 06:59:44 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Kiran Kumar B (INDIA)
Message: 60466
Thank you , Mike and Sonic
The article that I referred for the Interrupt handling through proc interface is given below: ( link)
http://wiki.phiepsilon.org/doku.php?id=user_mode_driver
Is this kind of handling supported by uClinux?
I agree with you that writing kernel modules is the best solution in terms of latency and performance.
As you suggested I will start with writing of the kernel module. From past few days have also read through the kerenl code and study reference. Request you to please suggest me in which file do I register the new GPIO Port-G pin 5 for interrupt capability? ( presently, I have tried adding it in the ezkit.c. This is been seen in target's /proc/irq/92 directory. Is this fine ? ) And also please let me the mechanism of transferring the read data from the SPI to user space.
Thank you
Kiran
QuoteReplyEditDelete
2008-08-14 09:43:03 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Mike Frysinger (UNITED STATES)
Message: 60478
that document covers internal details of how the UIO framework works. it is not something that end users have to do.
that said, UIO doesnt seem to build for nommu atm.
this document explains how to handle interrupts:
http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:interrupts
QuoteReplyEditDelete
2008-08-17 13:50:10 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Kiran Kumar B (INDIA)
Message: 60553
Thank you Mike , for confirming on UIO.
Please let me know whether my below mentioned thought / approach is correct .
I understand that I need to write a 'SPI protocol driver' ( kernel module ) for my new 'FPGA slave SPI device'.
In this driver, I need to register for GPIO interrupt ( this external hardware interrupt occurance every 1ms ). In the Interrupt service routine I need to read the SPI by calling 'spi_message_add_tail( )' or 'spi_async' ( of the file ' /include / linux / spi / spi.h ' ) The read data from SPI ( every 1ms ) can be stored locally in the kernel space memory.
From the user space, the application is going to asynchronously make 'read' system calls from the application theads which run at say 1ms. I need to have the implementation of ' fops ' in my new 'SPI protocol driver ' and also handle the user space 'read' system calls to provide the ALREADY read data from the SPI ( in kernel space). I need to use the ' copy_to_user' function in the implementation of the 'read' system call.
Having been said my understanding, few question are coming up in my mind !! ( please correct me, if I am wrong in my understanding )
Can I use and customize the bfin_spi_adc.c ( of . . / drivers / char / ) , which is a simple SPI frame work ? Can I request for a the GPIO IRQ in this file itself or do I need to write a separate-new kernel module for my FPGA ? This doubt arrised because ezkit.c ( of .. /arch / blackfin / mach-bf527 / boards/ ) has ' spi_board_info bfin_spi_board_info [ ] ' structure which already is addressing many spi devices, in which ' CONFIG_SPI_ADC_BF533 ' is one among them. If I write a new kernel module, I need to register as a new 'FPGA SPI protocol driver ' in the board info. Am I right ?
Is the SPI frame work specific to BF533 ? Can I use it without any modifications for BF527 ?
Or say for reference if I take the ' linux-2.6x / drivers / input / touchscreen / ad7877.c' SPI file and modify / customize for my FPGA SPI driver , How will I transfer the read data in the 1ms IRQ to my user space who needs data ? Should I add the 'fops' into this customized file and copy the information to the user on 'read' system call ?
Please correct me in my understanding and request you to suggest me the approach to take.
Greetings , - Kiran
QuoteReplyEditDelete
2008-08-18 20:02:40 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Mike Frysinger (UNITED STATES)
Message: 60602
that sounds reasonable in general
dont modify existing drivers ... copy them to a new file and customize it for your needs
the "BF533" in the config name is a historical artifcat ... the SPI framework works fine for all Blackfins
when copying drivers, you should use something that is similar to your device ... the spi adc driver sounds a lot closer than a touchscreen driver
QuoteReplyEditDelete
2008-08-19 05:25:23 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Kiran Kumar B (INDIA)
Message: 60636
Thank you for the comments Mike...
with spidev.c as reference I have started experimenting the kernel code.
Now I am able to create a kernelThread , which waits for event from the IRQ. I have also registered for a GPIO's IRQ ( a button of eval board Ezkit BF527 ) , which calls wake_up_interruptible ( ).On a button press from user, I am able to enter the kernel thread.
In this kerenel thread I need to call the spi_read. But without having the filp and inode, I am not able to do a successful do a spi_read. Its giving kernel panic !!
I do not have any user space application running. I am just trying to test the kernel for spi_read on occurance of an interrupt. Since the open device is not called from user space. I have copied a part of driver's open code to module init. After doing this also kerenel panic occured immediately after boot-up , since module init is called at boot.
How will I do a read spi device in the device driver's kthread , without getting struct file *filp information from the user ? How do I get rid of the kernel panic ?
- Kiran
QuoteReplyEditDelete
2008-08-19 11:02:04 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Mike Frysinger (UNITED STATES)
Message: 60652
you only have those structures when opening files or working with character devices. you arent, so you wont have any of those.
then again, you dont need any file pointers to simply do spi reads/writes. just create your buffers locally.
QuoteReplyEditDelete
2008-08-19 11:44:33 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Kiran Kumar B (INDIA)
Message: 60657
I tried taking a local backup of struct inode and struct filp in the function spi_devopen of spidev.c ( to use it in the spi_read call called from kthread) but kernel panic comes..!! Do you feel this way should actually work.. ?
QuoteReplyEditDelete
2008-08-19 13:23:38 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Mike Frysinger (UNITED STATES)
Message: 60661
no, that wont work at all. why are you muckin about with files anyways ? if your point is to catch an interrupt and then read/write some SPI data, you dont need any files to do that.
QuoteReplyEditDelete
2008-08-19 14:26:18 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Kiran Kumar B (INDIA)
Message: 60665
yes, my point is to catch an interrupt and then read/write some SPI data...
my new kthread code is in spidev.c ( just for testing ). Below is the code, in Bold is the code addition by me..
int fpga_irq(int irq, void *dev_id, struct pt_regs *regs)
{
printk("<1>IRQ ! \n");
cond = 1;
wake_up_interruptible( &my_waitqueue);
return IRQ_HANDLED;
}
/*------------------------------FPGA KTHREAD---------------------------------*/
static void fpga_kthread ()
{
struct spidev_data *spidev;
struct spi_device *spi;
ssize_t status = 0;
unsigned int count = 30; /* number of bytes read from FPGA */
int done =0;
while(!done)
{
wait_event_interruptible(my_waitqueue, (cond == 1) );
/* do something : read spi */
printk("<1>Thread Entered \n");
cond = 0;
/* -------------------READ ----------------*/
/* chipselect only toggles at start or end of operation */
spidev = backup_filp->private_data; /* filp saved from function open*/
spi = spidev->spi;
mutex_lock(&spidev->buf_lock);
status = spi_read(spi, spidev->buffer, count);
mutex_unlock(&spidev->buf_lock);
/* -------------------READ END ----------------*/
} /* end of while */
} /* end of thread */
/*------------------------FPGA KTHREAD END-----------------------------------*/
static int __init spidev_init(void)
{
int status;
int result; /* Kiran */
struct spidev_data *spidev;
struct file *filp;
struct inode *inode;
/* Claim our 256 reserved device numbers. Then register a class
* that will key udev/mdev to add/remove /dev nodes. Last, register
* the driver which manages those device numbers.
*/
/* Addition by Kiran for */
result = request_irq(IRQ_PG0, (void*) fpga_irq, IRQF_TRIGGER_HIGH, "Fpga_spi_irq", NULL);
if(result)
printk(KERN_NOTICE "Error %d requesting IRQ \n",result);
init_waitqueue_head(&my_waitqueue);
kernel_thread( fpga_kthread, NULL, 0 );
/* end */
.............
static int spidev_open(struct inode *inode, struct file *filp)
{
struct spidev_data *spidev;
int status = -ENXIO;
mutex_lock(&device_list_lock);
list_for_each_entry(spidev, &device_list, device_entry) {
if (spidev->dev.devt == inode->i_rdev) {
status = 0;
break;
}
}
if (status == 0) {
if (!spidev->buffer) {
spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);
if (!spidev->buffer) {
dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
status = -ENOMEM;
}
}
if (status == 0) {
spidev->users++;
filp->private_data = spidev;
backup_filp->private_data = spidev; /* Kiran , to use this filp in kthread to do spi_read*/
nonseekable_open(inode, filp);
}
} else
pr_debug("spidev: nothing for minor %d\n", iminor(inode));
mutex_unlock(&device_list_lock);
return status;
}
Please see the spi_read part in the FPGA kernel . Are there any problems with the code ? Do you mean I can not use
filp->private_data for reading ?
QuoteReplyEditDelete
2008-08-19 14:40:17 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Mike Frysinger (UNITED STATES)
Message: 60666
you cannot use random pointers if you havent set things up. if you havent opened any files, then you dont have any structures. just use hardcoded buffers to test things. otherwise you need to write a real cdev device so that userspace can read/write data which the kernel would work off of.
QuoteReplyEditDelete
2008-08-19 15:15:22 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Kiran Kumar B (INDIA)
Message: 60668
Thanks Mike, as you said right, in the user space I need to open SPI device for the structure to be available for read / write ... I tried the same , but was getting an ' kerenl panic ' exception , even if I open a SPI device from user application... There should be some problem with open, let me try fixing it... Below is the call trace for reference....
Call Trace:
[<00039da0>] _chrdev_open+0x44/0x170
[<00039eb0>] _chrdev_open+0x154/0x170
[<000361d6>] ___dentry_open+0xd6/0x188
[<00039d5c>] _chrdev_open+0x0/0x170
[<000362f0>] _nameidata_to_filp+0x20/0x34
[<00036334>] _do_filp_open+0x30/0x3c
[<0003607e>] _get_unused_fd+0x46/0xc8
[<00036376>] _do_sys_open+0x36/0xa8
[<00037e7c>] _sys_write+0x34/0x54
[<00036404>] _sys_open+0x18/0x20
[<000363ec>] _sys_open+0x0/0x20
[<00008000>] _l1_data_B_sram_free+0x10/0x54
Its seen that the "name of the device" passed by user during pen will be converted to filp and an unsued fd will be allocated to the new device . I think I might have problems in my open system call, doing this..!!
Once I am able to successfully open device from user space... I will try read call through kThread... Hope my approach is right.. ? As U said I will hardcode few things presently... my longer goals is actually to implement CDEV, but these experiments are for trials... ( building blocks for CDEV ! )
QuoteReplyEditDelete
2008-08-19 16:00:53 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Mike Frysinger (UNITED STATES)
Message: 60675
the process has information about the file being accessed, not the kernel thread
the spidev driver is a bit complicated as it's a generic framework designed to support an open ended scenario ... best if you start with a simpler cdev driver ... you can find some in the wiki (like the simple gpio driver)
QuoteReplyEditDelete
2008-10-29 13:51:05 Re: Latency in SPI User Mode Drivers using irq_proc_handler.
Mike Frysinger (UNITED STATES)
Message: 64373
the driver you refer to is not in mainline and never has been. you cant expect it to work.
i just tested UIO in the current svn trunk and it should work fine.
root:/> lsuio -v
uio0: name=STAMP-PB5, version=123, events=4
Device attributes:
uevent=DRIVER=uio_pdrv_genirq
modalias=platform:uio_pdrv_genirq
root:/> cat /proc/interrupts
6: 5258 Blackfin Core Timer
20: 0 BFIN_SPI_DMA
21: 0 BFIN_UART_RX
22: 2343 BFIN_UART_TX
38: 0 STAMP-PB5
40: 1 eth0
Err: 0
root:/> echo 1111 > enable
root:/> dd if=enable of=/dev/uio0 bs=4 count=1
1+0 records in
1+0 records out
root:/> dd if=/dev/uio0 of=/dev/null bs=4 count=1
<userspace sleeps here until i push PB1 on the STAMP board>
1+0 records in
1+0 records out
root:/> cat /proc/interrupts
6: 462873 Blackfin Core Timer
20: 0 BFIN_SPI_DMA
21: 0 BFIN_UART_RX
22: 6696 BFIN_UART_TX
38: 1 STAMP-PB5
40: 82 eth0
Err: 0
only change needed is to enable the driver "Userspace I/O platform driver with generic IRQ handling" and then add this to my board resources:
--- arch/blackfin/mach-bf533/boards/stamp.c (revision 5504)
+++ arch/blackfin/mach-bf533/boards/stamp.c (working copy)
@@ -38,6 +38,7 @@
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
#include <linux/usb/isp1362.h>
#endif
+#include <linux/uio_driver.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <asm/dma.h>
@@ -160,6 +161,20 @@ static struct platform_device stamp_flas
};
#endif
+struct uio_info uio_info_push_button = {
+ .name = "STAMP-PB5",
+ .version = "123",
+ .irq = IRQ_PF5,
+ .irq_flags = IRQF_TRIGGER_RISING,
+};
+static struct platform_device uio_push_button = {
+ .name = "uio_pdrv_genirq",
+ .id = 0,
+ .dev = {
+ .platform_data = &uio_info_push_button,
+ },
+};
+
#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
static struct mtd_partition bfin_spi_flash_partitions[] = {
{
@@ -558,6 +573,8 @@ static struct platform_device *stamp_dev
#if defined(CONFIG_MTD_BFIN_ASYNC) || defined(CONFIG_MTD_BFIN_ASYNC_MODULE)
&stamp_flash_device,
#endif
+
+ &uio_push_button,
};
static int __init stamp_init(void)