Hi i am trying to implement bus mastering with the OC PCI Bridge with a linux (Ubuntu Kernel 2.6.32-24) on a x86. The Bridge is working ok, but on the PC side i am having a problem. I am trying to allocate the buffer where the PCI card wil read/write from/to. But when i am calling pci_alloc_consistent i am getting the following error:
BUG: unable to handle kernel NULL pointer dereference at 00000004 IP: [] dma_generic_alloc_coherent+0xaf/0xc0
*pde = 0a417067 *pte = 00000000 Oops: 0002 [#1] SMPThe code where the function is being called is like
#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-
register_value = WB_RX_BUFFER_AM; memcpy_toio(current_address, ®ister_value, 4); current_address = pci_bridge_devices->page_addr + pci_bridge_devices-
register_value = WB_TX_BUFFER_AM; memcpy_toio(current_address, ®ister_value, 4); }
It is being called by the init function that is:
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(" 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("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("BAR%d range from %08X to %08X \n ", num_of_bases, dev-if(pci_read_config_byte(dev->pcidev,PCI_INTERRUPT_LINE, &dev-
{ 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; }
Thank you!