Hi, i am developing a driver for a custom PCI board. I am following
the example on Essential Linux Device Drivers, but when i am calling
the pci_alloc_consitent i get the following error:

Code:
Mar 29 15:18:42 luis-desktop kernel: [ 4520.075823] BUG: unable to 
handle kernel NULL pointer dereference at 00000004 
Mar 29 15:18:42 luis-desktop kernel: [ 4520.078277] IP: [<c010797f>] 
dma_generic_alloc_coherent+0xaf/0xc0 
Mar 29 15:18:42 luis-desktop kernel: [ 4520.078277] *pde = 0a417067 
*pte = 00000000 
Mar 29 15:18:42 luis-desktop kernel: [ 4520.078277] Oops: 0002 [#1] 
SMP

I am running on a x86 (Pentium III) with Ubuntu Kernel 2.6.32-24


I tryed to take a look at ldd3 but no answer so far...


The driver code is:


Code:
/* 
 * pci_bridge-driver.c - template Linux driver for the opencores' pci 
bridge . Works on * kernel 2.6.x 
 * 
 * tested on Xubuntu, kernel 2.6.20-15-generic 
 * 
 * 
 * Permission to use, copy, modify, and distribute this software for 
any 
 * purpose with or without fee is hereby granted. 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY 
 * RIGHTS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, 
DAMAGES 
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
OTHERWISE, 
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 
OR 
 * OTHER DEALINGS IN THE SOFTWARE. 
 */ 


/* 
 * Build/use notes (you'll probably need to be superuser to run most 
of 
 * the steps below): 
 * 
 * 1) How to build the driver: 
 * 
 *      $ make 
 * 
 * 2) How to install the driver: 
 * 
 *      $ insmod pci_bridge-driver.ko 
 * 
 * TODO: change the code and use misc device and udev, so to avoid the 
stuff below (3-4) !! 
 * 3) If pci_bridge_init_major (below) is 0, then obtain the major 
number: 
 * 
 *      $ cat /proc/devices 
 * 
 * Look for the line that contains the string "pci_bridge". The major 
 * number is to the left. 
 * 
 * 4) Make the pci_bridge device special file. Substitute the major 
 * number obtained above for <major_number>. 
 * 
 *      $ mknod /dev/pci_bridge c <major_number> 0 
 * 
 * 5) How to remove the driver: 
 * 
 *      $ rmmod pci_bridge-driver 
 */ 


#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/pci.h> 
#include <linux/init.h> 
#include <linux/cdev.h> 
#include <linux/fs.h> 
#include <linux/ioctl.h> 


//#include <asm/byteorder.h>              /* PCI is little endian */ 
#include <asm/uaccess.h>                /* copy to/from user */ 


#include "kint.h" 


#define PCI_BRIDGE_DEVICE_ID 0x0001 
#define PCI_BRIDGE_VENDOR_ID 0x1895 
#define PCI_DRIVER_NAME "pci_bridge" /* driver name */ 
#define BRIDGE_MEM_MAPPED 0 
#define BRIDGE_IO_MAPPED 1 


/* 
 * PCI device IDs supported by this driver. The PCI_DEVICE macro sets 
 * the vendor and device fields to its input arguments, sets subvendor 
 * and subdevice to PCI_ANY_ID. It does not set the class fields. 
 */ 
static struct pci_device_id pci_bridge_ids[] = 
{ 
        { PCI_DEVICE(PCI_BRIDGE_VENDOR_ID, PCI_BRIDGE_DEVICE_ID), }, 
        { 0, } 



}; 


/* 
 * For completeness, tell the module loading and hotplug systems 
 * what PCI devices this module supports. 
 */ 
MODULE_DEVICE_TABLE(pci, pci_bridge_ids); 

/* 
 * pci_register_driver parameter. 
 */ 
static int pci_bridge_probe(struct pci_dev *, const struct 
pci_device_id *); 
static void pci_bridge_remove(struct pci_dev *); 


static struct pci_driver pci_bridge_driver = 
{ 
        .name = PCI_DRIVER_NAME, 
        .id_table = pci_bridge_ids, 
        .probe = pci_bridge_probe, 
        .remove = pci_bridge_remove, 



}; 


/* 
 * File operations i/f. 
 */ 
int pci_bridge_open(struct inode *, struct file *); 
int pci_bridge_release(struct inode *, struct file *); 
ssize_t pci_bridge_read(struct file *, char __user *, size_t, loff_t 
*); 
ssize_t pci_bridge_write(struct file *, const char __user *, size_t, 
loff_t *); 
int pci_bridge_ioctl(struct inode *pnode, struct file *filp, unsigned 
int cmd, unsigned long arg); 
// seek file operation function 
loff_t  bridge_lseek(struct file *filp, loff_t offset, int origin); 

static void dma_descriptor_release(struct pci_dev *pdev); 
static void dma_descriptor_setup(struct pci_dev *pdev); 


static struct file_operations pci_bridge_fops = 
{ 
        read: pci_bridge_read, 
        write: pci_bridge_write, 
        open: pci_bridge_open, 
        release: pci_bridge_release, 
        ioctl: pci_bridge_ioctl, 
        llseek: bridge_lseek 



}; 


static int __init pci_bridge_init(void); 
static void __exit pci_bridge_exit(void); 

/* 
 * Driver major number. 0 = allocate dynamically. 
 */ 
static int pci_bridge_init_major = 0; 
static int pci_bridge_major; 


/* 
 * Per-device structure. 
 */ 
static struct pci_bridge_dev 
{ 
        struct cdev cdev;               /* Char device structure        */ 
        struct pci_dev *pcidev;         /* PCI device pointer           */ 
        int current_resource; 
        u32 page_addr; 
        u8 num_of_bases; 
        int base_map[6]; 
        u32 bases[6]; 
        u32 base_size[6]; 
        u32 base_page_offset; 
        u32 offset; 
        u8  interrupt_line; 



} *pci_bridge_devices; 


static struct device_data 
{ 
        void *dma_buffer_rx; 
        dma_addr_t dma_bus_rx; 
        void *dma_buffer_tx; 
        dma_addr_t dma_bus_tx; 


}*c_memory_map; 


/* 
 * pci_bridge_probe - pci_driver probe function. Just enable the PCI 
device. 
 * Could also check various configuration registers, find a specific 
PCI 
 * device, request a specific region, etc. 
 */ 
static int pci_bridge_probe(struct pci_dev *pcidev, const struct 
pci_device_id *id) 
{ 
        struct pci_bridge_dev *dev; 
        printk("pci_bridge_probe called ...\n"); 
        if(pcidev == NULL) 
        { 
                printk(KERN_NOTICE "pci_bridge_probe: PCI DEV is NULL\n"); 
                return -EINVAL; 
        } 

        dev = pci_bridge_devices; // only one device for now 
        if(dev == NULL) 
                printk("pci_bridge_probe: device structure not allocated\n"); 
        else 
        { 
                pci_enable_device(pcidev); 
                pci_set_master(pcidev); 
                dev->pcidev = pcidev; 
        } 


        return 0; 



} 


/* 
 * pci_bridge_remove - pci_driver remove function. Release allocated 
resources, 
 * etc. 
 */ 
static void __devexit pci_bridge_remove(struct pci_dev *dev) 
{ 
    printk("pci_bridge_remove called ...\n"); 


} 


/* 
 * pci_bridge_init - module init function. By convention, the function 
is 
 * declared static, even though it is not exported to the rest of the 
 * kernel unless explicitly requested via the EXPORT_SYMBOL macro. The 
 * __init qualifier tells the loader that the function is only used at 
 * module initialization time. 
 */ 
static int __init pci_bridge_init(void) 
{ 
        struct pci_bridge_dev *dev; 
        dev_t devno; 
        int result; 
        unsigned short num_of_bases; 
        u32 base_address; 
        printk("pci_bridge_init called ...\n"); 

        /* 
        * Allocate the per-device structure(s). 
        */ 
        pci_bridge_devices = kmalloc(sizeof(struct pci_bridge_dev), 
GFP_KERNEL); 
        if(pci_bridge_devices == NULL) 
        { 
                result = -ENOMEM; 
                goto fail; 
        } 


        /* 
        * Get a range of minor numbers to work with, asking for a dynamic 
        * major unless directed otherwise at load time. 
        */ 
        if(pci_bridge_init_major) 
        { 
                pci_bridge_major = pci_bridge_init_major; 
                devno = MKDEV(pci_bridge_major, 0); 
                result = register_chrdev_region(devno, 1, PCI_DRIVER_NAME); 
        } 
        else 
        { 
                result = alloc_chrdev_region(&devno, 0, 1, PCI_DRIVER_NAME); 
                pci_bridge_major = MAJOR(devno); 
        } 
        if(result < 0) 
        { 
                printk(KERN_NOTICE "pci_bridge: can't get major %d\n", 
pci_bridge_major); 
                goto fail; 
        } 


        dev = pci_bridge_devices;/* only one device for now */ 


        /* 
        * Initialize and add this device's character device table entry. 
        */ 
        dev->pcidev = NULL; 
        cdev_init(&dev->cdev, &pci_bridge_fops); 
        dev->cdev.owner = THIS_MODULE; 
        dev->cdev.ops = &pci_bridge_fops; 
        dev->offset = 0; 
        result = cdev_add(&dev->cdev, devno, 1); 
        if(result) 
        { 
                printk(KERN_NOTICE "Error %d adding %s device", result, 
PCI_DRIVER_NAME); 
                goto fail; 
        } 


        if((result = pci_register_driver(&pci_bridge_driver)) != 0) 
        { 
                printk(KERN_NOTICE "Error %d registering %s PCI device",result, 
PCI_DRIVER_NAME); 
                goto fail; 
        } 


        if(dev->pcidev == NULL) 
        { 
                printk(KERN_NOTICE "PCI DEV is NULL, probe failed?\n"); 
                goto fail; 
        } 


        base_address = pci_resource_start(dev->pcidev, 0); 


        printk("<1> First base address register found at %08X \n ", 
pci_resource_start(dev->pcidev, 0)); 
        num_of_bases = 0; 


        while 
        ((base_address = pci_resource_start(dev->pcidev, num_of_bases))!= 
0x00000000 && (num_of_bases < 6)) 
        { 
                unsigned long flags; 
                flags = pci_resource_flags(dev->pcidev, num_of_bases); 
                dev->bases[num_of_bases] = base_address; 
                dev->base_size[num_of_bases] = pci_resource_end(dev->pcidev, 
num_of_bases) - base_address + 1; 
                // check if resource is IO mapped 
                if (flags & IORESOURCE_IO) 
                    dev->base_map[num_of_bases] = BRIDGE_IO_MAPPED; 
                else 
                    dev->base_map[num_of_bases] = BRIDGE_MEM_MAPPED; 
                num_of_bases++; 
        } 


        if (num_of_bases < 1) 
                printk("<1>No implemented base address registers found! \n "); 


        dev->current_resource = - 1; 


        // store number of bases in structure 
        dev->num_of_bases = num_of_bases; 
        printk("num_of_bases found %d \n", num_of_bases); 
        // display information about all base addresses found in this 
procedure 
        for (num_of_bases = 0; num_of_bases < dev->num_of_bases; num_of_bases+ 
+) 
        { 
                printk("<1>BAR%d range from %08X to %08X \n ", num_of_bases, dev- 


>bases[num_of_bases], dev->bases[num_of_bases] + dev- 
>base_size[num_of_bases]); 


        } 

        if(pci_read_config_byte(dev->pcidev,PCI_INTERRUPT_LINE, &dev- 


>interrupt_line)) 


        { 
                printk("Could not get interrupt line"); 
                } 
        else 
        { 
                printk("Interrupt Line is %d \n", dev->interrupt_line); 
                } 
        dma_descriptor_setup(dev->pcidev); 

        return 0; 


fail: 
                pci_bridge_exit(); 
                return result; 



} 


/* 
 * pci_bridge_exit - module exit function. Release resources allocated 
 * by pci_bridge_init. 
 */ 
static void __exit pci_bridge_exit(void) 
{ 
        printk("pci_bridge_exit called ...\n"); 

        if(pci_bridge_devices) 
        { 
                struct pci_bridge_dev *dev; 
                dev = &pci_bridge_devices[0]; 
                dma_descriptor_release(dev->pcidev); 
                cdev_del(&dev->cdev); 
                kfree(pci_bridge_devices); 
                pci_bridge_devices = NULL; 
        } 
        unregister_chrdev_region(MKDEV(pci_bridge_major, 0), 1); 
        pci_bridge_major = 0; 
        pci_unregister_driver(&pci_bridge_driver); 



} 


/* 
 * pci_bridge_open - open file processing. 
 */ 
int pci_bridge_open(struct inode *inode, struct file *filep) 
{ 
        struct pci_bridge_dev *dev; 
        dev = container_of(inode->i_cdev, struct pci_bridge_dev, cdev); 
        filep->private_data = dev; // used by read, write, etc 
        dev->current_resource = -1; 
        /* Success */ 
        return 0; 


} 


/* 
 * pci_bridge_release - close processing. 
 */ 
int pci_bridge_release(struct inode *inode, struct file *filep) 
{ 
        /* Success */ 
        return 0; 


} 


/* 
 * seek file operation function 
 */ 
loff_t  bridge_lseek(struct file *filp, loff_t offset, int origin) 
{ 
        struct pci_bridge_dev *dev; 
        loff_t requested_offset; 
        int resource_num; 

        dev = filp->private_data; 
        resource_num = dev->current_resource; 
        switch (origin) 
        { 
                case SEEK_CUR:requested_offset = dev->offset + offset; break; 
                case SEEK_END:requested_offset = dev->base_size[resource_num] + 
offset; break; 
                default:requested_offset  = offset; break; 
        } 


        if ((requested_offset < 0) || (requested_offset > dev- 


>base_size[resource_num])) 


                return -EFAULT; 

        dev->offset = requested_offset; 
        return requested_offset; 



} 


/* 
 * pci_bridge_read - read processing. 
 */ 
ssize_t pci_bridge_read (struct file *filp, char *buf, size_t count, 
loff_t *offset_out ) 
{ 
        struct pci_bridge_dev *dev; 
        unsigned long current_address; 
        unsigned long actual_count; 
        unsigned long offset; 
        int resource_num; 
        int i; 
        unsigned int value; 
        unsigned int *kern_buf; 
        unsigned int *kern_buf_tmp; 
        unsigned long size; 
        int result; 

        dev = filp->private_data; 
        offset = dev->offset; 
        resource_num = dev->current_resource; 
        size   = dev->base_size[resource_num]; 
        current_address = dev->page_addr + dev->base_page_offset + dev- 



>offset; 


        if (dev->current_resource < 0) 
                return -ENODEV; 

        if (offset == size) 
                return 0; 


        if ( (offset + count) > size ) 
                actual_count = size - offset; 
        else 
                actual_count = count; 


        // verify range if it is OK to copy from 
        if ((result = access_ok(VERIFY_WRITE, buf, actual_count)) ==0) 
                return result; 


        kern_buf = kmalloc(actual_count, GFP_KERNEL | GFP_DMA); 
        kern_buf_tmp = kern_buf; 
        if (kern_buf <= 0) 
                return 0; 


        memcpy_fromio(kern_buf, current_address, actual_count); 
        i = actual_count/4; 
        while(i--) 
        { 
//              value = readl(current_address); 
                value = *(kern_buf); 
                put_user(value, ((unsigned int *)buf)); 
                buf += 4; 
                ++kern_buf; 
//              current_address += 4; 
        } 


        kfree(kern_buf_tmp); 
        dev->offset = dev->offset + actual_count; 
        *(offset_out) = dev->offset; 


        return actual_count; 
 } 


/* 
 * pci_bridge_write - write processing. 
 */ 
ssize_t pci_bridge_write (struct file *filp, const char *buf, size_t 
count, loff_t *offset_out) 
{ 
        struct pci_bridge_dev *dev; 
        unsigned long current_address; 
        unsigned long actual_count; 
        unsigned long offset; 
        int resource_num; 
        int i; 
        int value; 
        unsigned long size; 
        int result; 
        int *kern_buf; 
        int *kern_buf_tmp; 


        dev = filp->private_data; 
        current_address = dev->page_addr + dev->base_page_offset + dev- 


>offset; 


        resource_num = dev->current_resource; 
        size  = dev->base_size[resource_num]; 
        offset = dev->offset; 

        if (dev->current_resource < 0) 
                return -ENODEV; 


        if (offset == size) 
                return 0; 


        if ( (offset + count) > size ) 
                actual_count = size - offset; 
        else 
                actual_count = count; 


        // verify range if it is OK to copy from 
        if ((result = access_ok(VERIFY_READ, buf, actual_count)) == 0) 
                return result; 
        kern_buf = kmalloc(actual_count, GFP_KERNEL | GFP_DMA); 
        kern_buf_tmp = kern_buf; 
        if (kern_buf <= 0) 
                return 0; 
        i = actual_count/4; 
        while(i--) 
        { 
                get_user(value, ((int *)buf)); 
//              writel(value, current_address); 
                *kern_buf = value; 
                buf += 4; 
                //current_address += 4; 
                ++kern_buf; 
        } 


        memcpy_toio(current_address, kern_buf_tmp, actual_count); 
        kfree(kern_buf_tmp); 
        dev->offset = dev->offset + actual_count; 
        *(offset_out) = dev->offset; 


        return actual_count; 



} 


/* 
 * helper function for memory remaping 
 */ 
int open_mem_mapped(struct pci_bridge_dev *dev) 
{ 
        int resource_num = dev->current_resource; 
        unsigned long num_of_pages = 0; 
        unsigned long base = dev->bases[resource_num]; 
        unsigned long size = dev->base_size[resource_num]; 
        //printk("\n current resource=%d , size = %d, base=%08X", dev- 

>current_resource , size, dev->bases[resource_num]); 


        if (!(num_of_pages = (unsigned long)(size/PAGE_SIZE))); 
                num_of_pages++; 

        dev->base_page_offset = base & ~PAGE_MASK; 


        if ((dev->base_page_offset + size) < (num_of_pages*PAGE_SIZE)) 
                num_of_pages++; 


        // remap memory mapped space 
        dev->page_addr = (unsigned long)ioremap(base & PAGE_MASK, 
num_of_pages * PAGE_SIZE); 


        if (dev->page_addr == 0x00000000) 
                return -ENOMEM; 


        return 0; 



} 


/* 
 * ioctl: see kint.h for the meaning of args 
 */ 
int pci_bridge_ioctl(struct inode *pnode, struct file *filp, unsigned 
int cmd, unsigned long arg) 
{ 

        int error = 0; 
        unsigned long base; 
        unsigned long base_size; 
        struct pci_bridge_dev *dev; 
        dev = filp->private_data; 


        if (_IOC_TYPE(cmd) != BRIDGE_IOC_NUM) return -EINVAL; 
        if (_IOC_NR(cmd) > BRIDGE_IOC_MAX_NUM) return -EINVAL; 


        switch (cmd) 
        { 
                case BRIDGE_IOC_CURRESGET: 
                        // current resource - they start at 1 
                        return (dev->current_resource + 1); 


                case BRIDGE_IOC_CURRESSET: 
                        // check if resource is in a range of implemented resources 
                        if (arg < 0 ) 
                                return -EINVAL; 


                        // unmap previous resource if it was mapped 
                        if (dev->current_resource >= 0) 
                        { 
                                iounmap((void *)dev->page_addr); 
                        } 


                        if (arg == 0) 
                        { 
                                // previous resource unmaped - that's all 
                                dev->current_resource = -1; 
                                return 0; 
                        } 


                        if (dev->num_of_bases < arg) 
                                return -ENODEV; 


                        // IO mapped not supported yet 
                        if (dev->base_map[arg-1] == BRIDGE_IO_MAPPED) 
                        { 
                                // set current resource to none, since it was unmapped 
                                dev->current_resource = -1; 
                                return -ENODEV; 
                        } 
                        dev->current_resource= (int)(arg-1); 
                        // remap new resource 
                        if ( (error = open_mem_mapped(dev)) ) 
                        { 
                                dev->current_resource = -1; 
                                return error; 
                        } 
                        return 0; 


                case BRIDGE_IOC_CURBASE: 
                        // check if any resource is currently activated 
                        if (dev->current_resource>=0) 
                        { 
                                base = dev->bases[dev->current_resource]; 
                                printk("\n CURR_RES = %d",dev->current_resource ); 
                        } 
                        else 
                                base = 0x00000000; 


                        *(unsigned long *)arg = base; 
                        return 0; 


                case BRIDGE_IOC_CURBASEMAP: 
                        // check if any resource is currently activated 
                        if (dev->current_resource>=0) 
                                base = dev->page_addr; 
                        else 
                                base = 0x00000000; 


                        *(unsigned long *)arg = base; 


                        return 0; 


                case BRIDGE_IOC_CURBASESIZE: 
                        // check if any resource is currently activated 
                        if (dev->current_resource>=0) 
                                base_size = dev->base_size[dev->current_resource]; 
                        else 
                                base_size = 0x00000000; 


                        *(unsigned long *)arg = base_size; 
                        return 0; 


                case BRIDGE_IOC_NUMOFRES: 
                        return (dev->num_of_bases); 


                default: 
                        return -EINVAL; 


        } 



} 


#define TX_BUFFER_FLAGS         0x00 
#define RX_BUFFER_FLAGS         0x00 
#define TX_DATA_LEN             0x04 
#define RX_DATA_LEN             0x04 
#define TX_BUFFER_OFFSET        0x0c 
#define RX_BUFFER_OFFSET        0x0c 
#define TX_BUFFER_SIZE          4096 
#define RX_BUFFER_SIZE          4096 
#define WB_RX_BUFFER_AM         0xFF000000 
#define WB_TX_BUFFER_AM         0xFF000000 

static void dma_descriptor_setup(struct pci_dev *pdev) 
{ 
        unsigned long current_address; 
        unsigned int  register_value; 
        int error = 0; 
        unsigned int c_tx_data; 
        printk("DMA ALLOC ROUTINE STARTED\n"); 
        c_memory_map->dma_buffer_rx = pci_alloc_consistent(pdev, 
RX_BUFFER_SIZE+RX_BUFFER_OFFSET, &c_memory_map->dma_bus_rx); 
        printk("RX DMA BUFFER READY\n"); 
        c_memory_map->dma_buffer_tx = pci_alloc_consistent(pdev, 
TX_BUFFER_SIZE+TX_BUFFER_OFFSET, &c_memory_map->dma_bus_tx); 
        printk("TX DMA BUFFER READY\n"); 
        pci_bridge_devices->current_resource = 0; 
        if ( (error = open_mem_mapped(pci_bridge_devices)) ) 
        { 
                pci_bridge_devices->current_resource = -1; 
                printk("Could not set BAR0 on DMA alloc\n"); 
                return; 
        } 
        printk("PCI ADDRESS FOR TX IS %d AND PCI ADDRESS FOR RX IS %d\n", 
c_memory_map->dma_bus_rx, c_memory_map->dma_bus_tx); 
        current_address = pci_bridge_devices->page_addr + pci_bridge_devices- 


>base_page_offset + BRIDGE_W_AM1_ADDR; 


        register_value = WB_RX_BUFFER_AM; 
        memcpy_toio(current_address, &register_value, 4); 
        current_address = pci_bridge_devices->page_addr + pci_bridge_devices- 

>base_page_offset + BRIDGE_W_AM2_ADDR; 


        register_value = WB_TX_BUFFER_AM; 
        memcpy_toio(current_address, &register_value, 4); 


} 


static void dma_descriptor_release(struct pci_dev *pdev) 
{ 
        pci_free_consistent(pdev, RX_BUFFER_SIZE+RX_BUFFER_OFFSET, 
c_memory_map->dma_buffer_rx, c_memory_map->dma_bus_rx); 
        pci_free_consistent(pdev, TX_BUFFER_SIZE+TX_BUFFER_OFFSET, 
c_memory_map->dma_buffer_tx, c_memory_map->dma_bus_tx); 


} 


MODULE_LICENSE("GPL"); 

module_init(pci_bridge_init); 
module_exit(pci_bridge_exit);

Any help would be apreciated.


Thank you