Help with PCI driver for linux

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] SMP

The 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-

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); }

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-
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; }

Thank you!

Reply to
Sink0
Loading thread data ...

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.