On Thursday 24 July 2008, Misbah khan wrote:
> 
> Hi all ...
>  
> I am uploading the source code which is doing the following :-
> 
> 1. mapping cpld register using ioremap coping the data to circular buffer
> and remapping it to user space .
> 
> 2. It can also map kernel virtual dma memory to user space if compiled
> conditionally .
> 
> following is the problem which i am facing ...
> 
> 1. It is somitimes giving following kernel panic ....
> 
> nable to handle kernel NULL pointer dereference at virtual address 00000000
> pgd = c0004000
> [00000000] *pgd=00000000
> Internal error: Oops: 17 [#1]
> Modules linked in: fluke_driver tstamp sig_router mvci_spi mvci_sf_pcd
> mvci_sci_unidir_s1 mvci_sci_diff mvci_sci_bidir_s
> 1 mvci_rtmd_s1 mvci_kwiso_s1 mvci_kw1281_s1 mvci_kh_s1 mvci_j1850
> mvci_gm_sbc mvci_diagh_s1 g_ether mvci_dcl mvci_can1 f
> pga_conf arcotg_udc adc_dac keypad(F) splc501_lcd(F) cpld
> CPU: 0
> PC is at cascade+0x64/0x8c
> LR is at __init_begin+0x3fff8000/0x30
> pc : [<c00484ac>]    lr : [<00000000>]    Tainted: GF
> sp : c0293ea8  ip : 0040b000  fp : c0293ecc
> r10: 8001d9f0  r9 : c0292000  r8 : 00000001
> r7 : c0292000  r6 : 0000000c  r5 : c02fa048  r4 : 00000000
> r3 : c02fa2f8  r2 : 0000261a  r1 : bf01ab70  r0 : c02fa2f8
> Flags: Nzcv  IRQs off  FIQs on  Mode SVC_32  Segment kernel
> Control: C5387F
> Table: 8698C000  DAC: 00000017
> Process swapper (pid: 0, stack limit = 0xc0292250)
> Stack: (0xc0293ea8 to 0xc0294000)
> 3ea0:                   bf01ab70 c02fb440 0000000a 00000000 c02fa048
> 0000000a
> 3ec0: c0293efc c0293ed0 c0048810 c0048454 c0293eec c0293ee0 c002a30c
> 00000001
> 3ee0: c02f9e44 0000000a 00000002 00000001 c0293f1c c0293f00 c00442a0
> c0048794
> 3f00: c0293f2c 0000001d c0294740 00000000 c0293f2c c0293f20 c00446d4
> c0044254
> 3f20: c0293f4c c0293f30 c00217b0 c0044698 c0293f5c ffffffff 0000ffff
> 00000001
> 3f40: c0293fa4 c0293f50 c00209e4 c0021770 00000001 00000001 c0292000
> 00000000
> 3f60: c0022068 c0292000 c0298c44 c03121c0 8001da24 4107b364 8001d9f0
> c0293fa4
> 3f80: c0293fa8 c0293f98 c0021d48 c002209c 60000013 ffffffff c0293fbc
> c0293fa8
> 3fa0: c0021d48 c0022074 c02faae0 c02f292c c0293fcc c0293fc0 c00202e0
> c0021d24
> 3fc0: c0293ff4 c0293fd0 c0008848 c00202b4 c00083c4 00000000 00000000
> c02f29a8
> 3fe0: 00000000 00c5387d 00000000 c0293ff8 80008030 c00086e0 00000000
> 00000000
> Backtrace:
> [<c0048448>] (cascade+0x0/0x8c) from [<c0048810>]
> (run_timer_softirq+0x88/0x1e8)
>  r6 = 0000000A  r5 = C02FA048  r4 = 00000000
> [<c0048788>] (run_timer_softirq+0x0/0x1e8) from [<c00442a0>]
> (__do_softirq+0x58/0xc8)
>  r8 = 00000001  r7 = 00000002  r6 = 0000000A  r5 = C02F9E44
>  r4 = 00000001
> [<c0044248>] (__do_softirq+0x0/0xc8) from [<c00446d4>] (irq_exit+0x48/0x5c)
>  r6 = 00000000  r5 = C0294740  r4 = 0000001D
> [<c004468c>] (irq_exit+0x0/0x5c) from [<c00217b0>] (asm_do_IRQ+0x4c/0x64)
> [<c0021764>] (asm_do_IRQ+0x0/0x64) from [<c00209e4>] (__irq_svc+0x44/0x80)
>  r6 = 00000001  r5 = 0000FFFF  r4 = FFFFFFFF
> [<c0022068>] (default_idle+0x0/0x3c) from [<c0021d48>] (cpu_idle+0x30/0x5c)
> [<c0021d18>] (cpu_idle+0x0/0x5c) from [<c00202e0>] (rest_init+0x38/0x40)
>  r5 = C02F292C  r4 = C02FAAE0
> [<c00202a8>] (rest_init+0x0/0x40) from [<c0008848>]
> (start_kernel+0x174/0x1c0)
> [<c00086d4>] (start_kernel+0x0/0x1c0) from [<80008030>] (0x80008030)
> Code: e1530005 15822000 ebffffb6 e1a0e004 (e5944000)
>  <0>Kernel panic - not syncing: Aiee, killing interrupt handler!
> 
> 
> also when i run it on X86 PC i am able to get the data and no panic where in
> on the board it is giving the above error ....
> 
> 2. I can raed the data using the user application when i run it on X86 PC
> where in i cant able to read the data when i run it on the board the data i
> was getting was always '/0' filled buffer .
> 
> 
> Here is the compilete code .............
> 
> 
> static int McBSP_DriverOpen(struct inode *inode,struct file *file)
> {
>       /* Reintialize file operation structure */
>       file->f_op=&fluke_fops;
> 

this is already set.

>       printk(KERN_DEBUG" fluke driver open success \n");
> 
>       if (device_open_count == 0)
>       {
>               device_open_count = 1;
> 
>               /* Reset the read and write index*/
>               buf_index_area.write_index=0;
>               buf_index_area.read_index=-1;
>               buf_index_area.count_index=0;
> 
>               #ifdef SIMULATION
>               /* Initialize the Timer */
>               init_timer(&fluke_timer);
>               fluke_timer.expires = jiffies + (HZ*10);//Timer will Expire 
> after 60 sec
>               fluke_timer.data = 0;
>               fluke_timer.function = (void *)timer_func;
>               add_timer(&fluke_timer);
>               #endif
>       }
> 
>       return 0;
> }

Using the count in this way is racy, best write the code so
that it can allow multiple opens.

> irqreturn_t DataAcqIntHandler(int irq,void *dev_id, struct pt_regs *regs)
> {
>       printk(KERN_ALERT" In Interrupt Handler\n");
>       /* Data present status is set to wake up the read call */
>       data_present_status=1;
> 
>       /* Wake up the blocked Select call */
>       wake_up_interruptible(&wait_queue);
> 
>       #ifndef SIMULATION
>       /* Clear the interrupt in the interrupt pending registor */
>       cpi->ic_scprrh |=DATA_ACQ_INT_CLEAR;
>       #endif
> 
>       return IRQ_HANDLED;
> 
> }/* End of PpsIntrHandler() */

The interrupt handler should be able to deal with shared interrupts,
and needs to check if the interrupt came from this device, returning
IRQ_NONE otherwise.

> static int __init McBSP_DriverInit(void)
> {
>       unsigned int virt_addr = 0;
>       int mem = 0;
> 
>       //buf_area = vmalloc(sizeof(circularbuffer_S));
>       //if(!buf_area)
>       //{
>       //      printk(KERN_ALERT"vmalloc failed \n");
>       //      return -1;
>       //}
> 
> #if 0
>       /*
>       * Allocate memory for the circular buffer in the DMA coherent area
>       * and algin it in the Cache
>       */
>       mem = L1_CACHE_ALIGN(sizeof(circularbuffer_S));
> 
>       buf_ptr = (char *)dma_alloc_coherent(NULL, mem, &dma_addr,GFP_KERNEL);

no need for the cast.

>       printk(KERN_INFO" buf_ptr = 0x%x \n",(int )buf_ptr);
>       if(NULL == buf_ptr )
>       {
>               printk(KERN_ALERT" Allocation of Memory failure ");
>               return -1;
>       }
> 
>       buf_area = (circularbuffer_S *)(((unsigned int )buf_ptr + PAGE_SIZE - 
> 1) \
>                       & PAGE_MASK);
> 
>       printk(KERN_INFO" buf_area = 0x%x \n",(int )buf_area);
> 
>       if(NULL == buf_area)
>       {
>               printk(KERN_ALERT" Circular buffer memory not allocated \n");
>               return -1;
>       }
> 
>       /* Marking the Pages as reserved */
>       for (virt_addr = (unsigned int)buf_area; \
>       virt_addr < (unsigned int )buf_area + sizeof(circularbuffer_S);\
>       virt_addr += PAGE_SIZE)
>       {
>               /* Set the pages as reserved */
>               SetPageReserved(virt_to_page(virt_addr));
>               //mem_map_reserve(virt_to_page(virt_addr));
>       }

no need for SetPageReserved, it already is marked as in use through
the allocation.

>       phy_addr = virt_to_phys(buf_ptr);

You can't use virt_to_phys to get the dma address. You also don't need that
because you already have it in dma_addr.


>       printk(KERN_INFO"Allocated Memory for Circular Buffer at physical
> 0x0%x\n",phy_addr);
> 
> #else
> 
>       buf_area = ioremap(0xB2000000,0x4000); //(0xB2000000,0x4000);
> //(7700000,900000);
>       if(!buf_area)
>       {
>               printk(KERN_ALERT"ioremap failed \n");
>               return -1;
>       }

Don't hardcode the numbers here, you should get the values from the
device tree, and use of_iomap().
 
>       printk(" Ioremap mapped to virtual 0x0%x \n",buf_area);
>       *((unsigned int *)buf_area) = 0xa5a5a5a5;
>       printk(" Ioremap data  0x0%x \n",*((unsigned int *)buf_area + 0));
> 
> #endif
> 
>       /* Device major number is registered to set the driver entry point */
>       if(register_chrdev(MAJOR_NO,MODULE_NAME, &fluke_fops)==0)
>       {
>               printk(KERN_DEBUG" Fluke driver registeration success \n");
> 
>       }
>       else
>       {
>               printk(KERN_ALERT" Fluke driver registeration failed \n");
>               return -1;
>       }

Since it's just one device, it's easier to use a misc_device.
 
>       /*
>        * Register Data Acq interrupt request with specified irq and install 
> the
>        * handler
>        */
>        if(request_irq(DATA_ACQ_INT,(void *)DataAcqIntHandler, SA_INTERRUPT,
>                                                       MODULE_NAME, NULL)==0)
>       {
>               printk(KERN_DEBUG" Data Acq interrupt request returns success 
> \n");
>       }
>       else
>       {
>               printk(KERN_DEBUG" Data Acq interrupt request failed \n");
>               unregister_chrdev(MAJOR_NO,MODULE_NAME);
>               return -1;
> 
>       }

hardcoding interrupt numbers is broken, interrupt numbers are relative to
one interrupt controller. Use irq_of_parse_and_map.

> static int McBSP_DriverIoctl(struct inode *inode, struct file *file,\
>                                                                       
> unsigned int cmd, unsigned long param)
> {
>       int i;
>       daq_t daq_param;
> 
>       printk(KERN_DEBUG"In ioctl command \n");
> 
>       switch(cmd)
>       {
>               case START_ACQ_DATA:
> 
>                       if(copy_from_user(&daq_param,(void 
> *)param,sizeof(daq_param)))
>                       {
> 
>                               return -1;
>                       }
> 
>                       /* For Simulation we are writing the data */
>                       if(WriteBuf() < 0)
>                       {
>                               printk(" Writing to the memory failure \n");
>                               return -1;
>                       }
> 
>                       /* Wait for the Interrupt to occur */
>                       wait_event_interruptible( wait_queue, 
> data_present_status !=0);
> 
>                       printk("Read Index before read 
> %d\n",buf_index_area.read_index);
>                       data_present_status=0;

Racy, you could have multiple threads doing this ioctl.
Moreover, you should not block in an ioctl but rather
implement a poll() function for waiting.

>                       buf_index_area.read_index++;
>                       buf_index_area.read_index%=NO_FRAMES;
> 
>                       if(buf_index_area.read_index 
> ==((buf_index_area.write_index +1) %
> NO_FRAMES))
>                       //if(buf_index_area.read_index == 
> buf_index_area.write_index )
>                       {
>                               printk("Read failure because read and write 
> index are same\n");
>                               return -1;
>                       }
> 
>                       /* Decrement the count index to indicate the data 
> availibility */
>                       down(&mutex);
>                       buf_index_area.count_index--;
>                       up(&mutex);

New drivers should not use semaphores (up/down) in places where they can use 
real
mutexes (mutex_lock/mutex_unlock).

> static int McBSP_DriverMmap(struct file *file,struct  vm_area_struct *vma)
> {
> 
>       unsigned long start = vma->vm_start;
>       unsigned long size = vma->vm_end - vma->vm_start; //0x900000;
>       unsigned long phy_add = virt_to_phys(buf_ptr); //0x7700000;

virt_to_phys doesn't work on vmalloc memory.


>       int ret = 0;
> 
>       /* Make the mmaped area noncacheable */
>       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
> 
>       /* Set the Flags to give permissions to Mmaped area */
>       vma->vm_flags |=VM_RESERVED;
>       vma->vm_flags |=VM_READ;
>       vma->vm_flags |=VM_WRITE;
>       vma->vm_flags |=VM_IO;
>       //vma->vm_flags |=VM_SHARED;
>       //vma->vm_flags |=VM_LOCKED;

For memory, you typically want to set vm_page_prot to use non-guarded mapping,
so that user space accesses are faster.

Not sure if VM_IO is right for vmalloc.

        Arnd <><
_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

Reply via email to