Thread (27 messages) read the whole thread 27 messages, 7 authors, 2008-08-02

Re: how to allocate 9MB of memory in kernel ?

From: Misbah khan <hidden>
Date: 2008-07-25 08:43:37

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; 
} ...[show rest of quote]
Don't hardcode the numbers here, you should get the values from the 
device tree, and use of_iomap(). 

I am really unaware of how can we get this physical address from the device
tree which you have mentioned can you please explain this to me ???

Suppose there is one situation in which i have to map ram of the address
0x800000 to 9MB will it be good if i do this to map to user space 

static int McBSP_DriverMmap(struct file *file,struct  vm_area_struct *vma)
{

	unsigned long start = vma->vm_start ;
	unsigned long size = 0x900000 ;
	unsigned long phy_add = 0x800000;
	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;
	
	printk(KERN_DEBUG"In mmap function\n");

	/* Mmap the kernel buffer to user space */
	if(remap_pfn_range(vma,start,(phy_add >>
PAGE_SHIFT),size,vma->vm_page_prot))
	{
		printk(KERN_ALERT"remap_pfn_range failed\n");
		goto mmap_exit;

   	}

   	printk(KERN_ALERT"phy addr 0x%08X mmapped to virt addr 0x%08X, size =
0x%08X\n",
		(unsigned int)phy_add, (unsigned int)start, (unsigned int)size);

	/* Initialize the file operation structure of Mmaped area */
	vma->vm_ops=&mmap_op;

	/* Open the Mmaped area */
	MmapOpen(vma);

	mmap_exit:
	   	return ret;
}

suppose the same mapping i have to do using nopage method then shall i
specify the RAM physical address and sixe in the same manner ???


There is one more concern that i have now is that i am writing a pattern
(say 0xa5a5a5a5) to cpld by building the page using remap_pfn_range but when
i try to read it its showing the pattern as a5a5a5a50000000a5a5a5a50000000
like with zeros in between is it a non aligned page problem.

----- Misbah <><

Arnd Bergmann wrote:
On Thursday 24 July 2008, Misbah khan wrote:
quoted
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.
quoted
	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.
quoted
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.
quoted
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.
quoted
	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.
quoted
	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.

quoted
	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().
 
quoted
	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.
 
quoted
	/*
	 * 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.
quoted
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.
quoted
			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).
quoted
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.

quoted
	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
-- 
View this message in context: http://www.nabble.com/how-to-allocate-9MB-of-memory-in-kernel---tp18503022p18647614.html
Sent from the linuxppc-embedded mailing list archive at Nabble.com.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help