Working with GPIOs in kernel module IOCTLs - linux

I have working with GPIOs in my kernel module, while I set or reset GPIOS from an IOCTL I got the following warning in my "dmesg" Log.
[11115.549204] WARNING: CPU: 1 PID: 5199 at drivers/gpio/gpiolib.c:2415 gpiod_get_raw_value+0x7c/0xb8
[11115.558267] Modules linked in: ariodrv(O) [last unloaded: ariodrv]
[11115.564570] CPU: 1 PID: 5199 Comm: ARIO_RMG Tainted: G W O 4.9.166.RMG.-00002-gcbd9807b6c03-dirty #13
[11115.574776] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
[11115.581320] Backtrace:
[11115.583816] [<8010b150>] (dump_backtrace) from [<8010b3fc>] (show_stack+0x18/0x1c)
[11115.591426] r7:00000009 r6:600b0013 r5:80c1ae70 r4:00000000
[11115.597119] [<8010b3e4>] (show_stack) from [<803f51d4>] (dump_stack+0x9c/0xb0)
[11115.604380] [<803f5138>] (dump_stack) from [<80124878>] (__warn+0xec/0x104)
[11115.611367] r7:00000009 r6:80a39e28 r5:00000000 r4:00000000
[11115.617050] [<8012478c>] (__warn) from [<80124948>] (warn_slowpath_null+0x28/0x30)
[11115.624653] r9:8d696000 r8:7ea8cfa0 r7:0000000e r6:8d26e600 r5:8c1f9c54 r4:8c207f10
[11115.632434] [<80124920>] (warn_slowpath_null) from [<8042fbb8>] (gpiod_get_raw_value+0x7c/0xb8)
[11115.641177] [<8042fb3c>] (gpiod_get_raw_value) from [<7f00cd78>] (device_ioctl+0x334/0x9f8 [ariodrv])
[11115.650428] r5:8004d282 r4:7ea8cfa0
[11115.654034] [<7f00ca44>] (device_ioctl [ariodrv]) from [<80219c58>] (do_vfs_ioctl+0xa8/0x914)
[11115.662595] r7:0000000e r6:8d26e600 r5:8ccc5bc0 r4:7ea8cfa0
[11115.668278] [<80219bb0>] (do_vfs_ioctl) from [<8021a500>] (SyS_ioctl+0x3c/0x64)
[11115.675618] r10:00000036 r9:8d696000 r8:7ea8cfa0 r7:8004d282 r6:8d26e600 r5:0000000e
[11115.683477] r4:8d26e601
[11115.686035] [<8021a4c4>] (SyS_ioctl) from [<80107960>] (ret_fast_syscall+0x0/0x48)
[11115.693645] r9:8d696000 r8:80107b44 r7:00000036 r6:00000000 r5:768c611c r4:7ea8cf98
[11115.701504] ---[ end trace 7be84f1e05fd36af ]---
But if I set or get a value to a GPIO pin in another function, like init function of my module I don't get these warnings...
So the question is how exactly I should work with a GPIO pin in an IOCTL call?
This is part of my GPIO set IOCTL code:
IOCTL_FUNC(...) {
....
case IOCTL_RMG_GPIO_SET:
{
....
//I have initialized the GPIO pin as output before, and assume my gpio pin number is 4.
//int gpioNumber = 4;
//int value = 1;
gpio_set_value(gpioNumber, value);
break;
}
....
}
It doesn't matter either I get or set a value. If I use those GPIOs in an IOCTL call I got warning. But in other internal functions like init_module() or module_release() functions I can set and get these values without warning.
EDIT 1:
The problem I have is on GPIOs which are on my IOexpander (MCP23xxx series), This IOexpander works on i2c bus.
I don't have problem or any warning while using the GPIOs which are on my processor (iMX6DL).
EDIT 2:
#Tsyvarev and #0andriy Thank you guys, From this link I figured out gpiod_get_raw_value_cansleep() function is not what I need, Cause this function needs a GPIO descriptor to work and my kernel error was for that. But the functions gpio_get_value_cansleep() and gpio_set_value_cansleep() functions are the functions are suited for i2c IO expander.
So thank you for helping me, The working code is now:
IOCTL_FUNC(...) {
....
case IOCTL_RMG_GPIO_SET:
{
....
//I have initialized the GPIO pin as output before, and assume my gpio pin number is 4.
//int gpioNumber = 4;
//int value = 1;
gpio_set_value_cansleep(gpioNumber, value);
break;
}
case IOCTL_RMG_GPIO_GET:
{
....
//I have initialized the GPIO pin as output before, and assume my gpio pin number is 4.
//int gpioNumber = 4;
value = gpio_get_value_cansleep(gpioNumber);
break;
}
....
}

If you read the linux source at the warning, it tells you:
* This function should be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
WARN_ON(desc->gdev->chip->can_sleep);
You should be calling gpio_get_value_cansleep

Related

convert HW IRQ to Linux IRQ

I have a HW_IRQ is shared between 2 kernel modules. Module1 is loaded at the boot time and called: request_irq(linux_irq1, handler1, IRQF_SHARED, ...);. After booting up, I want to load the Module2 that shared the same HW_IRQ with the Module1. I need to call request_irq(linux_irq2, handler2, IRQF_SHARED, ...);. Actually 'linux_irq2' is equal to 'linux_irq1', but in Module2 I can not access to private data of Module1. Do you know how to convert HW_IRQ to 'linux_irq2' in Module2?
Module2 as a patch of Module1, it has no Device Tree node.
We can map HW IRQ to Linux IRQ by this:
u32 irq;
struct irq_desc *desc;
for (irq = 0; irq < NR_IRQS; irq++) {
desc = irq_to_desc(irq);
if (desc && desc->irq_data.hwirq == hwirq)
return desc->irq_data.irq;
}

How to set value of i2c PCA9570 gpio expander as early as possible during Linux boot?

I have written a working driver for the PCA9570. Its four outputs are set (and read back) via Linux's GPIO subsystem. e.g.
root#armbox:/sys/class/gpio# echo 508 > export
root#armbox:/sys/class/gpio# echo 509 > export
root#armbox:/sys/class/gpio# echo 510 > export
root#armbox:/sys/class/gpio# echo 511 > export
The problem is that the chip starts with its outputs high. https://www.nxp.com/docs/en/data-sheet/PCA9570.pdf section 8.1.
root#armbox:/sys/class/gpio# cat gpio508/value
1
root#armbox:/sys/class/gpio# cat gpio509/value
1
root#armbox:/sys/class/gpio# cat gpio510/value
1
root#armbox:/sys/class/gpio# cat gpio511/value
1
I can manually set them low from userspace, after boot. e.g.
root#armbox:/sys/class/gpio# echo 0 > gpio510/value
root#armbox:/sys/class/gpio# cat gpio510/value
0
How can I set the chip's outputs low as early as possible during the boot sequence?
I can hack my own driver to do this, during pca9570_probe(), but that feels very hacky. pca9570_probe() currently reads the values from the chip.
static int pca9570_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
...
ret = pca9570_readb(chip, &chip->reg);
if (ret)
goto out_failed;
return 0;
out_failed:
if (chip->client)
i2c_unregister_device(chip->client);
return -1;
}
Is there a correct way in Linux to specify GPIO values during boot, rather than hacking a driver?
P.S. The dts clause is:
pca9570: pca9570#48 {
compatible = "pca9570";
reg = <0x24>;
gpio-controller;
#gpio-cells = <4>;
};
You can use 'GPIO hogging' mechanism as described in DeviceTree gpio binding documentation. Quoting basic information:
GPIO hogging is a mechanism
providing automatic GPIO request and configuration as part of the
gpio-controller's driver probe function.
For example, we have this definition in our device tree for our gpio expander:
gpio_expander: tca6424a#22 {
compatible = "ti,tca6424";
reg = <0x22>;
[...] /* some other gpio expander configuration */
lcd-rst {
gpio-hog;
gpios = <7 GPIO_ACTIVE_LOW>;
output-low;
};
};
You don't need to extend your driver, it is part of the gpio subsystem.

The irq in kernel function asm_do_IRQ() is different from the one I request in module

I did some experiment with a cortex-A9 development board. I used gpio_to_irq() to get an irq num and I requested the irq and wrote a small driver with it , it was 196 in syslog . And I added some printks in asm_do_IRQ. When I triggered the gpio interrupt , the driver works fine but the irq num in asm_do_IRQ was 62 .I can't understand. Why the irq number was different from the one I request? The driver is as follow:
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#define GPIO_N 36 //gpio number
int flag = 0;
static irqreturn_t handler(int irq,void *dev_id)
{
printk("hello world hahahahahhahahah \n\n");
return 0;
}
static int __init gpio_test_init(void)
{
if(gpio_request_one(GPIO_N,GPIOF_DIR_IN,"some test")<0)
{
printk(KERN_ERR "Oops! BAD! BAD! BAD!\n\n");
return 0;
}
int irq,irq2;
irq = OMAP_GPIO_IRQ(TEST_GPIO);
printk("irq : %d \n",irq,irq2);
// ..................
// irq : 196 in dmesg
//......................
set_irq_type(irq,IRQ_TYPE_EDGE_FALLING);
enable_irq(gpio_to_irq(GPIO_N));
int err;
// request the irq ...
if((err = request_irq(irq,&handler,0,NULL,NULL))<0)
{
printk("err : %d\n",err);
return 0;
}
printk("gpio test init success!\n");
flag = 1;
return 0;
}
static void __exit gpio_test_exit(void)
{
int irq = gpio_to_irq(TEST_GPIO);
if(flag == 1)free_irq(irq,NULL);
gpio_free(TEST_GPIO);
printk("gpio test exit byebye!\n");
}
module_init(gpio_test_init);
module_exit(gpio_test_exit);
MODULE_LICENSE("GPL");
asm_do_IRQ in arch/arm/kernel/irq.c
asmlinkage void __exception_irq_entry
asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
printk("the irq : %d\n",irq);
//...............
// I get 62 here
//...............
irq_enter();
/*
* Some hardware gives randomly wrong interrupts. Rather
* than crashing, do something sensible.
*/
if (unlikely(irq >= nr_irqs)) {
if (printk_ratelimit())
printk(KERN_WARNING "Bad IRQ%u\n", irq);
ack_bad_irq(irq);
} else {
generic_handle_irq(irq);
}
/* AT91 specific workaround */
irq_finish(irq);
irq_exit();
set_irq_regs(old_regs);
}
This observation is likely due to the mapping between physical and virtual IRQ numbers. The numbers seen in your driver are virtual IRQ numbers, valid only when using the generic linux interrupt handling subsystem. The interrupt number in asm_do_IRQ will be the physical interrupt number provided by the interrupt fabric of the core.
I believe the OMAP processors support interrupts on GPIO pins. The way this is usually implemented is to allocate a single IRQ line for a bank of GPIO inputs, say 32 bits. When an interrupt occurs on any of the GPIOs, that IRQ line will activate. This is likely the number 62 on your processor. If you look in the manual for your processor, you should see that IRQ 62 corresponds to an interrupt on a GPIO bank.
Now, the linux GPIO subsystem will allow you to allocate an interrupt handler to any of the GPIOs, providing you with a mapping from a linux irq number to a physical irq number. The linux irq number in your case is 196. The GPIO subsystem is configured to handle all GPIO interrupts (say interrupt 62), read the GPIO register to determine which of the GPIO bits in a bank could have generated an interrupt, and then calls out the interrupt handler you've assigned with request_irq.
Here's a basic flow of control for a GPIO interrupt:
A change occurs on an interrupt in a GPIO bank. IRQ 62 is raised.
asm_do_IRQ runs on IRQ 62. The GPIO subsystem has been registered to handle IRQ 62 by the platform init code.
The GPIO subsystem reads the GPIO registers and determines that GPIO bit X has caused the interrupt. It calculates the mapping from bit X to the linux virtual IRQ number, in this case 196.
The GPIO interrupt handler then calls the generic_handle_irq function with 196, which calls your interrupt handler.
There is usually a static mapping defined by the platform between virtual IRQ numbers and physical IRQ numbers. To see this mapping,
enable CONFIG_VIRQ_DEBUG on kernels older than linux-3.4, or
enable CONFIG_IRQ_DOMAIN_DEBUG on newer kernels.
Then have a look to irq_domain_mapping debugfs file. E.g. on PowerPC:
# mount -t debugfs none /sys/kernel/debug
# cat /sys/kernel/debug/irq_domain_mapping
irq hwirq chip name chip data domain name
16 0x00009 IPIC 0xcf801c80 /soc8347#e0000000/pic#700
18 0x00012 IPIC 0xcf801c80 /soc8347#e0000000/pic#700
19 0x0000e IPIC 0xcf801c80 /soc8347#e0000000/pic#700
20 0x0000f IPIC 0xcf801c80 /soc8347#e0000000/pic#700
21 0x00010 IPIC 0xcf801c80 /soc8347#e0000000/pic#700
77 0x0004d IPIC 0xcf801c80 /soc8347#e0000000/pic#700

Linux device driver to allow an FPGA to DMA directly to CPU RAM

I'm writing a linux device driver to allow an FPGA (currently connected to the PC via PCI express) to DMA data directly into CPU RAM. This needs to happen without any interaction and user space needs to have access to the data. Some details:
- Running 64 bit Fedora 14
- System has 8GB of RAM
- The FPGA (Cyclone IV) is on a PCIe card
In an attempt to accomplish this I performed the following:
- Reserved the upper 2GB of RAM in grub with memmap 6GB$2GB (will not boot is I add mem=2GB). I can see that the upper 2GB of RAM is reserved in /proc/meminfo
- Mapped BAR0 to allow reading and writing to FPGA registers (this works perfectly)
- Implemented an mmap function in my driver with remap_pfn_range()
- Use ioremap to get the virtual address of the buffer
- Added ioctl calls (for testing) to write data to the buffer
- Tested the mmap by making an ioctl call to write data into the buffer and verified the data was in the buffer from user space
The problem I'm facing is when the FPGA starts to DMA data to the buffer address I provide. I constantly get PTE errors (from DMAR:) or with the code below I get the following error:
DMAR: [DMA Write] Request device [01:00.0] fault addr 186dc5000
DMAR: [fault reason 01] Present bit in root entry is clear
DRHD: handling fault status reg 3
The address in the first line increments by 0x1000 each time based on the DMA from the FPGA
Here's my init() code:
#define IMG_BUF_OFFSET 0x180000000UL // Location in RAM (6GB)
#define IMG_BUF_SIZE 0x80000000UL // Size of the Buffer (2GB)
#define pci_dma_h(addr) ((addr >> 16) >> 16)
#define pci_dma_l(addr) (addr & 0xffffffffUL)
if((pdev = pci_get_device(FPGA_VEN_ID, FPGA_DEV_ID, NULL)))
{
printk("FPGA Found on the PCIe Bus\n");
// Enable the device
if(pci_enable_device(pdev))
{
printk("Failed to enable PCI device\n");
return(-1);
}
// Enable bus master
pci_set_master(pdev);
pci_read_config_word(pdev, PCI_VENDOR_ID, &id);
printk("Vendor id: %x\n", id);
pci_read_config_word(pdev, PCI_DEVICE_ID, &id);
printk("Device id: %x\n", id);
pci_read_config_word(pdev, PCI_STATUS, &id);
printk("Device Status: %x\n", id);
pci_read_config_dword(pdev, PCI_COMMAND, &temp);
printk("Command Register : : %x\n", temp);
printk("Resources Allocated :\n");
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &temp);
printk("BAR0 : %x\n", temp);
// Get the starting address of BAR0
bar0_ptr = (unsigned int*)pcim_iomap(pdev, 0, FPGA_CONFIG_SIZE);
if(!bar0_ptr)
{
printk("Error mapping Bar0\n");
return -1;
}
printk("Remapped BAR0\n");
// Set DMA Masking
if(!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
{
pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
printk("Device setup for 64bit DMA\n");
}
else if(!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
{
pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
printk("Device setup for 32bit DMA\n");
}
else
{
printk(KERN_WARNING"No suitable DMA available.\n");
return -1;
}
// Get a pointer to reserved lower RAM in kernel address space (virtual address)
virt_addr = ioremap(IMG_BUF_OFFSET, IMG_BUF_SIZE);
kernel_image_buffer_ptr = (unsigned char*)virt_addr;
memset(kernel_image_buffer_ptr, 0, IMG_BUF_SIZE);
printk("Remapped image buffer: 0x%p\n", (void*)virt_addr);
}
Here's my mmap code:
unsigned long image_buffer;
unsigned int low;
unsigned int high;
if(remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
{
return(-EAGAIN);
}
image_buffer = (vma->vm_pgoff << PAGE_SHIFT);
if(0 > check_mem_region(IMG_BUF_OFFSET, IMG_BUF_SIZE))
{
printk("Failed to check region...memory in use\n");
return -1;
}
request_mem_region(IMG_BUF_OFFSET, IMG_BUF_SIZE, DRV_NAME);
// Get the bus address from the virtual address above
//dma_page = virt_to_page(addr);
//dma_offset = ((unsigned long)addr & ~PAGE_MASK);
//dma_addr = pci_map_page(pdev, dma_page, dma_offset, IMG_BUF_SIZE, PCI_DMA_FROMDEVICE);
//dma_addr = pci_map_single(pdev, image_buffer, IMG_BUF_SIZE, PCI_DMA_FROMDEVICE);
//dma_addr = IMG_BUF_OFFSET;
//printk("DMA Address: 0x%p\n", (void*)dma_addr);
// Write start or image buffer address to the FPGA
low = pci_dma_l(image_buffer);
low &= 0xfffffffc;
high = pci_dma_h(image_buffer);
if(high != 0)
low |= 0x00000001;
*(bar0_ptr + (17024/4)) = 0;
//printk("DMA Address LOW : 0x%x\n", cpu_to_le32(low));
//printk("DMA Address HIGH: 0x%x\n", cpu_to_le32(high));
*(bar0_ptr + (4096/4)) = cpu_to_le32(low); //2147483649;
*(bar0_ptr + (4100/4)) = cpu_to_le32(high);
*(bar0_ptr + (17052/4)) = cpu_to_le32(low & 0xfffffffe);//2147483648;
printk("Process Read Command: Addr:0x%x Ret:0x%x\n", 4096, *(bar0_ptr + (4096/4)));
printk("Process Read Command: Addr:0x%x Ret:0x%x\n", 4100, *(bar0_ptr + (4100/4)));
printk("Process Read Command: Addr:0x%x Ret:0x%x\n", 17052, *(bar0_ptr + (17052/4)));
return(0);
Thank you for any help you can provide.
Do you control the RTL code that writes the TLP packets yourself, or can you name the DMA engine and PCIe BFM (bus functional model) you are using? What do your packets look like in the simulator? Most decent BFM should trap this rather than let you find it post-deploy with a PCIe hardware capture system.
To target the upper 2GB of RAM you will need to be sending 2DW (64-bit) addresses from the device. Are the bits in your Fmt/Type set to do this? The faulting address looks like a masked 32-bit bus address, so something at this level is likely incorrect. Also bear in mind that because PCIe is big-endian take care when writing the target addresses to the PCIe device endpoint. You might have the lower bytes of the target address dropping into the payload if Fmt is incorrect - again a decent BFM should spot the resulting packet length mismatch.
If you have a recent motherboard/modern CPU, the PCIe endpoint should do PCIe AER (advanced error reporting), so if running a recent Centos/RHEL 6.3 you should get a dmesg report of endpoint faults. This is very useful as the report capture the first handful of DW's of the packet to special capture registers, so you can review the TLP as received.
In your kernel driver, I see you setup the DMA mask, that is not sufficient as you have not programmed the mmu to allow writes to the pages from the device. Look at the implementation of pci_alloc_consistent() to see what else you should be calling to achieve this.
If you are still looking for a reason, then it goes like this:
Your kernel has DMA_REMAPPING flags enabled by default, thus IOMMU is throwing the above error, as IOMMU context/domain entries are not programmed for your device.
You can try using intel_iommu=off in the kernel command line or putting IOMMU in bypass mode for your device.
Regards,
Samir

Why can't I handle NMI?

I want to handle NMI and do something when NMI occur. Firstly I write a naive nmi handler:
static irqreturn_t nmi_handler(int irq, void* dev_id) {
printk("-#_#- I'm TT, I am handling NMI.\n");
return IRQ_HANDLED;
}
And write a module to register my nmi handler, then use APIC to trigger NMI 5 times:
static void __init ipi_init(void) {
printk("-#_#- I'm coming again, hahaha!\n");
int result = request_irq(NMI_VECTOR,
nmi_handler, IRQF_DISABLED, "NMI Watchdog", NULL);
printk("--- the result of request_irq is: %d\n", result);
int i;
for (i = 0; i < 5; ++i) {
apic->send_IPI_allbutself(NMI_VECTOR);
ssleep(1);
}
}
Now I type "insmod xxx.ko" to install this module, after that, I check the /var/log/syslog:
kernel: [ 1166.231005] -#_#- I'm coming again, hahaha!
kernel: [ 1166.231028] --- the result of request_irq is: 0
kernel: [ 1166.231050] Uhhuh. NMI received for unknown reason 00 on CPU 1.
kernel: [ 1166.231055] Do you have a strange power saving mode enabled?
kernel: [ 1166.231058] Dazed and confused, but trying to continue
kernel: [ 1167.196293] Uhhuh. NMI received for unknown reason 00 on CPU 1.
kernel: [ 1167.196293] Do you have a strange power saving mode enabled?
kernel: [ 1167.196293] Dazed and confused, but trying to continue
kernel: [ 1168.201288] Uhhuh. NMI received for unknown reason 00 on CPU 1.
kernel: [ 1168.201288] Do you have a strange power saving mode enabled?
kernel: [ 1168.201288] Dazed and confused, but trying to continue
kernel: [ 1169.235553] Uhhuh. NMI received for unknown reason 00 on CPU 1.
kernel: [ 1169.235553] Do you have a strange power saving mode enabled?
kernel: [ 1169.235553] Dazed and confused, but trying to continue
kernel: [ 1170.236343] Uhhuh. NMI received for unknown reason 00 on CPU 1.
kernel: [ 1170.236343] Do you have a strange power saving mode enabled?
kernel: [ 1170.236343] Dazed and confused, but trying to continue
It shows that I register nmi_handler successfully(result=0), and NMI were triggered 5 times, but I didn't find sting that should be outputed in nmi_handler.
I work on Ubuntu 10.04 LTS, Intel Pentium 4 Dual-core.
Does it mean my NMI handler didn't execute?
How do I handler NMI in Linux?
Nobody?
My partner gave me 3 more days, so I read the source code and ULK3, now I can answer question 1:
Does it mean my NMI handle didn't execute?
In fact, IRQ number and INT vector number are different! The function request_irq() call setup_irq():
/**
* setup_irq - setup an interrupt
* #irq: Interrupt line to setup
* #act: irqaction for the interrupt
*
* Used to statically setup interrupts in the early boot process.
*/
int setup_irq(unsigned int irq, struct irqaction *act)
{
struct irq_desc *desc = irq_to_desc(irq);
return __setup_irq(irq, desc, act);
}
Look at this: #irq: Interrupt line to setup
. The argument irq is interrupt line number, not interrupt vector number. Look up ULK3 PDF, P203, Timer interrupt has IRQ 0, but its INT nr is 32! So I trigger the INT2(NMI) but my handler handle the INT34 actually! I want to find more evidence in source code(e.g. how to convert IRQ to INT? I modify my handler and init, I request irq=2, and Linux allot INT=50), but get nothing, expect linux-xxx/arch/x86/include/asm/irq_vectors.h
/*
* IDT vectors usable for external interrupt sources start
* at 0x20:
*/
#define FIRST_EXTERNAL_VECTOR 0x20
Wait me for a while...let me read more codes to answer question 2.

Resources