BUG: unable to handle kernel paging request at

25,434

Read Documentation/IO-mapping.txt (search for "iomap") and/or Chapter 15 of LDD3.

request_mem_region just ensures no other driver has already grabbed that memory region. You still need to map it into the kernel's VM space using iomap before you can read/write it.

Note that the whole pci_resource_start etc. dance is somewhat deprecated. I believe the recommended approach these days is:

pci_request_regions(pdev, "myname");  /* to request regions for all BARs */

Then:

void __iomem *base = pci_iomap(pdev, 0, pci_resources_len(pdev,0)); /* to map BAR 0 */

Then:

ioread32(base + offset);  /* Or readl(base + offset), but this is more generic */

And finally, at the end:

pci_iounmap(pdev, base);  /* Release kernel VM mapping (undoes pci_iomap) */
pci_release_regions(pdev); /* Release all regions (undoes pci_request_regions) */

You can do the first two manually by combining pci_resource_start, pci_resource_len, request_mem_region, and iomap. But the above is (a) shorter and (b) generic between memory-mapped devices and those that use the old x86 I/O space. (Not that there are a whole lot of those around anymore.)

Share:
25,434
kohpe
Author by

kohpe

Updated on March 03, 2020

Comments

  • kohpe
    kohpe about 4 years

    I am writing a PCI driver for a simple test device.

    Hardware is recognized correctly with lspci (as you can see my driver vabs has been registered):

    04:02.0 Non-VGA unclassified device: Device bace:55aa
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
        Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0
        Region 0: Memory at f0000000 (32-bit, prefetchable) [size=16M]
        Kernel driver in use: vabs
    

    Initialisation and deinitalisation of driver and PCI subystem works fine. I am getting a device number, and udev creates a device file.

    When reading from the device file I get the following error message:

    BUG: unable to handle kernel paging request at 00000000f0000000
    

    I request PCI ressources in the initialisation successfully. This returns 00000000f0000000 for memstart0, which is my base address 0 for PCI.

    memstart0 = pci_resource_start( pdev, 0 );
    memlen = pci_resource_len( pdev, 0 );
    if( request_mem_region(memstart0,memlen,pdev->dev.kobj.name)==NULL ) {
        dev_err(&pdev->dev,"Memory address conflict for device\n");
        goto cleanup_mem;
    }
    

    Trying to read from this memio address with the following code gives the mentioned error:

    ssize_t driver_read(struct file *instance, char __user *buffer, size_t max_bytes_to_read, loff_t *offset) {
        u32 test;
    
        dev_dbg(vabs_dev,"copying from %p\n", (void *) memstart0);
        test = readl((void *) memstart0);
    
        return max_bytes_to_read;
    }
    

    I also tried other access functions like memcpy_fromio, ioread32, and direct pointer access with the same result.

    The hardware works on a Windows machine. The only notable difference is that Windows reserves base address 0 as 00000000fd000000 while Linux reserves it as 00000000f0000000.

    This is for non-profit educational purpose in a public school. Thanks for your help!

  • kohpe
    kohpe over 11 years
    Thank you very much. It works now. I am using a book on driver programming which completely ignores the topic of paging!
  • Nemo
    Nemo over 11 years
    Glad I could help. You might consider accepting my answer :-)