LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] powerpc: i2c-mpc: make speed registers configurable via FDT
From: Jochen Friedrich @ 2008-07-25  8:51 UTC (permalink / raw)
  To: Wolfgang Grandegger; +Cc: Scott Wood, Linuxppc-dev
In-Reply-To: <488982B5.4070102@grandegger.com>

Hi Wolfgang,

> The I2C driver for the MPC currently uses a fixed speed hard-coded into
> the driver. This patch adds the FDT properties "fdr" and "dfsrr" for the
> corresponding I2C registers to make the speed configurable via FDT, 
> e.g.:
> 
>     i2c@3100 {
>         compatible = "fsl-i2c";
>         reg = <0x3100 0x100>;
>         interrupts = <43 2>;
>         interrupt-parent = <&mpic>;
>         dfsrr = <0x20>;
>         fdr = <0x03>;
>     };


Would it be possible to use the standard property "clock-frequency" for this
and calculate the register settings in the driver?

Thanks,
Jochen

^ permalink raw reply

* Re: how to allocate 9MB of memory in kernel ?
From: Arnd Bergmann @ 2008-07-25  8:50 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: Misbah khan
In-Reply-To: <18647614.post@talk.nabble.com>

On Friday 25 July 2008, Misbah khan wrote:
> 
> 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 ???

With current Linux versions, all powerpc machines come with an open-firmware
like device tree, which describes all devices that are part of the
system. If your machine doesn't run an actual open firmware implementation,
you most likely have the device tree source in arch/powerpc/boot/dts/,
and that needs to describe your device.

Your init function should then not assume that the device is there, but
register an of_platform_driver for that device.
When the driver is loaded, it is then bound to your hardware, and a
struct of_device gets passed to a probe() function that does the
actual initialization.
That is the device you pass to of_iomap in order to mmap the I/O range.

	Arnd <><

^ permalink raw reply

* Re: [PATCH 2/2][RT] powerpc - Make the irq reverse mapping radix tree lockless
From: Sebastien Dugue @ 2008-07-25  8:47 UTC (permalink / raw)
  To: benh
  Cc: Nick Piggin, Tim Chavez, Linux-rt, Peter Zijlstra, linux-kernel,
	Jean Pierre Dion, linux-ppc, Paul Mackerras, Gilles Carry
In-Reply-To: <1216975221.11188.102.camel@pasglop>

On Fri, 25 Jul 2008 18:40:21 +1000 Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:

> On Fri, 2008-07-25 at 10:36 +0200, Sebastien Dugue wrote:
> > On Fri, 25 Jul 2008 18:27:20 +1000 Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
> > 
> > > On Fri, 2008-07-25 at 09:49 +0200, Peter Zijlstra wrote:
> > > > 
> > > > 
> > > > The only advantage of the concurrent radix tree over this model is that
> > > > it can potentially do multiple modification operations at the same time.
> > > 
> > > Yup, we do not need that for the irq revmap... concurrent lookup is all we need.
> > > 
> > 
> >   Shouldn't we care about concurrent insertion and deletion in the tree? I agree
> > that concern might be a bit artificial but in theory that can happen.
> 
> Yes, we just need to protect it with a big hammer, like a spinlock, it's
> not a performance critical code path.

  Agreed. Will look into this in the next few days.

  Thanks,

  Sebastien.

^ permalink raw reply

* Re: how to allocate 9MB of memory in kernel ?
From: Misbah khan @ 2008-07-25  8:43 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <200807241131.12669.arnd@arndb.de>


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

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

^ permalink raw reply

* Re: [PATCH 2/2][RT] powerpc - Make the irq reverse mapping radix tree lockless
From: Benjamin Herrenschmidt @ 2008-07-25  8:40 UTC (permalink / raw)
  To: Sebastien Dugue
  Cc: Nick Piggin, Tim Chavez, Linux-rt, Peter Zijlstra, linux-kernel,
	Jean Pierre Dion, linux-ppc, Paul Mackerras, Gilles Carry
In-Reply-To: <20080725103601.2dbcd7e8@bull.net>

On Fri, 2008-07-25 at 10:36 +0200, Sebastien Dugue wrote:
> On Fri, 25 Jul 2008 18:27:20 +1000 Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
> 
> > On Fri, 2008-07-25 at 09:49 +0200, Peter Zijlstra wrote:
> > > 
> > > 
> > > The only advantage of the concurrent radix tree over this model is that
> > > it can potentially do multiple modification operations at the same time.
> > 
> > Yup, we do not need that for the irq revmap... concurrent lookup is all we need.
> > 
> 
>   Shouldn't we care about concurrent insertion and deletion in the tree? I agree
> that concern might be a bit artificial but in theory that can happen.

Yes, we just need to protect it with a big hammer, like a spinlock, it's
not a performance critical code path.

Ben.

^ permalink raw reply

* Re: [PATCH 2/2][RT] powerpc - Make the irq reverse mapping radix tree lockless
From: Sebastien Dugue @ 2008-07-25  8:36 UTC (permalink / raw)
  To: benh
  Cc: Nick Piggin, Tim Chavez, Linux-rt, Peter Zijlstra, linux-kernel,
	Jean Pierre Dion, linux-ppc, Paul Mackerras, Gilles Carry
In-Reply-To: <1216974440.11188.100.camel@pasglop>

On Fri, 25 Jul 2008 18:27:20 +1000 Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:

> On Fri, 2008-07-25 at 09:49 +0200, Peter Zijlstra wrote:
> > 
> > 
> > The only advantage of the concurrent radix tree over this model is that
> > it can potentially do multiple modification operations at the same time.
> 
> Yup, we do not need that for the irq revmap... concurrent lookup is all we need.
> 

  Shouldn't we care about concurrent insertion and deletion in the tree? I agree
that concern might be a bit artificial but in theory that can happen.

  Sebastien.

^ permalink raw reply

* Re: [PATCH 2/2][RT] powerpc - Make the irq reverse mapping radix tree lockless
From: Sebastien Dugue @ 2008-07-25  8:34 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Nick Piggin, Tim Chavez, Linux-rt, linux-kernel, Jean Pierre Dion,
	linux-ppc, Paul Mackerras, Gilles Carry
In-Reply-To: <1216972177.7257.351.camel@twins>


  Hi Peter,

On Fri, 25 Jul 2008 09:49:37 +0200 Peter Zijlstra <peterz@infradead.org> wr=
ote:

> On Thu, 2008-07-24 at 14:18 +0200, Sebastien Dugue wrote:
> > On Thu, 24 Jul 2008 21:11:34 +1000 Nick Piggin <nickpiggin@yahoo.com.au=
> wrote:
> >=20
> > > On Thursday 24 July 2008 20:50, Sebastien Dugue wrote:
> > > > From: Sebastien Dugue <sebastien.dugue@bull.net>
> > > > Date: Tue, 22 Jul 2008 11:56:41 +0200
> > > > Subject: [PATCH][RT] powerpc - Make the irq reverse mapping radix t=
ree
> > > > lockless
> > > >
> > > >   The radix tree used by interrupt controllers for their irq reverse
> > > > mapping (currently only the XICS found on pSeries) have a complex l=
ocking
> > > > scheme dating back to before the advent of the concurrent radix tre=
e on
> > > > preempt-rt.
> > > >
> > > >   Take advantage of this and of the fact that the items of the tree=
 are
> > > > pointers to a static array (irq_map) elements which can never go un=
der us
> > > > to simplify the locking.
> > > >
> > > >   Concurrency between readers and writers are handled by the intrin=
sic
> > > > properties of the concurrent radix tree. Concurrency between the tr=
ee
> > > > initialization which is done asynchronously with readers and writer=
s access
> > > > is handled via an atomic variable (revmap_trees_allocated) set when=
 the
> > > > tree has been initialized and checked before any reader or writer a=
ccess
> > > > just like we used to check for tree.gfp_mask !=3D 0 before.
> > >=20
> > > Hmm, RCU radix tree is in mainline too for quite a while. I thought
> > > Ben had already converted this code over ages ago...
> >=20
> >   Mainline does not have the concurrent radix tree which this patch
> > is based on, but maybe it's overkill and the RCU radix tree is enough.
> > Not sure, will have to think about it a bit more.
>=20
> Should be. The model of the concurrent radix tree can be mapped to
> spinlock + rcu radix tree.
>=20
> So instead of:
>=20
> > =EF=BB=BF+               DEFINE_RADIX_TREE_CONTEXT(ctx, tree);
> > +               radix_tree_lock(&ctx);
> > +               radix_tree_insert(ctx.tree, hwirq, &irq_map[virq]);
> > +               radix_tree_unlock(&ctx);
>=20
>=20
> you then write:
>=20
> 	spin_lock(&host->revmap_data.tree_lock);
> 	radix_tree_insert(&host->revmap_data.tree, hwirq, &irq_map[virq]);
> 	spin_unlock(&host->revmap_data.tree_lock);
>=20

  Cool, that will indeed makes it much easier to have something applicable
to mainline which works with preempt-rt.

>=20
> The only advantage of the concurrent radix tree over this model is that
> it can potentially do multiple modification operations at the same time.

  Well in theory that can happen if a module is loaded which creates a mapp=
ing
while another one is unloaded at the same time. The time window is pretty n=
arrow,
but still present nonetheless. That's why I chose to use the concurrent ver=
sion.

>=20
> Still, cool that you used it ;-)


  Yep, looked like what was needed until I realized it was not available in
mainline. Nice work though and good paper for explaining it all.

  Sebastien.

^ permalink raw reply

* Re: [PATCH 2/2][RT] powerpc - Make the irq reverse mapping radix tree lockless
From: Benjamin Herrenschmidt @ 2008-07-25  8:27 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Nick Piggin, Tim Chavez, Linux-rt, linux-kernel, Jean Pierre Dion,
	linux-ppc, Sebastien Dugue, Paul Mackerras, Gilles Carry
In-Reply-To: <1216972177.7257.351.camel@twins>

On Fri, 2008-07-25 at 09:49 +0200, Peter Zijlstra wrote:
> 
> 
> The only advantage of the concurrent radix tree over this model is that
> it can potentially do multiple modification operations at the same time.

Yup, we do not need that for the irq revmap... concurrent lookup is all we need.

Cheers,
Ben.

^ permalink raw reply

* [git pull] Please pull from powerpc.git merge branch
From: Benjamin Herrenschmidt @ 2008-07-25  8:13 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linuxppc-dev list, akpm, Linux Kernel list

Hi Linus !

Here's what should be the last batch of 'features' for powerpc for
this merge window, unless I missed something.

The binfmt_elf change is the one discussed earlier, acked by
Andrew, just slightly rebased on top of another binfmt_elf
patch that went in in the meantime.

git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git merge

Cheers,
Ben.

 Documentation/powerpc/booting-without-of.txt    |   57 +
 arch/powerpc/kernel/cputable.c                  |   11 
 arch/powerpc/kernel/entry_32.S                  |    6 
 arch/powerpc/kernel/iommu.c                     |   28 +
 arch/powerpc/kernel/lparcfg.c                   |  386 ++++++---
 arch/powerpc/kernel/process.c                   |   46 +
 arch/powerpc/kernel/prom_init.c                 |    9 
 arch/powerpc/kernel/ptrace.c                    |   72 +-
 arch/powerpc/kernel/signal.c                    |    6 
 arch/powerpc/kernel/sysfs.c                     |    3 
 arch/powerpc/kernel/traps.c                     |   16 
 arch/powerpc/kernel/vio.c                       | 1033 +++++++++++++++++++++++
 arch/powerpc/kernel/vmlinux.lds.S               |    2 
 arch/powerpc/mm/fault.c                         |   25 -
 arch/powerpc/platforms/52xx/Kconfig             |    2 
 arch/powerpc/platforms/cell/iommu.c             |   16 
 arch/powerpc/platforms/cell/spufs/sched.c       |   35 +
 arch/powerpc/platforms/cell/spufs/sputrace.c    |    3 
 arch/powerpc/platforms/iseries/iommu.c          |    3 
 arch/powerpc/platforms/pasemi/iommu.c           |    3 
 arch/powerpc/platforms/pseries/Kconfig          |   23 +
 arch/powerpc/platforms/pseries/Makefile         |    1 
 arch/powerpc/platforms/pseries/cmm.c            |  468 ++++++++++
 arch/powerpc/platforms/pseries/iommu.c          |   42 +
 arch/powerpc/platforms/pseries/plpar_wrappers.h |   10 
 arch/powerpc/platforms/pseries/setup.c          |   71 ++
 arch/powerpc/sysdev/dart_iommu.c                |    3 
 drivers/net/ibmveth.c                           |  189 +++-
 drivers/net/ibmveth.h                           |    5 
 drivers/of/of_i2c.c                             |    2 
 drivers/scsi/ibmvscsi/ibmvfc.c                  |   15 
 drivers/scsi/ibmvscsi/ibmvscsi.c                |   45 +
 drivers/scsi/ibmvscsi/ibmvscsi.h                |    2 
 fs/binfmt_elf.c                                 |   28 +
 include/asm-powerpc/cputable.h                  |    2 
 include/asm-powerpc/elf.h                       |    8 
 include/asm-powerpc/firmware.h                  |    3 
 include/asm-powerpc/hvcall.h                    |   23 -
 include/asm-powerpc/lppaca.h                    |    5 
 include/asm-powerpc/machdep.h                   |    2 
 include/asm-powerpc/mpc52xx_psc.h               |   40 +
 include/asm-powerpc/pgtable.h                   |   13 
 include/asm-powerpc/syscalls.h                  |    1 
 include/asm-powerpc/systbl.h                    |    6 
 include/asm-powerpc/system.h                    |    2 
 include/asm-powerpc/tlbflush.h                  |   11 
 include/asm-powerpc/unistd.h                    |    8 
 include/asm-powerpc/vio.h                       |   27 +
 include/linux/auxvec.h                          |    6 
 49 files changed, 2546 insertions(+), 277 deletions(-)
 create mode 100644 arch/powerpc/platforms/pseries/cmm.c

Andre Detsch (2):
      powerpc/spufs: fix aff_mutex and cbe_spu_info[n].list_mutex deadlock
      powerpc/spufs: better placement of spu affinity reference context

Benjamin Herrenschmidt (1):
      Move update_mmu_cache() declaration from tlbflush.h to pgtable.h

Brian King (4):
      powerpc/pseries: Utilities to set firmware page state
      powerpc/pseries: Add collaborative memory manager
      powerpc/pseries: Add CMO paging statistics
      ibmvfc: Add support for collaborative memory overcommit

Grant Likely (3):
      powerpc/mpc5200: Make mpc5200 GPIO driver select the GENERIC_GPIO config
      powerpc/mpc5200: add PSC SICR bit definitions
      of-bindings: Add binding documentation for SPI busses and devices

Jon Smirl (2):
      powerpc/mpc5200: Add AC97 register definitions for the MPC52xx PSC
      powerpc/mpc5200: Remove fsl-soc.c from mpc5200 build, it is not needed.

Luis Machado (1):
      powerpc: BookE hardware watchpoint support

Mark Nelson (1):
      powerpc/cell: Fixed IOMMU mapping uses weak ordering for a pcie endpoint

Milton Miller (1):
      powerpc/spufs: correct kcalloc usage

Nathan Fontenot (5):
      powerpc/pseries: Remove extraneous error reporting for hcall failures in lparcfg
      powerpc/pseries: Add memory entitlement capabilities to /proc/ppc64/lparcfg
      powerpc/pseries: Verify CMO memory entitlement updates with virtual I/O
      powerpc/pseries: Update arch vector to indicate support for CMO
      powerpc/pseries: Remove kmalloc call in handling writes to lparcfg

Nathan Fotenot (1):
      powerpc/pseries: Split processor entitlement retrieval and gathering to helper routines

Nathan Lynch (2):
      ELF loader support for auxvec base platform string
      powerpc: Enable AT_BASE_PLATFORM aux vector

Robert Jennings (6):
      powerpc/pseries: Split retrieval of processor entitlement data into a helper routine
      powerpc/pseries: Enable CMO feature during platform setup
      powerpc/pseries: iommu enablement for CMO
      powerpc/pseries: vio bus support for CMO
      ibmveth: enable driver for CMO
      ibmvscsi: driver enablement for CMO

Santiago Leon (1):
      ibmveth: Automatically enable larger rx buffer pools for larger mtu

Segher Boessenkool (1):
      powerpc: Fix compile error with binutils 2.15

Stephen Rothwell (1):
      powerpc: Fallout from sysdev API changes

Tony Breeds (1):
      powerpc: Wireup new syscalls

Wolfram Sang (1):
      powerpc/mpc5200: Fix wrong 'no interrupt' handling in of_i2c

^ permalink raw reply

* Re: sfx.c driver build failure
From: Michael Brown @ 2008-07-25  7:35 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list, Jeff Garzik, Linux Kernel list
In-Reply-To: <1216966559.11188.85.camel@pasglop>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 674 bytes --]

On Fri, 25 Jul 2008, Benjamin Herrenschmidt wrote:
> The sfx driver (which happens to be part of some of our test configs) 
> fails to build in current Linus tree on powerpc with this error:
> 
> /home/benh/kernels/linux-powerpc/drivers/net/sfc/efx.c: In function ÿÿefx_probe_interruptsÿÿ:
> /home/benh/kernels/linux-powerpc/drivers/net/sfc/efx.c:845: error: lvalue required as unary ÿÿ&ÿÿ oper
> and

I'm not the maintainer of that code; I wrote the original version, but 
it's now maintained by Solarflare.

I don't see anything on that line that ought to be architecture-specific.  
Could you send me the preprocessed efx.c from your powerpc build?

Michael

^ permalink raw reply

* Re: sfx.c driver build failure
From: Benjamin Herrenschmidt @ 2008-07-25  7:50 UTC (permalink / raw)
  To: Michael Brown; +Cc: linuxppc-dev list, Jeff Garzik, Linux Kernel list
In-Reply-To: <Pine.LNX.4.62.0807250831440.8217@dolphin.home>

On Fri, 2008-07-25 at 08:35 +0100, Michael Brown wrote:
> On Fri, 25 Jul 2008, Benjamin Herrenschmidt wrote:
> > The sfx driver (which happens to be part of some of our test configs) 
> > fails to build in current Linus tree on powerpc with this error:
> > 
> > /home/benh/kernels/linux-powerpc/drivers/net/sfc/efx.c: In function ÿÿefx_probe_interruptsÿÿ:
> > /home/benh/kernels/linux-powerpc/drivers/net/sfc/efx.c:845: error: lvalue required as unary ÿÿ&ÿÿ oper
> > and
> 
> I'm not the maintainer of that code; I wrote the original version, but 
> it's now maintained by Solarflare.
> 
> I don't see anything on that line that ought to be architecture-specific.  
> Could you send me the preprocessed efx.c from your powerpc build?

Apparently, it's a know generic breakage of the topology stuff,
it's beeing sorted out.

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH 2/2][RT] powerpc - Make the irq reverse mapping radix tree lockless
From: Peter Zijlstra @ 2008-07-25  7:49 UTC (permalink / raw)
  To: Sebastien Dugue
  Cc: Nick Piggin, Tim Chavez, Linux-rt, linux-kernel, Jean Pierre Dion,
	linux-ppc, Paul Mackerras, Gilles Carry
In-Reply-To: <20080724141839.477de30b@bull.net>

On Thu, 2008-07-24 at 14:18 +0200, Sebastien Dugue wrote:
> On Thu, 24 Jul 2008 21:11:34 +1000 Nick Piggin <nickpiggin@yahoo.com.au> wrote:
> 
> > On Thursday 24 July 2008 20:50, Sebastien Dugue wrote:
> > > From: Sebastien Dugue <sebastien.dugue@bull.net>
> > > Date: Tue, 22 Jul 2008 11:56:41 +0200
> > > Subject: [PATCH][RT] powerpc - Make the irq reverse mapping radix tree
> > > lockless
> > >
> > >   The radix tree used by interrupt controllers for their irq reverse
> > > mapping (currently only the XICS found on pSeries) have a complex locking
> > > scheme dating back to before the advent of the concurrent radix tree on
> > > preempt-rt.
> > >
> > >   Take advantage of this and of the fact that the items of the tree are
> > > pointers to a static array (irq_map) elements which can never go under us
> > > to simplify the locking.
> > >
> > >   Concurrency between readers and writers are handled by the intrinsic
> > > properties of the concurrent radix tree. Concurrency between the tree
> > > initialization which is done asynchronously with readers and writers access
> > > is handled via an atomic variable (revmap_trees_allocated) set when the
> > > tree has been initialized and checked before any reader or writer access
> > > just like we used to check for tree.gfp_mask != 0 before.
> > 
> > Hmm, RCU radix tree is in mainline too for quite a while. I thought
> > Ben had already converted this code over ages ago...
> 
>   Mainline does not have the concurrent radix tree which this patch
> is based on, but maybe it's overkill and the RCU radix tree is enough.
> Not sure, will have to think about it a bit more.

Should be. The model of the concurrent radix tree can be mapped to
spinlock + rcu radix tree.

So instead of:

> +               DEFINE_RADIX_TREE_CONTEXT(ctx, tree);
> +               radix_tree_lock(&ctx);
> +               radix_tree_insert(ctx.tree, hwirq, &irq_map[virq]);
> +               radix_tree_unlock(&ctx);


you then write:

	spin_lock(&host->revmap_data.tree_lock);
	radix_tree_insert(&host->revmap_data.tree, hwirq, &irq_map[virq]);
	spin_unlock(&host->revmap_data.tree_lock);


The only advantage of the concurrent radix tree over this model is that
it can potentially do multiple modification operations at the same time.

Still, cool that you used it ;-)

^ permalink raw reply

* [PATCH] powerpc: 85xx: add proper OF bus ids for the TQM85xx
From: Wolfgang Grandegger @ 2008-07-25  7:44 UTC (permalink / raw)
  To: Linuxppc-dev

Since recent modifications to the MPC I2C code, the MPC I2C buses are 
not found any more. This patch fixes the problem by adding proper OF
bus ids.

Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
---
 arch/powerpc/platforms/85xx/tqm85xx.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

Index: linux-2.6-galak/arch/powerpc/platforms/85xx/tqm85xx.c
===================================================================
--- linux-2.6-galak.orig/arch/powerpc/platforms/85xx/tqm85xx.c
+++ linux-2.6-galak/arch/powerpc/platforms/85xx/tqm85xx.c
@@ -156,15 +156,15 @@ static void tqm85xx_show_cpuinfo(struct 
 }
 
 static struct of_device_id __initdata of_bus_ids[] = {
+	{ .type = "soc", },
+	{ .compatible = "soc", },
 	{ .compatible = "simple-bus", },
 	{},
 };
 
 static int __init declare_of_platform_devices(void)
 {
-	of_platform_bus_probe(NULL, of_bus_ids, NULL);
-
-	return 0;
+	return of_platform_bus_probe(NULL, of_bus_ids, NULL);
 }
 machine_device_initcall(tqm85xx, declare_of_platform_devices);
 

^ permalink raw reply

* [PATCH] powerpc: i2c-mpc: make speed registers configurable via FDT
From: Wolfgang Grandegger @ 2008-07-25  7:37 UTC (permalink / raw)
  To: Linuxppc-dev

The I2C driver for the MPC currently uses a fixed speed hard-coded into
the driver. This patch adds the FDT properties "fdr" and "dfsrr" for the
corresponding I2C registers to make the speed configurable via FDT, 
e.g.:

    i2c@3100 {
        compatible = "fsl-i2c";
        reg = <0x3100 0x100>;
        interrupts = <43 2>;
        interrupt-parent = <&mpic>;
        dfsrr = <0x20>;
        fdr = <0x03>;
    };

Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
---
 Documentation/powerpc/dts-bindings/fsl/i2c.txt |    9 +++--
 drivers/i2c/busses/i2c-mpc.c                   |   45 ++++++++++++++++++++-----
 2 files changed, 42 insertions(+), 12 deletions(-)

Index: linux-2.6-galak/drivers/i2c/busses/i2c-mpc.c
===================================================================
--- linux-2.6-galak.orig/drivers/i2c/busses/i2c-mpc.c
+++ linux-2.6-galak/drivers/i2c/busses/i2c-mpc.c
@@ -56,6 +56,8 @@ struct mpc_i2c {
 	struct i2c_adapter adap;
 	int irq;
 	u32 flags;
+	u32 fdr;
+	u32 dfsrr;
 };
 
 static __inline__ void writeccr(struct mpc_i2c *i2c, u32 x)
@@ -156,13 +158,16 @@ static int i2c_wait(struct mpc_i2c *i2c,
 static void mpc_i2c_setclock(struct mpc_i2c *i2c)
 {
 	/* Set clock and filters */
+	pr_debug("I2C: flags=%#x fdr=%#x dfsrr=%#x\n",
+		 i2c->flags, i2c->fdr, i2c->dfsrr);
 	if (i2c->flags & FSL_I2C_DEV_SEPARATE_DFSRR) {
-		writeb(0x31, i2c->base + MPC_I2C_FDR);
-		writeb(0x10, i2c->base + MPC_I2C_DFSRR);
-	} else if (i2c->flags & FSL_I2C_DEV_CLOCK_5200)
-		writeb(0x3f, i2c->base + MPC_I2C_FDR);
-	else
-		writel(0x1031, i2c->base + MPC_I2C_FDR);
+		writeb(i2c->fdr, i2c->base + MPC_I2C_FDR);
+		writeb(i2c->dfsrr, i2c->base + MPC_I2C_DFSRR);
+	} else if (i2c->flags & FSL_I2C_DEV_CLOCK_5200) {
+		writeb(i2c->fdr, i2c->base + MPC_I2C_FDR);
+	} else {
+		writel(i2c->fdr, i2c->base + MPC_I2C_FDR);
+	}
 }
 
 static void mpc_i2c_start(struct mpc_i2c *i2c)
@@ -320,18 +325,40 @@ static int __devinit fsl_i2c_probe(struc
 {
 	int result = 0;
 	struct mpc_i2c *i2c;
+	const u32 *prop;
+	int prop_len;
 
 	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
 	if (!i2c)
 		return -ENOMEM;
 
-	if (of_get_property(op->node, "dfsrr", NULL))
-		i2c->flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
-
 	if (of_device_is_compatible(op->node, "fsl,mpc5200-i2c") ||
 			of_device_is_compatible(op->node, "mpc5200-i2c"))
 		i2c->flags |= FSL_I2C_DEV_CLOCK_5200;
 
+	prop = of_get_property(op->node, "dfsrr", &prop_len);
+	if (prop) {
+		i2c->flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
+		if (prop_len == sizeof(*prop))
+			i2c->dfsrr = *prop;
+		else
+			/* Set resonable default value */
+			i2c->dfsrr = 0x10;
+	}
+
+	prop = of_get_property(op->node, "fdr", &prop_len);
+	if (prop && prop_len == sizeof(*prop)) {
+		i2c->fdr = *prop;
+	} else {
+		/* Set resonable default values */
+		if (i2c->flags & FSL_I2C_DEV_SEPARATE_DFSRR)
+			i2c->fdr = 0x31;
+		else if (i2c->flags & FSL_I2C_DEV_CLOCK_5200)
+			i2c->fdr = 0x3f;
+		else
+			i2c->fdr = 0x1031;
+	}
+
 	init_waitqueue_head(&i2c->queue);
 
 	i2c->base = of_iomap(op->node, 0);
Index: linux-2.6-galak/Documentation/powerpc/dts-bindings/fsl/i2c.txt
===================================================================
--- linux-2.6-galak.orig/Documentation/powerpc/dts-bindings/fsl/i2c.txt
+++ linux-2.6-galak/Documentation/powerpc/dts-bindings/fsl/i2c.txt
@@ -16,10 +16,12 @@ Recommended properties :
    controller you have.
  - interrupt-parent : the phandle for the interrupt controller that
    services interrupts for this device.
- - dfsrr : boolean; if defined, indicates that this I2C device has
-   a digital filter sampling rate register
  - fsl5200-clocking : boolean; if defined, indicated that this device
    uses the FSL 5200 clocking mechanism.
+ - dfsrr : boolean or <v>; if defined, indicates that this I2C device has
+   a digital filter sampling rate register. Optionally you can specify a
+   value v for the this register.
+ - fdr : <v>, if defined, the FDR register will be set to the value v.
 
 Example :
 	i2c@3000 {
@@ -28,5 +30,6 @@ Example :
 		reg = <3000 18>;
 		device_type = "i2c";
 		compatible  = "fsl-i2c";
-		dfsrr;
+		fdr = <0x20>
+		dfsrr = <0x03>;
 	};

^ permalink raw reply

* [PATCH v3 4/4] powerpc/mpc5200: Add mpc5200-spi (non-PSC) device driver
From: Grant Likely @ 2008-07-25  7:33 UTC (permalink / raw)
  To: linux-kernel, akpm, spi-devel-general, dbrownell, linuxppc-dev,
	jonsmirl
In-Reply-To: <20080725072549.8485.90723.stgit@trillian.secretlab.ca>

From: Grant Likely <grant.likely@secretlab.ca>

Adds support for the dedicated SPI device on the Freescale MPC5200(b)
SoC.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 drivers/spi/Kconfig             |    8 +
 drivers/spi/Makefile            |    1 
 drivers/spi/mpc52xx_spi.c       |  595 +++++++++++++++++++++++++++++++++++++++
 include/linux/spi/mpc52xx_spi.h |   10 +
 4 files changed, 614 insertions(+), 0 deletions(-)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 2303521..68e4a4a 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -116,6 +116,14 @@ config SPI_LM70_LLP
 	  which interfaces to an LM70 temperature sensor using
 	  a parallel port.
 
+config SPI_MPC52xx
+	tristate "Freescale MPC52xx SPI (non-PSC) controller support"
+	depends on PPC_MPC52xx && SPI
+	select SPI_MASTER_OF
+	help
+	  This drivers supports the MPC52xx SPI controller in master SPI
+	  mode.
+
 config SPI_MPC52xx_PSC
 	tristate "Freescale MPC52xx PSC SPI controller"
 	depends on PPC_MPC52xx && EXPERIMENTAL
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 7fca043..340b878 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_SPI_PXA2XX)		+= pxa2xx_spi.o
 obj-$(CONFIG_SPI_OMAP_UWIRE)		+= omap_uwire.o
 obj-$(CONFIG_SPI_OMAP24XX)		+= omap2_mcspi.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
+obj-$(CONFIG_SPI_MPC52xx)		+= mpc52xx_spi.o
 obj-$(CONFIG_SPI_MPC83xx)		+= spi_mpc83xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx.o
diff --git a/drivers/spi/mpc52xx_spi.c b/drivers/spi/mpc52xx_spi.c
new file mode 100644
index 0000000..453690f
--- /dev/null
+++ b/drivers/spi/mpc52xx_spi.c
@@ -0,0 +1,595 @@
+/*
+ * MPC52xx SPI master driver.
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ *
+ * This is the driver for the MPC5200's dedicated SPI device (not for a
+ * PSC in SPI mode)
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/of_platform.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/mpc52xx_spi.h>
+#include <linux/of_spi.h>
+#include <linux/io.h>
+#include <asm/time.h>
+#include <asm/mpc52xx.h>
+
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_DESCRIPTION("MPC52xx SPI (non-PSC) Driver");
+MODULE_LICENSE("GPL");
+
+/* Register offsets */
+#define SPI_CTRL1	0x00
+#define SPI_CTRL1_SPIE		(1 << 7)
+#define SPI_CTRL1_SPE		(1 << 6)
+#define SPI_CTRL1_MSTR		(1 << 4)
+#define SPI_CTRL1_CPOL		(1 << 3)
+#define SPI_CTRL1_CPHA		(1 << 2)
+#define SPI_CTRL1_SSOE		(1 << 1)
+#define SPI_CTRL1_LSBFE		(1 << 0)
+
+#define SPI_CTRL2	0x01
+#define SPI_BRR		0x04
+
+#define SPI_STATUS	0x05
+#define SPI_STATUS_SPIF		(1 << 7)
+#define SPI_STATUS_WCOL		(1 << 6)
+#define SPI_STATUS_MODF		(1 << 4)
+
+#define SPI_DATA	0x09
+#define SPI_PORTDATA	0x0d
+#define SPI_DATADIR	0x10
+
+/* FSM state return values */
+#define FSM_STOP	0
+#define FSM_POLL	1
+#define FSM_CONTINUE	2
+
+/* Driver internal data */
+struct mpc52xx_spi {
+	struct spi_master *master;
+	u32 sysclk;
+	void __iomem *regs;
+	int irq0;	/* MODF irq */
+	int irq1;	/* SPIF irq */
+	int ipb_freq;
+
+	/* Statistics */
+	int msg_count;
+	int wcol_count;
+	int wcol_ticks;
+	u32 wcol_tx_timestamp;
+	int modf_count;
+	int byte_count;
+
+	/* Hooks for platform modification of behaviour */
+	void (*premessage)(struct spi_message *m, void *context);
+	void *premessage_context;
+
+	struct list_head queue;		/* queue of pending messages */
+	spinlock_t lock;
+	struct work_struct work;
+
+
+	/* Details of current transfer (length, and buffer pointers) */
+	struct spi_message *message;	/* current message */
+	struct spi_transfer *transfer;	/* current transfer */
+	int (*state)(int irq, struct mpc52xx_spi *ms, u8 status, u8 data);
+	int len;
+	int timestamp;
+	u8 *rx_buf;
+	const u8 *tx_buf;
+	int cs_change;
+};
+
+/*
+ * CS control function
+ */
+static void mpc52xx_spi_chipsel(struct mpc52xx_spi *ms, int value)
+{
+	if (value)
+		writeb(0, ms->regs + SPI_PORTDATA); /* Assert SS pin */
+	else
+		writeb(0x08, ms->regs + SPI_PORTDATA); /* Deassert SS pin */
+}
+
+/*
+ * Start a new transfer.  This is called both by the idle state
+ * for the first transfer in a message, and by the wait state when the
+ * previous transfer in a message is complete.
+ */
+static void mpc52xx_spi_start_transfer(struct mpc52xx_spi *ms)
+{
+	ms->rx_buf = ms->transfer->rx_buf;
+	ms->tx_buf = ms->transfer->tx_buf;
+	ms->len = ms->transfer->len;
+
+	/* Activate the chip select */
+	if (ms->cs_change)
+		mpc52xx_spi_chipsel(ms, 1);
+	ms->cs_change = ms->transfer->cs_change;
+
+	/* Write out the first byte */
+	ms->wcol_tx_timestamp = get_tbl();
+	if (ms->tx_buf)
+		writeb(*ms->tx_buf++, ms->regs + SPI_DATA);
+	else
+		writeb(0, ms->regs + SPI_DATA);
+}
+
+/* Forward declaration of state handlers */
+static int mpc52xx_spi_fsmstate_transfer(int irq, struct mpc52xx_spi *ms,
+					 u8 status, u8 data);
+static int mpc52xx_spi_fsmstate_wait(int irq, struct mpc52xx_spi *ms,
+				     u8 status, u8 data);
+
+/*
+ * IDLE state
+ *
+ * No transfers are in progress; if another transfer is pending then retrieve
+ * it and kick it off.  Otherwise, stop processing the state machine
+ */
+static int
+mpc52xx_spi_fsmstate_idle(int irq, struct mpc52xx_spi *ms, u8 status, u8 data)
+{
+	struct spi_message *m;
+	struct spi_device *spi;
+	int spr, sppr;
+	u8 ctrl1;
+
+	if (status && (irq != NO_IRQ))
+		dev_err(&ms->master->dev, "spurious irq, status=0x%.2x\n",
+			status);
+
+	/* Check if there is another transfer waiting */
+	if (list_empty(&ms->queue))
+		return FSM_STOP;
+
+	/* Get the next message */
+	spin_lock(&ms->lock);
+
+	/* Call the pre-message hook with a pointer to the next
+	 * message.  The pre-message hook may enqueue a new message for
+	 * changing the chip select value to the head of the queue */
+	m = list_first_entry(&ms->queue, struct spi_message, queue);
+	if (ms->premessage)
+		ms->premessage(m, ms->premessage_context);
+
+	/* reget the head of the queue (the premessage hook may have enqueued
+	 * something before it.) and drop the spinlock */
+	ms->message = list_first_entry(&ms->queue, struct spi_message, queue);
+	list_del_init(&ms->message->queue);
+	spin_unlock(&ms->lock);
+
+	/* Setup the controller parameters */
+	ctrl1 = SPI_CTRL1_SPIE | SPI_CTRL1_SPE | SPI_CTRL1_MSTR;
+	spi = ms->message->spi;
+	if (spi->mode & SPI_CPHA)
+		ctrl1 |= SPI_CTRL1_CPHA;
+	if (spi->mode & SPI_CPOL)
+		ctrl1 |= SPI_CTRL1_CPOL;
+	if (spi->mode & SPI_LSB_FIRST)
+		ctrl1 |= SPI_CTRL1_LSBFE;
+	writeb(ctrl1, ms->regs + SPI_CTRL1);
+
+	/* Setup the controller speed */
+	/* minimum divider is '2'.  Also, add '1' to force rounding up. */
+	sppr = ((ms->ipb_freq / ms->message->spi->max_speed_hz) + 1) >> 1;
+	spr = 0;
+	if (sppr < 1)
+		sppr = 1;
+	while (((sppr - 1) & ~0x7) != 0) {
+		sppr = (sppr + 1) >> 1; /* add '1' to force rounding up */
+		spr++;
+	}
+	sppr--;		/* sppr quantity in register is offset by 1 */
+	if (spr > 7) {
+		/* Don't overrun limits of SPI baudrate register */
+		spr = 7;
+		sppr = 7;
+	}
+	writeb(sppr << 4 | spr, ms->regs + SPI_BRR); /* Set speed */
+
+	ms->cs_change = 1;
+	ms->transfer = container_of(ms->message->transfers.next,
+				    struct spi_transfer, transfer_list);
+
+	mpc52xx_spi_start_transfer(ms);
+	ms->state = mpc52xx_spi_fsmstate_transfer;
+
+#if defined(VERBOSE_DEBUG)
+	dev_info(&ms->master->dev, "msg:%p, max_speed:%i, brr:%.2x\n",
+		 ms->message, ms->message->spi->max_speed_hz,
+		 readb(ms->regs + SPI_BRR));
+#endif
+
+	return FSM_CONTINUE;
+}
+
+/*
+ * TRANSFER state
+ *
+ * In the middle of a transfer.  If the SPI core has completed processing
+ * a byte, then read out the received data and write out the next byte
+ * (unless this transfer is finished; in which case go on to the wait
+ * state)
+ */
+static int mpc52xx_spi_fsmstate_transfer(int irq, struct mpc52xx_spi *ms,
+					 u8 status, u8 data)
+{
+	if (!status)
+		return ms->irq0 == NO_IRQ ? FSM_POLL : FSM_STOP;
+
+	if (status & SPI_STATUS_WCOL) {
+		/* The SPI device is stoopid.  At slower speeds, it may raise
+		 * the SPIF flag before the state machine is actually finished.
+		 * which causes a collision (internal to the state machine
+		 * only).  The manual recommends inserting a delay between
+		 * receving the interrupt and sending the next byte, but
+		 * it can also be worked around simply by retrying the
+		 * transfer which is what we do here. */
+		ms->wcol_count++;
+		ms->wcol_ticks += get_tbl() - ms->wcol_tx_timestamp;
+		ms->wcol_tx_timestamp = get_tbl();
+		data = 0;
+		if (ms->tx_buf)
+			data = *(ms->tx_buf-1);
+		writeb(data, ms->regs + SPI_DATA); /* try again */
+		return FSM_CONTINUE;
+	} else if (status & SPI_STATUS_MODF) {
+		ms->modf_count++;
+		dev_err(&ms->master->dev, "mod fault\n");
+		mpc52xx_spi_chipsel(ms, 0);
+		ms->message->status = -EIO;
+		if (ms->message->complete)
+			ms->message->complete(ms->message->context);
+		ms->state = mpc52xx_spi_fsmstate_idle;
+		return FSM_CONTINUE;
+	}
+
+	/* Read data out of the spi device */
+	ms->byte_count++;
+	if (ms->rx_buf)
+		*ms->rx_buf++ = data;
+
+	/* Is the transfer complete? */
+	ms->len--;
+	if (ms->len == 0) {
+		ms->timestamp = get_tbl();
+		ms->timestamp += ms->transfer->delay_usecs * tb_ticks_per_usec;
+		ms->state = mpc52xx_spi_fsmstate_wait;
+		return FSM_CONTINUE;
+	}
+
+	/* Write out the next byte */
+	ms->wcol_tx_timestamp = get_tbl();
+	if (ms->tx_buf)
+		writeb(*ms->tx_buf++, ms->regs + SPI_DATA);
+	else
+		writeb(0, ms->regs + SPI_DATA);
+
+	return FSM_CONTINUE;
+}
+
+/*
+ * WAIT state
+ *
+ * A transfer has completed; need to wait for the delay period to complete
+ * before starting the next transfer
+ */
+static int
+mpc52xx_spi_fsmstate_wait(int irq, struct mpc52xx_spi *ms, u8 status, u8 data)
+{
+	if (status && irq != NO_IRQ)
+		dev_err(&ms->master->dev, "spurious irq, status=0x%.2x\n",
+			status);
+
+	if (((int)get_tbl()) - ms->timestamp < 0)
+		return FSM_POLL;
+
+	ms->message->actual_length += ms->transfer->len;
+
+	/* Check if there is another transfer in this message.  If there
+	 * aren't then deactivate CS, notify sender, and drop back to idle
+	 * to start the next message. */
+	if (ms->transfer->transfer_list.next == &ms->message->transfers) {
+		ms->msg_count++;
+		mpc52xx_spi_chipsel(ms, 0);
+		ms->message->status = 0;
+		if (ms->message->complete)
+			ms->message->complete(ms->message->context);
+		ms->state = mpc52xx_spi_fsmstate_idle;
+		return FSM_CONTINUE;
+	}
+
+	/* There is another transfer; kick it off */
+
+	if (ms->cs_change)
+		mpc52xx_spi_chipsel(ms, 0);
+
+	ms->transfer = container_of(ms->transfer->transfer_list.next,
+				    struct spi_transfer, transfer_list);
+	mpc52xx_spi_start_transfer(ms);
+	ms->state = mpc52xx_spi_fsmstate_transfer;
+	return FSM_CONTINUE;
+}
+
+/*
+ * IRQ handler
+ */
+static irqreturn_t mpc52xx_spi_irq(int irq, void *_ms)
+{
+	struct mpc52xx_spi *ms = _ms;
+	int rc = FSM_CONTINUE;
+	u8 status, data;
+
+	while (rc == FSM_CONTINUE) {
+		/* Interrupt cleared by read of STATUS followed by
+		 * read of DATA registers*/
+		status = readb(ms->regs + SPI_STATUS);
+		data = readb(ms->regs + SPI_DATA); /* clear status */
+		rc = ms->state(irq, ms, status, data);
+	}
+
+	if (rc == FSM_POLL)
+		schedule_work(&ms->work);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Workqueue method of running the state machine
+ */
+static void mpc52xx_spi_wq(struct work_struct *work)
+{
+	struct mpc52xx_spi *ms = container_of(work, struct mpc52xx_spi, work);
+	mpc52xx_spi_irq(NO_IRQ, ms);
+}
+
+/*
+ * spi_master callbacks
+ */
+
+static int mpc52xx_spi_setup(struct spi_device *spi)
+{
+	return 0;
+}
+
+static int mpc52xx_spi_transfer(struct spi_device *spi, struct spi_message *m)
+{
+	struct mpc52xx_spi *ms = spi_master_get_devdata(spi->master);
+	unsigned long flags;
+
+	m->actual_length = 0;
+	m->status = -EINPROGRESS;
+
+	spin_lock_irqsave(&ms->lock, flags);
+	list_add_tail(&m->queue, &ms->queue);
+	spin_unlock_irqrestore(&ms->lock, flags);
+	schedule_work(&ms->work);
+
+	return 0;
+}
+
+/*
+ * Hook to modify premessage hook
+ */
+void mpc52xx_spi_set_premessage_hook(struct spi_master *master,
+				     void (*hook)(struct spi_message *m,
+						  void *context),
+				     void *hook_context)
+{
+	struct mpc52xx_spi *ms = spi_master_get_devdata(master);
+	ms->premessage = hook;
+	ms->premessage_context = hook_context;
+}
+EXPORT_SYMBOL(mpc52xx_spi_set_premessage_hook);
+
+/*
+ * SysFS files
+ */
+static int
+*mpc52xx_spi_sysfs_get_counter(struct mpc52xx_spi *ms, const char *name)
+{
+	if (strcmp(name, "msg_count") == 0)
+		return &ms->msg_count;
+	if (strcmp(name, "byte_count") == 0)
+		return &ms->byte_count;
+	if (strcmp(name, "wcol_count") == 0)
+		return &ms->wcol_count;
+	if (strcmp(name, "wcol_ticks") == 0)
+		return &ms->wcol_ticks;
+	if (strcmp(name, "modf_count") == 0)
+		return &ms->modf_count;
+	return NULL;
+}
+
+static ssize_t mpc52xx_spi_show_count(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	struct spi_master *master = container_of(dev, struct spi_master, dev);
+	struct mpc52xx_spi *ms = spi_master_get_devdata(master);
+	int *counter;
+
+	counter = mpc52xx_spi_sysfs_get_counter(ms, attr->attr.name);
+	if (!counter)
+		return sprintf(buf, "error\n");
+	return sprintf(buf, "%d\n", *counter);
+}
+
+static ssize_t mpc52xx_spi_set_count(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct spi_master *master = container_of(dev, struct spi_master, dev);
+	struct mpc52xx_spi *ms = spi_master_get_devdata(master);
+	int *counter;
+	int value = simple_strtoul(buf, NULL, 0);
+
+	counter = mpc52xx_spi_sysfs_get_counter(ms, attr->attr.name);
+	if (counter)
+		*counter = value;
+	return count;
+}
+
+DEVICE_ATTR(msg_count, 0644, mpc52xx_spi_show_count, mpc52xx_spi_set_count);
+DEVICE_ATTR(byte_count, 0644, mpc52xx_spi_show_count, mpc52xx_spi_set_count);
+DEVICE_ATTR(wcol_count, 0644, mpc52xx_spi_show_count, mpc52xx_spi_set_count);
+DEVICE_ATTR(wcol_ticks, 0644, mpc52xx_spi_show_count, mpc52xx_spi_set_count);
+DEVICE_ATTR(modf_count, 0644, mpc52xx_spi_show_count, mpc52xx_spi_set_count);
+
+/*
+ * OF Platform Bus Binding
+ */
+static int __devinit mpc52xx_spi_of_probe(struct of_device *op,
+					  const struct of_device_id *match)
+{
+	struct spi_master *master;
+	struct mpc52xx_spi *ms;
+	void __iomem *regs;
+	const u32 *prop;
+	int rc, len;
+
+	/* MMIO registers */
+	dev_dbg(&op->dev, "probing mpc5200 SPI device\n");
+	regs = of_iomap(op->node, 0);
+	if (!regs)
+		return -ENODEV;
+
+	/* initialize the device */
+	writeb(SPI_CTRL1_SPIE | SPI_CTRL1_SPE | SPI_CTRL1_MSTR, regs+SPI_CTRL1);
+	writeb(0x0, regs + SPI_CTRL2);
+	writeb(0xe, regs + SPI_DATADIR);	/* Set output pins */
+	writeb(0x8, regs + SPI_PORTDATA);	/* Deassert /SS signal */
+
+	/* Clear the status register and re-read it to check for a MODF
+	 * failure.  This driver cannot currently handle multiple masters
+	 * on the SPI bus.  This fault will also occur if the SPI signals
+	 * are not connected to any pins (port_config setting) */
+	readb(regs + SPI_STATUS);
+	readb(regs + SPI_DATA);
+	if (readb(regs + SPI_STATUS) & SPI_STATUS_MODF) {
+		dev_err(&op->dev, "mode fault; is port_config correct?\n");
+		return -EIO;
+	}
+
+	dev_dbg(&op->dev, "allocating spi_master struct\n");
+	master = spi_alloc_master(&op->dev, sizeof *ms);
+	if (!master)
+		return -ENOMEM;
+	master->bus_num = -1;
+	master->num_chipselect = 1;
+	prop = of_get_property(op->node, "num-slaves", &len);
+	if (prop && len >= sizeof(*prop))
+		master->num_chipselect = *prop;
+
+	master->setup = mpc52xx_spi_setup;
+	master->transfer = mpc52xx_spi_transfer;
+	dev_set_drvdata(&op->dev, master);
+
+	ms = spi_master_get_devdata(master);
+	ms->master = master;
+	ms->regs = regs;
+	ms->irq0 = irq_of_parse_and_map(op->node, 0);
+	ms->irq1 = irq_of_parse_and_map(op->node, 1);
+	ms->state = mpc52xx_spi_fsmstate_idle;
+	ms->ipb_freq = mpc52xx_find_ipb_freq(op->node);
+	spin_lock_init(&ms->lock);
+	INIT_LIST_HEAD(&ms->queue);
+	INIT_WORK(&ms->work, mpc52xx_spi_wq);
+
+	dev_dbg(&op->dev, "registering spi_master struct\n");
+	rc = spi_register_master(master);
+	if (rc < 0)
+		goto err_register;
+
+	/* Decide if interrupts can be used */
+	if ((ms->irq0 != NO_IRQ) && (ms->irq1 != NO_IRQ)) {
+		rc = request_irq(ms->irq0, mpc52xx_spi_irq, IRQF_SAMPLE_RANDOM,
+				  "mpc5200-spi-modf", ms);
+		rc |= request_irq(ms->irq1, mpc52xx_spi_irq, IRQF_SAMPLE_RANDOM,
+				  "mpc5200-spi-spiF", ms);
+		if (rc) {
+			free_irq(ms->irq0, ms);
+			free_irq(ms->irq1, ms);
+			ms->irq0 = ms->irq1 = NO_IRQ;
+			dev_info(&op->dev, "using polled mode\n");
+		}
+	} else {
+		/* operate in polled mode */
+		ms->irq0 = ms->irq1 = NO_IRQ;
+		dev_info(&op->dev, "using polled mode\n");
+	}
+
+	/* Create SysFS files */
+	rc = device_create_file(&ms->master->dev, &dev_attr_msg_count);
+	rc |= device_create_file(&ms->master->dev, &dev_attr_byte_count);
+	rc |= device_create_file(&ms->master->dev, &dev_attr_wcol_count);
+	rc |= device_create_file(&ms->master->dev, &dev_attr_wcol_ticks);
+	rc |= device_create_file(&ms->master->dev, &dev_attr_modf_count);
+	if (rc)
+		dev_info(&ms->master->dev, "error creating sysfs files\n");
+
+	dev_info(&ms->master->dev, "registered MPC5200 SPI bus\n");
+
+	of_register_spi_devices(master, op->node);
+
+	return rc;
+
+ err_register:
+	dev_err(&ms->master->dev, "initialization failed\n");
+	spi_master_put(master);
+	return rc;
+}
+
+static void __devexit mpc52xx_spi_of_remove(struct of_device *op)
+{
+	struct spi_master *master = dev_get_drvdata(&op->dev);
+	struct mpc52xx_spi *ms = spi_master_get_devdata(master);
+
+	device_remove_file(&ms->master->dev, &dev_attr_msg_count);
+	device_remove_file(&ms->master->dev, &dev_attr_byte_count);
+	device_remove_file(&ms->master->dev, &dev_attr_wcol_count);
+	device_remove_file(&ms->master->dev, &dev_attr_wcol_ticks);
+	device_remove_file(&ms->master->dev, &dev_attr_modf_count);
+
+	free_irq(ms->irq0, ms);
+	free_irq(ms->irq1, ms);
+
+	spi_unregister_master(master);
+	spi_master_put(master);
+	iounmap(ms->regs);
+}
+
+static struct of_device_id mpc52xx_spi_of_match[] __devinitdata = {
+	{ .compatible = "fsl,mpc5200-spi", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
+
+static struct of_platform_driver mpc52xx_spi_of_driver = {
+	.owner = THIS_MODULE,
+	.name = "mpc52xx-spi",
+	.match_table = mpc52xx_spi_of_match,
+	.probe = mpc52xx_spi_of_probe,
+	.remove = __exit_p(mpc52xx_spi_of_remove),
+};
+
+static int __init mpc52xx_spi_init(void)
+{
+	return of_register_platform_driver(&mpc52xx_spi_of_driver);
+}
+module_init(mpc52xx_spi_init);
+
+static void __exit mpc52xx_spi_exit(void)
+{
+	of_unregister_platform_driver(&mpc52xx_spi_of_driver);
+}
+module_exit(mpc52xx_spi_exit);
+
diff --git a/include/linux/spi/mpc52xx_spi.h b/include/linux/spi/mpc52xx_spi.h
new file mode 100644
index 0000000..d1004cf
--- /dev/null
+++ b/include/linux/spi/mpc52xx_spi.h
@@ -0,0 +1,10 @@
+
+#ifndef INCLUDE_MPC5200_SPI_H
+#define INCLUDE_MPC5200_SPI_H
+
+extern void mpc52xx_spi_set_premessage_hook(struct spi_master *master,
+					    void (*hook)(struct spi_message *m,
+							 void *context),
+					    void *hook_context);
+
+#endif

^ permalink raw reply related

* [PATCH v3 3/4] spi: Add OF binding support for SPI busses
From: Grant Likely @ 2008-07-25  7:33 UTC (permalink / raw)
  To: linux-kernel, akpm, spi-devel-general, dbrownell, linuxppc-dev,
	jonsmirl
In-Reply-To: <20080725072549.8485.90723.stgit@trillian.secretlab.ca>

From: Grant Likely <grant.likely@secretlab.ca>

This patch adds support for populating an SPI bus based on data in the
OF device tree.  This is useful for powerpc platforms which use the
device tree instead of discrete code for describing platform layout.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 drivers/of/Kconfig     |    6 +++
 drivers/of/Makefile    |    1 +
 drivers/of/of_spi.c    |   93 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/of_spi.h |   18 +++++++++
 4 files changed, 118 insertions(+), 0 deletions(-)

diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 3a7a11a..edd6e92 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -13,3 +13,9 @@ config OF_I2C
 	depends on PPC_OF && I2C
 	help
 	  OpenFirmware I2C accessors
+
+config OF_SPI
+	def_tristate SPI
+	depends on OF && PPC_OF && SPI
+	help
+	  OpenFirmware SPI accessors
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 548772e..4c3c6f8 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -2,3 +2,4 @@ obj-y = base.o
 obj-$(CONFIG_OF_DEVICE) += device.o platform.o
 obj-$(CONFIG_OF_GPIO)   += gpio.o
 obj-$(CONFIG_OF_I2C)	+= of_i2c.o
+obj-$(CONFIG_OF_SPI)	+= of_spi.o
diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c
new file mode 100644
index 0000000..b01eec0
--- /dev/null
+++ b/drivers/of/of_spi.c
@@ -0,0 +1,93 @@
+/*
+ * SPI OF support routines
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ *
+ * Support routines for deriving SPI device attachments from the device
+ * tree.
+ */
+
+#include <linux/of.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/of_spi.h>
+
+/**
+ * of_register_spi_devices - Register child devices onto the SPI bus
+ * @master:	Pointer to spi_master device
+ * @np:		parent node of SPI device nodes
+ *
+ * Registers an spi_device for each child node of 'np' which has a 'reg'
+ * property.
+ */
+void of_register_spi_devices(struct spi_master *master, struct device_node *np)
+{
+	struct spi_device *spi;
+	struct device_node *nc;
+	const u32 *prop;
+	int rc;
+	int len;
+
+	for_each_child_of_node(np, nc) {
+		/* Alloc an spi_device */
+		spi = spi_alloc_device(master);
+		if (!spi) {
+			dev_err(&master->dev, "spi_device alloc error for %s\n",
+				nc->full_name);
+			spi_dev_put(spi);
+			continue;
+		}
+
+		/* Select device driver */
+		if (of_modalias_node(nc, spi->modalias,
+				     sizeof(spi->modalias)) < 0) {
+			dev_err(&master->dev, "cannot find modalias for %s\n",
+				nc->full_name);
+			spi_dev_put(spi);
+			continue;
+		}
+
+		/* Device address */
+		prop = of_get_property(nc, "reg", &len);
+		if (!prop || len < sizeof(*prop)) {
+			dev_err(&master->dev, "%s has no 'reg' property\n",
+				nc->full_name);
+			spi_dev_put(spi);
+			continue;
+		}
+		spi->chip_select = *prop;
+
+		/* Mode (clock phase/polarity/etc.) */
+		if (of_find_property(nc, "spi-cpha", NULL))
+			spi->mode |= SPI_CPHA;
+		if (of_find_property(nc, "spi-cpol", NULL))
+			spi->mode |= SPI_CPOL;
+
+		/* Device speed */
+		prop = of_get_property(nc, "spi-max-frequency", &len);
+		if (!prop || len < sizeof(*prop)) {
+			dev_err(&master->dev, "%s has no 'spi-max-frequency' property\n",
+				nc->full_name);
+			spi_dev_put(spi);
+			continue;
+		}
+		spi->max_speed_hz = *prop;
+
+		/* IRQ */
+		spi->irq = irq_of_parse_and_map(nc, 0);
+
+		/* Store a pointer to the node in the device structure */
+		of_node_get(nc);
+		spi->dev.archdata.of_node = nc;
+
+		/* Register the new device */
+		request_module(spi->modalias);
+		rc = spi_add_device(spi);
+		if (rc) {
+			dev_err(&master->dev, "spi_device register error %s\n",
+				nc->full_name);
+			spi_dev_put(spi);
+		}
+
+	}
+}
+EXPORT_SYMBOL(of_register_spi_devices);
diff --git a/include/linux/of_spi.h b/include/linux/of_spi.h
new file mode 100644
index 0000000..5f71ee8
--- /dev/null
+++ b/include/linux/of_spi.h
@@ -0,0 +1,18 @@
+/*
+ * OpenFirmware SPI support routines
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ *
+ * Support routines for deriving SPI device attachments from the device
+ * tree.
+ */
+
+#ifndef __LINUX_OF_SPI_H
+#define __LINUX_OF_SPI_H
+
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+
+extern void of_register_spi_devices(struct spi_master *master,
+				    struct device_node *np);
+
+#endif /* __LINUX_OF_SPI */

^ permalink raw reply related

* [PATCH v3 2/4] spi: split up spi_new_device() to allow two stage registration.
From: Grant Likely @ 2008-07-25  7:33 UTC (permalink / raw)
  To: linux-kernel, akpm, spi-devel-general, dbrownell, linuxppc-dev,
	jonsmirl
In-Reply-To: <20080725072549.8485.90723.stgit@trillian.secretlab.ca>

From: Grant Likely <grant.likely@secretlab.ca>

spi_new_device() allocates and registers an spi device all in one swoop.
If the driver needs to add extra data to the spi_device before it is
registered, then this causes problems.

This patch splits the allocation and registration portions of code out
of spi_new_device() and creates three new functions; spi_alloc_device(),
spi_register_device(), and spi_device_release().  spi_new_device() is
modified to use the new functions for allocation and registration.
None of the existing users of spi_new_device() should be affected by
this change.

Drivers using the new API can forego the use of an spi_board_info
structure to describe the device layout and populate data into the
spi_device structure directly.

This change is in preparation for adding an OF device tree parser to
generate spi_devices based on data in the device tree.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 drivers/spi/spi.c       |  139 ++++++++++++++++++++++++++++++++---------------
 include/linux/spi/spi.h |   10 +++
 2 files changed, 105 insertions(+), 44 deletions(-)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index ecca4a6..2077ef5 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -178,6 +178,96 @@ struct boardinfo {
 static LIST_HEAD(board_list);
 static DEFINE_MUTEX(board_lock);
 
+/**
+ * spi_alloc_device - Allocate a new SPI device
+ * @master: Controller to which device is connected
+ * Context: can sleep
+ *
+ * Allows a driver to allocate and initialize and spi_device without
+ * registering it immediately.  This allows a driver to directly
+ * fill the spi_device with device parameters before calling
+ * spi_add_device() on it.
+ *
+ * Caller is responsible to call spi_add_device() on the returned
+ * spi_device structure to add it to the SPI master.  If the caller
+ * needs to discard the spi_device without adding it, then it should
+ * call spi_dev_put() on it.
+ *
+ * Returns a pointer to the new device, or NULL.
+ */
+struct spi_device *spi_alloc_device(struct spi_master *master)
+{
+	struct spi_device	*spi;
+	struct device		*dev = master->dev.parent;
+
+	if (!spi_master_get(master))
+		return NULL;
+
+	spi = kzalloc(sizeof *spi, GFP_KERNEL);
+	if (!spi) {
+		dev_err(dev, "cannot alloc spi_device\n");
+		spi_master_put(master);
+		return NULL;
+	}
+
+	spi->master = master;
+	spi->dev.parent = dev;
+	spi->dev.bus = &spi_bus_type;
+	spi->dev.release = spidev_release;
+	device_initialize(&spi->dev);
+	return spi;
+}
+EXPORT_SYMBOL_GPL(spi_alloc_device);
+
+/**
+ * spi_add_device - Add an spi_device allocated with spi_alloc_device
+ * @spi: spi_device to register
+ *
+ * Companion function to spi_alloc_device.  Devices allocated with
+ * spi_alloc_device can be added onto the spi bus with this function.
+ *
+ * Returns 0 on success; non-zero on failure
+ */
+int spi_add_device(struct spi_device *spi)
+{
+	struct device *dev = spi->master->dev.parent;
+	int status;
+
+	/* Chipselects are numbered 0..max; validate. */
+	if (spi->chip_select >= spi->master->num_chipselect) {
+		dev_err(dev, "cs%d > max %d\n",
+			spi->chip_select,
+			spi->master->num_chipselect);
+		return -EINVAL;
+	}
+
+	/* Set the bus ID string */
+	snprintf(spi->dev.bus_id, sizeof spi->dev.bus_id,
+			"%s.%u", spi->master->dev.bus_id,
+			spi->chip_select);
+
+	/* drivers may modify this initial i/o setup */
+	status = spi->master->setup(spi);
+	if (status < 0) {
+		dev_err(dev, "can't %s %s, status %d\n",
+				"setup", spi->dev.bus_id, status);
+		return status;
+	}
+
+	/* driver core catches callers that misbehave by defining
+	 * devices that already exist.
+	 */
+	status = device_add(&spi->dev);
+	if (status < 0) {
+		dev_err(dev, "can't %s %s, status %d\n",
+				"add", spi->dev.bus_id, status);
+		return status;
+	}
+
+	dev_dbg(dev, "registered child %s\n", spi->dev.bus_id);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(spi_add_device);
 
 /**
  * spi_new_device - instantiate one new SPI device
@@ -197,7 +287,6 @@ struct spi_device *spi_new_device(struct spi_master *master,
 				  struct spi_board_info *chip)
 {
 	struct spi_device	*proxy;
-	struct device		*dev = master->dev.parent;
 	int			status;
 
 	/* NOTE:  caller did any chip->bus_num checks necessary.
@@ -207,66 +296,28 @@ struct spi_device *spi_new_device(struct spi_master *master,
 	 * suggests syslogged diagnostics are best here (ugh).
 	 */
 
-	/* Chipselects are numbered 0..max; validate. */
-	if (chip->chip_select >= master->num_chipselect) {
-		dev_err(dev, "cs%d > max %d\n",
-			chip->chip_select,
-			master->num_chipselect);
-		return NULL;
-	}
-
-	if (!spi_master_get(master))
+	proxy = spi_alloc_device(master);
+	if (!proxy)
 		return NULL;
 
 	WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
 
-	proxy = kzalloc(sizeof *proxy, GFP_KERNEL);
-	if (!proxy) {
-		dev_err(dev, "can't alloc dev for cs%d\n",
-			chip->chip_select);
-		goto fail;
-	}
-	proxy->master = master;
 	proxy->chip_select = chip->chip_select;
 	proxy->max_speed_hz = chip->max_speed_hz;
 	proxy->mode = chip->mode;
 	proxy->irq = chip->irq;
 	strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
-
-	snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id,
-			"%s.%u", master->dev.bus_id,
-			chip->chip_select);
-	proxy->dev.parent = dev;
-	proxy->dev.bus = &spi_bus_type;
 	proxy->dev.platform_data = (void *) chip->platform_data;
 	proxy->controller_data = chip->controller_data;
 	proxy->controller_state = NULL;
-	proxy->dev.release = spidev_release;
 
-	/* drivers may modify this initial i/o setup */
-	status = master->setup(proxy);
+	status = spi_add_device(proxy);
 	if (status < 0) {
-		dev_err(dev, "can't %s %s, status %d\n",
-				"setup", proxy->dev.bus_id, status);
-		goto fail;
+		spi_dev_put(proxy);
+		return NULL;
 	}
 
-	/* driver core catches callers that misbehave by defining
-	 * devices that already exist.
-	 */
-	status = device_register(&proxy->dev);
-	if (status < 0) {
-		dev_err(dev, "can't %s %s, status %d\n",
-				"add", proxy->dev.bus_id, status);
-		goto fail;
-	}
-	dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id);
 	return proxy;
-
-fail:
-	spi_master_put(master);
-	kfree(proxy);
-	return NULL;
 }
 EXPORT_SYMBOL_GPL(spi_new_device);
 
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index a9cc29d..d203d08 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -778,8 +778,18 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
  * use spi_new_device() to describe each device.  You can also call
  * spi_unregister_device() to start making that device vanish, but
  * normally that would be handled by spi_unregister_master().
+ *
+ * You can also use spi_alloc_device() and spi_add_device() to
+ * for a two stage registration of an SPI device.  This gives the caller
+ * some more control over the spi_device structure before it is registered
  */
 extern struct spi_device *
+spi_alloc_device(struct spi_master *master);
+
+extern int
+spi_add_device(struct spi_device *spi);
+
+extern struct spi_device *
 spi_new_device(struct spi_master *, struct spi_board_info *);
 
 static inline void

^ permalink raw reply related

* [PATCH v3 1/4] of: adapt of_find_i2c_driver() to be usable by SPI also
From: Grant Likely @ 2008-07-25  7:33 UTC (permalink / raw)
  To: linux-kernel, akpm, spi-devel-general, dbrownell, linuxppc-dev,
	jonsmirl
In-Reply-To: <20080725072549.8485.90723.stgit@trillian.secretlab.ca>

From: Grant Likely <grant.likely@secretlab.ca>

SPI has a similar problem as I2C in that it needs to determine an
appropriate modalias value for each device node.  This patch adapts
the of_i2c of_find_i2c_driver() function to be usable by of_spi also.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 drivers/of/base.c   |   88 +++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/of/of_i2c.c |   64 ++-----------------------------------
 include/linux/of.h  |    1 +
 3 files changed, 92 insertions(+), 61 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 23ffb7c..ad8ac1a 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -385,3 +385,91 @@ struct device_node *of_find_matching_node(struct device_node *from,
 	return np;
 }
 EXPORT_SYMBOL(of_find_matching_node);
+
+/**
+ * of_modalias_table: Table of explicit compatible ==> modalias mappings
+ *
+ * This table allows particulare compatible property values to be mapped
+ * to modalias strings.  This is useful for busses which do not directly
+ * understand the OF device tree but are populated based on data contained
+ * within the device tree.  SPI and I2C are the two current users of this
+ * table.
+ *
+ * In most cases, devices do not need to be listed in this table because
+ * the modalias value can be derived directly from the compatible table.
+ * However, if for any reason a value cannot be derived, then this table
+ * provides a method to override the implicit derivation.
+ *
+ * At the moment, a single table is used for all bus types because it is
+ * assumed that the data size is small and that the compatible values
+ * should already be distinct enough to differentiate between SPI, I2C
+ * and other devices.
+ */
+struct of_modalias_table {
+	char *of_device;
+	char *modalias;
+};
+static struct of_modalias_table of_modalias_table[] = {
+	/* Empty for now; add entries as needed */
+};
+
+/**
+ * of_modalias_node - Lookup appropriate modalias for a device node
+ * @node:	pointer to a device tree node
+ * @modalias:	Pointer to buffer that modalias value will be copied into
+ * @len:	Length of modalias value
+ *
+ * Based on the value of the compatible property, this routine will determine
+ * an appropriate modalias value for a particular device tree node.  Three
+ * separate methods are used to derive a modalias value.
+ *
+ * First method is to lookup the compatible value in of_modalias_table.
+ * Second is to look for a "linux,<modalias>" entry in the compatible list
+ * and used that for modalias.  Third is to strip off the manufacturer
+ * prefix from the first compatible entry and use the remainder as modalias
+ *
+ * This routine returns 0 on success
+ */
+int of_modalias_node(struct device_node *node, char *modalias, int len)
+{
+	int i, cplen;
+	const char *compatible;
+	const char *p;
+
+	/* 1. search for exception list entry */
+	for (i = 0; i < ARRAY_SIZE(of_modalias_table); i++) {
+		compatible = of_modalias_table[i].of_device;
+		if (!of_device_is_compatible(node, compatible))
+			continue;
+		strlcpy(modalias, of_modalias_table[i].modalias, len);
+		return 0;
+	}
+
+	compatible = of_get_property(node, "compatible", &cplen);
+	if (!compatible)
+		return -ENODEV;
+
+	/* 2. search for linux,<modalias> entry */
+	p = compatible;
+	while (cplen > 0) {
+		if (!strncmp(p, "linux,", 6)) {
+			p += 6;
+			strlcpy(modalias, p, len);
+			return 0;
+		}
+
+		i = strlen(p) + 1;
+		p += i;
+		cplen -= i;
+	}
+
+	/* 3. take first compatible entry and strip manufacturer */
+	p = strchr(compatible, ',');
+	if (!p)
+		return -ENODEV;
+	p++;
+	strlcpy(modalias, p, len);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_modalias_node);
+
diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
index 344e1b0..6a98dc8 100644
--- a/drivers/of/of_i2c.c
+++ b/drivers/of/of_i2c.c
@@ -16,62 +16,6 @@
 #include <linux/of_i2c.h>
 #include <linux/module.h>
 
-struct i2c_driver_device {
-	char    *of_device;
-	char    *i2c_type;
-};
-
-static struct i2c_driver_device i2c_devices[] = {
-};
-
-static int of_find_i2c_driver(struct device_node *node,
-			      struct i2c_board_info *info)
-{
-	int i, cplen;
-	const char *compatible;
-	const char *p;
-
-	/* 1. search for exception list entry */
-	for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) {
-		if (!of_device_is_compatible(node, i2c_devices[i].of_device))
-			continue;
-		if (strlcpy(info->type, i2c_devices[i].i2c_type,
-			    I2C_NAME_SIZE) >= I2C_NAME_SIZE)
-			return -ENOMEM;
-
-		return 0;
-	}
-
-	compatible = of_get_property(node, "compatible", &cplen);
-	if (!compatible)
-		return -ENODEV;
-
-	/* 2. search for linux,<i2c-type> entry */
-	p = compatible;
-	while (cplen > 0) {
-		if (!strncmp(p, "linux,", 6)) {
-			p += 6;
-			if (strlcpy(info->type, p,
-				    I2C_NAME_SIZE) >= I2C_NAME_SIZE)
-				return -ENOMEM;
-			return 0;
-		}
-
-		i = strlen(p) + 1;
-		p += i;
-		cplen -= i;
-	}
-
-	/* 3. take fist compatible entry and strip manufacturer */
-	p = strchr(compatible, ',');
-	if (!p)
-		return -ENODEV;
-	p++;
-	if (strlcpy(info->type, p, I2C_NAME_SIZE) >= I2C_NAME_SIZE)
-		return -ENOMEM;
-	return 0;
-}
-
 void of_register_i2c_devices(struct i2c_adapter *adap,
 			     struct device_node *adap_node)
 {
@@ -83,6 +27,9 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
 		const u32 *addr;
 		int len;
 
+		if (of_modalias_node(node, info.type, sizeof(info.type)) < 0)
+			continue;
+
 		addr = of_get_property(node, "reg", &len);
 		if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) {
 			printk(KERN_ERR
@@ -92,11 +39,6 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
 
 		info.irq = irq_of_parse_and_map(node, 0);
 
-		if (of_find_i2c_driver(node, &info) < 0) {
-			irq_dispose_mapping(info.irq);
-			continue;
-		}
-
 		info.addr = *addr;
 
 		request_module(info.type);
diff --git a/include/linux/of.h b/include/linux/of.h
index 59a61bd..79886ad 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -70,5 +70,6 @@ extern int of_n_addr_cells(struct device_node *np);
 extern int of_n_size_cells(struct device_node *np);
 extern const struct of_device_id *of_match_node(
 	const struct of_device_id *matches, const struct device_node *node);
+extern int of_modalias_node(struct device_node *node, char *modalias, int len);
 
 #endif /* _LINUX_OF_H */

^ permalink raw reply related

* [PATCH v3 0/4 REPOST] OF infrastructure for SPI devices
From: Grant Likely @ 2008-07-25  7:33 UTC (permalink / raw)
  To: linux-kernel, akpm, spi-devel-general, dbrownell, linuxppc-dev,
	jonsmirl

I don't know what to do with these patches.  I'd really like to see them
in .27, and now that akpm has cleared his queue, the prerequisite patch
has been merged so they are ready to go in.  However, even though there
has been favourable reception on the SPI and linuxppc lists for these
changes I don't have any acks from anybody yet.

David, can you please reply on if you are okay with these patches
getting merged?  If so, do you want me to merge them via my tree, or
do you want to pick them up?

Thanks,
g.

--
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: sfx.c driver build failure
From: Ingo Molnar @ 2008-07-25  7:32 UTC (permalink / raw)
  To: Stephen Rothwell
  Cc: linuxppc-dev list, Jeff Garzik, Linux Kernel list, Michael Brown
In-Reply-To: <20080725171715.9287c823.sfr@canb.auug.org.au>


* Stephen Rothwell <sfr@canb.auug.org.au> wrote:

> On Fri, 25 Jul 2008 16:15:59 +1000 Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
> >
> > The sfx driver (which happens to be part of some of our test configs)
> > fails to build in current Linus tree on powerpc with this error:
> > 
> > /home/benh/kernels/linux-powerpc/drivers/net/sfc/efx.c: In function ‘efx_probe_interrupts’:
> > /home/benh/kernels/linux-powerpc/drivers/net/sfc/efx.c:845: error: lvalue required as unary ‘&’ operand
> 
> Commit 695a6b456307455a10059512208e8ed0d376ecd3 "topology: work around 
> topology_core_siblings() breakage" in linux-next (from the cpus4096 
> tree) comments out the offending lines ...  With the comment "the 
> topology API is a mess right now".

there's a patch from Mike Travis that solves it all from grounds up and 
which approach has the ack of Rusty as well, but it's not fully tested 
through yet - i will get to it later today.

	Ingo

^ permalink raw reply

* Re: sfx.c driver build failure
From: Stephen Rothwell @ 2008-07-25  7:17 UTC (permalink / raw)
  To: benh
  Cc: list, Michael Brown, linuxppc-dev list, Linux, Ingo Molnar,
	Jeff Garzik
In-Reply-To: <1216966559.11188.85.camel@pasglop>

[-- Attachment #1: Type: text/plain, Size: 806 bytes --]

On Fri, 25 Jul 2008 16:15:59 +1000 Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
>
> The sfx driver (which happens to be part of some of our test configs)
> fails to build in current Linus tree on powerpc with this error:
> 
> /home/benh/kernels/linux-powerpc/drivers/net/sfc/efx.c: In function ‘efx_probe_interrupts’:
> /home/benh/kernels/linux-powerpc/drivers/net/sfc/efx.c:845: error: lvalue required as unary ‘&’ operand

Commit 695a6b456307455a10059512208e8ed0d376ecd3 "topology: work around
topology_core_siblings() breakage" in linux-next (from the cpus4096 tree)
comments out the offending lines ...  With the comment "the topology API
is a mess right now".

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply

* [PATCH] Wireup new syscalls
From: Tony Breeds @ 2008-07-25  6:21 UTC (permalink / raw)
  To: Paul Mackerras, Benjamin Herrenschmidt; +Cc: linuxppc-dev

signalfd4, eventfd2, epoll_create1, dup3, pipe2 and inotify_init1

Signed-off-by: Tony Breeds <tony@bakeyournoodle.com>
---

Tested on POWER6.

 include/asm-powerpc/syscalls.h |    1 +
 include/asm-powerpc/systbl.h   |    6 ++++++
 include/asm-powerpc/unistd.h   |    8 +++++++-
 3 files changed, 14 insertions(+), 1 deletions(-)

diff --git a/include/asm-powerpc/syscalls.h b/include/asm-powerpc/syscalls.h
index 2b8a458..eb8eb40 100644
--- a/include/asm-powerpc/syscalls.h
+++ b/include/asm-powerpc/syscalls.h
@@ -31,6 +31,7 @@ asmlinkage int sys_vfork(unsigned long p1, unsigned long p2,
 		unsigned long p3, unsigned long p4, unsigned long p5,
 		unsigned long p6, struct pt_regs *regs);
 asmlinkage long sys_pipe(int __user *fildes);
+asmlinkage long sys_pipe2(int __user *fildes, int flags);
 asmlinkage long sys_rt_sigaction(int sig,
 		const struct sigaction __user *act,
 		struct sigaction __user *oact, size_t sigsetsize);
diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h
index ae7085c..e084272 100644
--- a/include/asm-powerpc/systbl.h
+++ b/include/asm-powerpc/systbl.h
@@ -316,3 +316,9 @@ COMPAT_SYS(fallocate)
 SYSCALL(subpage_prot)
 COMPAT_SYS_SPU(timerfd_settime)
 COMPAT_SYS_SPU(timerfd_gettime)
+COMPAT_SYS_SPU(signalfd4)
+SYSCALL_SPU(eventfd2)
+SYSCALL_SPU(epoll_create1)
+SYSCALL_SPU(dup3)
+SYSCALL_SPU(pipe2)
+SYSCALL(inotify_init1)
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index ce91bb6..e07d0c7 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -335,10 +335,16 @@
 #define __NR_subpage_prot	310
 #define __NR_timerfd_settime	311
 #define __NR_timerfd_gettime	312
+#define __NR_signalfd4		313
+#define __NR_eventfd2		314
+#define __NR_epoll_create1	315
+#define __NR_dup3		316
+#define __NR_pipe2		317
+#define __NR_inotify_init1	318
 
 #ifdef __KERNEL__
 
-#define __NR_syscalls		313
+#define __NR_syscalls		319
 
 #define __NR__exit __NR_exit
 #define NR_syscalls	__NR_syscalls


Yours Tony

  linux.conf.au        http://linux.conf.au/ || http://lca2008.linux.org.au/
  Jan 28 - Feb 02 2008 The Australian Linux Technical Conference!

^ permalink raw reply related

* sfx.c driver build failure
From: Benjamin Herrenschmidt @ 2008-07-25  6:15 UTC (permalink / raw)
  To: Michael Brown; +Cc: linuxppc-dev list, Jeff Garzik, Linux Kernel list

Hi Michael !

The sfx driver (which happens to be part of some of our test configs)
fails to build in current Linus tree on powerpc with this error:

/home/benh/kernels/linux-powerpc/drivers/net/sfc/efx.c: In function ‘efx_probe_interrupts’:
/home/benh/kernels/linux-powerpc/drivers/net/sfc/efx.c:845: error: lvalue required as unary ‘&’ oper
and

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH 2/2][RT] powerpc - Make the irq reverse mapping radix tree lockless
From: Benjamin Herrenschmidt @ 2008-07-25  5:13 UTC (permalink / raw)
  To: Nick Piggin
  Cc: Tim Chavez, Linux-rt, linux-kernel, Jean Pierre Dion, linux-ppc,
	Sebastien Dugue, Paul Mackerras, Gilles Carry
In-Reply-To: <200807242111.35338.nickpiggin@yahoo.com.au>


> >   Concurrency between readers and writers are handled by the intrinsic
> > properties of the concurrent radix tree. Concurrency between the tree
> > initialization which is done asynchronously with readers and writers access
> > is handled via an atomic variable (revmap_trees_allocated) set when the
> > tree has been initialized and checked before any reader or writer access
> > just like we used to check for tree.gfp_mask != 0 before.
> 
> Hmm, RCU radix tree is in mainline too for quite a while. I thought
> Ben had already converted this code over ages ago...
> 
> Nothing against the -rt patch, but mainline should probably be updated
> to use RCU as well?

No, I haven't updated that code yet, and yes, we should do it :-)

Cheers,
Ben.

^ permalink raw reply

* Re: linux-next: kbuild tree build failure
From: Stephen Rothwell @ 2008-07-25  4:13 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: Benjamin, Milton Miller, linuxppc-dev, linux-next, Mackerras,
	Paul
In-Reply-To: <20080707184038.aaeb8d40.sfr@canb.auug.org.au>

[-- Attachment #1: Type: text/plain, Size: 614 bytes --]

Hi Sam,

On Mon, 7 Jul 2008 18:40:38 +1000 Stephen Rothwell <sfr@canb.auug.org.au> wrote:
>
> Today's linux-next build (powerpc ppc64_defconfig) failed like this:
> 
> arch/powerpc/platforms/cell/spu_base.c: In function '__spu_trap_data_seg':
> arch/powerpc/platforms/cell/spu_base.c:194: error: duplicate case value
> arch/powerpc/platforms/cell/spu_base.c:177: error: previously used here

This still fails in linux-next today.  We need some solution before you
send these commits to Linus.

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox