Handling Hardware interrupts in Linux - linux-kernel

I am working on a embedded linux platform running Linux 2.6 . I would love to know how to do the following.
1) I have a hardware interrupt source irq7 which shows up in /proc/interrupts
cat /proc/interrupts | grep IRQ7
M547X_8X 71: 1916076 PCI IRQ7
2) For PCI IRQ7, each time i press a button, 3rd value value changes
M547X_8X 71: 2177862 PCI IRQ7
Doesn't this mean my switch press is recognized?
Now i want to trigger a user program from sleep when i press this button. How do i write
this user space program using interrupts or signal?
Should i write a driver program for this?
Can you suggest resources that i should look into?

You should take a look on gpio key on linux. After exporting the interrupt to /dev/input/eventXXX, you can use evtest tool for check from user space.

Related

how can we make kernel boot to the login prompt or shell without initramfs?

For example in a videa about u-boot, https://www.youtube.com/watch?v=INWghYZH3hI, near time 43:01, I see the lecturer gives u-boot the kernel address and fdt address but not the initramfs address. (bootz 0x80000000 - 0x80800000) but linux boots to the login prompt and he can log in.
How come this is possible? I understand after the kernel boots it starts init process in the initramfs.(I forgot there were a precedence). Without initramfs, how is it possible to run login process or shell?
(it's related to programming so I ask it here. If requested I can move it to unix stackexchange. Is there a method of moving a question to somerewhere else automatically? guess not..)
this is what I learned from the comments with combination with my previous knowledge.
you can embed the initramfs.tar.gz file in the kernel binary image using CONFIG_INITRAMFS_SOURCE=nitramfs.cpio.gz in the configuration. (menuconfig). The initramfs image is placed at the end of the kernel image maybe (I remember).
But this was not the case in the youtube video I mentioned in my question. Near 40:29 in the video, the kernel boot command is shown to have "root=/dev/mmcblk0p1 rootfstype=ext4 rootwait console=tty0e,115200". So it's telling the kernel to use SD card 0's partition 1 as the root system after boot, instead of using initramfs.(when you want to use initramfs, you specify root=/dev/ram and pass the initramfs location. in qemu you use -initrd initramfs.cpio.gz option, or in real machine this information is passed through the device tree to the kernel, in the chosen node's initrd-start and initrd-end address.).

How to do a TRUE rescan of PCIe bus

I have an FPGA (Like most of the people asking this question) that gets configured after my Linux kernel does the initial PCIe bus scan and enumeration. As you can guess, the FPGA implements a PCIe endpoint.
I would Like to have the PCIe core re-enumerate the ENTIRE PCIe bus so that my FPGA will then show up and I can load my driver module. I would also like the ability to SWAP the FPGA load out for a different configuration. By this I mean I would like to be able to:
Boot Linux
Configure FPGA
Enumerate PCIe endpoint and load module
Remove PCIe endpoint
Re-configure FPGA
Re-enumerate PCIe endpoint
All without rebooting Linux
Here are solutions that have been proposed elsewhere but do not solve the problem.
echo 1 > /sys/bus/pci/rescan This seems to work (only sometimes) and it does not work if I want to hotswap the FPGA load after it was first enumerated.
Can the Hotplug/power managment facilities of PCIe be used to make this work? If so is there any good resources for how to use the Hotplug system with PCIe? (LDD does not quite cover it thoroughly enough)
Re-enumerating the PCIe bus/tree via echo 1 > /sys/bus/pci/rescan is the correct solution. We are using it the same way as you described it.
We are using echo 1 > $pcidevice/remove to disconnect the driver from the device and to detach the device from the tree. The driver (xillybus) is not unloaded, just disconnected.
A better solution is to rescan only the node where your FPGA is attached to. This reduces the over all impact for the system.
This technique is used in the RC3E FPGA cloud system.
This is really dependent on exactly what is changed on the FPGA. The problem is in how PCIe enumeration and address assignment is done, particularly how the PCIe switches are configured. The allocation MUST be done in one shot as a depth-first search. After this is complete, it is not possible to go insert additional bus numbers or address space without changing all of the subsequent allocations, which would require reloading all of the corresponding device drivers. Basically, once the bus is enumerated and addresses are assigned, you can't change the overall allocations without re-enumerating the entire bus, which requires a reboot. Preallocating resources on a specific PCIe port can alleviate this problem, and is required for PCIe hot plugging.
If the PCIe BAR configuration has not changed, then usually doing a remove/hot reset/rescan is sufficient and no reboots are required.
If the BAR configuration has changed, then it's a different story. If the new BARs are smaller, then there should be no problem. But if the new BARs are larger or there are more BARs, if there isn't enough address space allocated to the switch port that the device is attached to, then those BARs cannot be allocated address space and the device will fail to enumerate. In this case, a reboot is required to so that resources can be reassigned. Don't forget that there are also 32 bit BARs and 64 bit BARs and these BARs are assigned form two different pools of address space, so changing BAR types can also require a reboot to re-enumerate.
If you're going from no device to a device (i.e. blank FPGA to configured FPGA), then bus numbers may need to be reassigned, which requires a reboot.
From The Doctor
Here is how to reset the Vegas before same as a reset in windows. This is based on the Vendor ID.
lspci -n | grep 1002: | egrep -v ".1"| awk '{print "find /sys | grep ""$1"/rescan" -| tac -;"}' | sh - | sed s/^/echo\ 1\ >\ "&/g | sed s/$/"/g
The output of that put in your /etc/rc.local to reset your Vegas after bootup similar to the devcon restart script.
echo 1 > "/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/rescan"
echo 1 > "/sys/devices/pci0000:00/0000:00:1c.5/0000:03:00.0/rescan"
echo 1 > "/sys/devices/pci0000:00/0000:00:1d.0/0000:06:00.0/rescan"
echo 1 > "/sys/devices/pci0000:00/0000:00:1d.1/0000:07:00.0/rescan"

From Kernel Space to User Space: Inner-workings of Interrupts

I have been trying to understand how do h/w interrupts end up in some user space code, through the kernel.
My research led me to understand that:
1- An external device needs attention from CPU
2- It signals the CPU by raising an interrupt (h/w trance to cpu or bus)
3- The CPU asserts, saves current context, looks up address of ISR in the
interrupt descriptor table (vector)
4- CPU switches to kernel (privileged) mode and executes the ISR.
Question #1: How did the kernel store ISR address in interrupt vector table? It might probably be done by sending the CPU some piece of assembly described in the CPUs user manual? The more detail on this subject the better please.
In user space how can a programmer write a piece of code that listens to a h/w device notifications?
This is what I understand so far.
5- The kernel driver for that specific device has now the message from the device and is now executing the ISR.
Question #3:If the programmer in user space wanted to poll the device, I would assume this would be done through a system call (or at least this is what I understood so far). How is this done? How can a driver tell the kernel to be called upon a specific systemcall so that it can execute the request from the user? And then what happens, how does the driver gives back the requested data to user space?
I might be completely off track here, any guidance would be appreciated.
I am not looking for specific details answers, I am only trying to understand the general picture.
Question #1: How did the kernel store ISR address in interrupt vector table?
Driver calls request_irq kernel function (defined in include/linux/interrupt.h and in kernel/irq/manage.c), and Linux kernel will register it in right way according to current CPU/arch rules.
It might probably be done by sending the CPU some piece of assembly described in the CPUs user manual?
In x86 Linux kernel stores ISR in Interrupt Descriptor Table (IDT), it format is described by vendor (Intel - volume 3) and also in many resources like http://en.wikipedia.org/wiki/Interrupt_descriptor_table and http://wiki.osdev.org/IDT and http://phrack.org/issues/59/4.html and http://en.wikibooks.org/wiki/X86_Assembly/Advanced_Interrupts.
Pointer to IDT table is registered in special CPU register (IDTR) with special assembler commands: LIDT and SIDT.
If the programmer in user space wanted to poll the device, I would assume this would be done through a system call (or at least this is what I understood so far). How is this done? How can a driver tell the kernel to be called upon a specific systemcall so that it can execute the request from the user? And then what happens, how does the driver gives back the requested data to user space?
Driver usually registers some device special file in /dev; pointers to several driver functions are registered for this file as "File Operations". User-space program opens this file (syscall open), and kernels calls device's special code for open; then program calls poll or read syscall on this fd, kernel will call *poll or *read of driver's file operations (http://www.makelinux.net/ldd3/chp-3-sect-7.shtml). Driver may put caller to sleep (wait_event*) and irq handler will wake it up (wake_up* - http://www.makelinux.net/ldd3/chp-6-sect-2 ).
You can read more about linux driver creation in book LINUX DEVICE DRIVERS (2005) by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman: https://lwn.net/Kernel/LDD3/
Chapter 3: Char Drivers https://lwn.net/images/pdf/LDD3/ch03.pdf
Chapter 10: Interrupt Handling https://lwn.net/images/pdf/LDD3/ch10.pdf

Unable to change gpio value

Currently I'm trying to check the booting time of an Tixi board using systemd on a 2.6.39 linux kernel. To do so I created a service file that calls a bash script which sets and uses a gpio. The problem is that my systems is not allowing me to change the value of the gpio. I can sucessfully export it, change its direction, but NOT the value. I have connected an oscilloscope to check if the value had changed in the hardware but not updated in the file as suggested in some forums, but it was the same: the value just doesn't change!
I should also point out that the same script is working if I use system V, with exactly the same coonfiguration for the kernel, busybox and filesystem.
It is very ironic because I'm already the root of the systems, nevertheless even changing the permissions of the file, would not allow me to change its value. There is also no feedback from the kernel saying that the operation was not possible, but rather it looks as if it was possible but when I check the value, it was the same as before.
I also tried to run that in the Raspbian with a 3.12 (which I changed to systemd) and it was in fact possible to do it, just in the normal way from userspace.
I would appreciate if you have any idea oh what might be the problem since I already run out of ideas.
Thanks
PS: This is the code that should work on the bash line:
echo 0 > /sys/class/gpio/gpio104/value
more /sys/class/gpio/gpio104/value
// I get 1 not 0 as I requested
Nevertheless the same lines of code in the same board work if I use systemV but not if I use systemd
Probably cause by the lack of udev in your new setup which change the permission for those gpio in /sys/class. You might want to just put back udev to see if it fixes your problem.
I don't know your image setting, but each gpio pins needs to be exported prior to usage. Are you doing it or it's done automatically? If you have omap mux kernel switch, you do something like :
echo 0x104 > /sys/kernel/debug/omap_mux/cam_d5 (set mode 4 as stipulate in TI Sitara TRM)
echo 104 > /sys/class/gpio/export (export the pin)
echo out > /sys/class/gpio/gpio104/direction (set the pin as output)
Also do a dmesg | grep gpio and see if there's any initializing problem with the gpio mux.
Actually I've faced an issue similar to your's , ie was not able to change the value of set of gpio pin manually
Finally the result obtained was even though the name of that pin is gpio it can only be used for input only (DM3730 gpiO_114 and gpio_115).
So please refer to the datasheet and confirm it can be used for I/O operations..

change smp_affinity from linux device driver

If I examine the
cat /proc/interrupts
command, all the IRQs are listed under cpu0 in SMP system.
I can change the smp_affinity mask to tag the IRQ to particular CPU using following command.
echo "4" > /proc/irq/230/smp_affinity
Above command sets the affinity mask of the interrupt 230 to CPU 2.
I would like achieve same from linux kernel module. How can I do this?
I see create_proc_entry method which allows to create new proc entry.
Is there any method which we can use to write existing proc entry?
In a kernel module you can just call the kernel API function irq_set_affinity(...) directly. No need to go through /proc. See: http://lxr.free-electrons.com/source/kernel/irq/manage.c#L189

Resources