LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] powerpc, hw_breakpoints: Fix CONFIG_HAVE_HW_BREAKPOINT off-case in ptrace_set_debugreg
From: Ingo Molnar @ 2011-05-06  6:13 UTC (permalink / raw)
  To: Frederic Weisbecker, Benjamin Herrenschmidt, Paul Mackerras
  Cc: Prasad, LPPC, LKML, v2.6.33..
In-Reply-To: <1304639598-4707-1-git-send-email-fweisbec@gmail.com>


* Frederic Weisbecker <fweisbec@gmail.com> wrote:

> We make use of ptrace_get_breakpoints() / ptrace_put_breakpoints()
> to protect ptrace_set_debugreg() even if CONFIG_HAVE_HW_BREAKPOINT
> if off. However in this case, these APIs are not implemented.
> 
> To fix this, push the protection down inside the relevant ifdef.
> Best would be to export the code inside CONFIG_HAVE_HW_BREAKPOINT
> into a standalone function to cleanup the ifdefury there and call
> the breakpoint ref API inside. But as it is more invasive, this
> should be rather made in an -rc1.
> 
> Fixes:
> 
> arch/powerpc/kernel/ptrace.c:1594: error: implicit declaration of function 'ptrace_get_breakpoints'
> make[2]: *** [arch/powerpc/kernel/ptrace.o] Error 1
> make[1]: *** [arch/powerpc/kernel] Error 2
> make: *** [sub-make] Error 2

Thanks.

I'll need a PowerPC ack for this. Note: it's dependent on hw-breakpoint fixes 
in tip:perf/urgent so the commit will want to go there too.

Thanks,

	Ingo

^ permalink raw reply

* Re: [PATCH 2/2] powerpc/pseries: Add support for IO event interrupts
From: Benjamin Herrenschmidt @ 2011-05-06  3:51 UTC (permalink / raw)
  To: Tseng-Hui (Frank) Lin; +Cc: tsenglin, linuxppc-dev
In-Reply-To: <1304634768.5943.4.camel@flin.austin.ibm.com>

On Thu, 2011-05-05 at 17:32 -0500, Tseng-Hui (Frank) Lin wrote:
> From: Tseng-Hui (Frank) Lin <thlin@linux.vnet.ibm.com>
> 
> This patch adds support for handling IO Event interrupts which come
> through at the /event-sources/ibm,io-events device tree node.
> 
> The interrupts come through ibm,io-events device tree node are generated
> by the firmware to report IO events. The firmware uses the same interrupt
> to report multiple types of events for multiple devices. Each device may
> have its own event handler. This patch implements a plateform interrupt
> handler that is triggered by the IO event interrupts come through
> ibm,io-events device tree node, pull in the IO events from RTAS and call
> device event handlers registered in the notifier list.
> 
> Device event handlers are expected to use atomic_notifier_chain_register()
> and atomic_notifier_chain_unregister() to register/unregister their
> event handler in pseries_ioei_notifier_list list with IO event interrupt.
> Device event handlers are responsible to identify if the event belongs
> to the device event handler. The device event handle should return NOTIFY_OK
> after the event is handled if the event belongs to the device event handler,
> or NOTIFY_DONE otherwise.
> 
> Change log:
> - Fixed compilation errors
> - Fix comments to be docbook compliant
> - Fix some code format
> 
> Signed-off-by: Tseng-Hui (Frank) Lin <thlin@us.ibm.com>
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---

Next time, please put the change log -after- the "---" so it is not part
of what gets committed. I've fixed it up by hand for now.

Cheers,
Ben.

>  arch/powerpc/include/asm/io_event_irq.h       |   54 ++++++
>  arch/powerpc/platforms/pseries/Kconfig        |   18 ++
>  arch/powerpc/platforms/pseries/Makefile       |    1 +
>  arch/powerpc/platforms/pseries/io_event_irq.c |  231 +++++++++++++++++++++++++
>  4 files changed, 304 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/io_event_irq.h b/arch/powerpc/include/asm/io_event_irq.h
> new file mode 100644
> index 0000000..b1a9a1b
> --- /dev/null
> +++ b/arch/powerpc/include/asm/io_event_irq.h
> @@ -0,0 +1,54 @@
> +/*
> + * Copyright 2010, 2011 Mark Nelson and Tseng-Hui (Frank) Lin, IBM Corporation
> + *
> + *  This program is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU General Public License
> + *  as published by the Free Software Foundation; either version
> + *  2 of the License, or (at your option) any later version.
> + */
> +
> +#ifndef _ASM_POWERPC_IO_EVENT_IRQ_H
> +#define _ASM_POWERPC_IO_EVENT_IRQ_H
> +
> +#include <linux/types.h>
> +#include <linux/notifier.h>
> +
> +#define PSERIES_IOEI_RPC_MAX_LEN 216
> +
> +#define PSERIES_IOEI_TYPE_ERR_DETECTED		0x01
> +#define PSERIES_IOEI_TYPE_ERR_RECOVERED		0x02
> +#define PSERIES_IOEI_TYPE_EVENT			0x03
> +#define PSERIES_IOEI_TYPE_RPC_PASS_THRU		0x04
> +
> +#define PSERIES_IOEI_SUBTYPE_NOT_APP		0x00
> +#define PSERIES_IOEI_SUBTYPE_REBALANCE_REQ	0x01
> +#define PSERIES_IOEI_SUBTYPE_NODE_ONLINE	0x03
> +#define PSERIES_IOEI_SUBTYPE_NODE_OFFLINE	0x04
> +#define PSERIES_IOEI_SUBTYPE_DUMP_SIZE_CHANGE	0x05
> +#define PSERIES_IOEI_SUBTYPE_TORRENT_IRV_UPDATE	0x06
> +#define PSERIES_IOEI_SUBTYPE_TORRENT_HFI_CFGED	0x07
> +
> +#define PSERIES_IOEI_SCOPE_NOT_APP		0x00
> +#define PSERIES_IOEI_SCOPE_RIO_HUB		0x36
> +#define PSERIES_IOEI_SCOPE_RIO_BRIDGE		0x37
> +#define PSERIES_IOEI_SCOPE_PHB			0x38
> +#define PSERIES_IOEI_SCOPE_EADS_GLOBAL		0x39
> +#define PSERIES_IOEI_SCOPE_EADS_SLOT		0x3A
> +#define PSERIES_IOEI_SCOPE_TORRENT_HUB		0x3B
> +#define PSERIES_IOEI_SCOPE_SERVICE_PROC		0x51
> +
> +/* Platform Event Log Format, Version 6, data portition of IO event section */
> +struct pseries_io_event {
> +	uint8_t event_type;		/* 0x00 IO-Event Type		*/
> +	uint8_t rpc_data_len;		/* 0x01 RPC data length		*/
> +	uint8_t scope;			/* 0x02 Error/Event Scope	*/
> +	uint8_t event_subtype;		/* 0x03 I/O-Event Sub-Type	*/
> +	uint32_t drc_index;		/* 0x04 DRC Index		*/
> +	uint8_t rpc_data[PSERIES_IOEI_RPC_MAX_LEN];
> +					/* 0x08 RPC Data (0-216 bytes,	*/
> +					/* padded to 4 bytes alignment)	*/
> +};
> +
> +extern struct atomic_notifier_head pseries_ioei_notifier_list;
> +
> +#endif /* _ASM_POWERPC_IO_EVENT_IRQ_H */
> diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
> index b044922..71af4c5 100644
> --- a/arch/powerpc/platforms/pseries/Kconfig
> +++ b/arch/powerpc/platforms/pseries/Kconfig
> @@ -50,6 +50,24 @@ config SCANLOG
>  	tristate "Scanlog dump interface"
>  	depends on RTAS_PROC && PPC_PSERIES
>  
> +config IO_EVENT_IRQ
> +	bool "IO Event Interrupt support"
> +	depends on PPC_PSERIES
> +	default y
> +	help
> +	  Select this option, if you want to enable support for IO Event
> +	  interrupts. IO event interrupt is a mechanism provided by RTAS
> +	  to return information about hardware error and non-error events
> +	  which may need OS attention. RTAS returns events for multiple
> +	  event types and scopes. Device drivers can register their handlers
> +	  to receive events.
> +
> +	  This option will only enable the IO event platform code. You
> +	  will still need to enable or compile the actual drivers
> +	  that use this infrastruture to handle IO event interrupts.
> +
> +	  Say Y if you are unsure.
> +
>  config LPARCFG
>  	bool "LPAR Configuration Data"
>  	depends on PPC_PSERIES || PPC_ISERIES
> diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
> index 4cfefba..3556e40 100644
> --- a/arch/powerpc/platforms/pseries/Makefile
> +++ b/arch/powerpc/platforms/pseries/Makefile
> @@ -21,6 +21,7 @@ obj-$(CONFIG_HCALL_STATS)	+= hvCall_inst.o
>  obj-$(CONFIG_PHYP_DUMP)		+= phyp_dump.o
>  obj-$(CONFIG_CMM)		+= cmm.o
>  obj-$(CONFIG_DTL)		+= dtl.o
> +obj-$(CONFIG_IO_EVENT_IRQ)	+= io_event_irq.o
>  
>  ifeq ($(CONFIG_PPC_PSERIES),y)
>  obj-$(CONFIG_SUSPEND)		+= suspend.o
> diff --git a/arch/powerpc/platforms/pseries/io_event_irq.c b/arch/powerpc/platforms/pseries/io_event_irq.c
> new file mode 100644
> index 0000000..c829e60
> --- /dev/null
> +++ b/arch/powerpc/platforms/pseries/io_event_irq.c
> @@ -0,0 +1,231 @@
> +/*
> + * Copyright 2010 2011 Mark Nelson and Tseng-Hui (Frank) Lin, IBM Corporation
> + *
> + *  This program is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU General Public License
> + *  as published by the Free Software Foundation; either version
> + *  2 of the License, or (at your option) any later version.
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/of.h>
> +#include <linux/list.h>
> +#include <linux/notifier.h>
> +
> +#include <asm/machdep.h>
> +#include <asm/rtas.h>
> +#include <asm/irq.h>
> +#include <asm/io_event_irq.h>
> +
> +#include "pseries.h"
> +
> +/*
> + * IO event interrupt is a mechanism provided by RTAS to return
> + * information about hardware error and non-error events. Device
> + * drivers can register their event handlers to receive events.
> + * Device drivers are expected to use atomic_notifier_chain_register()
> + * and atomic_notifier_chain_unregister() to register and unregister
> + * their event handlers. Since multiple IO event types and scopes
> + * share an IO event interrupt, the event handlers are called one
> + * by one until the IO event is claimed by one of the handlers.
> + * The event handlers are expected to return NOTIFY_OK if the
> + * event is handled by the event handler or NOTIFY_DONE if the
> + * event does not belong to the handler.
> + *
> + * Usage:
> + *
> + * Notifier function:
> + * #include <asm/io_event_irq.h>
> + * int event_handler(struct notifier_block *nb, unsigned long val, void *data) {
> + * 	p = (struct pseries_io_event_sect_data *) data;
> + * 	if (! is_my_event(p->scope, p->event_type)) return NOTIFY_DONE;
> + * 		:
> + * 		:
> + * 	return NOTIFY_OK;
> + * }
> + * struct notifier_block event_nb = {
> + * 	.notifier_call = event_handler,
> + * }
> + *
> + * Registration:
> + * atomic_notifier_chain_register(&pseries_ioei_notifier_list, &event_nb);
> + *
> + * Unregistration:
> + * atomic_notifier_chain_unregister(&pseries_ioei_notifier_list, &event_nb);
> + */
> +
> +ATOMIC_NOTIFIER_HEAD(pseries_ioei_notifier_list);
> +EXPORT_SYMBOL_GPL(pseries_ioei_notifier_list);
> +
> +static int ioei_check_exception_token;
> +
> +/* pSeries event log format */
> +
> +/* Two bytes ASCII section IDs */
> +#define PSERIES_ELOG_SECT_ID_PRIV_HDR		(('P' << 8) | 'H')
> +#define PSERIES_ELOG_SECT_ID_USER_HDR		(('U' << 8) | 'H')
> +#define PSERIES_ELOG_SECT_ID_PRIMARY_SRC	(('P' << 8) | 'S')
> +#define PSERIES_ELOG_SECT_ID_EXTENDED_UH	(('E' << 8) | 'H')
> +#define PSERIES_ELOG_SECT_ID_FAILING_MTMS	(('M' << 8) | 'T')
> +#define PSERIES_ELOG_SECT_ID_SECONDARY_SRC	(('S' << 8) | 'S')
> +#define PSERIES_ELOG_SECT_ID_DUMP_LOCATOR	(('D' << 8) | 'H')
> +#define PSERIES_ELOG_SECT_ID_FW_ERROR		(('S' << 8) | 'W')
> +#define PSERIES_ELOG_SECT_ID_IMPACT_PART_ID	(('L' << 8) | 'P')
> +#define PSERIES_ELOG_SECT_ID_LOGIC_RESOURCE_ID	(('L' << 8) | 'R')
> +#define PSERIES_ELOG_SECT_ID_HMC_ID		(('H' << 8) | 'M')
> +#define PSERIES_ELOG_SECT_ID_EPOW		(('E' << 8) | 'P')
> +#define PSERIES_ELOG_SECT_ID_IO_EVENT		(('I' << 8) | 'E')
> +#define PSERIES_ELOG_SECT_ID_MANUFACT_INFO	(('M' << 8) | 'I')
> +#define PSERIES_ELOG_SECT_ID_CALL_HOME		(('C' << 8) | 'H')
> +#define PSERIES_ELOG_SECT_ID_USER_DEF		(('U' << 8) | 'D')
> +
> +/* Vendor specific Platform Event Log Format, Version 6, section header */
> +struct pseries_elog_section {
> +	uint16_t id;			/* 0x00 2-byte ASCII section ID	*/
> +	uint16_t length;		/* 0x02 Section length in bytes	*/
> +	uint8_t version;		/* 0x04 Section version		*/
> +	uint8_t subtype;		/* 0x05 Section subtype		*/
> +	uint16_t creator_component;	/* 0x06 Creator component ID	*/
> +	uint8_t data[];			/* 0x08 Start of section data	*/
> +};
> +
> +static char ioei_rtas_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
> +
> +/**
> + * Find data portion of a specific section in RTAS extended event log.
> + * @elog: RTAS error/event log.
> + * @sect_id: secsion ID.
> + *
> + * Return:
> + *	pointer to the section data of the specified section
> + *	NULL if not found
> + */
> +static struct pseries_elog_section *find_xelog_section(struct rtas_error_log *elog,
> +						       uint16_t sect_id)
> +{
> +	struct rtas_ext_event_log_v6 *xelog =
> +		(struct rtas_ext_event_log_v6 *) elog->buffer;
> +	struct pseries_elog_section *sect;
> +	unsigned char *p, *log_end;
> +
> +	/* Check that we understand the format */
> +	if (elog->extended_log_length < sizeof(struct rtas_ext_event_log_v6) ||
> +	    xelog->log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG ||
> +	    xelog->company_id != RTAS_V6EXT_COMPANY_ID_IBM)
> +		return NULL;
> +
> +	log_end = elog->buffer + elog->extended_log_length;
> +	p = xelog->vendor_log;
> +	while (p < log_end) {
> +		sect = (struct pseries_elog_section *)p;
> +		if (sect->id == sect_id)
> +			return sect;
> +		p += sect->length;
> +	}
> +	return NULL;
> +}
> +
> +/**
> + * Find the data portion of an IO Event section from event log.
> + * @elog: RTAS error/event log.
> + *
> + * Return:
> + * 	pointer to a valid IO event section data. NULL if not found.
> + */
> +static struct pseries_io_event * ioei_find_event(struct rtas_error_log *elog)
> +{
> +	struct pseries_elog_section *sect;
> +
> +	/* We should only ever get called for io-event interrupts, but if
> +	 * we do get called for another type then something went wrong so
> +	 * make some noise about it.
> +	 * RTAS_TYPE_IO only exists in extended event log version 6 or later.
> +	 * No need to check event log version.
> +	 */
> +	if (unlikely(elog->type != RTAS_TYPE_IO)) {
> +		printk_once(KERN_WARNING "io_event_irq: Unexpected event type %d",
> +			    elog->type);
> +		return NULL;
> +	}
> +
> +	sect = find_xelog_section(elog, PSERIES_ELOG_SECT_ID_IO_EVENT);
> +	if (unlikely(!sect)) {
> +		printk_once(KERN_WARNING "io_event_irq: RTAS extended event "
> +			    "log does not contain an IO Event section. "
> +			    "Could be a bug in system firmware!\n");
> +		return NULL;
> +	}
> +	return (struct pseries_io_event *) &sect->data;
> +}
> +
> +/*
> + * PAPR:
> + * - check-exception returns the first found error or event and clear that
> + *   error or event so it is reported once.
> + * - Each interrupt returns one event. If a plateform chooses to report
> + *   multiple events through a single interrupt, it must ensure that the
> + *   interrupt remains asserted until check-exception has been used to
> + *   process all out-standing events for that interrupt.
> + *
> + * Implementation notes:
> + * - Events must be processed in the order they are returned. Hence,
> + *   sequential in nature.
> + * - The owner of an event is determined by combinations of scope,
> + *   event type, and sub-type. There is no easy way to pre-sort clients
> + *   by scope or event type alone. For example, Torrent ISR route change
> + *   event is reported with scope 0x00 (Not Applicatable) rather than
> + *   0x3B (Torrent-hub). It is better to let the clients to identify
> + *   who owns the the event.
> + */
> +
> +static irqreturn_t ioei_interrupt(int irq, void *dev_id)
> +{
> +	struct pseries_io_event *event;
> +	int rtas_rc;
> +
> +	for (;;) {
> +		rtas_rc = rtas_call(ioei_check_exception_token, 6, 1, NULL,
> +				    RTAS_VECTOR_EXTERNAL_INTERRUPT,
> +				    virq_to_hw(irq),
> +				    RTAS_IO_EVENTS, 1 /* Time Critical */,
> +				    __pa(ioei_rtas_buf),
> +				    RTAS_DATA_BUF_SIZE);
> +		if (rtas_rc != 0)
> +			break;
> +
> +		event = ioei_find_event((struct rtas_error_log *)ioei_rtas_buf);
> +		if (!event)
> +			continue;
> +
> +		atomic_notifier_call_chain(&pseries_ioei_notifier_list,
> +					   0, event);
> +	}
> +	return IRQ_HANDLED;
> +}
> +
> +static int __init ioei_init(void)
> +{
> +	struct device_node *np;
> +
> +	ioei_check_exception_token = rtas_token("check-exception");
> +	if (ioei_check_exception_token == RTAS_UNKNOWN_SERVICE) {
> +		pr_warning("IO Event IRQ not supported on this system !\n");
> +		return -ENODEV;
> +	}
> +	np = of_find_node_by_path("/event-sources/ibm,io-events");
> +	if (np) {
> +		request_event_sources_irqs(np, ioei_interrupt, "IO_EVENT");
> +		of_node_put(np);
> +	} else {
> +		pr_err("io_event_irq: No ibm,io-events on system! "
> +		       "IO Event interrupt disabled.\n");
> +		return -ENODEV;
> +	}
> +	return 0;
> +}
> +machine_subsys_initcall(pseries, ioei_init);
> +
> 

^ permalink raw reply

* Re: [PATCH 4/4] powerpc/mpic: add the mpic global timer support
From: Benjamin Herrenschmidt @ 2011-05-06  3:30 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <F923130F-46AA-4E8E-89B0-27FC9EC020BD@kernel.crashing.org>

On Thu, 2011-05-05 at 20:07 -0500, Kumar Gala wrote:
> On Mar 24, 2011, at 4:43 PM, Scott Wood wrote:
> 
> > Add support for MPIC timers as requestable interrupt sources.
> > 
> > Based on http://patchwork.ozlabs.org/patch/20941/ by Dave Liu.
> > 
> > Signed-off-by: Dave Liu <daveliu@freescale.com>
> > Signed-off-by: Scott Wood <scottwood@freescale.com>
> > ---
> > arch/powerpc/include/asm/mpic.h |    3 +-
> > arch/powerpc/sysdev/mpic.c      |   92 ++++++++++++++++++++++++++++++++++++---
> > 2 files changed, 88 insertions(+), 7 deletions(-)
> 
> Ben,
> 
> Did you plan on review and pull this in or expect me to?

I might have been waiting for you I think ... :-) Or I wasn't sure. Feel
free to pick them up (if you do so, tag them as such in patchwork).

Cheers,
Ben.

> - k
> 
> 
> > 
> > diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
> > index 25a0cb3..664bee6 100644
> > --- a/arch/powerpc/include/asm/mpic.h
> > +++ b/arch/powerpc/include/asm/mpic.h
> > @@ -263,6 +263,7 @@ struct mpic
> > #ifdef CONFIG_SMP
> > 	struct irq_chip		hc_ipi;
> > #endif
> > +	struct irq_chip		hc_tm;
> > 	const char		*name;
> > 	/* Flags */
> > 	unsigned int		flags;
> > @@ -281,7 +282,7 @@ struct mpic
> > 
> > 	/* vector numbers used for internal sources (ipi/timers) */
> > 	unsigned int		ipi_vecs[4];
> > -	unsigned int		timer_vecs[4];
> > +	unsigned int		timer_vecs[8];
> > 
> > 	/* Spurious vector to program into unused sources */
> > 	unsigned int		spurious_vec;
> > diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
> > index 69f96ec..c173e67 100644
> > --- a/arch/powerpc/sysdev/mpic.c
> > +++ b/arch/powerpc/sysdev/mpic.c
> > @@ -219,6 +219,28 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu
> > 	_mpic_write(mpic->reg_type, &mpic->gregs, offset, value);
> > }
> > 
> > +static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm)
> > +{
> > +	unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) +
> > +			      ((tm & 3) * MPIC_INFO(TIMER_STRIDE));
> > +
> > +	if (tm >= 4)
> > +		offset += 0x1000 / 4;
> > +
> > +	return _mpic_read(mpic->reg_type, &mpic->tmregs, offset);
> > +}
> > +
> > +static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value)
> > +{
> > +	unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) +
> > +			      ((tm & 3) * MPIC_INFO(TIMER_STRIDE));
> > +
> > +	if (tm >= 4)
> > +		offset += 0x1000 / 4;
> > +
> > +	_mpic_write(mpic->reg_type, &mpic->tmregs, offset, value);
> > +}
> > +
> > static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
> > {
> > 	unsigned int cpu = mpic_processor_id(mpic);
> > @@ -269,6 +291,8 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
> > #define mpic_write(b,r,v)	_mpic_write(mpic->reg_type,&(b),(r),(v))
> > #define mpic_ipi_read(i)	_mpic_ipi_read(mpic,(i))
> > #define mpic_ipi_write(i,v)	_mpic_ipi_write(mpic,(i),(v))
> > +#define mpic_tm_read(i)		_mpic_tm_read(mpic,(i))
> > +#define mpic_tm_write(i,v)	_mpic_tm_write(mpic,(i),(v))
> > #define mpic_cpu_read(i)	_mpic_cpu_read(mpic,(i))
> > #define mpic_cpu_write(i,v)	_mpic_cpu_write(mpic,(i),(v))
> > #define mpic_irq_read(s,r)	_mpic_irq_read(mpic,(s),(r))
> > @@ -628,6 +652,13 @@ static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq)
> > 	return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]);
> > }
> > 
> > +/* Determine if the linux irq is a timer */
> > +static unsigned int mpic_is_tm(struct mpic *mpic, unsigned int irq)
> > +{
> > +	unsigned int src = mpic_irq_to_hw(irq);
> > +
> > +	return (src >= mpic->timer_vecs[0] && src <= mpic->timer_vecs[7]);
> > +}
> > 
> > /* Convert a cpu mask from logical to physical cpu numbers. */
> > static inline u32 mpic_physmask(u32 cpumask)
> > @@ -814,6 +845,25 @@ static void mpic_end_ipi(struct irq_data *d)
> > 
> > #endif /* CONFIG_SMP */
> > 
> > +static void mpic_unmask_tm(struct irq_data *d)
> > +{
> > +	struct mpic *mpic = mpic_from_irq_data(d);
> > +	unsigned int src = mpic_irq_to_hw(d->irq) - mpic->timer_vecs[0];
> > +
> > +	DBG("%s: enable_tm: %d (tm %d)\n", mpic->name, irq, src);
> > +	mpic_tm_write(src, mpic_tm_read(src) & ~MPIC_VECPRI_MASK);
> > +	mpic_tm_read(src);
> > +}
> > +
> > +static void mpic_mask_tm(struct irq_data *d)
> > +{
> > +	struct mpic *mpic = mpic_from_irq_data(d);
> > +	unsigned int src = mpic_irq_to_hw(d->irq) - mpic->timer_vecs[0];
> > +
> > +	mpic_tm_write(src, mpic_tm_read(src) | MPIC_VECPRI_MASK);
> > +	mpic_tm_read(src);
> > +}
> > +
> > int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
> > 		      bool force)
> > {
> > @@ -948,6 +998,12 @@ static struct irq_chip mpic_ipi_chip = {
> > };
> > #endif /* CONFIG_SMP */
> > 
> > +static struct irq_chip mpic_tm_chip = {
> > +	.irq_mask	= mpic_mask_tm,
> > +	.irq_unmask	= mpic_unmask_tm,
> > +	.irq_eoi	= mpic_end_irq,
> > +};
> > +
> > #ifdef CONFIG_MPIC_U3_HT_IRQS
> > static struct irq_chip mpic_irq_ht_chip = {
> > 	.irq_startup	= mpic_startup_ht_irq,
> > @@ -991,6 +1047,16 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
> > 	}
> > #endif /* CONFIG_SMP */
> > 
> > +	if (hw >= mpic->timer_vecs[0] && hw <= mpic->timer_vecs[7]) {
> > +		WARN_ON(!(mpic->flags & MPIC_PRIMARY));
> > +
> > +		DBG("mpic: mapping as timer\n");
> > +		set_irq_chip_data(virq, mpic);
> > +		set_irq_chip_and_handler(virq, &mpic->hc_tm,
> > +					 handle_fasteoi_irq);
> > +		return 0;
> > +	}
> > +
> > 	if (hw >= mpic->irq_count)
> > 		return -EINVAL;
> > 
> > @@ -1147,6 +1213,9 @@ struct mpic * __init mpic_alloc(struct device_node *node,
> > 	mpic->hc_ipi.name = name;
> > #endif /* CONFIG_SMP */
> > 
> > +	mpic->hc_tm = mpic_tm_chip;
> > +	mpic->hc_tm.name = name;
> > +
> > 	mpic->flags = flags;
> > 	mpic->isu_size = isu_size;
> > 	mpic->irq_count = irq_count;
> > @@ -1157,10 +1226,14 @@ struct mpic * __init mpic_alloc(struct device_node *node,
> > 	else
> > 		intvec_top = 255;
> > 
> > -	mpic->timer_vecs[0] = intvec_top - 8;
> > -	mpic->timer_vecs[1] = intvec_top - 7;
> > -	mpic->timer_vecs[2] = intvec_top - 6;
> > -	mpic->timer_vecs[3] = intvec_top - 5;
> > +	mpic->timer_vecs[0] = intvec_top - 12;
> > +	mpic->timer_vecs[1] = intvec_top - 11;
> > +	mpic->timer_vecs[2] = intvec_top - 10;
> > +	mpic->timer_vecs[3] = intvec_top - 9;
> > +	mpic->timer_vecs[4] = intvec_top - 8;
> > +	mpic->timer_vecs[5] = intvec_top - 7;
> > +	mpic->timer_vecs[6] = intvec_top - 6;
> > +	mpic->timer_vecs[7] = intvec_top - 5;
> > 	mpic->ipi_vecs[0]   = intvec_top - 4;
> > 	mpic->ipi_vecs[1]   = intvec_top - 3;
> > 	mpic->ipi_vecs[2]   = intvec_top - 2;
> > @@ -1363,15 +1436,17 @@ void __init mpic_init(struct mpic *mpic)
> > 	/* Set current processor priority to max */
> > 	mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
> > 
> > -	/* Initialize timers: just disable them all */
> > +	/* Initialize timers to our reserved vectors and mask them for now */
> > 	for (i = 0; i < 4; i++) {
> > 		mpic_write(mpic->tmregs,
> > 			   i * MPIC_INFO(TIMER_STRIDE) +
> > -			   MPIC_INFO(TIMER_DESTINATION), 0);
> > +			   MPIC_INFO(TIMER_DESTINATION),
> > +			   1 << hard_smp_processor_id());
> > 		mpic_write(mpic->tmregs,
> > 			   i * MPIC_INFO(TIMER_STRIDE) +
> > 			   MPIC_INFO(TIMER_VECTOR_PRI),
> > 			   MPIC_VECPRI_MASK |
> > +			   (9 << MPIC_VECPRI_PRIORITY_SHIFT) |
> > 			   (mpic->timer_vecs[0] + i));
> > 	}
> > 
> > @@ -1480,6 +1555,11 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
> > 			~MPIC_VECPRI_PRIORITY_MASK;
> > 		mpic_ipi_write(src - mpic->ipi_vecs[0],
> > 			       reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
> > +	} else if (mpic_is_tm(mpic, irq)) {
> > +		reg = mpic_tm_read(src - mpic->timer_vecs[0]) &
> > +			~MPIC_VECPRI_PRIORITY_MASK;
> > +		mpic_tm_write(src - mpic->timer_vecs[0],
> > +			      reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
> > 	} else {
> > 		reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI))
> > 			& ~MPIC_VECPRI_PRIORITY_MASK;
> > -- 
> > 1.7.1

^ permalink raw reply

* Re: [PATCH v2 3/7] mmc: sdhci: make sdhci-of device drivers self registered
From: Shawn Guo @ 2011-05-06  2:15 UTC (permalink / raw)
  To: Anton Vorontsov
  Cc: Chris Ball, sameo, Arnd Bergmann, patches, devicetree-discuss,
	linux-mmc, Saeed Bishara, Xiaobo Xie, kernel, Mike Rapoport,
	Olof Johansson, Shawn Guo, linuxppc-dev, Albert Herranz,
	linux-arm-kernel
In-Reply-To: <20110505142344.GA13400@oksana.dev.rtsoft.ru>

On Thu, May 05, 2011 at 06:23:44PM +0400, Anton Vorontsov wrote:
> On Thu, May 05, 2011 at 09:22:54PM +0800, Shawn Guo wrote:
> [...]
> > - * Copyright (c) 2007 Freescale Semiconductor, Inc.
> > - * Copyright (c) 2009 MontaVista Software, Inc.
> > - *
> > - * Authors: Xiaobo Xie <X.Xie@freescale.com>
> > - *	    Anton Vorontsov <avorontsov@ru.mvista.com>
> [...]
> > -#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
> > -
> > -/*
> > - * These accessors are designed for big endian hosts doing I/O to
> > - * little endian controllers incorporating a 32-bit hardware byte swapper.
> > - */
> > -
> > -u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg)
> > -{
> > -	return in_be32(host->ioaddr + reg);
> > -}
> > -
> > -u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg)
> > -{
> > -	return in_be16(host->ioaddr + (reg ^ 0x2));
> > -}
> > -
> > -u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg)
> > -{
> > -	return in_8(host->ioaddr + (reg ^ 0x3));
> > -}
> > -
> > -void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg)
> > -{
> > -	out_be32(host->ioaddr + reg, val);
> > -}
> > -
> > -void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
> > -{
> > -	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> > -	int base = reg & ~0x3;
> > -	int shift = (reg & 0x2) * 8;
> > -
> > -	switch (reg) {
> > -	case SDHCI_TRANSFER_MODE:
> > -		/*
> > -		 * Postpone this write, we must do it together with a
> > -		 * command write that is down below.
> > -		 */
> > -		pltfm_host->xfer_mode_shadow = val;
> > -		return;
> > -	case SDHCI_COMMAND:
> > -		sdhci_be32bs_writel(host, val << 16 | pltfm_host->xfer_mode_shadow,
> > -				    SDHCI_TRANSFER_MODE);
> > -		return;
> > -	}
> > -	clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift);
> > -}
> > -
> > -void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
> > -{
> > -	int base = reg & ~0x3;
> > -	int shift = (reg & 0x3) * 8;
> > -
> > -	clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
> > -}
> > -#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
> [...]
> > +#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
> > +/*
> > + * These accessors are designed for big endian hosts doing I/O to
> > + * little endian controllers incorporating a 32-bit hardware byte swapper.
> > + */
> > +u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg)
> > +{
> > +	return in_be32(host->ioaddr + reg);
> > +}
> > +
> > +u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg)
> > +{
> > +	return in_be16(host->ioaddr + (reg ^ 0x2));
> > +}
> > +
> > +u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg)
> > +{
> > +	return in_8(host->ioaddr + (reg ^ 0x3));
> > +}
> > +
> > +void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg)
> > +{
> > +	out_be32(host->ioaddr + reg, val);
> > +}
> > +
> > +void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
> > +{
> > +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> > +	int base = reg & ~0x3;
> > +	int shift = (reg & 0x2) * 8;
> > +
> > +	switch (reg) {
> > +	case SDHCI_TRANSFER_MODE:
> > +		/*
> > +		 * Postpone this write, we must do it together with a
> > +		 * command write that is down below.
> > +		 */
> > +		pltfm_host->xfer_mode_shadow = val;
> > +		return;
> > +	case SDHCI_COMMAND:
> > +		sdhci_be32bs_writel(host, val << 16 | pltfm_host->xfer_mode_shadow,
> > +				    SDHCI_TRANSFER_MODE);
> > +		return;
> > +	}
> > +	clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift);
> > +}
> > +
> > +void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
> > +{
> > +	int base = reg & ~0x3;
> > +	int shift = (reg & 0x3) * 8;
> > +
> > +	clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
> > +}
> > +#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
> 
> I noticed you're very careful wrt copyright/authorship notices,
> except for this case. How about retaining copyright stuff when
> you merge these two files?
> 
Obviously, need to be more careful.  Will add.  Thanks.

-- 
Regards,
Shawn

^ permalink raw reply

* Re: [PATCH 4/4] powerpc/mpic: add the mpic global timer support
From: Kumar Gala @ 2011-05-06  1:07 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <20110324214355.GC9524@schlenkerla.am.freescale.net>


On Mar 24, 2011, at 4:43 PM, Scott Wood wrote:

> Add support for MPIC timers as requestable interrupt sources.
>=20
> Based on http://patchwork.ozlabs.org/patch/20941/ by Dave Liu.
>=20
> Signed-off-by: Dave Liu <daveliu@freescale.com>
> Signed-off-by: Scott Wood <scottwood@freescale.com>
> ---
> arch/powerpc/include/asm/mpic.h |    3 +-
> arch/powerpc/sysdev/mpic.c      |   92 =
++++++++++++++++++++++++++++++++++++---
> 2 files changed, 88 insertions(+), 7 deletions(-)

Ben,

Did you plan on review and pull this in or expect me to?

- k


>=20
> diff --git a/arch/powerpc/include/asm/mpic.h =
b/arch/powerpc/include/asm/mpic.h
> index 25a0cb3..664bee6 100644
> --- a/arch/powerpc/include/asm/mpic.h
> +++ b/arch/powerpc/include/asm/mpic.h
> @@ -263,6 +263,7 @@ struct mpic
> #ifdef CONFIG_SMP
> 	struct irq_chip		hc_ipi;
> #endif
> +	struct irq_chip		hc_tm;
> 	const char		*name;
> 	/* Flags */
> 	unsigned int		flags;
> @@ -281,7 +282,7 @@ struct mpic
>=20
> 	/* vector numbers used for internal sources (ipi/timers) */
> 	unsigned int		ipi_vecs[4];
> -	unsigned int		timer_vecs[4];
> +	unsigned int		timer_vecs[8];
>=20
> 	/* Spurious vector to program into unused sources */
> 	unsigned int		spurious_vec;
> diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
> index 69f96ec..c173e67 100644
> --- a/arch/powerpc/sysdev/mpic.c
> +++ b/arch/powerpc/sysdev/mpic.c
> @@ -219,6 +219,28 @@ static inline void _mpic_ipi_write(struct mpic =
*mpic, unsigned int ipi, u32 valu
> 	_mpic_write(mpic->reg_type, &mpic->gregs, offset, value);
> }
>=20
> +static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm)
> +{
> +	unsigned int offset =3D MPIC_INFO(TIMER_VECTOR_PRI) +
> +			      ((tm & 3) * MPIC_INFO(TIMER_STRIDE));
> +
> +	if (tm >=3D 4)
> +		offset +=3D 0x1000 / 4;
> +
> +	return _mpic_read(mpic->reg_type, &mpic->tmregs, offset);
> +}
> +
> +static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, =
u32 value)
> +{
> +	unsigned int offset =3D MPIC_INFO(TIMER_VECTOR_PRI) +
> +			      ((tm & 3) * MPIC_INFO(TIMER_STRIDE));
> +
> +	if (tm >=3D 4)
> +		offset +=3D 0x1000 / 4;
> +
> +	_mpic_write(mpic->reg_type, &mpic->tmregs, offset, value);
> +}
> +
> static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
> {
> 	unsigned int cpu =3D mpic_processor_id(mpic);
> @@ -269,6 +291,8 @@ static inline void _mpic_irq_write(struct mpic =
*mpic, unsigned int src_no,
> #define mpic_write(b,r,v)	_mpic_write(mpic->reg_type,&(b),(r),(v))
> #define mpic_ipi_read(i)	_mpic_ipi_read(mpic,(i))
> #define mpic_ipi_write(i,v)	_mpic_ipi_write(mpic,(i),(v))
> +#define mpic_tm_read(i)		_mpic_tm_read(mpic,(i))
> +#define mpic_tm_write(i,v)	_mpic_tm_write(mpic,(i),(v))
> #define mpic_cpu_read(i)	_mpic_cpu_read(mpic,(i))
> #define mpic_cpu_write(i,v)	_mpic_cpu_write(mpic,(i),(v))
> #define mpic_irq_read(s,r)	_mpic_irq_read(mpic,(s),(r))
> @@ -628,6 +652,13 @@ static unsigned int mpic_is_ipi(struct mpic =
*mpic, unsigned int irq)
> 	return (src >=3D mpic->ipi_vecs[0] && src <=3D =
mpic->ipi_vecs[3]);
> }
>=20
> +/* Determine if the linux irq is a timer */
> +static unsigned int mpic_is_tm(struct mpic *mpic, unsigned int irq)
> +{
> +	unsigned int src =3D mpic_irq_to_hw(irq);
> +
> +	return (src >=3D mpic->timer_vecs[0] && src <=3D =
mpic->timer_vecs[7]);
> +}
>=20
> /* Convert a cpu mask from logical to physical cpu numbers. */
> static inline u32 mpic_physmask(u32 cpumask)
> @@ -814,6 +845,25 @@ static void mpic_end_ipi(struct irq_data *d)
>=20
> #endif /* CONFIG_SMP */
>=20
> +static void mpic_unmask_tm(struct irq_data *d)
> +{
> +	struct mpic *mpic =3D mpic_from_irq_data(d);
> +	unsigned int src =3D mpic_irq_to_hw(d->irq) - =
mpic->timer_vecs[0];
> +
> +	DBG("%s: enable_tm: %d (tm %d)\n", mpic->name, irq, src);
> +	mpic_tm_write(src, mpic_tm_read(src) & ~MPIC_VECPRI_MASK);
> +	mpic_tm_read(src);
> +}
> +
> +static void mpic_mask_tm(struct irq_data *d)
> +{
> +	struct mpic *mpic =3D mpic_from_irq_data(d);
> +	unsigned int src =3D mpic_irq_to_hw(d->irq) - =
mpic->timer_vecs[0];
> +
> +	mpic_tm_write(src, mpic_tm_read(src) | MPIC_VECPRI_MASK);
> +	mpic_tm_read(src);
> +}
> +
> int mpic_set_affinity(struct irq_data *d, const struct cpumask =
*cpumask,
> 		      bool force)
> {
> @@ -948,6 +998,12 @@ static struct irq_chip mpic_ipi_chip =3D {
> };
> #endif /* CONFIG_SMP */
>=20
> +static struct irq_chip mpic_tm_chip =3D {
> +	.irq_mask	=3D mpic_mask_tm,
> +	.irq_unmask	=3D mpic_unmask_tm,
> +	.irq_eoi	=3D mpic_end_irq,
> +};
> +
> #ifdef CONFIG_MPIC_U3_HT_IRQS
> static struct irq_chip mpic_irq_ht_chip =3D {
> 	.irq_startup	=3D mpic_startup_ht_irq,
> @@ -991,6 +1047,16 @@ static int mpic_host_map(struct irq_host *h, =
unsigned int virq,
> 	}
> #endif /* CONFIG_SMP */
>=20
> +	if (hw >=3D mpic->timer_vecs[0] && hw <=3D mpic->timer_vecs[7]) =
{
> +		WARN_ON(!(mpic->flags & MPIC_PRIMARY));
> +
> +		DBG("mpic: mapping as timer\n");
> +		set_irq_chip_data(virq, mpic);
> +		set_irq_chip_and_handler(virq, &mpic->hc_tm,
> +					 handle_fasteoi_irq);
> +		return 0;
> +	}
> +
> 	if (hw >=3D mpic->irq_count)
> 		return -EINVAL;
>=20
> @@ -1147,6 +1213,9 @@ struct mpic * __init mpic_alloc(struct =
device_node *node,
> 	mpic->hc_ipi.name =3D name;
> #endif /* CONFIG_SMP */
>=20
> +	mpic->hc_tm =3D mpic_tm_chip;
> +	mpic->hc_tm.name =3D name;
> +
> 	mpic->flags =3D flags;
> 	mpic->isu_size =3D isu_size;
> 	mpic->irq_count =3D irq_count;
> @@ -1157,10 +1226,14 @@ struct mpic * __init mpic_alloc(struct =
device_node *node,
> 	else
> 		intvec_top =3D 255;
>=20
> -	mpic->timer_vecs[0] =3D intvec_top - 8;
> -	mpic->timer_vecs[1] =3D intvec_top - 7;
> -	mpic->timer_vecs[2] =3D intvec_top - 6;
> -	mpic->timer_vecs[3] =3D intvec_top - 5;
> +	mpic->timer_vecs[0] =3D intvec_top - 12;
> +	mpic->timer_vecs[1] =3D intvec_top - 11;
> +	mpic->timer_vecs[2] =3D intvec_top - 10;
> +	mpic->timer_vecs[3] =3D intvec_top - 9;
> +	mpic->timer_vecs[4] =3D intvec_top - 8;
> +	mpic->timer_vecs[5] =3D intvec_top - 7;
> +	mpic->timer_vecs[6] =3D intvec_top - 6;
> +	mpic->timer_vecs[7] =3D intvec_top - 5;
> 	mpic->ipi_vecs[0]   =3D intvec_top - 4;
> 	mpic->ipi_vecs[1]   =3D intvec_top - 3;
> 	mpic->ipi_vecs[2]   =3D intvec_top - 2;
> @@ -1363,15 +1436,17 @@ void __init mpic_init(struct mpic *mpic)
> 	/* Set current processor priority to max */
> 	mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
>=20
> -	/* Initialize timers: just disable them all */
> +	/* Initialize timers to our reserved vectors and mask them for =
now */
> 	for (i =3D 0; i < 4; i++) {
> 		mpic_write(mpic->tmregs,
> 			   i * MPIC_INFO(TIMER_STRIDE) +
> -			   MPIC_INFO(TIMER_DESTINATION), 0);
> +			   MPIC_INFO(TIMER_DESTINATION),
> +			   1 << hard_smp_processor_id());
> 		mpic_write(mpic->tmregs,
> 			   i * MPIC_INFO(TIMER_STRIDE) +
> 			   MPIC_INFO(TIMER_VECTOR_PRI),
> 			   MPIC_VECPRI_MASK |
> +			   (9 << MPIC_VECPRI_PRIORITY_SHIFT) |
> 			   (mpic->timer_vecs[0] + i));
> 	}
>=20
> @@ -1480,6 +1555,11 @@ void mpic_irq_set_priority(unsigned int irq, =
unsigned int pri)
> 			~MPIC_VECPRI_PRIORITY_MASK;
> 		mpic_ipi_write(src - mpic->ipi_vecs[0],
> 			       reg | (pri << =
MPIC_VECPRI_PRIORITY_SHIFT));
> +	} else if (mpic_is_tm(mpic, irq)) {
> +		reg =3D mpic_tm_read(src - mpic->timer_vecs[0]) &
> +			~MPIC_VECPRI_PRIORITY_MASK;
> +		mpic_tm_write(src - mpic->timer_vecs[0],
> +			      reg | (pri << =
MPIC_VECPRI_PRIORITY_SHIFT));
> 	} else {
> 		reg =3D mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI))
> 			& ~MPIC_VECPRI_PRIORITY_MASK;
> --=20
> 1.7.1

^ permalink raw reply

* Re: [PATCH 3/4] powerpc/mpic: parse 4-cell intspec types other than zero
From: Kumar Gala @ 2011-05-06  1:07 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <20110324214354.GB9524@schlenkerla.am.freescale.net>


On Mar 24, 2011, at 4:43 PM, Scott Wood wrote:

> Signed-off-by: Scott Wood <scottwood@freescale.com>
> ---
> arch/powerpc/include/asm/mpic.h |    2 ++
> arch/powerpc/sysdev/mpic.c      |   37 =
++++++++++++++++++++++++++++++++++++-
> 2 files changed, 38 insertions(+), 1 deletions(-)

Ben,

Did you plan on review and pull this in or expect me to?

- k

>=20
> diff --git a/arch/powerpc/include/asm/mpic.h =
b/arch/powerpc/include/asm/mpic.h
> index 7005ee0..25a0cb3 100644
> --- a/arch/powerpc/include/asm/mpic.h
> +++ b/arch/powerpc/include/asm/mpic.h
> @@ -371,6 +371,8 @@ struct mpic
>  * NOTE: This flag trumps MPIC_WANTS_RESET.
>  */
> #define MPIC_NO_RESET			0x00004000
> +/* Freescale MPIC (compatible includes "fsl,mpic") */
> +#define MPIC_FSL			0x00008000
>=20
> /* MPIC HW modification ID */
> #define MPIC_REGSET_MASK		0xf0000000
> diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
> index 0f7c671..69f96ec 100644
> --- a/arch/powerpc/sysdev/mpic.c
> +++ b/arch/powerpc/sysdev/mpic.c
> @@ -6,6 +6,7 @@
>  *  with various broken implementations of this HW.
>  *
>  *  Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
> + *  Copyright 2010-2011 Freescale Semiconductor, Inc.
>  *
>  *  This file is subject to the terms and conditions of the GNU =
General Public
>  *  License.  See the file COPYING in the main directory of this =
archive
> @@ -1030,6 +1031,7 @@ static int mpic_host_xlate(struct irq_host *h, =
struct device_node *ct,
> 			   irq_hw_number_t *out_hwirq, unsigned int =
*out_flags)
>=20
> {
> +	struct mpic *mpic =3D h->host_data;
> 	static unsigned char map_mpic_senses[4] =3D {
> 		IRQ_TYPE_EDGE_RISING,
> 		IRQ_TYPE_LEVEL_LOW,
> @@ -1038,7 +1040,38 @@ static int mpic_host_xlate(struct irq_host *h, =
struct device_node *ct,
> 	};
>=20
> 	*out_hwirq =3D intspec[0];
> -	if (intsize > 1) {
> +	if (intsize >=3D 4 && (mpic->flags & MPIC_FSL)) {
> +		/*
> +		 * Freescale MPIC with extended intspec:
> +		 * First two cells are as usual.  Third specifies
> +		 * an "interrupt type".  Fourth is type-specific data.
> +		 *
> +		 * See =
Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
> +		 */
> +		switch (intspec[2]) {
> +		case 0:
> +		case 1: /* no EISR/EIMR support for now, treat as shared =
IRQ */
> +			break;
> +		case 2:
> +			if (intspec[0] >=3D ARRAY_SIZE(mpic->ipi_vecs))
> +				return -EINVAL;
> +
> +			*out_hwirq =3D mpic->ipi_vecs[intspec[0]];
> +			break;
> +		case 3:
> +			if (intspec[0] >=3D =
ARRAY_SIZE(mpic->timer_vecs))
> +				return -EINVAL;
> +
> +			*out_hwirq =3D mpic->timer_vecs[intspec[0]];
> +			break;
> +		default:
> +			pr_debug("%s: unknown irq type %u\n",
> +				 __func__, intspec[2]);
> +			return -EINVAL;
> +		}
> +
> +		*out_flags =3D map_mpic_senses[intspec[1] & 3];
> +	} else if (intsize > 1) {
> 		u32 mask =3D 0x3;
>=20
> 		/* Apple invented a new race of encoding on machines =
with
> @@ -1137,6 +1170,8 @@ struct mpic * __init mpic_alloc(struct =
device_node *node,
> 	/* Check for "big-endian" in device-tree */
> 	if (node && of_get_property(node, "big-endian", NULL) !=3D NULL)
> 		mpic->flags |=3D MPIC_BIG_ENDIAN;
> +	if (node && of_device_is_compatible(node, "fsl,mpic"))
> +		mpic->flags |=3D MPIC_FSL;
>=20
> 	/* Look for protected sources */
> 	if (node) {
> --=20
> 1.7.1
>=20

^ permalink raw reply

* Re: [PATCH 3/3] [repost] powerpc/eeh: Display eeh error location for bus and device
From: Benjamin Herrenschmidt @ 2011-05-06  0:50 UTC (permalink / raw)
  To: Richard A Lary; +Cc: antonb, linuxppc-dev
In-Reply-To: <1304642771.2513.487.camel@pasglop>

On Fri, 2011-05-06 at 10:46 +1000, Benjamin Herrenschmidt wrote:
> On Wed, 2011-05-04 at 15:57 -0700, Richard A Lary wrote:
> > From: Richard A Lary <rlary@linux.vnet.ibm.com>
> > 
> >   For adapters which have devices under a PCIe switch/bridge it is informative
> >   to display information for both the PCIe switch/bridge and the device on
> >   which the bus error was detected.
> > 
> >   rebased to powerpc-next
> > 
> > Signed-off-by: Richard A Lary <rlary@linux.vnet.ibm.com>
> > ---
> 
> Not sure what you're doing but it still doesn't apply for me. I think
> the patch is whitespace damaged. IE. Some spaces have been added at
> the beginning of each line. IE. "context" lines (nor patch lines
> that start with - or +) seem to have -two- spaces at the beginning
> of each line for some reason.
> 
> I suspect whatever you're using for email is corrupting patches.

BTW. I've hand applied it this time.

Cheers,
Ben.

> Cheers,
> Ben.
> 
> > ---
> >   arch/powerpc/platforms/pseries/eeh_driver.c |   22 	13 +	9 -	0 !
> >   1 file changed, 13 insertions(+), 9 deletions(-)
> > 
> > Index: b/arch/powerpc/platforms/pseries/eeh_driver.c
> > ===================================================================
> > --- a/arch/powerpc/platforms/pseries/eeh_driver.c
> > +++ b/arch/powerpc/platforms/pseries/eeh_driver.c
> > @@ -328,7 +328,7 @@ struct pci_dn * handle_eeh_events (struc
> >   	struct pci_bus *frozen_bus;
> >   	int rc = 0;
> >   	enum pci_ers_result result = PCI_ERS_RESULT_NONE;
> > -	const char *location, *pci_str, *drv_str;
> > +	const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str;
> > 
> >   	frozen_dn = find_device_pe(event->dn);
> >   	if (!frozen_dn) {
> > @@ -364,13 +364,8 @@ struct pci_dn * handle_eeh_events (struc
> >   	frozen_pdn = PCI_DN(frozen_dn);
> >   	frozen_pdn->eeh_freeze_count++;
> > 
> > -	if (frozen_pdn->pcidev) {
> > -		pci_str = pci_name (frozen_pdn->pcidev);
> > -		drv_str = pcid_name (frozen_pdn->pcidev);
> > -	} else {
> > -		pci_str = eeh_pci_name(event->dev);
> > -		drv_str = pcid_name (event->dev);
> > -	}
> > +	pci_str = eeh_pci_name(event->dev);
> > +	drv_str = pcid_name(event->dev);
> >   	
> >   	if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES)
> >   		goto excess_failures;
> > @@ -378,8 +373,17 @@ struct pci_dn * handle_eeh_events (struc
> >   	printk(KERN_WARNING
> >   	   "EEH: This PCI device has failed %d times in the last hour:\n",
> >   		frozen_pdn->eeh_freeze_count);
> > +
> > +	if (frozen_pdn->pcidev) {
> > +		bus_pci_str = pci_name(frozen_pdn->pcidev);
> > +		bus_drv_str = pcid_name(frozen_pdn->pcidev);
> > +		printk(KERN_WARNING
> > +			"EEH: Bus location=%s driver=%s pci addr=%s\n",
> > +			location, bus_drv_str, bus_pci_str);
> > +	}
> > +
> >   	printk(KERN_WARNING
> > -		"EEH: location=%s driver=%s pci addr=%s\n",
> > +		"EEH: Device location=%s driver=%s pci addr=%s\n",
> >   		location, drv_str, pci_str);
> > 
> >   	/* Walk the various device drivers attached to this slot through
> 

^ permalink raw reply

* Re: [PATCH 3/3] [repost] powerpc/eeh: Display eeh error location for bus and device
From: Benjamin Herrenschmidt @ 2011-05-06  0:46 UTC (permalink / raw)
  To: Richard A Lary; +Cc: antonb, linuxppc-dev
In-Reply-To: <4DC1D9CE.4050104@linux.vnet.ibm.com>

On Wed, 2011-05-04 at 15:57 -0700, Richard A Lary wrote:
> From: Richard A Lary <rlary@linux.vnet.ibm.com>
> 
>   For adapters which have devices under a PCIe switch/bridge it is informative
>   to display information for both the PCIe switch/bridge and the device on
>   which the bus error was detected.
> 
>   rebased to powerpc-next
> 
> Signed-off-by: Richard A Lary <rlary@linux.vnet.ibm.com>
> ---

Not sure what you're doing but it still doesn't apply for me. I think
the patch is whitespace damaged. IE. Some spaces have been added at
the beginning of each line. IE. "context" lines (nor patch lines
that start with - or +) seem to have -two- spaces at the beginning
of each line for some reason.

I suspect whatever you're using for email is corrupting patches.

Cheers,
Ben.

> ---
>   arch/powerpc/platforms/pseries/eeh_driver.c |   22 	13 +	9 -	0 !
>   1 file changed, 13 insertions(+), 9 deletions(-)
> 
> Index: b/arch/powerpc/platforms/pseries/eeh_driver.c
> ===================================================================
> --- a/arch/powerpc/platforms/pseries/eeh_driver.c
> +++ b/arch/powerpc/platforms/pseries/eeh_driver.c
> @@ -328,7 +328,7 @@ struct pci_dn * handle_eeh_events (struc
>   	struct pci_bus *frozen_bus;
>   	int rc = 0;
>   	enum pci_ers_result result = PCI_ERS_RESULT_NONE;
> -	const char *location, *pci_str, *drv_str;
> +	const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str;
> 
>   	frozen_dn = find_device_pe(event->dn);
>   	if (!frozen_dn) {
> @@ -364,13 +364,8 @@ struct pci_dn * handle_eeh_events (struc
>   	frozen_pdn = PCI_DN(frozen_dn);
>   	frozen_pdn->eeh_freeze_count++;
> 
> -	if (frozen_pdn->pcidev) {
> -		pci_str = pci_name (frozen_pdn->pcidev);
> -		drv_str = pcid_name (frozen_pdn->pcidev);
> -	} else {
> -		pci_str = eeh_pci_name(event->dev);
> -		drv_str = pcid_name (event->dev);
> -	}
> +	pci_str = eeh_pci_name(event->dev);
> +	drv_str = pcid_name(event->dev);
>   	
>   	if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES)
>   		goto excess_failures;
> @@ -378,8 +373,17 @@ struct pci_dn * handle_eeh_events (struc
>   	printk(KERN_WARNING
>   	   "EEH: This PCI device has failed %d times in the last hour:\n",
>   		frozen_pdn->eeh_freeze_count);
> +
> +	if (frozen_pdn->pcidev) {
> +		bus_pci_str = pci_name(frozen_pdn->pcidev);
> +		bus_drv_str = pcid_name(frozen_pdn->pcidev);
> +		printk(KERN_WARNING
> +			"EEH: Bus location=%s driver=%s pci addr=%s\n",
> +			location, bus_drv_str, bus_pci_str);
> +	}
> +
>   	printk(KERN_WARNING
> -		"EEH: location=%s driver=%s pci addr=%s\n",
> +		"EEH: Device location=%s driver=%s pci addr=%s\n",
>   		location, drv_str, pci_str);
> 
>   	/* Walk the various device drivers attached to this slot through

^ permalink raw reply

* [PATCH] powerpc, hw_breakpoints: Fix CONFIG_HAVE_HW_BREAKPOINT off-case in ptrace_set_debugreg
From: Frederic Weisbecker @ 2011-05-05 23:53 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: Frederic Weisbecker, LPPC, LKML, Prasad, v2.6.33..

We make use of ptrace_get_breakpoints() / ptrace_put_breakpoints()
to protect ptrace_set_debugreg() even if CONFIG_HAVE_HW_BREAKPOINT
if off. However in this case, these APIs are not implemented.

To fix this, push the protection down inside the relevant ifdef.
Best would be to export the code inside CONFIG_HAVE_HW_BREAKPOINT
into a standalone function to cleanup the ifdefury there and call
the breakpoint ref API inside. But as it is more invasive, this
should be rather made in an -rc1.

Fixes:

arch/powerpc/kernel/ptrace.c:1594: error: implicit declaration of function 'ptrace_get_breakpoints'
make[2]: *** [arch/powerpc/kernel/ptrace.o] Error 1
make[1]: *** [arch/powerpc/kernel] Error 2
make: *** [sub-make] Error 2

Reported-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Prasad <prasad@linux.vnet.ibm.com>
Cc: v2.6.33.. <stable@kernel.org>
---
 arch/powerpc/kernel/ptrace.c |   15 +++++++++++----
 1 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 4edeeb3..a6ae1cf 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -933,12 +933,16 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
 	if (data && !(data & DABR_TRANSLATION))
 		return -EIO;
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
+	if (ptrace_get_breakpoints(task) < 0)
+		return -ESRCH;
+
 	bp = thread->ptrace_bps[0];
 	if ((!data) || !(data & (DABR_DATA_WRITE | DABR_DATA_READ))) {
 		if (bp) {
 			unregister_hw_breakpoint(bp);
 			thread->ptrace_bps[0] = NULL;
 		}
+		ptrace_put_breakpoints(task);
 		return 0;
 	}
 	if (bp) {
@@ -948,9 +952,12 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
 					(DABR_DATA_WRITE | DABR_DATA_READ),
 							&attr.bp_type);
 		ret =  modify_user_hw_breakpoint(bp, &attr);
-		if (ret)
+		if (ret) {
+			ptrace_put_breakpoints(task);
 			return ret;
+		}
 		thread->ptrace_bps[0] = bp;
+		ptrace_put_breakpoints(task);
 		thread->dabr = data;
 		return 0;
 	}
@@ -965,9 +972,12 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
 							ptrace_triggered, task);
 	if (IS_ERR(bp)) {
 		thread->ptrace_bps[0] = NULL;
+		ptrace_put_breakpoints(task);
 		return PTR_ERR(bp);
 	}
 
+	ptrace_put_breakpoints(task);
+
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
 
 	/* Move contents to the DABR register */
@@ -1591,10 +1601,7 @@ long arch_ptrace(struct task_struct *child, long request,
 	}
 
 	case PTRACE_SET_DEBUGREG:
-		if (ptrace_get_breakpoints(child) < 0)
-			return -ESRCH;
 		ret = ptrace_set_debugreg(child, addr, data);
-		ptrace_put_breakpoints(child);
 		break;
 
 #ifdef CONFIG_PPC64
-- 
1.7.3.2

^ permalink raw reply related

* [PATCH 2/2] powerpc/pseries: Add support for IO event interrupts
From: Tseng-Hui (Frank) Lin @ 2011-05-05 22:32 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: tsenglin


From: Tseng-Hui (Frank) Lin <thlin@linux.vnet.ibm.com>

This patch adds support for handling IO Event interrupts which come
through at the /event-sources/ibm,io-events device tree node.

The interrupts come through ibm,io-events device tree node are generated
by the firmware to report IO events. The firmware uses the same interrupt
to report multiple types of events for multiple devices. Each device may
have its own event handler. This patch implements a plateform interrupt
handler that is triggered by the IO event interrupts come through
ibm,io-events device tree node, pull in the IO events from RTAS and call
device event handlers registered in the notifier list.

Device event handlers are expected to use atomic_notifier_chain_register()
and atomic_notifier_chain_unregister() to register/unregister their
event handler in pseries_ioei_notifier_list list with IO event interrupt.
Device event handlers are responsible to identify if the event belongs
to the device event handler. The device event handle should return NOTIFY_OK
after the event is handled if the event belongs to the device event handler,
or NOTIFY_DONE otherwise.

Change log:
- Fixed compilation errors
- Fix comments to be docbook compliant
- Fix some code format

Signed-off-by: Tseng-Hui (Frank) Lin <thlin@us.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 arch/powerpc/include/asm/io_event_irq.h       |   54 ++++++
 arch/powerpc/platforms/pseries/Kconfig        |   18 ++
 arch/powerpc/platforms/pseries/Makefile       |    1 +
 arch/powerpc/platforms/pseries/io_event_irq.c |  231 +++++++++++++++++++++++++
 4 files changed, 304 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/include/asm/io_event_irq.h b/arch/powerpc/include/asm/io_event_irq.h
new file mode 100644
index 0000000..b1a9a1b
--- /dev/null
+++ b/arch/powerpc/include/asm/io_event_irq.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010, 2011 Mark Nelson and Tseng-Hui (Frank) Lin, IBM Corporation
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ASM_POWERPC_IO_EVENT_IRQ_H
+#define _ASM_POWERPC_IO_EVENT_IRQ_H
+
+#include <linux/types.h>
+#include <linux/notifier.h>
+
+#define PSERIES_IOEI_RPC_MAX_LEN 216
+
+#define PSERIES_IOEI_TYPE_ERR_DETECTED		0x01
+#define PSERIES_IOEI_TYPE_ERR_RECOVERED		0x02
+#define PSERIES_IOEI_TYPE_EVENT			0x03
+#define PSERIES_IOEI_TYPE_RPC_PASS_THRU		0x04
+
+#define PSERIES_IOEI_SUBTYPE_NOT_APP		0x00
+#define PSERIES_IOEI_SUBTYPE_REBALANCE_REQ	0x01
+#define PSERIES_IOEI_SUBTYPE_NODE_ONLINE	0x03
+#define PSERIES_IOEI_SUBTYPE_NODE_OFFLINE	0x04
+#define PSERIES_IOEI_SUBTYPE_DUMP_SIZE_CHANGE	0x05
+#define PSERIES_IOEI_SUBTYPE_TORRENT_IRV_UPDATE	0x06
+#define PSERIES_IOEI_SUBTYPE_TORRENT_HFI_CFGED	0x07
+
+#define PSERIES_IOEI_SCOPE_NOT_APP		0x00
+#define PSERIES_IOEI_SCOPE_RIO_HUB		0x36
+#define PSERIES_IOEI_SCOPE_RIO_BRIDGE		0x37
+#define PSERIES_IOEI_SCOPE_PHB			0x38
+#define PSERIES_IOEI_SCOPE_EADS_GLOBAL		0x39
+#define PSERIES_IOEI_SCOPE_EADS_SLOT		0x3A
+#define PSERIES_IOEI_SCOPE_TORRENT_HUB		0x3B
+#define PSERIES_IOEI_SCOPE_SERVICE_PROC		0x51
+
+/* Platform Event Log Format, Version 6, data portition of IO event section */
+struct pseries_io_event {
+	uint8_t event_type;		/* 0x00 IO-Event Type		*/
+	uint8_t rpc_data_len;		/* 0x01 RPC data length		*/
+	uint8_t scope;			/* 0x02 Error/Event Scope	*/
+	uint8_t event_subtype;		/* 0x03 I/O-Event Sub-Type	*/
+	uint32_t drc_index;		/* 0x04 DRC Index		*/
+	uint8_t rpc_data[PSERIES_IOEI_RPC_MAX_LEN];
+					/* 0x08 RPC Data (0-216 bytes,	*/
+					/* padded to 4 bytes alignment)	*/
+};
+
+extern struct atomic_notifier_head pseries_ioei_notifier_list;
+
+#endif /* _ASM_POWERPC_IO_EVENT_IRQ_H */
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index b044922..71af4c5 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -50,6 +50,24 @@ config SCANLOG
 	tristate "Scanlog dump interface"
 	depends on RTAS_PROC && PPC_PSERIES
 
+config IO_EVENT_IRQ
+	bool "IO Event Interrupt support"
+	depends on PPC_PSERIES
+	default y
+	help
+	  Select this option, if you want to enable support for IO Event
+	  interrupts. IO event interrupt is a mechanism provided by RTAS
+	  to return information about hardware error and non-error events
+	  which may need OS attention. RTAS returns events for multiple
+	  event types and scopes. Device drivers can register their handlers
+	  to receive events.
+
+	  This option will only enable the IO event platform code. You
+	  will still need to enable or compile the actual drivers
+	  that use this infrastruture to handle IO event interrupts.
+
+	  Say Y if you are unsure.
+
 config LPARCFG
 	bool "LPAR Configuration Data"
 	depends on PPC_PSERIES || PPC_ISERIES
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 4cfefba..3556e40 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_HCALL_STATS)	+= hvCall_inst.o
 obj-$(CONFIG_PHYP_DUMP)		+= phyp_dump.o
 obj-$(CONFIG_CMM)		+= cmm.o
 obj-$(CONFIG_DTL)		+= dtl.o
+obj-$(CONFIG_IO_EVENT_IRQ)	+= io_event_irq.o
 
 ifeq ($(CONFIG_PPC_PSERIES),y)
 obj-$(CONFIG_SUSPEND)		+= suspend.o
diff --git a/arch/powerpc/platforms/pseries/io_event_irq.c b/arch/powerpc/platforms/pseries/io_event_irq.c
new file mode 100644
index 0000000..c829e60
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/io_event_irq.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2010 2011 Mark Nelson and Tseng-Hui (Frank) Lin, IBM Corporation
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/list.h>
+#include <linux/notifier.h>
+
+#include <asm/machdep.h>
+#include <asm/rtas.h>
+#include <asm/irq.h>
+#include <asm/io_event_irq.h>
+
+#include "pseries.h"
+
+/*
+ * IO event interrupt is a mechanism provided by RTAS to return
+ * information about hardware error and non-error events. Device
+ * drivers can register their event handlers to receive events.
+ * Device drivers are expected to use atomic_notifier_chain_register()
+ * and atomic_notifier_chain_unregister() to register and unregister
+ * their event handlers. Since multiple IO event types and scopes
+ * share an IO event interrupt, the event handlers are called one
+ * by one until the IO event is claimed by one of the handlers.
+ * The event handlers are expected to return NOTIFY_OK if the
+ * event is handled by the event handler or NOTIFY_DONE if the
+ * event does not belong to the handler.
+ *
+ * Usage:
+ *
+ * Notifier function:
+ * #include <asm/io_event_irq.h>
+ * int event_handler(struct notifier_block *nb, unsigned long val, void *data) {
+ * 	p = (struct pseries_io_event_sect_data *) data;
+ * 	if (! is_my_event(p->scope, p->event_type)) return NOTIFY_DONE;
+ * 		:
+ * 		:
+ * 	return NOTIFY_OK;
+ * }
+ * struct notifier_block event_nb = {
+ * 	.notifier_call = event_handler,
+ * }
+ *
+ * Registration:
+ * atomic_notifier_chain_register(&pseries_ioei_notifier_list, &event_nb);
+ *
+ * Unregistration:
+ * atomic_notifier_chain_unregister(&pseries_ioei_notifier_list, &event_nb);
+ */
+
+ATOMIC_NOTIFIER_HEAD(pseries_ioei_notifier_list);
+EXPORT_SYMBOL_GPL(pseries_ioei_notifier_list);
+
+static int ioei_check_exception_token;
+
+/* pSeries event log format */
+
+/* Two bytes ASCII section IDs */
+#define PSERIES_ELOG_SECT_ID_PRIV_HDR		(('P' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_USER_HDR		(('U' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_PRIMARY_SRC	(('P' << 8) | 'S')
+#define PSERIES_ELOG_SECT_ID_EXTENDED_UH	(('E' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_FAILING_MTMS	(('M' << 8) | 'T')
+#define PSERIES_ELOG_SECT_ID_SECONDARY_SRC	(('S' << 8) | 'S')
+#define PSERIES_ELOG_SECT_ID_DUMP_LOCATOR	(('D' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_FW_ERROR		(('S' << 8) | 'W')
+#define PSERIES_ELOG_SECT_ID_IMPACT_PART_ID	(('L' << 8) | 'P')
+#define PSERIES_ELOG_SECT_ID_LOGIC_RESOURCE_ID	(('L' << 8) | 'R')
+#define PSERIES_ELOG_SECT_ID_HMC_ID		(('H' << 8) | 'M')
+#define PSERIES_ELOG_SECT_ID_EPOW		(('E' << 8) | 'P')
+#define PSERIES_ELOG_SECT_ID_IO_EVENT		(('I' << 8) | 'E')
+#define PSERIES_ELOG_SECT_ID_MANUFACT_INFO	(('M' << 8) | 'I')
+#define PSERIES_ELOG_SECT_ID_CALL_HOME		(('C' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_USER_DEF		(('U' << 8) | 'D')
+
+/* Vendor specific Platform Event Log Format, Version 6, section header */
+struct pseries_elog_section {
+	uint16_t id;			/* 0x00 2-byte ASCII section ID	*/
+	uint16_t length;		/* 0x02 Section length in bytes	*/
+	uint8_t version;		/* 0x04 Section version		*/
+	uint8_t subtype;		/* 0x05 Section subtype		*/
+	uint16_t creator_component;	/* 0x06 Creator component ID	*/
+	uint8_t data[];			/* 0x08 Start of section data	*/
+};
+
+static char ioei_rtas_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
+
+/**
+ * Find data portion of a specific section in RTAS extended event log.
+ * @elog: RTAS error/event log.
+ * @sect_id: secsion ID.
+ *
+ * Return:
+ *	pointer to the section data of the specified section
+ *	NULL if not found
+ */
+static struct pseries_elog_section *find_xelog_section(struct rtas_error_log *elog,
+						       uint16_t sect_id)
+{
+	struct rtas_ext_event_log_v6 *xelog =
+		(struct rtas_ext_event_log_v6 *) elog->buffer;
+	struct pseries_elog_section *sect;
+	unsigned char *p, *log_end;
+
+	/* Check that we understand the format */
+	if (elog->extended_log_length < sizeof(struct rtas_ext_event_log_v6) ||
+	    xelog->log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG ||
+	    xelog->company_id != RTAS_V6EXT_COMPANY_ID_IBM)
+		return NULL;
+
+	log_end = elog->buffer + elog->extended_log_length;
+	p = xelog->vendor_log;
+	while (p < log_end) {
+		sect = (struct pseries_elog_section *)p;
+		if (sect->id == sect_id)
+			return sect;
+		p += sect->length;
+	}
+	return NULL;
+}
+
+/**
+ * Find the data portion of an IO Event section from event log.
+ * @elog: RTAS error/event log.
+ *
+ * Return:
+ * 	pointer to a valid IO event section data. NULL if not found.
+ */
+static struct pseries_io_event * ioei_find_event(struct rtas_error_log *elog)
+{
+	struct pseries_elog_section *sect;
+
+	/* We should only ever get called for io-event interrupts, but if
+	 * we do get called for another type then something went wrong so
+	 * make some noise about it.
+	 * RTAS_TYPE_IO only exists in extended event log version 6 or later.
+	 * No need to check event log version.
+	 */
+	if (unlikely(elog->type != RTAS_TYPE_IO)) {
+		printk_once(KERN_WARNING "io_event_irq: Unexpected event type %d",
+			    elog->type);
+		return NULL;
+	}
+
+	sect = find_xelog_section(elog, PSERIES_ELOG_SECT_ID_IO_EVENT);
+	if (unlikely(!sect)) {
+		printk_once(KERN_WARNING "io_event_irq: RTAS extended event "
+			    "log does not contain an IO Event section. "
+			    "Could be a bug in system firmware!\n");
+		return NULL;
+	}
+	return (struct pseries_io_event *) &sect->data;
+}
+
+/*
+ * PAPR:
+ * - check-exception returns the first found error or event and clear that
+ *   error or event so it is reported once.
+ * - Each interrupt returns one event. If a plateform chooses to report
+ *   multiple events through a single interrupt, it must ensure that the
+ *   interrupt remains asserted until check-exception has been used to
+ *   process all out-standing events for that interrupt.
+ *
+ * Implementation notes:
+ * - Events must be processed in the order they are returned. Hence,
+ *   sequential in nature.
+ * - The owner of an event is determined by combinations of scope,
+ *   event type, and sub-type. There is no easy way to pre-sort clients
+ *   by scope or event type alone. For example, Torrent ISR route change
+ *   event is reported with scope 0x00 (Not Applicatable) rather than
+ *   0x3B (Torrent-hub). It is better to let the clients to identify
+ *   who owns the the event.
+ */
+
+static irqreturn_t ioei_interrupt(int irq, void *dev_id)
+{
+	struct pseries_io_event *event;
+	int rtas_rc;
+
+	for (;;) {
+		rtas_rc = rtas_call(ioei_check_exception_token, 6, 1, NULL,
+				    RTAS_VECTOR_EXTERNAL_INTERRUPT,
+				    virq_to_hw(irq),
+				    RTAS_IO_EVENTS, 1 /* Time Critical */,
+				    __pa(ioei_rtas_buf),
+				    RTAS_DATA_BUF_SIZE);
+		if (rtas_rc != 0)
+			break;
+
+		event = ioei_find_event((struct rtas_error_log *)ioei_rtas_buf);
+		if (!event)
+			continue;
+
+		atomic_notifier_call_chain(&pseries_ioei_notifier_list,
+					   0, event);
+	}
+	return IRQ_HANDLED;
+}
+
+static int __init ioei_init(void)
+{
+	struct device_node *np;
+
+	ioei_check_exception_token = rtas_token("check-exception");
+	if (ioei_check_exception_token == RTAS_UNKNOWN_SERVICE) {
+		pr_warning("IO Event IRQ not supported on this system !\n");
+		return -ENODEV;
+	}
+	np = of_find_node_by_path("/event-sources/ibm,io-events");
+	if (np) {
+		request_event_sources_irqs(np, ioei_interrupt, "IO_EVENT");
+		of_node_put(np);
+	} else {
+		pr_err("io_event_irq: No ibm,io-events on system! "
+		       "IO Event interrupt disabled.\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+machine_subsys_initcall(pseries, ioei_init);
+

^ permalink raw reply related

* Re: [RFC][PATCH] powerpc: respect how command line nr_cpus is set
From: Benjamin Herrenschmidt @ 2011-05-05 22:29 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <B122211D-FA1E-4B0D-8399-6EC4F701FCDF@kernel.crashing.org>


> From Documentation/kernel-parameters.txt:
> 
>         nr_cpus=        [SMP] Maximum number of processors that an SMP kernel
>                         could support.  nr_cpus=n : n >= 1 limits the kernel to
>                         supporting 'n' processors. Later in runtime you can not
>                         use hotplug cpu feature to put more cpu back to online.
>                         just like you compile the kernel NR_CPUS=n
> 
> Which makes me think we should have max_cpus be an absolute limit.

Ok, looks like I've been confusing nr_cpus= vs. max_cpus= or something
like that.

I'll have a look at your patch later today.

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH 2/2] powerpc: add support for MPIC message register API
From: Meador Inge @ 2011-05-05 21:41 UTC (permalink / raw)
  To: Scott Wood
  Cc: Wood Scott-B07421, devicetree-discuss@lists.ozlabs.org,
	Hollis Blanchard, Kushwaha Prabhakar-B32579,
	openmcapi-dev@googlegroups.com, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20110503101921.45f31d34@schlenkerla.am.freescale.net>

On 05/03/2011 10:19 AM, Scott Wood wrote:
> In the absence of partitioning, no driver should need a specific one.  With
> partitioning, let the system designer mark those resources as reserved so
> they don't get allocated. :-)

That seem reasonable.  Back to the device tree then.  One option is to bring
back the sister-send property 'mpic-msgr-send-mask', which was discussed some
months back.  For example, consider:

	/* OS 1 */
	mpic_msgr_block0: mpic-msgr-block@41400 {
		compatible = "fsl,mpic-v3.1-msgr";
		reg = <0x41400 0x200>;
		interrupts = <0xb0 2 0xb2 2>;
		mpic-msgr-receive-mask = <0x5>;
		mpic-msgr-send-mask = <0xa>;
	};

	mpic_msgr_block1: mpic-msgr-block@42400 {
		compatible = "fsl,mpic-v3.1-msgr";
		reg = <0x42400 0x200>;
		interrupts = <0xb4 2 0xb6 2>;
		mpic-msgr-receive-mask = <0x5>;
	};

	/* OS 2 */
	mpic_msgr_block0: mpic-msgr-block@41400 {
		compatible = "fsl,mpic-v3.1-msgr";
		reg = <0x41400 0x200>;
		interrupts = <0xb0 2 0xb2 2>;
		mpic-msgr-receive-mask = <0xa>;
		mpic-msgr-send-mask = <0x5>;
	};

	mpic_msgr_block1: mpic-msgr-block@42400 {
		compatible = "fsl,mpic-v3.1-msgr";
		reg = <0x42400 0x200>;
		interrupts = <0xb4 2 0xb6 2>;
		mpic-msgr-send-mask = <0x5>;
	};

In block0 for both OSes, all registers are partitioned and are thus not
available for allocation.  In block1 for both OSes, registers 0 and 2 are
reserved and registers 1 and 3 are available for general allocation.

So any register mentioned in one of 'mpic-msgr-receive-mask' or
'mpic-msgr-send-mask' is out of the running for general allocation.
If neither of the properties appear, then all registers are available
for general allocation.

You could get into trouble with this method with cases like:

	/* OS 1 */
	mpic_msgr_block0: mpic-msgr-block@41400 {
		compatible = "fsl,mpic-v3.1-msgr";
		reg = <0x41400 0x200>;
		interrupts = <0xb0 2 0xb2 2>;
		mpic-msgr-send-mask = <0xa>;
	};

	/* OS 2 */
	mpic_msgr_block0: mpic-msgr-block@41400 {
		compatible = "fsl,mpic-v3.1-msgr";
		reg = <0x41400 0x200>;
		interrupts = <0xb0 2 0xb2 2>;
		mpic-msgr-receive-mask = <0x5>;
	};

Now OS 1 has registers 0 and 2 available for general allocation, which
OS 2 is receiving on.  However, we already have that problem if someone
botches the masks.  So I am not very worried about that.

Clearly this is just one method, but I think tagging what is available from the
device tree is a must.


Thoughts?


-- 
Meador Inge     | meador_inge AT mentor.com
Mentor Embedded | http://www.mentor.com/embedded-software

^ permalink raw reply

* Re: [PATCH 0/1] ppc4xx: Fix PCIe scanning for the 460SX
From: Tirumala Marri @ 2011-05-05 16:44 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Ayman El-Khashab, Paul Mackerras
In-Reply-To: <1304487166.2513.351.camel@pasglop>

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

>
> Also, the patch removes the code for waiting for the link to be up with
> a comment "What DCR has the link status on the 460SX?". Please fix that
> (Tirumala, can you provide the missing information ?)
>

It is not one register. Here is the flow for Gen-1.
1. PECFGn_DLLSTA[3] will be asserted when pci-e link comes up.
2. now progream the UTL buffer configuration registers.
3. SW should assert PEUTLn_PCTL[0] to cause flow control initialization.
This is memory mapped using GPL register REGBH , REBAL and REGMSK
4. Now check for the PEUTLN_PSTA[8] for the flow control init completion.

[-- Attachment #2: Type: text/html, Size: 853 bytes --]

^ permalink raw reply

* [PATCH v2] powerpc: Use the deterministic mode of ar
From: Michal Marek @ 2011-05-05 15:22 UTC (permalink / raw)
  To: linux-kbuild; +Cc: linuxppc-dev, Paul Mackerras, linux-kernel
In-Reply-To: <1302015561-21047-1-git-send-email-mmarek@suse.cz>

Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: linuxppc-dev@lists.ozlabs.org
Signed-off-by: Michal Marek <mmarek@suse.cz>

---

Hi,

this version fixes build with binutils <= 2.19 by first checking if ar(1)
supports the D option. It depends on a previous patch in the kbuild tree,
commit 40df759e (kbuild: Fix build with binutils <= 2.19) in linux-next,
so it will need to go through the kbuild tree. But feedback from the PPC
maintainers would be appreciated.

Thanks
Michal

---
 arch/powerpc/boot/Makefile |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 8917816..f0543f8 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -127,7 +127,7 @@ quiet_cmd_bootas = BOOTAS  $@
       cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
 
 quiet_cmd_bootar = BOOTAR  $@
-      cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $(filter-out FORCE,$^); mv $@.$$$$ $@
+      cmd_bootar = $(CROSS32AR) -cr$(KBUILD_ARFLAGS) $@.$$$$ $(filter-out FORCE,$^); mv $@.$$$$ $@
 
 $(obj-libfdt): $(obj)/%.o: $(srctree)/scripts/dtc/libfdt/%.c FORCE
 	$(call if_changed_dep,bootcc)
-- 
1.7.4.1

^ permalink raw reply related

* Re: [PATCH v2 1/7] mmc: sdhci: make sdhci-pltfm device drivers self registered
From: Anton Vorontsov @ 2011-05-05 14:24 UTC (permalink / raw)
  To: Shawn Guo
  Cc: sameo, Arnd Bergmann, patches, devicetree-discuss, linux-mmc,
	Saeed Bishara, Xiaobo Xie, kernel, Mike Rapoport, Olof Johansson,
	Chris Ball, linuxppc-dev, Albert Herranz, linux-arm-kernel
In-Reply-To: <1304601778-13837-2-git-send-email-shawn.guo@linaro.org>

On Thu, May 05, 2011 at 09:22:52PM +0800, Shawn Guo wrote:
[...]
> +static int __devinit sdhci_cns3xxx_probe(struct platform_device *pdev)
> +{
> +	return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata);
> +}
> +
> +static int __devexit sdhci_cns3xxx_remove(struct platform_device *pdev)
> +{
> +	return sdhci_pltfm_unregister(pdev);
> +}
> +
> +static struct platform_driver sdhci_cns3xxx_driver = {
> +	.driver		= {
> +		.name	= "sdhci-cns3xxx",
> +		.owner	= THIS_MODULE,
> +	},
> +	.probe		= sdhci_cns3xxx_probe,
> +	.remove		= __devexit_p(sdhci_cns3xxx_remove),
> +#ifdef CONFIG_PM
> +	.suspend	= sdhci_pltfm_suspend,
> +	.resume		= sdhci_pltfm_resume,
> +#endif
> +};
> +
> +static int __init sdhci_cns3xxx_init(void)
> +{
> +	return platform_driver_register(&sdhci_cns3xxx_driver);
> +}
> +module_init(sdhci_cns3xxx_init);
> +
> +static void __exit sdhci_cns3xxx_exit(void)
> +{
> +	platform_driver_unregister(&sdhci_cns3xxx_driver);
> +}
> +module_exit(sdhci_cns3xxx_exit);

I don't think I like this duplicate code for each platform sub-
driver. It's repetitive and annoying. :-/

But considering that ARM will be multiplatform soon, we don't
want to have every mach-* stuff in the single sdhci-pltfm.

So... OK. If that compiles, I'm fine with it. :-D

Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>

Thanks!

-- 
Anton Vorontsov
Email: cbouatmailru@gmail.com

^ permalink raw reply

* Re: [PATCH v2 2/7] mmc: sdhci: eliminate sdhci_of_host and sdhci_of_data
From: Anton Vorontsov @ 2011-05-05 14:23 UTC (permalink / raw)
  To: Shawn Guo
  Cc: sameo, Arnd Bergmann, patches, devicetree-discuss, linux-mmc,
	Saeed Bishara, Xiaobo Xie, kernel, Mike Rapoport, Olof Johansson,
	Chris Ball, linuxppc-dev, Albert Herranz, linux-arm-kernel
In-Reply-To: <1304601778-13837-3-git-send-email-shawn.guo@linaro.org>

On Thu, May 05, 2011 at 09:22:53PM +0800, Shawn Guo wrote:
> The patch migrates the use of sdhci_of_host and sdhci_of_data to
> sdhci_pltfm_host and sdhci_pltfm_data, so that the former pair can
> be eliminated.
> 
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> Reviewed-by: Grant Likely <grant.likely@secretlab.ca>

Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>

Thanks!

-- 
Anton Vorontsov
Email: cbouatmailru@gmail.com

^ permalink raw reply

* Re: [PATCH v2 3/7] mmc: sdhci: make sdhci-of device drivers self registered
From: Anton Vorontsov @ 2011-05-05 14:23 UTC (permalink / raw)
  To: Shawn Guo
  Cc: sameo, Arnd Bergmann, patches, devicetree-discuss, linux-mmc,
	Saeed Bishara, Xiaobo Xie, kernel, Mike Rapoport, Olof Johansson,
	Chris Ball, linuxppc-dev, Albert Herranz, linux-arm-kernel
In-Reply-To: <1304601778-13837-4-git-send-email-shawn.guo@linaro.org>

On Thu, May 05, 2011 at 09:22:54PM +0800, Shawn Guo wrote:
[...]
> - * Copyright (c) 2007 Freescale Semiconductor, Inc.
> - * Copyright (c) 2009 MontaVista Software, Inc.
> - *
> - * Authors: Xiaobo Xie <X.Xie@freescale.com>
> - *	    Anton Vorontsov <avorontsov@ru.mvista.com>
[...]
> -#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
> -
> -/*
> - * These accessors are designed for big endian hosts doing I/O to
> - * little endian controllers incorporating a 32-bit hardware byte swapper.
> - */
> -
> -u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg)
> -{
> -	return in_be32(host->ioaddr + reg);
> -}
> -
> -u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg)
> -{
> -	return in_be16(host->ioaddr + (reg ^ 0x2));
> -}
> -
> -u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg)
> -{
> -	return in_8(host->ioaddr + (reg ^ 0x3));
> -}
> -
> -void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg)
> -{
> -	out_be32(host->ioaddr + reg, val);
> -}
> -
> -void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
> -{
> -	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> -	int base = reg & ~0x3;
> -	int shift = (reg & 0x2) * 8;
> -
> -	switch (reg) {
> -	case SDHCI_TRANSFER_MODE:
> -		/*
> -		 * Postpone this write, we must do it together with a
> -		 * command write that is down below.
> -		 */
> -		pltfm_host->xfer_mode_shadow = val;
> -		return;
> -	case SDHCI_COMMAND:
> -		sdhci_be32bs_writel(host, val << 16 | pltfm_host->xfer_mode_shadow,
> -				    SDHCI_TRANSFER_MODE);
> -		return;
> -	}
> -	clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift);
> -}
> -
> -void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
> -{
> -	int base = reg & ~0x3;
> -	int shift = (reg & 0x3) * 8;
> -
> -	clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
> -}
> -#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
[...]
> +#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
> +/*
> + * These accessors are designed for big endian hosts doing I/O to
> + * little endian controllers incorporating a 32-bit hardware byte swapper.
> + */
> +u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg)
> +{
> +	return in_be32(host->ioaddr + reg);
> +}
> +
> +u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg)
> +{
> +	return in_be16(host->ioaddr + (reg ^ 0x2));
> +}
> +
> +u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg)
> +{
> +	return in_8(host->ioaddr + (reg ^ 0x3));
> +}
> +
> +void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg)
> +{
> +	out_be32(host->ioaddr + reg, val);
> +}
> +
> +void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
> +{
> +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> +	int base = reg & ~0x3;
> +	int shift = (reg & 0x2) * 8;
> +
> +	switch (reg) {
> +	case SDHCI_TRANSFER_MODE:
> +		/*
> +		 * Postpone this write, we must do it together with a
> +		 * command write that is down below.
> +		 */
> +		pltfm_host->xfer_mode_shadow = val;
> +		return;
> +	case SDHCI_COMMAND:
> +		sdhci_be32bs_writel(host, val << 16 | pltfm_host->xfer_mode_shadow,
> +				    SDHCI_TRANSFER_MODE);
> +		return;
> +	}
> +	clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift);
> +}
> +
> +void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
> +{
> +	int base = reg & ~0x3;
> +	int shift = (reg & 0x3) * 8;
> +
> +	clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
> +}
> +#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */

I noticed you're very careful wrt copyright/authorship notices,
except for this case. How about retaining copyright stuff when
you merge these two files?

The patch itself looks great though.

Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>

^ permalink raw reply

* Re: [PATCH v2 5/7] mmc: sdhci: consolidate sdhci-of-esdhc and sdhci-esdhc-imx
From: Anton Vorontsov @ 2011-05-05 14:20 UTC (permalink / raw)
  To: Shawn Guo
  Cc: sameo, Arnd Bergmann, patches, devicetree-discuss, linux-mmc,
	Saeed Bishara, Xiaobo Xie, kernel, Mike Rapoport, Olof Johansson,
	Chris Ball, linuxppc-dev, Albert Herranz, linux-arm-kernel
In-Reply-To: <1304601778-13837-6-git-send-email-shawn.guo@linaro.org>

On Thu, May 05, 2011 at 09:22:56PM +0800, Shawn Guo wrote:
> This patch is to consolidate SDHCI driver for Freescale eSDHC
> controller found on both MPCxxx and i.MX platforms.  It merges
> sdhci-of-esdhc.c into sdhci-esdhc.c, so that the same pair of
> .probe/.remove hook works with eSDHC for two platforms.
> 
> As the results, sdhci-of-esdhc.c and sdhci-esdhc.h are removed, and
> header esdhc.h containing the definition of esdhc_platform_data is
> put into the public folder.
> 
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>

I'm not sure if that makes sense to merge these two.
I'd rather vote for renaming sdhci-of-esdhc to sdhci-esdhc-mpc. :-)

-- 
Anton Vorontsov
Email: cbouatmailru@gmail.com

^ permalink raw reply

* Re: [PATCH 0/6] General device tree irq domain infrastructure
From: Sebastian Andrzej Siewior @ 2011-05-05 14:14 UTC (permalink / raw)
  To: Grant Likely
  Cc: Michal Simek, devicetree-discuss, x86, linux-kernel, Ralf Baechle,
	hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev
In-Reply-To: <BANLkTimQ7GsUton3nvJof8YB8k6cnx4rFQ@mail.gmail.com>

Grant Likely wrote:
> Okay, I'll take another hack at it.  Unfortunately I've got a great
> big unmaskable interrupt in the form of UDS next week, but I'll be
> back on it the week after.

And I thought you were a NMI.

> 
> g.

Sebastian

^ permalink raw reply

* Re: [PATCH v2 6/7] mmc: sdhci: merge two sdhci-pltfm.h into one
From: Anton Vorontsov @ 2011-05-05 14:13 UTC (permalink / raw)
  To: Shawn Guo
  Cc: sameo, Arnd Bergmann, patches, devicetree-discuss, linux-mmc,
	Saeed Bishara, Xiaobo Xie, kernel, Mike Rapoport, Olof Johansson,
	Chris Ball, linuxppc-dev, Albert Herranz, linux-arm-kernel
In-Reply-To: <1304601778-13837-7-git-send-email-shawn.guo@linaro.org>

On Thu, May 05, 2011 at 09:22:57PM +0800, Shawn Guo wrote:
> The structure sdhci_pltfm_data is not necessarily to be in a public
> header like include/linux/mmc/sdhci-pltfm.h, so the patch moves it
> into drivers/mmc/host/sdhci-pltfm.h and eliminates the former one.
> 
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> Reviewed-by: Grant Likely <grant.likely@secretlab.ca>
> Reviewed-by: Wolfram Sang <w.sang@pengutronix.de>

Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>

^ permalink raw reply

* Re: [PATCH 0/6] General device tree irq domain infrastructure
From: Grant Likely @ 2011-05-05 14:07 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <alpine.LFD.2.02.1105051026370.3005@ionos>

On Thu, May 5, 2011 at 2:37 AM, Thomas Gleixner <tglx@linutronix.de> wrote:
> On Thu, 5 May 2011, Benjamin Herrenschmidt wrote:
>> > As for the mapping, I agree that the functionality is generally
>> > useful, I'm just not fond of the current implementation. =A0I think it
>> > is more complex than it needs to be and I'm not excited about bring it
>> > over to the other architectures as-is.
>>
>> Nobody cares about the current implementation. What is important is
>> indeed the functionality. The basic thing I think everybody agrees is
>> that you need to extend the irq_desc (or data, whatever tglx prefers)
>> with two bits of information: Some identifier of the domain and some
>> identifier of the interrupt number within that domain.
>
> irq_data because that's what is handed into the callbacks and you
> probably want to have the HW number there.

Okay, I'll take another hack at it.  Unfortunately I've got a great
big unmaskable interrupt in the form of UDS next week, but I'll be
back on it the week after.

g.

^ permalink raw reply

* [PATCH v2 7/7] ARM: mxc: remove esdhc.h and use the public one
From: Shawn Guo @ 2011-05-05 13:22 UTC (permalink / raw)
  To: linux-mmc
  Cc: Chris Ball, sameo, Arnd Bergmann, patches, Shawn Guo,
	devicetree-discuss, Saeed Bishara, Xiaobo Xie, kernel,
	Mike Rapoport, Olof Johansson, Anton Vorontsov, linuxppc-dev,
	Albert Herranz, linux-arm-kernel
In-Reply-To: <1304601778-13837-1-git-send-email-shawn.guo@linaro.org>

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 .../plat-mxc/devices/platform-sdhci-esdhc-imx.c    |    1 -
 arch/arm/plat-mxc/include/mach/devices-common.h    |    2 +-
 2 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/arch/arm/plat-mxc/devices/platform-sdhci-esdhc-imx.c b/arch/arm/plat-mxc/devices/platform-sdhci-esdhc-imx.c
index 6b2940b..b401689 100644
--- a/arch/arm/plat-mxc/devices/platform-sdhci-esdhc-imx.c
+++ b/arch/arm/plat-mxc/devices/platform-sdhci-esdhc-imx.c
@@ -8,7 +8,6 @@
 
 #include <mach/hardware.h>
 #include <mach/devices-common.h>
-#include <mach/esdhc.h>
 
 #define imx_sdhci_esdhc_imx_data_entry_single(soc, _id, hwid) \
 	{								\
diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h
index 8658c9c..c95ab13 100644
--- a/arch/arm/plat-mxc/include/mach/devices-common.h
+++ b/arch/arm/plat-mxc/include/mach/devices-common.h
@@ -243,7 +243,7 @@ struct imx_mxc_w1_data {
 struct platform_device *__init imx_add_mxc_w1(
 		const struct imx_mxc_w1_data *data);
 
-#include <mach/esdhc.h>
+#include <linux/mmc/esdhc.h>
 struct imx_sdhci_esdhc_imx_data {
 	int id;
 	resource_size_t iobase;
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH v2 6/7] mmc: sdhci: merge two sdhci-pltfm.h into one
From: Shawn Guo @ 2011-05-05 13:22 UTC (permalink / raw)
  To: linux-mmc
  Cc: Chris Ball, sameo, Arnd Bergmann, patches, Shawn Guo,
	devicetree-discuss, Saeed Bishara, Xiaobo Xie, kernel,
	Mike Rapoport, Olof Johansson, Anton Vorontsov, linuxppc-dev,
	Albert Herranz, linux-arm-kernel
In-Reply-To: <1304601778-13837-1-git-send-email-shawn.guo@linaro.org>

The structure sdhci_pltfm_data is not necessarily to be in a public
header like include/linux/mmc/sdhci-pltfm.h, so the patch moves it
into drivers/mmc/host/sdhci-pltfm.h and eliminates the former one.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Grant Likely <grant.likely@secretlab.ca>
Reviewed-by: Wolfram Sang <w.sang@pengutronix.de>
---
 drivers/mmc/host/sdhci-cns3xxx.c |    1 -
 drivers/mmc/host/sdhci-esdhc.c   |    1 -
 drivers/mmc/host/sdhci-pltfm.h   |    6 +++++-
 include/linux/mmc/sdhci-pltfm.h  |   29 -----------------------------
 4 files changed, 5 insertions(+), 32 deletions(-)
 delete mode 100644 include/linux/mmc/sdhci-pltfm.h

diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c
index ac4b26f..025d1a5 100644
--- a/drivers/mmc/host/sdhci-cns3xxx.c
+++ b/drivers/mmc/host/sdhci-cns3xxx.c
@@ -15,7 +15,6 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/mmc/host.h>
-#include <linux/mmc/sdhci-pltfm.h>
 #include <mach/cns3xxx.h>
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
diff --git a/drivers/mmc/host/sdhci-esdhc.c b/drivers/mmc/host/sdhci-esdhc.c
index f3b4ff5..f005cb8 100644
--- a/drivers/mmc/host/sdhci-esdhc.c
+++ b/drivers/mmc/host/sdhci-esdhc.c
@@ -22,7 +22,6 @@
 #include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/mmc/host.h>
-#include <linux/mmc/sdhci-pltfm.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/esdhc.h>
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index fe27b83..fd72694 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -14,9 +14,13 @@
 #include <linux/clk.h>
 #include <linux/types.h>
 #include <linux/platform_device.h>
-#include <linux/mmc/sdhci-pltfm.h>
 #include <linux/mmc/sdhci.h>
 
+struct sdhci_pltfm_data {
+	struct sdhci_ops *ops;
+	unsigned int quirks;
+};
+
 struct sdhci_pltfm_host {
 	struct clk *clk;
 	void *priv; /* to handle quirks across io-accessor calls */
diff --git a/include/linux/mmc/sdhci-pltfm.h b/include/linux/mmc/sdhci-pltfm.h
deleted file mode 100644
index f1c2ac3..0000000
--- a/include/linux/mmc/sdhci-pltfm.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Platform data declarations for the sdhci-pltfm driver.
- *
- * Copyright (c) 2010 MontaVista Software, LLC.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#ifndef _SDHCI_PLTFM_H
-#define _SDHCI_PLTFM_H
-
-struct sdhci_ops;
-
-/**
- * struct sdhci_pltfm_data - SDHCI platform-specific information & hooks
- * @ops: optional pointer to the platform-provided SDHCI ops
- * @quirks: optional SDHCI quirks
- */
-struct sdhci_pltfm_data {
-	struct sdhci_ops *ops;
-	unsigned int quirks;
-};
-
-#endif /* _SDHCI_PLTFM_H */
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH v2 5/7] mmc: sdhci: consolidate sdhci-of-esdhc and sdhci-esdhc-imx
From: Shawn Guo @ 2011-05-05 13:22 UTC (permalink / raw)
  To: linux-mmc
  Cc: Chris Ball, sameo, Arnd Bergmann, patches, Shawn Guo,
	devicetree-discuss, Saeed Bishara, Xiaobo Xie, kernel,
	Mike Rapoport, Olof Johansson, Anton Vorontsov, linuxppc-dev,
	Albert Herranz, linux-arm-kernel
In-Reply-To: <1304601778-13837-1-git-send-email-shawn.guo@linaro.org>

This patch is to consolidate SDHCI driver for Freescale eSDHC
controller found on both MPCxxx and i.MX platforms.  It merges
sdhci-of-esdhc.c into sdhci-esdhc.c, so that the same pair of
.probe/.remove hook works with eSDHC for two platforms.

As the results, sdhci-of-esdhc.c and sdhci-esdhc.h are removed, and
header esdhc.h containing the definition of esdhc_platform_data is
put into the public folder.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/mmc/host/Kconfig          |   38 ++++---
 drivers/mmc/host/Makefile         |    3 +-
 drivers/mmc/host/sdhci-esdhc.c    |  244 +++++++++++++++++++++++++++++++++----
 drivers/mmc/host/sdhci-esdhc.h    |   81 ------------
 drivers/mmc/host/sdhci-of-esdhc.c |  142 ---------------------
 include/linux/mmc/esdhc.h         |   27 ++++
 6 files changed, 273 insertions(+), 262 deletions(-)
 delete mode 100644 drivers/mmc/host/sdhci-esdhc.h
 delete mode 100644 drivers/mmc/host/sdhci-of-esdhc.c
 create mode 100644 include/linux/mmc/esdhc.h

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index fdd20ad..e32cb76 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -81,17 +81,6 @@ config MMC_RICOH_MMC
 
 	  If unsure, say Y.
 
-config MMC_SDHCI_OF_ESDHC
-	bool "SDHCI OF support for the Freescale eSDHC controller"
-	depends on MMC_SDHCI
-	depends on PPC_OF
-	select MMC_SDHCI_PLTFM
-	select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
-	help
-	  This selects the Freescale eSDHC controller support.
-
-	  If unsure, say N.
-
 config MMC_SDHCI_OF_HLWD
 	bool "SDHCI OF support for the Nintendo Wii SDHCI controllers"
 	depends on MMC_SDHCI
@@ -122,15 +111,34 @@ config MMC_SDHCI_CNS3XXX
 
 	  If unsure, say N.
 
+config MMC_SDHCI_ESDHC
+	bool
+	depends on MMC_SDHCI
+	select MMC_SDHCI_PLTFM
+	help
+	  This selects SDHCI driver for Freescale eSDHC controller.
+
+config MMC_SDHCI_ESDHC_MPC
+	bool "SDHCI support for the Freescale eSDHC MPC controller"
+	depends on MMC_SDHCI
+	depends on PPC_OF && PPC_CLOCK
+	select MMC_SDHCI_ESDHC
+	select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+	help
+	  This selects the Freescale eSDHC controller support on the
+	  MPC platforms.
+
+	  If unsure, say N.
+
 config MMC_SDHCI_ESDHC_IMX
-	tristate "SDHCI platform support for the Freescale eSDHC i.MX controller"
+	tristate "SDHCI support for the Freescale eSDHC i.MX controller"
 	depends on ARCH_MX25 || ARCH_MX35 || ARCH_MX5
 	depends on MMC_SDHCI
-	select MMC_SDHCI_PLTFM
+	select MMC_SDHCI_ESDHC
 	select MMC_SDHCI_IO_ACCESSORS
 	help
-	  This selects the Freescale eSDHC controller support on the platform
-	  bus, found on platforms like mx35/51.
+	  This selects the Freescale eSDHC controller support on platforms
+          like mx25/mx35/mx5x.
 
 	  If unsure, say N.
 
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 186f0ed..a3f1df8 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -45,10 +45,9 @@ obj-$(CONFIG_MMC_USHC)		+= ushc.o
 
 obj-$(CONFIG_MMC_SDHCI_PLTFM)		+= sdhci-pltfm.o
 obj-$(CONFIG_MMC_SDHCI_CNS3XXX)		+= sdhci-cns3xxx.o
-obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)	+= sdhci-esdhc.o
+obj-$(CONFIG_MMC_SDHCI_ESDHC)		+= sdhci-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_DOVE)		+= sdhci-dove.o
 obj-$(CONFIG_MMC_SDHCI_TEGRA)		+= sdhci-tegra.o
-obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)	+= sdhci-of-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_OF_HLWD)		+= sdhci-of-hlwd.o
 
 ifeq ($(CONFIG_CB710_DEBUG),y)
diff --git a/drivers/mmc/host/sdhci-esdhc.c b/drivers/mmc/host/sdhci-esdhc.c
index 8da57d4..f3b4ff5 100644
--- a/drivers/mmc/host/sdhci-esdhc.c
+++ b/drivers/mmc/host/sdhci-esdhc.c
@@ -1,7 +1,11 @@
 /*
- * Freescale eSDHC i.MX controller driver for the platform bus.
+ * Freescale eSDHC i.MX controller driver for MPCxxx and i.MX.
  *
- * derived from the OF-version.
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *   Author: Xiaobo Xie <X.Xie@freescale.com>
+ *
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ *   Author: Anton Vorontsov <avorontsov@ru.mvista.com>
  *
  * Copyright (c) 2010 Pengutronix e.K.
  *   Author: Wolfram Sang <w.sang@pengutronix.de>
@@ -21,11 +25,40 @@
 #include <linux/mmc/sdhci-pltfm.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sdio.h>
+#include <linux/mmc/esdhc.h>
+#ifdef CONFIG_MMC_SDHCI_ESDHC_IMX
 #include <mach/hardware.h>
-#include <mach/esdhc.h>
+#endif
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
-#include "sdhci-esdhc.h"
+
+/*
+ * Ops and quirks for the Freescale eSDHC controller.
+ */
+
+#define ESDHC_DEFAULT_QUIRKS	(SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
+				SDHCI_QUIRK_NO_BUSY_IRQ | \
+				SDHCI_QUIRK_NONSTANDARD_CLOCK | \
+				SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
+				SDHCI_QUIRK_PIO_NEEDS_DELAY | \
+				SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
+
+#define ESDHC_SYSTEM_CONTROL	0x2c
+#define ESDHC_CLOCK_MASK	0x0000fff0
+#define ESDHC_PREDIV_SHIFT	8
+#define ESDHC_DIVIDER_SHIFT	4
+#define ESDHC_CLOCK_PEREN	0x00000004
+#define ESDHC_CLOCK_HCKEN	0x00000002
+#define ESDHC_CLOCK_IPGEN	0x00000001
+
+/* OF-specific */
+#define ESDHC_DMA_SYSCTL	0x40c
+#define ESDHC_DMA_SNOOP		0x00000040
+
+#define ESDHC_HOST_CONTROL_RES	0x05
+
+/* pltfm-specific */
+#define ESDHC_HOST_CONTROL_LE	0x20
 
 /* VENDOR SPEC register */
 #define SDHCI_VENDOR_SPEC		0xC0
@@ -50,6 +83,117 @@ struct pltfm_imx_data {
 	u32 scratchpad;
 };
 
+static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	int pre_div = 2;
+	int div = 1;
+	u32 temp;
+
+	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+	temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
+		| ESDHC_CLOCK_MASK);
+	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+
+	if (clock == 0)
+		goto out;
+
+	while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
+		pre_div *= 2;
+
+	while (host->max_clk / pre_div / div > clock && div < 16)
+		div++;
+
+	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
+		clock, host->max_clk / pre_div / div);
+
+	pre_div >>= 1;
+	div--;
+
+	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+	temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
+		| (div << ESDHC_DIVIDER_SHIFT)
+		| (pre_div << ESDHC_PREDIV_SHIFT));
+	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+	mdelay(100);
+out:
+	host->clock = clock;
+}
+
+#ifdef CONFIG_MMC_SDHCI_ESDHC_MPC
+static u16 esdhc_readw(struct sdhci_host *host, int reg)
+{
+	u16 ret;
+
+	if (unlikely(reg == SDHCI_HOST_VERSION))
+		ret = in_be16(host->ioaddr + reg);
+	else
+		ret = sdhci_be32bs_readw(host, reg);
+	return ret;
+}
+
+static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
+{
+	if (reg == SDHCI_BLOCK_SIZE) {
+		/*
+		 * Two last DMA bits are reserved, and first one is used for
+		 * non-standard blksz of 4096 bytes that we don't support
+		 * yet. So clear the DMA boundary bits.
+		 */
+		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
+	}
+	sdhci_be32bs_writew(host, val, reg);
+}
+
+static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+	/* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
+	if (reg == SDHCI_HOST_CONTROL)
+		val &= ~ESDHC_HOST_CONTROL_RES;
+	sdhci_be32bs_writeb(host, val, reg);
+}
+
+static int esdhc_of_enable_dma(struct sdhci_host *host)
+{
+	setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
+	return 0;
+}
+
+static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+	return pltfm_host->clock;
+}
+
+static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+	return pltfm_host->clock / 256 / 16;
+}
+
+static struct sdhci_ops sdhci_esdhc_mpc_ops = {
+	.read_l = sdhci_be32bs_readl,
+	.read_w = esdhc_readw,
+	.read_b = sdhci_be32bs_readb,
+	.write_l = sdhci_be32bs_writel,
+	.write_w = esdhc_writew,
+	.write_b = esdhc_writeb,
+	.set_clock = esdhc_set_clock,
+	.enable_dma = esdhc_of_enable_dma,
+	.get_max_clock = esdhc_of_get_max_clock,
+	.get_min_clock = esdhc_of_get_min_clock,
+};
+
+static struct sdhci_pltfm_data sdhci_esdhc_mpc_pdata = {
+	/* card detection could be handled via GPIO */
+	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
+		| SDHCI_QUIRK_NO_CARD_NO_RESET,
+	.ops = &sdhci_esdhc_mpc_ops,
+};
+#endif /* CONFIG_MMC_SDHCI_ESDHC_MPC */
+
+#ifdef CONFIG_MMC_SDHCI_ESDHC_IMX
 static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
 {
 	void __iomem *base = host->ioaddr + (reg & ~0x3);
@@ -191,7 +335,7 @@ static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
 	return clk_get_rate(pltfm_host->clk) / 256 / 16;
 }
 
-static struct sdhci_ops sdhci_esdhc_ops = {
+static struct sdhci_ops sdhci_esdhc_imx_ops = {
 	.read_l = esdhc_readl_le,
 	.read_w = esdhc_readw_le,
 	.write_l = esdhc_writel_le,
@@ -206,8 +350,35 @@ static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
 	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
 			| SDHCI_QUIRK_BROKEN_CARD_DETECTION,
 	/* ADMA has issues. Might be fixable */
-	.ops = &sdhci_esdhc_ops,
+	.ops = &sdhci_esdhc_imx_ops,
+};
+#endif /* CONFIG_MMC_SDHCI_ESDHC_IMX */
+
+#ifdef CONFIG_OF
+#include <linux/of_device.h>
+static const struct of_device_id sdhci_esdhc_dt_ids[] = {
+#ifdef CONFIG_MMC_SDHCI_ESDHC_IMX
+	{ .compatible = "fsl,imx-esdhc", .data = &sdhci_esdhc_imx_pdata },
+#endif
+#ifdef CONFIG_MMC_SDHCI_ESDHC_MPC
+	{ .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc_mpc_pdata },
+	{ .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc_mpc_pdata },
+	{ .compatible = "fsl,esdhc", .data = &sdhci_esdhc_mpc_pdata },
+#endif
+	{ }
 };
+MODULE_DEVICE_TABLE(platform, sdhci_esdhc_dt_ids);
+#else
+#define sdhci_esdhc_dt_ids NULL
+#endif
+
+static const struct platform_device_id sdhci_esdhc_pltfm_ids[] = {
+#ifdef CONFIG_MMC_SDHCI_ESDHC_IMX
+	{ "sdhci-esdhc-imx", (kernel_ulong_t)&sdhci_esdhc_imx_pdata },
+#endif
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, sdhci_esdhc_pltfm_ids);
 
 static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
 {
@@ -227,8 +398,20 @@ static irqreturn_t cd_irq(int irq, void *data)
 	return IRQ_HANDLED;
 };
 
-static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
+#ifndef CONFIG_MMC_SDHCI_ESDHC_IMX
+#define cpu_is_mx25()	(0)
+#define cpu_is_mx35()	(0)
+#define cpu_is_mx51()	(0)
+#define cpu_is_imx()	(0)
+#else
+#define cpu_is_imx()	(1)
+#endif
+
+static int __devinit sdhci_esdhc_probe(struct platform_device *pdev)
 {
+	const struct platform_device_id *platid = platform_get_device_id(pdev);
+	const struct of_device_id *dtid = pdev->dev.of_match;
+	struct sdhci_pltfm_data *pdata;
 	struct sdhci_pltfm_host *pltfm_host;
 	struct sdhci_host *host;
 	struct esdhc_platform_data *boarddata;
@@ -236,12 +419,24 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 	int err;
 	struct pltfm_imx_data *imx_data;
 
-	host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
+	if (platid && platid->driver_data)
+		pdata = (void *)platid->driver_data;
+	else if (dtid && dtid->data)
+		pdata = dtid->data;
+	else
+		pdata = pdev->dev.platform_data;
+
+	host = sdhci_pltfm_init(pdev, pdata);
 	if (IS_ERR(host))
 		return PTR_ERR(host);
 
+	sdhci_get_of_property(pdev);
+
 	pltfm_host = sdhci_priv(host);
 
+	if (!cpu_is_imx())
+		goto add_host;
+
 	imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
 	if (!imx_data)
 		return -ENOMEM;
@@ -263,7 +458,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 		/* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
 		host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
 		/* write_protect can't be routed to controller, use gpio */
-		sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro;
+		pdata->ops->get_ro = esdhc_pltfm_get_ro;
 	}
 
 	if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()))
@@ -302,6 +497,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 		host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
 	}
 
+ add_host:
 	err = sdhci_add_host(host);
 	if (err)
 		goto err_add_host;
@@ -322,7 +518,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 	return err;
 }
 
-static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
+static int __devexit sdhci_esdhc_remove(struct platform_device *pdev)
 {
 	struct sdhci_host *host = platform_get_drvdata(pdev);
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -351,31 +547,35 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static struct platform_driver sdhci_esdhc_imx_driver = {
+static struct platform_driver sdhci_esdhc_driver = {
 	.driver		= {
-		.name	= "sdhci-esdhc-imx",
+		.name	= "sdhci-esdhc",
 		.owner	= THIS_MODULE,
+		.of_match_table = sdhci_esdhc_dt_ids,
 	},
-	.probe		= sdhci_esdhc_imx_probe,
-	.remove		= __devexit_p(sdhci_esdhc_imx_remove),
+	.probe		= sdhci_esdhc_probe,
+	.remove		= __devexit_p(sdhci_esdhc_remove),
+	.id_table	= sdhci_esdhc_pltfm_ids,
 #ifdef CONFIG_PM
 	.suspend	= sdhci_pltfm_suspend,
 	.resume		= sdhci_pltfm_resume,
 #endif
 };
  
-static int __init sdhci_esdhc_imx_init(void)
+static int __init sdhci_esdhc_init(void)
 {
-	return platform_driver_register(&sdhci_esdhc_imx_driver);
+	return platform_driver_register(&sdhci_esdhc_driver);
 }
-module_init(sdhci_esdhc_imx_init);
+module_init(sdhci_esdhc_init);
 
-static void __exit sdhci_esdhc_imx_exit(void)
+static void __exit sdhci_esdhc_exit(void)
 {
-	platform_driver_unregister(&sdhci_esdhc_imx_driver);
+	platform_driver_unregister(&sdhci_esdhc_driver);
 }
-module_exit(sdhci_esdhc_imx_exit);
+module_exit(sdhci_esdhc_exit);
 
-MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
-MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("SDHCI driver for Freescale eSDHC");
+MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, "
+	      "Anton Vorontsov <avorontsov@ru.mvista.com>, "
+	      "Wolfram Sang <w.sang@pengutronix.de>");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
deleted file mode 100644
index c3b08f1..0000000
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Freescale eSDHC controller driver generics for OF and pltfm.
- *
- * Copyright (c) 2007 Freescale Semiconductor, Inc.
- * Copyright (c) 2009 MontaVista Software, Inc.
- * Copyright (c) 2010 Pengutronix e.K.
- *   Author: Wolfram Sang <w.sang@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
- */
-
-#ifndef _DRIVERS_MMC_SDHCI_ESDHC_H
-#define _DRIVERS_MMC_SDHCI_ESDHC_H
-
-/*
- * Ops and quirks for the Freescale eSDHC controller.
- */
-
-#define ESDHC_DEFAULT_QUIRKS	(SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
-				SDHCI_QUIRK_NO_BUSY_IRQ | \
-				SDHCI_QUIRK_NONSTANDARD_CLOCK | \
-				SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
-				SDHCI_QUIRK_PIO_NEEDS_DELAY | \
-				SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
-
-#define ESDHC_SYSTEM_CONTROL	0x2c
-#define ESDHC_CLOCK_MASK	0x0000fff0
-#define ESDHC_PREDIV_SHIFT	8
-#define ESDHC_DIVIDER_SHIFT	4
-#define ESDHC_CLOCK_PEREN	0x00000004
-#define ESDHC_CLOCK_HCKEN	0x00000002
-#define ESDHC_CLOCK_IPGEN	0x00000001
-
-/* pltfm-specific */
-#define ESDHC_HOST_CONTROL_LE	0x20
-
-/* OF-specific */
-#define ESDHC_DMA_SYSCTL	0x40c
-#define ESDHC_DMA_SNOOP		0x00000040
-
-#define ESDHC_HOST_CONTROL_RES	0x05
-
-static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
-{
-	int pre_div = 2;
-	int div = 1;
-	u32 temp;
-
-	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
-	temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
-		| ESDHC_CLOCK_MASK);
-	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
-
-	if (clock == 0)
-		goto out;
-
-	while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
-		pre_div *= 2;
-
-	while (host->max_clk / pre_div / div > clock && div < 16)
-		div++;
-
-	dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
-		clock, host->max_clk / pre_div / div);
-
-	pre_div >>= 1;
-	div--;
-
-	temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
-	temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
-		| (div << ESDHC_DIVIDER_SHIFT)
-		| (pre_div << ESDHC_PREDIV_SHIFT));
-	sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
-	mdelay(100);
-out:
-	host->clock = clock;
-}
-
-#endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
deleted file mode 100644
index 2db6a45..0000000
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Freescale eSDHC controller driver.
- *
- * Copyright (c) 2007 Freescale Semiconductor, Inc.
- * Copyright (c) 2009 MontaVista Software, Inc.
- *
- * Authors: Xiaobo Xie <X.Xie@freescale.com>
- *	    Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/mmc/host.h>
-#include "sdhci-pltfm.h"
-#include "sdhci.h"
-#include "sdhci-esdhc.h"
-
-static u16 esdhc_readw(struct sdhci_host *host, int reg)
-{
-	u16 ret;
-
-	if (unlikely(reg == SDHCI_HOST_VERSION))
-		ret = in_be16(host->ioaddr + reg);
-	else
-		ret = sdhci_be32bs_readw(host, reg);
-	return ret;
-}
-
-static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
-{
-	if (reg == SDHCI_BLOCK_SIZE) {
-		/*
-		 * Two last DMA bits are reserved, and first one is used for
-		 * non-standard blksz of 4096 bytes that we don't support
-		 * yet. So clear the DMA boundary bits.
-		 */
-		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
-	}
-	sdhci_be32bs_writew(host, val, reg);
-}
-
-static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
-{
-	/* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
-	if (reg == SDHCI_HOST_CONTROL)
-		val &= ~ESDHC_HOST_CONTROL_RES;
-	sdhci_be32bs_writeb(host, val, reg);
-}
-
-static int esdhc_of_enable_dma(struct sdhci_host *host)
-{
-	setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
-	return 0;
-}
-
-static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host)
-{
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-
-	return pltfm_host->clock;
-}
-
-static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
-{
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-
-	return pltfm_host->clock / 256 / 16;
-}
-
-static struct sdhci_ops sdhci_esdhc_ops = {
-	.read_l = sdhci_be32bs_readl,
-	.read_w = esdhc_readw,
-	.read_b = sdhci_be32bs_readb,
-	.write_l = sdhci_be32bs_writel,
-	.write_w = esdhc_writew,
-	.write_b = esdhc_writeb,
-	.set_clock = esdhc_set_clock,
-	.enable_dma = esdhc_of_enable_dma,
-	.get_max_clock = esdhc_of_get_max_clock,
-	.get_min_clock = esdhc_of_get_min_clock,
-};
-
-static struct sdhci_pltfm_data sdhci_esdhc_pdata = {
-	/* card detection could be handled via GPIO */
-	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
-		| SDHCI_QUIRK_NO_CARD_NO_RESET,
-	.ops = &sdhci_esdhc_ops,
-};
-
-static int __devinit sdhci_esdhc_probe(struct platform_device *pdev)
-{
-	return sdhci_pltfm_register(pdev, &sdhci_esdhc_pdata);
-}
-
-static int __devexit sdhci_esdhc_remove(struct platform_device *pdev)
-{
-	return sdhci_pltfm_unregister(pdev);
-}
-
-static const struct of_device_id sdhci_esdhc_of_match[] = {
-	{ .compatible = "fsl,mpc8379-esdhc" },
-	{ .compatible = "fsl,mpc8536-esdhc" },
-	{ .compatible = "fsl,esdhc" },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, sdhci_esdhc_of_match);
-
-static struct platform_driver sdhci_esdhc_driver = {
-	.driver = {
-		.name = "sdhci-esdhc",
-		.owner = THIS_MODULE,
-		.of_match_table = sdhci_esdhc_of_match,
-	},
-	.probe = sdhci_esdhc_probe,
-	.remove = __devexit_p(sdhci_esdhc_remove),
-#ifdef CONFIG_PM
-	.suspend = sdhci_pltfm_suspend,
-	.resume = sdhci_pltfm_resume,
-#endif
-};
-
-static int __init sdhci_esdhc_init(void)
-{
-	return platform_driver_register(&sdhci_esdhc_driver);
-}
-module_init(sdhci_esdhc_init);
-
-static void __exit sdhci_esdhc_exit(void)
-{
-	platform_driver_unregister(&sdhci_esdhc_driver);
-}
-module_exit(sdhci_esdhc_exit);
-
-MODULE_DESCRIPTION("SDHCI OF driver for Freescale MPC eSDHC");
-MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, "
-	      "Anton Vorontsov <avorontsov@ru.mvista.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mmc/esdhc.h b/include/linux/mmc/esdhc.h
new file mode 100644
index 0000000..e0f6598
--- /dev/null
+++ b/include/linux/mmc/esdhc.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2010 Wolfram Sang <w.sang@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#ifndef __LINUX_MMC_ESDHC_H
+#define __LINUX_MMC_ESDHC_H
+
+/**
+ * struct esdhc_platform_data - optional platform data for esdhc
+ *
+ * strongly recommended for i.MX25/35, not needed for other variants
+ *
+ * @wp_gpio:	gpio for write_protect (-EINVAL if unused)
+ * @cd_gpio:	gpio for card_detect interrupt (-EINVAL if unused)
+ */
+
+struct esdhc_platform_data {
+	unsigned int wp_gpio;
+	unsigned int cd_gpio;
+};
+
+#endif /* __LINUX_MMC_ESDHC_H */
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH v2 4/7] sdhci: rename sdhci-esdhc-imx.c to sdhci-esdhc.c
From: Shawn Guo @ 2011-05-05 13:22 UTC (permalink / raw)
  To: linux-mmc
  Cc: Chris Ball, sameo, Arnd Bergmann, patches, Shawn Guo,
	devicetree-discuss, Saeed Bishara, Xiaobo Xie, kernel,
	Mike Rapoport, Olof Johansson, Anton Vorontsov, linuxppc-dev,
	Albert Herranz, linux-arm-kernel
In-Reply-To: <1304601778-13837-1-git-send-email-shawn.guo@linaro.org>

The patch renames the file to prepare for the consolidation
sdhci-of-esdhc and sdhci-esdhc-imx.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/mmc/host/Makefile          |    2 +-
 drivers/mmc/host/sdhci-esdhc-imx.c |  381 ------------------------------------
 drivers/mmc/host/sdhci-esdhc.c     |  381 ++++++++++++++++++++++++++++++++++++
 3 files changed, 382 insertions(+), 382 deletions(-)
 delete mode 100644 drivers/mmc/host/sdhci-esdhc-imx.c
 create mode 100644 drivers/mmc/host/sdhci-esdhc.c

diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 01d38a1..186f0ed 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -45,7 +45,7 @@ obj-$(CONFIG_MMC_USHC)		+= ushc.o
 
 obj-$(CONFIG_MMC_SDHCI_PLTFM)		+= sdhci-pltfm.o
 obj-$(CONFIG_MMC_SDHCI_CNS3XXX)		+= sdhci-cns3xxx.o
-obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)	+= sdhci-esdhc-imx.o
+obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)	+= sdhci-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_DOVE)		+= sdhci-dove.o
 obj-$(CONFIG_MMC_SDHCI_TEGRA)		+= sdhci-tegra.o
 obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)	+= sdhci-of-esdhc.o
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
deleted file mode 100644
index 8da57d4..0000000
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Freescale eSDHC i.MX controller driver for the platform bus.
- *
- * derived from the OF-version.
- *
- * Copyright (c) 2010 Pengutronix e.K.
- *   Author: Wolfram Sang <w.sang@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
- */
-
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/gpio.h>
-#include <linux/slab.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/sdhci-pltfm.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sdio.h>
-#include <mach/hardware.h>
-#include <mach/esdhc.h>
-#include "sdhci.h"
-#include "sdhci-pltfm.h"
-#include "sdhci-esdhc.h"
-
-/* VENDOR SPEC register */
-#define SDHCI_VENDOR_SPEC		0xC0
-#define  SDHCI_VENDOR_SPEC_SDIO_QUIRK	0x00000002
-
-#define ESDHC_FLAG_GPIO_FOR_CD_WP	(1 << 0)
-/*
- * The CMDTYPE of the CMD register (offset 0xE) should be set to
- * "11" when the STOP CMD12 is issued on imx53 to abort one
- * open ended multi-blk IO. Otherwise the TC INT wouldn't
- * be generated.
- * In exact block transfer, the controller doesn't complete the
- * operations automatically as required at the end of the
- * transfer and remains on hold if the abort command is not sent.
- * As a result, the TC flag is not asserted and SW  received timeout
- * exeception. Bit1 of Vendor Spec registor is used to fix it.
- */
-#define ESDHC_FLAG_MULTIBLK_NO_INT	(1 << 1)
-
-struct pltfm_imx_data {
-	int flags;
-	u32 scratchpad;
-};
-
-static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
-{
-	void __iomem *base = host->ioaddr + (reg & ~0x3);
-	u32 shift = (reg & 0x3) * 8;
-
-	writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
-}
-
-static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
-{
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct pltfm_imx_data *imx_data = pltfm_host->priv;
-
-	/* fake CARD_PRESENT flag on mx25/35 */
-	u32 val = readl(host->ioaddr + reg);
-
-	if (unlikely((reg == SDHCI_PRESENT_STATE)
-			&& (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP))) {
-		struct esdhc_platform_data *boarddata =
-				host->mmc->parent->platform_data;
-
-		if (boarddata && gpio_is_valid(boarddata->cd_gpio)
-				&& gpio_get_value(boarddata->cd_gpio))
-			/* no card, if a valid gpio says so... */
-			val &= SDHCI_CARD_PRESENT;
-		else
-			/* ... in all other cases assume card is present */
-			val |= SDHCI_CARD_PRESENT;
-	}
-
-	return val;
-}
-
-static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
-{
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct pltfm_imx_data *imx_data = pltfm_host->priv;
-
-	if (unlikely((reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)
-			&& (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP)))
-		/*
-		 * these interrupts won't work with a custom card_detect gpio
-		 * (only applied to mx25/35)
-		 */
-		val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
-
-	if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
-				&& (reg == SDHCI_INT_STATUS)
-				&& (val & SDHCI_INT_DATA_END))) {
-			u32 v;
-			v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
-			v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK;
-			writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
-	}
-
-	writel(val, host->ioaddr + reg);
-}
-
-static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
-{
-	if (unlikely(reg == SDHCI_HOST_VERSION))
-		reg ^= 2;
-
-	return readw(host->ioaddr + reg);
-}
-
-static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
-{
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct pltfm_imx_data *imx_data = pltfm_host->priv;
-
-	switch (reg) {
-	case SDHCI_TRANSFER_MODE:
-		/*
-		 * Postpone this write, we must do it together with a
-		 * command write that is down below.
-		 */
-		if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
-				&& (host->cmd->opcode == SD_IO_RW_EXTENDED)
-				&& (host->cmd->data->blocks > 1)
-				&& (host->cmd->data->flags & MMC_DATA_READ)) {
-			u32 v;
-			v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
-			v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK;
-			writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
-		}
-		imx_data->scratchpad = val;
-		return;
-	case SDHCI_COMMAND:
-		if ((host->cmd->opcode == MMC_STOP_TRANSMISSION)
-			&& (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
-			val |= SDHCI_CMD_ABORTCMD;
-		writel(val << 16 | imx_data->scratchpad,
-			host->ioaddr + SDHCI_TRANSFER_MODE);
-		return;
-	case SDHCI_BLOCK_SIZE:
-		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
-		break;
-	}
-	esdhc_clrset_le(host, 0xffff, val, reg);
-}
-
-static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
-{
-	u32 new_val;
-
-	switch (reg) {
-	case SDHCI_POWER_CONTROL:
-		/*
-		 * FSL put some DMA bits here
-		 * If your board has a regulator, code should be here
-		 */
-		return;
-	case SDHCI_HOST_CONTROL:
-		/* FSL messed up here, so we can just keep those two */
-		new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS);
-		/* ensure the endianess */
-		new_val |= ESDHC_HOST_CONTROL_LE;
-		/* DMA mode bits are shifted */
-		new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
-
-		esdhc_clrset_le(host, 0xffff, new_val, reg);
-		return;
-	}
-	esdhc_clrset_le(host, 0xff, val, reg);
-}
-
-static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
-{
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-
-	return clk_get_rate(pltfm_host->clk);
-}
-
-static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
-{
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-
-	return clk_get_rate(pltfm_host->clk) / 256 / 16;
-}
-
-static struct sdhci_ops sdhci_esdhc_ops = {
-	.read_l = esdhc_readl_le,
-	.read_w = esdhc_readw_le,
-	.write_l = esdhc_writel_le,
-	.write_w = esdhc_writew_le,
-	.write_b = esdhc_writeb_le,
-	.set_clock = esdhc_set_clock,
-	.get_max_clock = esdhc_pltfm_get_max_clock,
-	.get_min_clock = esdhc_pltfm_get_min_clock,
-};
-
-static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
-	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
-			| SDHCI_QUIRK_BROKEN_CARD_DETECTION,
-	/* ADMA has issues. Might be fixable */
-	.ops = &sdhci_esdhc_ops,
-};
-
-static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
-{
-	struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
-
-	if (boarddata && gpio_is_valid(boarddata->wp_gpio))
-		return gpio_get_value(boarddata->wp_gpio);
-	else
-		return -ENOSYS;
-}
-
-static irqreturn_t cd_irq(int irq, void *data)
-{
-	struct sdhci_host *sdhost = (struct sdhci_host *)data;
-
-	tasklet_schedule(&sdhost->card_tasklet);
-	return IRQ_HANDLED;
-};
-
-static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
-{
-	struct sdhci_pltfm_host *pltfm_host;
-	struct sdhci_host *host;
-	struct esdhc_platform_data *boarddata;
-	struct clk *clk;
-	int err;
-	struct pltfm_imx_data *imx_data;
-
-	host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
-	if (IS_ERR(host))
-		return PTR_ERR(host);
-
-	pltfm_host = sdhci_priv(host);
-
-	imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
-	if (!imx_data)
-		return -ENOMEM;
-	pltfm_host->priv = imx_data;
-
-	clk = clk_get(mmc_dev(host->mmc), NULL);
-	if (IS_ERR(clk)) {
-		dev_err(mmc_dev(host->mmc), "clk err\n");
-		err = PTR_ERR(clk);
-		goto err_clk_get;
-	}
-	clk_enable(clk);
-	pltfm_host->clk = clk;
-
-	if (!cpu_is_mx25())
-		host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
-
-	if (cpu_is_mx25() || cpu_is_mx35()) {
-		/* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
-		host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
-		/* write_protect can't be routed to controller, use gpio */
-		sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro;
-	}
-
-	if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()))
-		imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
-
-	boarddata = host->mmc->parent->platform_data;
-	if (boarddata) {
-		err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
-		if (err) {
-			dev_warn(mmc_dev(host->mmc),
-				"no write-protect pin available!\n");
-			boarddata->wp_gpio = err;
-		}
-
-		err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");
-		if (err) {
-			dev_warn(mmc_dev(host->mmc),
-				"no card-detect pin available!\n");
-			goto no_card_detect_pin;
-		}
-
-		/* i.MX5x has issues to be researched */
-		if (!cpu_is_mx25() && !cpu_is_mx35())
-			goto not_supported;
-
-		err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,
-				 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-				 mmc_hostname(host->mmc), host);
-		if (err) {
-			dev_warn(mmc_dev(host->mmc), "request irq error\n");
-			goto no_card_detect_irq;
-		}
-
-		imx_data->flags |= ESDHC_FLAG_GPIO_FOR_CD_WP;
-		/* Now we have a working card_detect again */
-		host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
-	}
-
-	err = sdhci_add_host(host);
-	if (err)
-		goto err_add_host;
-
-	return 0;
-
- no_card_detect_irq:
-	gpio_free(boarddata->cd_gpio);
- no_card_detect_pin:
-	boarddata->cd_gpio = err;
- not_supported:
-	kfree(imx_data);
- err_add_host:
-	clk_disable(pltfm_host->clk);
-	clk_put(pltfm_host->clk);
- err_clk_get:
-	sdhci_pltfm_free(pdev);
-	return err;
-}
-
-static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
-{
-	struct sdhci_host *host = platform_get_drvdata(pdev);
-	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-	struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
-	struct pltfm_imx_data *imx_data = pltfm_host->priv;
-	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
-
-	sdhci_remove_host(host, dead);
-
-	if (boarddata && gpio_is_valid(boarddata->wp_gpio))
-		gpio_free(boarddata->wp_gpio);
-
-	if (boarddata && gpio_is_valid(boarddata->cd_gpio)) {
-		gpio_free(boarddata->cd_gpio);
-
-		if (!(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION))
-			free_irq(gpio_to_irq(boarddata->cd_gpio), host);
-	}
-
-	clk_disable(pltfm_host->clk);
-	clk_put(pltfm_host->clk);
-	kfree(imx_data);
-
-	sdhci_pltfm_free(pdev);
-
-	return 0;
-}
-
-static struct platform_driver sdhci_esdhc_imx_driver = {
-	.driver		= {
-		.name	= "sdhci-esdhc-imx",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= sdhci_esdhc_imx_probe,
-	.remove		= __devexit_p(sdhci_esdhc_imx_remove),
-#ifdef CONFIG_PM
-	.suspend	= sdhci_pltfm_suspend,
-	.resume		= sdhci_pltfm_resume,
-#endif
-};
- 
-static int __init sdhci_esdhc_imx_init(void)
-{
-	return platform_driver_register(&sdhci_esdhc_imx_driver);
-}
-module_init(sdhci_esdhc_imx_init);
-
-static void __exit sdhci_esdhc_imx_exit(void)
-{
-	platform_driver_unregister(&sdhci_esdhc_imx_driver);
-}
-module_exit(sdhci_esdhc_imx_exit);
-
-MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
-MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-esdhc.c b/drivers/mmc/host/sdhci-esdhc.c
new file mode 100644
index 0000000..8da57d4
--- /dev/null
+++ b/drivers/mmc/host/sdhci-esdhc.c
@@ -0,0 +1,381 @@
+/*
+ * Freescale eSDHC i.MX controller driver for the platform bus.
+ *
+ * derived from the OF-version.
+ *
+ * Copyright (c) 2010 Pengutronix e.K.
+ *   Author: Wolfram Sang <w.sang@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdhci-pltfm.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+#include <mach/hardware.h>
+#include <mach/esdhc.h>
+#include "sdhci.h"
+#include "sdhci-pltfm.h"
+#include "sdhci-esdhc.h"
+
+/* VENDOR SPEC register */
+#define SDHCI_VENDOR_SPEC		0xC0
+#define  SDHCI_VENDOR_SPEC_SDIO_QUIRK	0x00000002
+
+#define ESDHC_FLAG_GPIO_FOR_CD_WP	(1 << 0)
+/*
+ * The CMDTYPE of the CMD register (offset 0xE) should be set to
+ * "11" when the STOP CMD12 is issued on imx53 to abort one
+ * open ended multi-blk IO. Otherwise the TC INT wouldn't
+ * be generated.
+ * In exact block transfer, the controller doesn't complete the
+ * operations automatically as required at the end of the
+ * transfer and remains on hold if the abort command is not sent.
+ * As a result, the TC flag is not asserted and SW  received timeout
+ * exeception. Bit1 of Vendor Spec registor is used to fix it.
+ */
+#define ESDHC_FLAG_MULTIBLK_NO_INT	(1 << 1)
+
+struct pltfm_imx_data {
+	int flags;
+	u32 scratchpad;
+};
+
+static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
+{
+	void __iomem *base = host->ioaddr + (reg & ~0x3);
+	u32 shift = (reg & 0x3) * 8;
+
+	writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
+}
+
+static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = pltfm_host->priv;
+
+	/* fake CARD_PRESENT flag on mx25/35 */
+	u32 val = readl(host->ioaddr + reg);
+
+	if (unlikely((reg == SDHCI_PRESENT_STATE)
+			&& (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP))) {
+		struct esdhc_platform_data *boarddata =
+				host->mmc->parent->platform_data;
+
+		if (boarddata && gpio_is_valid(boarddata->cd_gpio)
+				&& gpio_get_value(boarddata->cd_gpio))
+			/* no card, if a valid gpio says so... */
+			val &= SDHCI_CARD_PRESENT;
+		else
+			/* ... in all other cases assume card is present */
+			val |= SDHCI_CARD_PRESENT;
+	}
+
+	return val;
+}
+
+static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = pltfm_host->priv;
+
+	if (unlikely((reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)
+			&& (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP)))
+		/*
+		 * these interrupts won't work with a custom card_detect gpio
+		 * (only applied to mx25/35)
+		 */
+		val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
+
+	if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
+				&& (reg == SDHCI_INT_STATUS)
+				&& (val & SDHCI_INT_DATA_END))) {
+			u32 v;
+			v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
+			v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK;
+			writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
+	}
+
+	writel(val, host->ioaddr + reg);
+}
+
+static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
+{
+	if (unlikely(reg == SDHCI_HOST_VERSION))
+		reg ^= 2;
+
+	return readw(host->ioaddr + reg);
+}
+
+static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = pltfm_host->priv;
+
+	switch (reg) {
+	case SDHCI_TRANSFER_MODE:
+		/*
+		 * Postpone this write, we must do it together with a
+		 * command write that is down below.
+		 */
+		if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
+				&& (host->cmd->opcode == SD_IO_RW_EXTENDED)
+				&& (host->cmd->data->blocks > 1)
+				&& (host->cmd->data->flags & MMC_DATA_READ)) {
+			u32 v;
+			v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
+			v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK;
+			writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
+		}
+		imx_data->scratchpad = val;
+		return;
+	case SDHCI_COMMAND:
+		if ((host->cmd->opcode == MMC_STOP_TRANSMISSION)
+			&& (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
+			val |= SDHCI_CMD_ABORTCMD;
+		writel(val << 16 | imx_data->scratchpad,
+			host->ioaddr + SDHCI_TRANSFER_MODE);
+		return;
+	case SDHCI_BLOCK_SIZE:
+		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
+		break;
+	}
+	esdhc_clrset_le(host, 0xffff, val, reg);
+}
+
+static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
+{
+	u32 new_val;
+
+	switch (reg) {
+	case SDHCI_POWER_CONTROL:
+		/*
+		 * FSL put some DMA bits here
+		 * If your board has a regulator, code should be here
+		 */
+		return;
+	case SDHCI_HOST_CONTROL:
+		/* FSL messed up here, so we can just keep those two */
+		new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS);
+		/* ensure the endianess */
+		new_val |= ESDHC_HOST_CONTROL_LE;
+		/* DMA mode bits are shifted */
+		new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
+
+		esdhc_clrset_le(host, 0xffff, new_val, reg);
+		return;
+	}
+	esdhc_clrset_le(host, 0xff, val, reg);
+}
+
+static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+	return clk_get_rate(pltfm_host->clk);
+}
+
+static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+	return clk_get_rate(pltfm_host->clk) / 256 / 16;
+}
+
+static struct sdhci_ops sdhci_esdhc_ops = {
+	.read_l = esdhc_readl_le,
+	.read_w = esdhc_readw_le,
+	.write_l = esdhc_writel_le,
+	.write_w = esdhc_writew_le,
+	.write_b = esdhc_writeb_le,
+	.set_clock = esdhc_set_clock,
+	.get_max_clock = esdhc_pltfm_get_max_clock,
+	.get_min_clock = esdhc_pltfm_get_min_clock,
+};
+
+static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
+	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
+			| SDHCI_QUIRK_BROKEN_CARD_DETECTION,
+	/* ADMA has issues. Might be fixable */
+	.ops = &sdhci_esdhc_ops,
+};
+
+static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
+{
+	struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
+
+	if (boarddata && gpio_is_valid(boarddata->wp_gpio))
+		return gpio_get_value(boarddata->wp_gpio);
+	else
+		return -ENOSYS;
+}
+
+static irqreturn_t cd_irq(int irq, void *data)
+{
+	struct sdhci_host *sdhost = (struct sdhci_host *)data;
+
+	tasklet_schedule(&sdhost->card_tasklet);
+	return IRQ_HANDLED;
+};
+
+static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
+{
+	struct sdhci_pltfm_host *pltfm_host;
+	struct sdhci_host *host;
+	struct esdhc_platform_data *boarddata;
+	struct clk *clk;
+	int err;
+	struct pltfm_imx_data *imx_data;
+
+	host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
+	if (IS_ERR(host))
+		return PTR_ERR(host);
+
+	pltfm_host = sdhci_priv(host);
+
+	imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
+	if (!imx_data)
+		return -ENOMEM;
+	pltfm_host->priv = imx_data;
+
+	clk = clk_get(mmc_dev(host->mmc), NULL);
+	if (IS_ERR(clk)) {
+		dev_err(mmc_dev(host->mmc), "clk err\n");
+		err = PTR_ERR(clk);
+		goto err_clk_get;
+	}
+	clk_enable(clk);
+	pltfm_host->clk = clk;
+
+	if (!cpu_is_mx25())
+		host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+
+	if (cpu_is_mx25() || cpu_is_mx35()) {
+		/* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
+		host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
+		/* write_protect can't be routed to controller, use gpio */
+		sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro;
+	}
+
+	if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()))
+		imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
+
+	boarddata = host->mmc->parent->platform_data;
+	if (boarddata) {
+		err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
+		if (err) {
+			dev_warn(mmc_dev(host->mmc),
+				"no write-protect pin available!\n");
+			boarddata->wp_gpio = err;
+		}
+
+		err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");
+		if (err) {
+			dev_warn(mmc_dev(host->mmc),
+				"no card-detect pin available!\n");
+			goto no_card_detect_pin;
+		}
+
+		/* i.MX5x has issues to be researched */
+		if (!cpu_is_mx25() && !cpu_is_mx35())
+			goto not_supported;
+
+		err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,
+				 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+				 mmc_hostname(host->mmc), host);
+		if (err) {
+			dev_warn(mmc_dev(host->mmc), "request irq error\n");
+			goto no_card_detect_irq;
+		}
+
+		imx_data->flags |= ESDHC_FLAG_GPIO_FOR_CD_WP;
+		/* Now we have a working card_detect again */
+		host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+	}
+
+	err = sdhci_add_host(host);
+	if (err)
+		goto err_add_host;
+
+	return 0;
+
+ no_card_detect_irq:
+	gpio_free(boarddata->cd_gpio);
+ no_card_detect_pin:
+	boarddata->cd_gpio = err;
+ not_supported:
+	kfree(imx_data);
+ err_add_host:
+	clk_disable(pltfm_host->clk);
+	clk_put(pltfm_host->clk);
+ err_clk_get:
+	sdhci_pltfm_free(pdev);
+	return err;
+}
+
+static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
+{
+	struct sdhci_host *host = platform_get_drvdata(pdev);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
+	struct pltfm_imx_data *imx_data = pltfm_host->priv;
+	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+
+	sdhci_remove_host(host, dead);
+
+	if (boarddata && gpio_is_valid(boarddata->wp_gpio))
+		gpio_free(boarddata->wp_gpio);
+
+	if (boarddata && gpio_is_valid(boarddata->cd_gpio)) {
+		gpio_free(boarddata->cd_gpio);
+
+		if (!(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION))
+			free_irq(gpio_to_irq(boarddata->cd_gpio), host);
+	}
+
+	clk_disable(pltfm_host->clk);
+	clk_put(pltfm_host->clk);
+	kfree(imx_data);
+
+	sdhci_pltfm_free(pdev);
+
+	return 0;
+}
+
+static struct platform_driver sdhci_esdhc_imx_driver = {
+	.driver		= {
+		.name	= "sdhci-esdhc-imx",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= sdhci_esdhc_imx_probe,
+	.remove		= __devexit_p(sdhci_esdhc_imx_remove),
+#ifdef CONFIG_PM
+	.suspend	= sdhci_pltfm_suspend,
+	.resume		= sdhci_pltfm_resume,
+#endif
+};
+ 
+static int __init sdhci_esdhc_imx_init(void)
+{
+	return platform_driver_register(&sdhci_esdhc_imx_driver);
+}
+module_init(sdhci_esdhc_imx_init);
+
+static void __exit sdhci_esdhc_imx_exit(void)
+{
+	platform_driver_unregister(&sdhci_esdhc_imx_driver);
+}
+module_exit(sdhci_esdhc_imx_exit);
+
+MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
-- 
1.7.4.1

^ permalink raw reply related


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