Re: how to allocate 9MB of memory in kernel ?
From: Arnd Bergmann <arnd@arndb.de>
Date: 2008-07-24 09:31:19
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 <><