ARM and Linux spin_lock_irqsave concern - linux

This is my first query in stack exchange so please bear with me. Almost all the questions which come to my mind already got resolved from the forum, but I cannot able to found this one.
I have made a simple device driver in Linux where in my_init() function I have written following code:-
spinlock_t mylock = SPIN_LOCK_UNLOCKED
static int __init my_init()
{
unsigned long flags;
printk("Testing spinlock\n");
spin_lock_irqsave(&mylock, flag);
printk("Grabbing spinlock and return\n");
}
Thus simply I am returning without releasing the spinlock.According to the theory and Linux source code, the Interrupt got disabled in ARM. So I seen CPSR register of ARM using debugger with 'I' bit gets masked and thus IRQ are disabled. However to my surprise the Linux prompt and even schedule() function are working as usual.
So my query is in Linux do we use IRQ mode only for some of the peripherals? If this is the case how can we guarantee perfect synchronization between Thread Context and Interrupt Context?
A bit detail about my Target : TI81xx Soc, Linux 3.2, Lauterbach Debugger.
Thanks

Related

Shutdown (embedded) linux from kernel-space

I'm working on a modified version of the 2.6.35 kernel for Olinuxino, an ARM9 based platform. I'm trying to modify the power management driver (the architecture specific part).
The processor is a Freescale i.MX23. This processor has a "special" pin, called PSWITCH, that triggers an interrupt that is handled by the power management driver.
If the switch is pressed,the system goes to standby. This is done in the driver by calling pm_suspend(PM_SUSPEND_STANDBY).
Given my hardware setup, I'd like to, instead, shutdown the system.
So my question is:
What is the preferred way for a kernel-space process to trigger a clean system halt/poweroff?
I suppose there's a nice little function call out there, but I couldn't find it so far.
My kernel code (the file I'm working on is arch/arm/mach-mx23/pm.c) can be found here: github.com/spairal/linux-for-lobster, though my question calls for a general Linux kernel approach.
The most general way would be for your driver to invoke shutdown as a userspace helper:
static const char * const shutdown_argv[] =
{ "/sbin/shutdown", "-h", "-P", "now", NULL };
call_usermodehelper(shutdown_argv[0], shutdown_argv, NULL, UMH_NO_WAIT);
(Presuming you have a /sbin/shutdown binary installed). This will shut userspace down cleanly, unmount filesystems and then request the kernel shutdown and power off.
However, you may be able to do better than this - for example if you can guarantee that there's no disk filesystems mounted read/write, you could tell a kernel thread to invoke the kernel_power_off() function (it shouldn't be done from interrupt context).

Where can I find IRQF_NODELAY flag in Linux kernel?

I got an error when I built a device driver with IRQF_NODELAY in Linux 3.0.9.
And I found that IRQF_NODELAY was disappeared since somewhere after 2.6.x.
For the realtime job, I need an ISR that is not working as a thread.
Because I patched vanilla kernel with RT-Linux, the default ISR mode is not a real ISR but a thread.
Is IRQF_NODELAY deprecated? Can I use some flag equivalent to IRQF_NODELAY?
IRQ_NODELAY was replaced by IRQF_NO_THREAD. It works fine, I have used it for one project. You can pass it as third argument in the request_irq function.

Debugging kernel hang because of IOCTL calls

I am trying to make a kernel module which is working on 2.6.32 kernel to work on 3.6 kernel. We use IOCTL calls to update structures in Linux Kernel Module. These calls are working fine in 2.6.32 kernel.
When I try the same in 3.6 kernel I am facing kernel hang whenever ioctl calls are made from user-space application. Its a socket based interface not a file based interface hence we use the ioctl under struct proto_ops.
How can I debug this scenario as there is no core dump generated. To copy data from userspace I am using copy_from_user command.
Any pointers for debugging this scenario would be very helpful
ioctl() is one of the remaining parts of the kernel which runs under the Big Kernel Lock (BKL). In the past, the usage of the BKL has made it possible for long-running ioctl() methods to create long latencies for unrelated processes.
Follows an explanation of the patch that introduced unlocked_ioctl and compat_ioctl into 2.6.11. The removal of the ioctl field happened a lot later, in 2.6.36.
Explanation: When ioctl was executed, it took the Big Kernel Lock (BKL), so nothing else could execute at the same time. This is very bad on a multiprocessor machine, so there was a big effort to get rid of the BKL. First, unlocked_ioctl was introduced. It lets each driver writer choose what lock to use instead. This can be difficult, so there was a period of transition during which old drivers still worked (using ioctl) but new drivers could use the improved interface (unlocked_ioctl). Eventually all drivers were converted and ioctl could be removed.
compat_ioctl is actually unrelated, even though it was added at the same time. Its purpose is to allow 32-bit userland programs to make ioctl calls on a 64-bit kernel. The meaning of the last argument to ioctl depends on the driver, so there is no way to do a driver-independent conversion.
Reference: The new way of ioctl() by Jonathan Corbet

request_irq succeeds but interrupt is never detected

I am running embedded linux 3.2.6 on an ARM processor. I am using a modified version of atmel's serial driver to control the 4 USART ports on my device. When I use the driver compiled with the kernel, all works fine. But I want to run the driver as a kernel module instead. I make all of the necessary changes and disable the internal driver and everything seems fine. The 4 tty devices are registered successfully and I can see that the all of my probe and initialization functions work correctly.
So here's the problem:
When I try to write to any of the devices, my "start transmit" function gets called but then waits for an interrupt from the usart which never occurs. So the write just hangs, and using a logic analyzer I can see that RTS gets asserted but no bytes show up on the tx line. I know that my call to request_irq succeeds and yet i never see any of the irq entries in /proc/interrupts. In the driver, I have also tried using request_irq to register a separate interrupt handler for a gpio line, and this works fine.
I know that this is a problem that is probably hard to diagnose, but I am looking for ANY possible suggestions that could lead me in the right direction to finding a solution. Let me know if you need any clarifications. Thank you
The symptoms reads like a peripheral clock that has not been enabled (or turned off): the device can be initialized w/o errors and an I/O operation can be setup, but the device doesn't do anything; it plays dead. Since no I/O ever starts, you're never going to get an interrupt indicating completion!
The other thing to check are the conditional compilation directives for HW configuration structures in your arch/arm/mach-xxx/zzz_devices.c file.
Make sure that the serial port structures have something like:
#if defined(CONFIG_SERIAL_ATMEL) || defined(CONFIG_SERIAL_ATMEL_MODULE)
and not just
#if defined(CONFIG_SERIAL_ATMEL)
Addendum
I could be wrong but the clock shouldn't have any effect on the CTS pin causing an interrupt, right?
Not right.
These digital circuits are synchronous state machines: without a clock, a change-of-state by an input cannot be processed.
Also, SoCs and modern uControllers use the peripheral clocks as on/off switches for those integrated peripherals. There is often way more functionality, i.e. peripherals, on the silicon chip than can actually be used, mostly due to insufficient quantity of pins to the board. So disabling the clocks to unused devices is employed to reduce power consumption.
You are far too focused on interrupts.
You do not have a solvable interrupt problem; those are secondary failures.
The lack of output when attempting to transmit is far more significant and revealing.
The root cause is probably a flawed configuration of the USART devices, since transmitting bits is an automatic operation for a configured & operational USART.
If the difference between not-working versus working is loadable module versus static linking, then the root cause is going to be something fundamental (and trivial) like my two suggestions.
Also your lack of acknowledgement regarding the #if defined(), e.g. you didn't respond with "Oh yeah, we already knew that", raises a gigantic red flag that says "Fix me first!"
Addendum 2
I'm tempted to delete this answer after discovering that the Atmel serial driver cannot be configured/built as a loadable module using make menuconfig (which is the premise for half of the answer). (Of course the Kconfig file could be hacked to make the config variable tristate instead of boolean to overcome the module restriction.) I've left a comment for the OP. But I also wanted to preserve the comment to Mr. Stratton pointing out how symbols in the .config file are (not) used.
So I did finally fix my problem. Thank you for the responses, none of them directly solved my problem but they did prompt further examination of my code. After some trial and error I finally got it working. I had originally moved the platform_device structures for each usart from /mach-at91/xxx_devices.c to my loadable module. Well for some reason the structures weren't getting the correct data to map to the hardware, I suppose because it wasn't correctly linking the symbols from the kernel (never got an error message though) and so some of the registration functions weren't even getting called. I ended up moving the structures and platform_device_register calls back into the devices file. I also decided to keep the driver for the console built-in using the original atmel_serial.c driver. I had to change the platform_device name for the console in both the devices file and in the built-in atmel_serial.c file in order for it to not conflict with my usart ports driver. I found that changing the platform_device and platform_driver name for the usarts from anything but "atmel_usart" resulted in usart transmission failing. I really don't understand why, but i'm just leaving it as atmel_usart so it works.
Thanks again to everybody who responded to my problem.

What linux kernel code creates /sys/devices/system/cpu/cpuX?

I am developing a cpufreq driver (as a loadable kernel module) for the microblaze architecture. I have some FPGA logic that is able to scale the on-system clock and it works quite well. I have followed the information in Documentation/cpu-freq/cpu-drivers.txt and looked at the model in the blackfin cpufreq driver.
I have also made the necessary changes to arch/microblaze/Kconfig in order to have the cpufreq options built into the kernel (not modules).
When I first loaded the driver, cpufreq_register_driver() was returning -ENODEV, which implied that it couldn't find a CPU. I set the driver flag to CPUFREQ_STICKY and was able to insert the module.
However, at this point I realized that /sys/devices/system/cpu/cpu0 isn't present (although /sys/devices/system/cpu/cpufreq is there). So, why is that? What part of the kernel code is responsible for creating that directory?
I discovered where the /sys/devices/system/cpu/cpuX sysfs entry was created by looking at the cpufreq_cpu_callback() in drivers/cpufreq/cpufreq.c. This has a call to get_cpu_sysdev(), which I assumed was the element that I was looking for.
This call is defined in drivers/base/cpu.c, where I also noticed the code that puts together the cpu specific sysdev entry; register_cpu(). For most architectures, this is in arch/${ARCH}/kernel/setup.c, and I used the blackfin code as an example.
DEFINE_PER_CPU(struct cpu, cpu_data);
static int __init topology_init(void)
{
unsigned int cpu;
for_each_possible_cpu(cpu) {
register_cpu(&per_cpu(cpu_data, cpu), cpu);
}
return 0;
}
After adding this code to arch/microblaze/kernel/setup.c, I now have the directory I need and I'm able to make use of the different governors available to talk to my cpufreq driver. Now I just have to make sleep 1 take 1 second at 1/3 the clock rate instead of 3 seconds!

Resources