LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] powerpc: remove "config MPC10X_OPENPIC"
From: Paul Bolle @ 2013-04-08 19:35 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras; +Cc: linuxppc-dev, linux-kernel

The last users of Kconfig symbol MPC10X_OPENPIC were removed in v2.6.27.
Its Kconfig entry can be removed now.

Signed-off-by: Paul Bolle <pebolle@tiscali.nl>
---
Untested.

 arch/powerpc/platforms/embedded6xx/Kconfig | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index 5a8f50a9..302ba43 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -9,7 +9,6 @@ config LINKSTATION
 	select FSL_SOC
 	select PPC_UDBG_16550 if SERIAL_8250
 	select DEFAULT_UIMAGE
-	select MPC10X_OPENPIC
 	select MPC10X_BRIDGE
 	help
 	  Select LINKSTATION if configuring for one of PPC- (MPC8241)
@@ -24,7 +23,6 @@ config STORCENTER
 	select MPIC
 	select FSL_SOC
 	select PPC_UDBG_16550 if SERIAL_8250
-	select MPC10X_OPENPIC
 	select MPC10X_BRIDGE
 	help
 	  Select STORCENTER if configuring for the iomega StorCenter
@@ -84,9 +82,6 @@ config MV64X60
 	select PPC_INDIRECT_PCI
 	select CHECK_CACHE_COHERENCY
 
-config MPC10X_OPENPIC
-	bool
-
 config GAMECUBE_COMMON
 	bool
 
-- 
1.7.11.7

^ permalink raw reply related

* [PATCH v3 1/4] powerpc/mpic: add irq_set_wake support
From: Wang Dongsheng @ 2013-04-09  2:22 UTC (permalink / raw)
  To: scottwood; +Cc: linuxppc-dev, Wang Dongsheng

Add irq_set_wake support. Just add IRQF_NO_SUSPEND to desc->action->flag.
So the wake up interrupt will not be disable in suspend_device_irqs.

Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
---
v3:
* Modify: Change "EINVAL" to "ENXIO" in mpic_irq_set_wake()

v2:
* Add: Check freescale chip in mpic_irq_set_wake().
* Remove: Support mpic_irq_set_wake() in ht_chip.

 arch/powerpc/sysdev/mpic.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 3b2efd4..ae709d2 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -920,6 +920,22 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
 	return IRQ_SET_MASK_OK_NOCOPY;
 }
 
+static int mpic_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+	struct irq_desc *desc = container_of(d, struct irq_desc, irq_data);
+	struct mpic *mpic = mpic_from_irq_data(d);
+
+	if (!(mpic->flags & MPIC_FSL))
+		return -ENXIO;
+
+	if (on)
+		desc->action->flags |= IRQF_NO_SUSPEND;
+	else
+		desc->action->flags &= ~IRQF_NO_SUSPEND;
+
+	return 0;
+}
+
 void mpic_set_vector(unsigned int virq, unsigned int vector)
 {
 	struct mpic *mpic = mpic_from_irq(virq);
@@ -957,6 +973,7 @@ static struct irq_chip mpic_irq_chip = {
 	.irq_unmask	= mpic_unmask_irq,
 	.irq_eoi	= mpic_end_irq,
 	.irq_set_type	= mpic_set_irq_type,
+	.irq_set_wake	= mpic_irq_set_wake,
 };
 
 #ifdef CONFIG_SMP
@@ -971,6 +988,7 @@ static struct irq_chip mpic_tm_chip = {
 	.irq_mask	= mpic_mask_tm,
 	.irq_unmask	= mpic_unmask_tm,
 	.irq_eoi	= mpic_end_irq,
+	.irq_set_wake	= mpic_irq_set_wake,
 };
 
 #ifdef CONFIG_MPIC_U3_HT_IRQS
-- 
1.8.0

^ permalink raw reply related

* [PATCH v3 2/4] powerpc/mpic: add global timer support
From: Wang Dongsheng @ 2013-04-09  2:22 UTC (permalink / raw)
  To: scottwood; +Cc: linuxppc-dev, Wang Dongsheng
In-Reply-To: <1365474152-21524-1-git-send-email-dongsheng.wang@freescale.com>

The MPIC global timer is a hardware timer inside the Freescale PIC complying
with OpenPIC standard. When the specified interval times out, the hardware
timer generates an interrupt. The driver currently is only tested on fsl chip,
but it can potentially support other global timers complying to OpenPIC
standard.

The two independent groups of global timer on fsl chip, group A and group B,
are identical in their functionality, except that they appear at different
locations within the PIC register map. The hardware timer can be cascaded to
create timers larger than the default 31-bit global timers. Timer cascade
fields allow configuration of up to two 63-bit timers. But These two groups
of timers cannot be cascaded together.

It can be used as a wakeup source for low power modes. It also could be used
as periodical timer for protocols, drivers and etc.

Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
v2:
* Modify: Set timer clock frequency in timer_group_get_freq().
* Modify: Change some of the comments. 

 arch/powerpc/include/asm/mpic_timer.h |  46 +++
 arch/powerpc/platforms/Kconfig        |  12 +
 arch/powerpc/sysdev/Makefile          |   1 +
 arch/powerpc/sysdev/mpic_timer.c      | 593 ++++++++++++++++++++++++++++++++++
 4 files changed, 652 insertions(+)
 create mode 100644 arch/powerpc/include/asm/mpic_timer.h
 create mode 100644 arch/powerpc/sysdev/mpic_timer.c

diff --git a/arch/powerpc/include/asm/mpic_timer.h b/arch/powerpc/include/asm/mpic_timer.h
new file mode 100644
index 0000000..0e23cd4
--- /dev/null
+++ b/arch/powerpc/include/asm/mpic_timer.h
@@ -0,0 +1,46 @@
+/*
+ * arch/powerpc/include/asm/mpic_timer.h
+ *
+ * Header file for Mpic Global Timer
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Wang Dongsheng <Dongsheng.Wang@freescale.com>
+ *	   Li Yang <leoli@freescale.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 __MPIC_TIMER__
+#define __MPIC_TIMER__
+
+#include <linux/interrupt.h>
+#include <linux/time.h>
+
+struct mpic_timer {
+	void			*dev;
+	struct cascade_priv	*cascade_handle;
+	unsigned int		num;
+	unsigned int		irq;
+};
+
+#ifdef CONFIG_MPIC_TIMER
+struct mpic_timer *mpic_request_timer(irq_handler_t fn,  void *dev,
+		const struct timeval *time);
+void mpic_start_timer(struct mpic_timer *handle);
+void mpic_stop_timer(struct mpic_timer *handle);
+void mpic_get_remain_time(struct mpic_timer *handle, struct timeval *time);
+void mpic_free_timer(struct mpic_timer *handle);
+#else
+struct mpic_timer *mpic_request_timer(irq_handler_t fn,  void *dev,
+		const struct timeval *time) { return NULL; }
+void mpic_start_timer(struct mpic_timer *handle) { }
+void mpic_stop_timer(struct mpic_timer *handle) { }
+void mpic_get_remain_time(struct mpic_timer *handle, struct timeval *time) { }
+void mpic_free_timer(struct mpic_timer *handle) { }
+#endif
+
+#endif
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 48a920d..c447b3c 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -87,6 +87,18 @@ config MPIC
 	bool
 	default n
 
+config MPIC_TIMER
+	bool "MPIC Global Timer"
+	depends on MPIC && FSL_SOC
+	default n
+	help
+	  The MPIC global timer is a hardware timer inside the
+	  Freescale PIC complying with OpenPIC standard. When the
+	  specified interval times out, the hardware timer generates
+	  an interrupt. The driver currently is only tested on fsl
+	  chip, but it can potentially support other global timers
+	  complying with the OpenPIC standard.
+
 config PPC_EPAPR_HV_PIC
 	bool
 	default n
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index a57600b..ff6184a 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -4,6 +4,7 @@ ccflags-$(CONFIG_PPC64)		:= -mno-minimal-toc
 
 mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
 obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y)
+obj-$(CONFIG_MPIC_TIMER)        += mpic_timer.o
 mpic-msgr-obj-$(CONFIG_MPIC_MSGR)	+= mpic_msgr.o
 obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y) $(mpic-msgr-obj-y)
 obj-$(CONFIG_PPC_EPAPR_HV_PIC)	+= ehv_pic.o
diff --git a/arch/powerpc/sysdev/mpic_timer.c b/arch/powerpc/sysdev/mpic_timer.c
new file mode 100644
index 0000000..c06db92
--- /dev/null
+++ b/arch/powerpc/sysdev/mpic_timer.c
@@ -0,0 +1,593 @@
+/*
+ * MPIC timer driver
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ * Author: Dongsheng Wang <Dongsheng.Wang@freescale.com>
+ *	   Li Yang <leoli@freescale.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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/syscore_ops.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/io.h>
+
+#include <asm/mpic_timer.h>
+
+#define FSL_GLOBAL_TIMER		0x1
+
+/* Clock Ratio
+ * Divide by 64 0x00000300
+ * Divide by 32 0x00000200
+ * Divide by 16 0x00000100
+ * Divide by  8 0x00000000 (Hardware default div)
+ */
+#define MPIC_TIMER_TCR_CLKDIV		0x00000300
+
+#define MPIC_TIMER_TCR_ROVR_OFFSET	24
+
+#define TIMER_STOP			0x80000000
+#define TIMERS_PER_GROUP		4
+#define MAX_TICKS			(~0U >> 1)
+#define MAX_TICKS_CASCADE		(~0U)
+#define TIMER_OFFSET(num)		(1 << (TIMERS_PER_GROUP - 1 - num))
+
+/* tv_usec should be less than ONE_SECOND, otherwise use tv_sec */
+#define ONE_SECOND			1000000
+
+struct timer_regs {
+	u32	gtccr;
+	u32	res0[3];
+	u32	gtbcr;
+	u32	res1[3];
+	u32	gtvpr;
+	u32	res2[3];
+	u32	gtdr;
+	u32	res3[3];
+};
+
+struct cascade_priv {
+	u32 tcr_value;			/* TCR register: CASC & ROVR value */
+	unsigned int cascade_map;	/* cascade map */
+	unsigned int timer_num;		/* cascade control timer */
+};
+
+struct timer_group_priv {
+	struct timer_regs __iomem	*regs;
+	struct mpic_timer		timer[TIMERS_PER_GROUP];
+	struct list_head		node;
+	unsigned int			timerfreq;
+	unsigned int			idle;
+	unsigned int			flags;
+	spinlock_t			lock;
+	void __iomem			*group_tcr;
+};
+
+static struct cascade_priv cascade_timer[] = {
+	/* cascade timer 0 and 1 */
+	{0x1, 0xc, 0x1},
+	/* cascade timer 1 and 2 */
+	{0x2, 0x6, 0x2},
+	/* cascade timer 2 and 3 */
+	{0x4, 0x3, 0x3}
+};
+
+static LIST_HEAD(timer_group_list);
+
+static void convert_ticks_to_time(struct timer_group_priv *priv,
+		const u64 ticks, struct timeval *time)
+{
+	u64 tmp_sec;
+
+	time->tv_sec = (__kernel_time_t)div_u64(ticks, priv->timerfreq);
+	tmp_sec = (u64)time->tv_sec * (u64)priv->timerfreq;
+
+	time->tv_usec = (__kernel_suseconds_t)
+		div_u64((ticks - tmp_sec) * 1000000, priv->timerfreq);
+
+	return;
+}
+
+/* the time set by the user is converted to "ticks" */
+static int convert_time_to_ticks(struct timer_group_priv *priv,
+		const struct timeval *time, u64 *ticks)
+{
+	u64 max_value;		/* prevent u64 overflow */
+	u64 tmp = 0;
+
+	u64 tmp_sec;
+	u64 tmp_ms;
+	u64 tmp_us;
+
+	max_value = div_u64(ULLONG_MAX, priv->timerfreq);
+
+	if (time->tv_sec > max_value ||
+			(time->tv_sec == max_value && time->tv_usec > 0))
+		return -EINVAL;
+
+	tmp_sec = (u64)time->tv_sec * (u64)priv->timerfreq;
+	tmp += tmp_sec;
+
+	tmp_ms = time->tv_usec / 1000;
+	tmp_ms = div_u64((u64)tmp_ms * (u64)priv->timerfreq, 1000);
+	tmp += tmp_ms;
+
+	tmp_us = time->tv_usec % 1000;
+	tmp_us = div_u64((u64)tmp_us * (u64)priv->timerfreq, 1000000);
+	tmp += tmp_us;
+
+	*ticks = tmp;
+
+	return 0;
+}
+
+/* detect whether there is a cascade timer available */
+static struct mpic_timer *detect_idle_cascade_timer(
+					struct timer_group_priv *priv)
+{
+	struct cascade_priv *casc_priv;
+	unsigned int map;
+	unsigned int array_size = ARRAY_SIZE(cascade_timer);
+	unsigned int num;
+	unsigned int i;
+	unsigned long flags;
+
+	casc_priv = cascade_timer;
+	for (i = 0; i < array_size; i++) {
+		spin_lock_irqsave(&priv->lock, flags);
+		map = casc_priv->cascade_map & priv->idle;
+		if (map == casc_priv->cascade_map) {
+			num = casc_priv->timer_num;
+			priv->timer[num].cascade_handle = casc_priv;
+
+			/* set timer busy */
+			priv->idle &= ~casc_priv->cascade_map;
+			spin_unlock_irqrestore(&priv->lock, flags);
+			return &priv->timer[num];
+		}
+		spin_unlock_irqrestore(&priv->lock, flags);
+		casc_priv++;
+	}
+
+	return NULL;
+}
+
+static int set_cascade_timer(struct timer_group_priv *priv, u64 ticks,
+		unsigned int num)
+{
+	struct cascade_priv *casc_priv;
+	u32 tcr;
+	u32 tmp_ticks;
+	u32 rem_ticks;
+
+	/* set group tcr reg for cascade */
+	casc_priv = priv->timer[num].cascade_handle;
+	if (!casc_priv)
+		return -EINVAL;
+
+	tcr = casc_priv->tcr_value |
+		(casc_priv->tcr_value << MPIC_TIMER_TCR_ROVR_OFFSET);
+	setbits32(priv->group_tcr, tcr);
+
+	tmp_ticks = div_u64_rem(ticks, MAX_TICKS_CASCADE, &rem_ticks);
+
+	out_be32(&priv->regs[num].gtccr, 0);
+	out_be32(&priv->regs[num].gtbcr, tmp_ticks | TIMER_STOP);
+
+	out_be32(&priv->regs[num - 1].gtccr, 0);
+	out_be32(&priv->regs[num - 1].gtbcr, rem_ticks);
+
+	return 0;
+}
+
+static struct mpic_timer *get_cascade_timer(struct timer_group_priv *priv,
+					u64 ticks)
+{
+	struct mpic_timer *allocated_timer;
+
+	/* Two cascade timers: Support the maximum time */
+	const u64 max_ticks = (u64)MAX_TICKS * (u64)MAX_TICKS_CASCADE;
+	int ret;
+
+	if (ticks > max_ticks)
+		return NULL;
+
+	/* detect idle timer */
+	allocated_timer = detect_idle_cascade_timer(priv);
+	if (!allocated_timer)
+		return NULL;
+
+	/* set ticks to timer */
+	ret = set_cascade_timer(priv, ticks, allocated_timer->num);
+	if (ret < 0)
+		return NULL;
+
+	return allocated_timer;
+}
+
+static struct mpic_timer *get_timer(const struct timeval *time)
+{
+	struct timer_group_priv *priv;
+	struct mpic_timer *timer;
+
+	u64 ticks;
+	unsigned int num;
+	unsigned int i;
+	unsigned long flags;
+	int ret;
+
+	list_for_each_entry(priv, &timer_group_list, node) {
+		ret = convert_time_to_ticks(priv, time, &ticks);
+		if (ret < 0)
+			return NULL;
+
+		if (ticks > MAX_TICKS) {
+			if (!(priv->flags & FSL_GLOBAL_TIMER))
+				return NULL;
+
+			timer = get_cascade_timer(priv, ticks);
+			if (!timer)
+				continue;
+
+			return timer;
+		}
+
+		for (i = 0; i < TIMERS_PER_GROUP; i++) {
+			/* one timer: Reverse allocation */
+			num = TIMERS_PER_GROUP - 1 - i;
+			spin_lock_irqsave(&priv->lock, flags);
+			if (priv->idle & (1 << i)) {
+				/* set timer busy */
+				priv->idle &= ~(1 << i);
+				/* set ticks & stop timer */
+				out_be32(&priv->regs[num].gtbcr,
+					ticks | TIMER_STOP);
+				out_be32(&priv->regs[num].gtccr, 0);
+				priv->timer[num].cascade_handle = NULL;
+				spin_unlock_irqrestore(&priv->lock, flags);
+				return &priv->timer[num];
+			}
+			spin_unlock_irqrestore(&priv->lock, flags);
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * mpic_start_timer - start hardware timer
+ * @handle: the timer to be started.
+ *
+ * It will do ->fn(->dev) callback from the hardware interrupt at
+ * the ->timeval point in the future.
+ */
+void mpic_start_timer(struct mpic_timer *handle)
+{
+	struct timer_group_priv *priv = container_of(handle,
+			struct timer_group_priv, timer[handle->num]);
+
+	clrbits32(&priv->regs[handle->num].gtbcr, TIMER_STOP);
+}
+EXPORT_SYMBOL(mpic_start_timer);
+
+/**
+ * mpic_stop_timer - stop hardware timer
+ * @handle: the timer to be stoped
+ *
+ * The timer periodically generates an interrupt. Unless user stops the timer.
+ */
+void mpic_stop_timer(struct mpic_timer *handle)
+{
+	struct timer_group_priv *priv = container_of(handle,
+			struct timer_group_priv, timer[handle->num]);
+	struct cascade_priv *casc_priv;
+
+	setbits32(&priv->regs[handle->num].gtbcr, TIMER_STOP);
+
+	casc_priv = priv->timer[handle->num].cascade_handle;
+	if (casc_priv) {
+		out_be32(&priv->regs[handle->num].gtccr, 0);
+		out_be32(&priv->regs[handle->num - 1].gtccr, 0);
+	} else {
+		out_be32(&priv->regs[handle->num].gtccr, 0);
+	}
+}
+EXPORT_SYMBOL(mpic_stop_timer);
+
+/**
+ * mpic_get_remain_time - get timer time
+ * @handle: the timer to be selected.
+ * @time: time for timer
+ *
+ * Query timer remaining time.
+ */
+void mpic_get_remain_time(struct mpic_timer *handle, struct timeval *time)
+{
+	struct timer_group_priv *priv = container_of(handle,
+			struct timer_group_priv, timer[handle->num]);
+	struct cascade_priv *casc_priv;
+
+	u64 ticks;
+	u32 tmp_ticks;
+
+	casc_priv = priv->timer[handle->num].cascade_handle;
+	if (casc_priv) {
+		tmp_ticks = in_be32(&priv->regs[handle->num].gtccr);
+		ticks = ((u64)tmp_ticks & UINT_MAX) * (u64)MAX_TICKS_CASCADE;
+		tmp_ticks = in_be32(&priv->regs[handle->num - 1].gtccr);
+		ticks += tmp_ticks;
+	} else {
+		ticks = in_be32(&priv->regs[handle->num].gtccr);
+	}
+
+	convert_ticks_to_time(priv, ticks, time);
+}
+EXPORT_SYMBOL(mpic_get_remain_time);
+
+/**
+ * mpic_free_timer - free hardware timer
+ * @handle: the timer to be removed.
+ *
+ * Free the timer.
+ *
+ * Note: can not be used in interrupt context.
+ */
+void mpic_free_timer(struct mpic_timer *handle)
+{
+	struct timer_group_priv *priv = container_of(handle,
+			struct timer_group_priv, timer[handle->num]);
+
+	struct cascade_priv *casc_priv;
+	unsigned long flags;
+
+	mpic_stop_timer(handle);
+
+	casc_priv = priv->timer[handle->num].cascade_handle;
+
+	free_irq(priv->timer[handle->num].irq, priv->timer[handle->num].dev);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (casc_priv) {
+		u32 tcr;
+		tcr = casc_priv->tcr_value | (casc_priv->tcr_value <<
+					MPIC_TIMER_TCR_ROVR_OFFSET);
+		clrbits32(priv->group_tcr, tcr);
+		priv->idle |= casc_priv->cascade_map;
+		priv->timer[handle->num].cascade_handle = NULL;
+	} else {
+		priv->idle |= TIMER_OFFSET(handle->num);
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL(mpic_free_timer);
+
+/**
+ * mpic_request_timer - get a hardware timer
+ * @fn: interrupt handler function
+ * @dev: callback function of the data
+ * @time: time for timer
+ *
+ * This executes the "request_irq", returning NULL
+ * else "handle" on success.
+ */
+struct mpic_timer *mpic_request_timer(irq_handler_t fn, void *dev,
+					const struct timeval *time)
+{
+	struct mpic_timer *allocated_timer;
+	int ret;
+
+	if (list_empty(&timer_group_list))
+		return NULL;
+
+	if (!(time->tv_sec + time->tv_usec) ||
+			time->tv_sec < 0 || time->tv_usec < 0)
+		return NULL;
+
+	if (time->tv_usec > ONE_SECOND)
+		return NULL;
+
+	allocated_timer = get_timer(time);
+	if (!allocated_timer)
+		return NULL;
+
+	ret = request_irq(allocated_timer->irq, fn,
+			IRQF_TRIGGER_LOW, "global-timer", dev);
+	if (ret) {
+		mpic_free_timer(allocated_timer);
+		return NULL;
+	}
+
+	allocated_timer->dev = dev;
+
+	return allocated_timer;
+}
+EXPORT_SYMBOL(mpic_request_timer);
+
+static int timer_group_get_freq(struct device_node *np,
+			struct timer_group_priv *priv)
+{
+	u32 div;
+
+	if (priv->flags & FSL_GLOBAL_TIMER) {
+		struct device_node *dn;
+
+		dn = of_find_compatible_node(NULL, NULL, "fsl,mpic");
+		if (dn) {
+			of_property_read_u32(dn, "clock-frequency",
+					&priv->timerfreq);
+			of_node_put(dn);
+		}
+	}
+
+	if (priv->timerfreq <= 0)
+		return -EINVAL;
+
+	if (priv->flags & FSL_GLOBAL_TIMER) {
+		div = (1 << (MPIC_TIMER_TCR_CLKDIV >> 8)) * 8;
+		priv->timerfreq /= div;
+	}
+
+	return 0;
+}
+
+static int timer_group_get_irq(struct device_node *np,
+		struct timer_group_priv *priv)
+{
+	const u32 all_timer[] = { 0, TIMERS_PER_GROUP };
+	const u32 *p;
+	u32 offset;
+	u32 count;
+
+	unsigned int i;
+	unsigned int j;
+	unsigned int irq_index = 0;
+	unsigned int irq;
+	int len;
+
+	p = of_get_property(np, "fsl,available-ranges", &len);
+	if (p && len % (2 * sizeof(u32)) != 0) {
+		pr_err("%s: malformed available-ranges property.\n",
+				np->full_name);
+		return -EINVAL;
+	}
+
+	if (!p) {
+		p = all_timer;
+		len = sizeof(all_timer);
+	}
+
+	len /= 2 * sizeof(u32);
+
+	for (i = 0; i < len; i++) {
+		offset = p[i * 2];
+		count = p[i * 2 + 1];
+		for (j = 0; j < count; j++) {
+			irq = irq_of_parse_and_map(np, irq_index);
+			if (!irq) {
+				pr_err("%s: irq parse and map failed.\n",
+						np->full_name);
+				return -EINVAL;
+			}
+
+			/* Set timer idle */
+			priv->idle |= TIMER_OFFSET((offset + j));
+			priv->timer[offset + j].irq = irq;
+			priv->timer[offset + j].num = offset + j;
+			irq_index++;
+		}
+	}
+
+	return 0;
+}
+
+static void timer_group_init(struct device_node *np)
+{
+	struct timer_group_priv *priv;
+	unsigned int i = 0;
+	int ret;
+
+	priv = kzalloc(sizeof(struct timer_group_priv), GFP_KERNEL);
+	if (!priv) {
+		pr_err("%s: cannot allocate memory for group.\n",
+				np->full_name);
+		return;
+	}
+
+	if (of_device_is_compatible(np, "fsl,mpic-global-timer"))
+		priv->flags |= FSL_GLOBAL_TIMER;
+
+	priv->regs = of_iomap(np, i++);
+	if (!priv->regs) {
+		pr_err("%s: cannot ioremap timer register address.\n",
+				np->full_name);
+		goto out;
+	}
+
+	if (priv->flags & FSL_GLOBAL_TIMER) {
+		priv->group_tcr = of_iomap(np, i++);
+		if (!priv->group_tcr) {
+			pr_err("%s: cannot ioremap tcr address.\n",
+					np->full_name);
+			goto out;
+		}
+	}
+
+	ret = timer_group_get_freq(np, priv);
+	if (ret < 0) {
+		pr_err("%s: cannot get timer frequency.\n", np->full_name);
+		goto out;
+	}
+
+	ret = timer_group_get_irq(np, priv);
+	if (ret < 0) {
+		pr_err("%s: cannot get timer irqs.\n", np->full_name);
+		goto out;
+	}
+
+	spin_lock_init(&priv->lock);
+
+	/* Init FSL timer hardware */
+	if (priv->flags & FSL_GLOBAL_TIMER)
+		setbits32(priv->group_tcr, MPIC_TIMER_TCR_CLKDIV);
+
+	list_add_tail(&priv->node, &timer_group_list);
+
+	return;
+
+out:
+	if (priv->regs)
+		iounmap(priv->regs);
+
+	if (priv->group_tcr)
+		iounmap(priv->group_tcr);
+
+	kfree(priv);
+}
+
+static void mpic_timer_resume(void)
+{
+	struct timer_group_priv *priv;
+
+	list_for_each_entry(priv, &timer_group_list, node) {
+		/* Init FSL timer hardware */
+		if (priv->flags & FSL_GLOBAL_TIMER)
+			setbits32(priv->group_tcr, MPIC_TIMER_TCR_CLKDIV);
+	}
+}
+
+static const struct of_device_id mpic_timer_ids[] = {
+	{ .compatible = "fsl,mpic-global-timer", },
+	{},
+};
+
+static struct syscore_ops mpic_timer_syscore_ops = {
+	.resume = mpic_timer_resume,
+};
+
+static int __init mpic_timer_init(void)
+{
+	struct device_node *np = NULL;
+
+	for_each_matching_node(np, mpic_timer_ids)
+		timer_group_init(np);
+
+	register_syscore_ops(&mpic_timer_syscore_ops);
+
+	if (list_empty(&timer_group_list))
+		return -ENODEV;
+
+	return 0;
+}
+subsys_initcall(mpic_timer_init);
-- 
1.8.0

^ permalink raw reply related

* [PATCH v3 3/4] powerpc/mpic: create mpic subsystem object
From: Wang Dongsheng @ 2013-04-09  2:22 UTC (permalink / raw)
  To: scottwood; +Cc: linuxppc-dev, Wang Dongsheng
In-Reply-To: <1365474152-21524-1-git-send-email-dongsheng.wang@freescale.com>

Register a mpic subsystem at /sys/devices/system/

Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
---
 arch/powerpc/include/asm/mpic.h | 2 ++
 arch/powerpc/sysdev/mpic.c      | 8 ++++++++
 2 files changed, 10 insertions(+)

diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
index c0f9ef9..fa70e9b 100644
--- a/arch/powerpc/include/asm/mpic.h
+++ b/arch/powerpc/include/asm/mpic.h
@@ -339,6 +339,8 @@ struct mpic
 #endif
 };
 
+extern struct bus_type mpic_subsys;
+
 /*
  * MPIC flags (passed to mpic_alloc)
  *
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index ae709d2..58e7661 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -48,6 +48,12 @@
 #define DBG(fmt...)
 #endif
 
+struct bus_type mpic_subsys = {
+	.name = "mpic",
+	.dev_name = "mpic",
+};
+EXPORT_SYMBOL_GPL(mpic_subsys);
+
 static struct mpic *mpics;
 static struct mpic *mpic_primary;
 static DEFINE_RAW_SPINLOCK(mpic_lock);
@@ -1989,6 +1995,8 @@ static struct syscore_ops mpic_syscore_ops = {
 static int mpic_init_sys(void)
 {
 	register_syscore_ops(&mpic_syscore_ops);
+	subsys_system_register(&mpic_subsys, NULL);
+
 	return 0;
 }
 
-- 
1.8.0

^ permalink raw reply related

* [PATCH v3 4/4] powerpc/fsl: add MPIC timer wakeup support
From: Wang Dongsheng @ 2013-04-09  2:22 UTC (permalink / raw)
  To: scottwood; +Cc: linuxppc-dev, Wang Dongsheng, Zhao Chenhui
In-Reply-To: <1365474152-21524-1-git-send-email-dongsheng.wang@freescale.com>

The driver provides a way to wake up the system by the MPIC timer.

For example,
echo 5 > /sys/devices/system/mpic/timer_wakeup
echo standby > /sys/power/state

After 5 seconds the MPIC timer will generate an interrupt to wake up
the system.

Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
v2:
* Remove: Create mpic subsystem.

 arch/powerpc/platforms/Kconfig              |   9 ++
 arch/powerpc/sysdev/Makefile                |   1 +
 arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c | 161 ++++++++++++++++++++++++++++
 3 files changed, 171 insertions(+)
 create mode 100644 arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c

diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index c447b3c..3d934ba 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -99,6 +99,15 @@ config MPIC_TIMER
 	  chip, but it can potentially support other global timers
 	  complying with the OpenPIC standard.
 
+config FSL_MPIC_TIMER_WAKEUP
+	tristate "Freescale MPIC global timer wakeup driver"
+	depends on FSL_SOC &&  MPIC_TIMER && PM
+	default n
+	help
+	  The driver provides a way to wake up the system by MPIC
+	  timer.
+	  e.g. "echo 5 > /sys/devices/system/mpic/timer_wakeup"
+
 config PPC_EPAPR_HV_PIC
 	bool
 	default n
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index ff6184a..e1b8a80 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -5,6 +5,7 @@ ccflags-$(CONFIG_PPC64)		:= -mno-minimal-toc
 mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
 obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y)
 obj-$(CONFIG_MPIC_TIMER)        += mpic_timer.o
+obj-$(CONFIG_FSL_MPIC_TIMER_WAKEUP)	+= fsl_mpic_timer_wakeup.o
 mpic-msgr-obj-$(CONFIG_MPIC_MSGR)	+= mpic_msgr.o
 obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y) $(mpic-msgr-obj-y)
 obj-$(CONFIG_PPC_EPAPR_HV_PIC)	+= ehv_pic.o
diff --git a/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c b/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c
new file mode 100644
index 0000000..1707bf0
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c
@@ -0,0 +1,161 @@
+/*
+ * MPIC timer wakeup driver
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * 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/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+
+#include <asm/mpic_timer.h>
+#include <asm/mpic.h>
+
+struct fsl_mpic_timer_wakeup {
+	struct mpic_timer *timer;
+	struct work_struct free_work;
+};
+
+static struct fsl_mpic_timer_wakeup *fsl_wakeup;
+static DEFINE_MUTEX(sysfs_lock);
+
+static void fsl_free_resource(struct work_struct *ws)
+{
+	struct fsl_mpic_timer_wakeup *wakeup =
+		container_of(ws, struct fsl_mpic_timer_wakeup, free_work);
+
+	mutex_lock(&sysfs_lock);
+
+	if (wakeup->timer) {
+		disable_irq_wake(wakeup->timer->irq);
+		mpic_free_timer(wakeup->timer);
+	}
+
+	wakeup->timer = NULL;
+	mutex_unlock(&sysfs_lock);
+}
+
+static irqreturn_t fsl_mpic_timer_irq(int irq, void *dev_id)
+{
+	struct fsl_mpic_timer_wakeup *wakeup = dev_id;
+
+	schedule_work(&wakeup->free_work);
+
+	return wakeup->timer ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static ssize_t fsl_timer_wakeup_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct timeval interval;
+	int val = 0;
+
+	mutex_lock(&sysfs_lock);
+	if (fsl_wakeup->timer) {
+		mpic_get_remain_time(fsl_wakeup->timer, &interval);
+		val = interval.tv_sec + 1;
+	}
+	mutex_unlock(&sysfs_lock);
+
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t fsl_timer_wakeup_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf,
+				size_t count)
+{
+	struct timeval interval;
+	int ret;
+
+	interval.tv_usec = 0;
+	if (kstrtol(buf, 0, &interval.tv_sec))
+		return -EINVAL;
+
+	mutex_lock(&sysfs_lock);
+
+	if (fsl_wakeup->timer) {
+		disable_irq_wake(fsl_wakeup->timer->irq);
+		mpic_free_timer(fsl_wakeup->timer);
+		fsl_wakeup->timer = NULL;
+	}
+
+	if (!interval.tv_sec) {
+		mutex_unlock(&sysfs_lock);
+		return count;
+	}
+
+	fsl_wakeup->timer = mpic_request_timer(fsl_mpic_timer_irq,
+						fsl_wakeup, &interval);
+	if (!fsl_wakeup->timer) {
+		mutex_unlock(&sysfs_lock);
+		return -EINVAL;
+	}
+
+	ret = enable_irq_wake(fsl_wakeup->timer->irq);
+	if (ret) {
+		mpic_free_timer(fsl_wakeup->timer);
+		fsl_wakeup->timer = NULL;
+		mutex_unlock(&sysfs_lock);
+
+		return ret;
+	}
+
+	mpic_start_timer(fsl_wakeup->timer);
+
+	mutex_unlock(&sysfs_lock);
+
+	return count;
+}
+
+static struct device_attribute mpic_attributes = __ATTR(timer_wakeup, 0644,
+			fsl_timer_wakeup_show, fsl_timer_wakeup_store);
+
+static int __init fsl_wakeup_sys_init(void)
+{
+	int ret;
+
+	fsl_wakeup = kzalloc(sizeof(struct fsl_mpic_timer_wakeup), GFP_KERNEL);
+	if (!fsl_wakeup)
+		return -ENOMEM;
+
+	INIT_WORK(&fsl_wakeup->free_work, fsl_free_resource);
+
+	ret = device_create_file(mpic_subsys.dev_root, &mpic_attributes);
+	if (ret)
+		kfree(fsl_wakeup);
+
+	return ret;
+}
+
+static void __exit fsl_wakeup_sys_exit(void)
+{
+	device_remove_file(mpic_subsys.dev_root, &mpic_attributes);
+
+	mutex_lock(&sysfs_lock);
+
+	if (fsl_wakeup->timer) {
+		disable_irq_wake(fsl_wakeup->timer->irq);
+		mpic_free_timer(fsl_wakeup->timer);
+	}
+
+	kfree(fsl_wakeup);
+
+	mutex_unlock(&sysfs_lock);
+}
+
+module_init(fsl_wakeup_sys_init);
+module_exit(fsl_wakeup_sys_exit);
+
+MODULE_DESCRIPTION("Freescale MPIC global timer wakeup driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Wang Dongsheng <dongsheng.wang@freescale.com>");
-- 
1.8.0

^ permalink raw reply related

* RE: [PATCH 1/4][v2] powerpc/fsl-booke: Add initial silicon device tree files for B4860 and B4420
From: Aggrwal Poonam-B10812 @ 2013-04-09  5:42 UTC (permalink / raw)
  To: Leekha Shaveta-B20052, Kumar Gala; +Cc: linuxppc-dev@lists.ozlabs.org list
In-Reply-To: <E12D2F89F87F4A49B0320A4C2DE7E749152991@039-SN2MPN1-011.039d.mgd.msft.net>



> -----Original Message-----
> From: Linuxppc-dev [mailto:linuxppc-dev-
> bounces+poonam.aggrwal=3Dfreescale.com@lists.ozlabs.org] On Behalf Of
> Leekha Shaveta-B20052
> Sent: Monday, April 08, 2013 10:18 AM
> To: Kumar Gala
> Cc: linuxppc-dev@lists.ozlabs.org list
> Subject: RE: [PATCH 1/4][v2] powerpc/fsl-booke: Add initial silicon
> device tree files for B4860 and B4420
>=20
>=20
>=20
> -----Original Message-----
> From: Leekha Shaveta-B20052
> Sent: Friday, April 05, 2013 9:13 PM
> To: 'Kumar Gala'
> Cc: linuxppc-dev@lists.ozlabs.org list
> Subject: RE: [PATCH 1/4][v2] powerpc/fsl-booke: Add initial silicon
> device tree files for B4860 and B4420
>=20
>=20
>=20
> -----Original Message-----
> From: Kumar Gala [mailto:galak@kernel.crashing.org]
> Sent: Friday, April 05, 2013 7:53 PM
> To: Leekha Shaveta-B20052
> Cc: linuxppc-dev@lists.ozlabs.org list
> Subject: Re: [PATCH 1/4][v2] powerpc/fsl-booke: Add initial silicon
> device tree files for B4860 and B4420
>=20
>=20
> On Apr 5, 2013, at 1:33 AM, Shaveta Leekha wrote:
>=20
> > B4860 and B4420 are similar that share some commonalities
> >
> > * common features have been added in b4si-pre.dtsi and b4si-post.dtsi
> > * differences are added in respective silicon files of B4860 and B4420
> >
> > There are several things missing from the device trees of B4860 and
> B4420:
> >
> > * DPAA related nodes (Qman, Bman, Fman, Rman)
> > * DSP related nodes/information
> > * serdes, sfp(security fuse processor), thermal, gpio, maple, cpri,
> > quad timers nodes
> >
> > Signed-off-by: Shaveta Leekha <shaveta@freescale.com>
> > Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> > Signed-off-by: Li Yang <leoli@freescale.com>
> > Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com>
> > Signed-off-by: Varun Sethi <Varun.Sethi@freescale.com>
> > Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com>
> > Signed-off-by: Ramneek Mehresh <ramneek.mehresh@freescale.com>
> > Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
> > Signed-off-by: Andy Fleming <afleming@freescale.com>
> > Signed-off-by: Vakul Garg <vakul@freescale.com>
> > ---
> > v2:
> >  - incorporated review comments on commits message
> >  - change unit address of cpu nodes to match the reg property
> >
> > arch/powerpc/boot/dts/fsl/b4420si-post.dtsi |   94 ++++++++++
> > arch/powerpc/boot/dts/fsl/b4420si-pre.dtsi  |   49 +++++
> > arch/powerpc/boot/dts/fsl/b4860si-post.dtsi |  138 ++++++++++++++
> > arch/powerpc/boot/dts/fsl/b4860si-pre.dtsi  |   59 ++++++
> > arch/powerpc/boot/dts/fsl/b4si-post.dtsi    |  262
> +++++++++++++++++++++++++++
> > arch/powerpc/boot/dts/fsl/b4si-pre.dtsi     |   65 +++++++
> > 6 files changed, 667 insertions(+), 0 deletions(-) create mode 100644
> > arch/powerpc/boot/dts/fsl/b4420si-post.dtsi
> > create mode 100644 arch/powerpc/boot/dts/fsl/b4420si-pre.dtsi
> > create mode 100644 arch/powerpc/boot/dts/fsl/b4860si-post.dtsi
> > create mode 100644 arch/powerpc/boot/dts/fsl/b4860si-pre.dtsi
> > create mode 100644 arch/powerpc/boot/dts/fsl/b4si-post.dtsi
> > create mode 100644 arch/powerpc/boot/dts/fsl/b4si-pre.dtsi
>=20
> Is there a reason you didn't get rid of b4si-pre.dtsi and just merge it
> into b4860si-pre.dtsi & b4420-pre.dtsi?
> [SL] No particular reason. I have just tried to re-factored these files
> as you have suggested. Hence managed the commonalities in B4 files and
> differences in B4860's and B4420's respective files to reduce duplicity.
>=20
> Regards,
> Shaveta
>=20
> [SL] Kumar, please suggest.

Please suggest , if this re-factoring for pre-si dtsi should not be require=
d.
This was done to keep things uniform.

Accordingly we will send a re-spin if required.

Regards
Poonam
>=20
> Regards,
> Shaveta
>=20
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev

^ permalink raw reply

* [PATCH] powerpc: fix compiling CONFIG_PPC_TRANSACTIONAL_MEM when CONFIG_ALTIVEC=n
From: Michael Neuling @ 2013-04-09  6:18 UTC (permalink / raw)
  To: benh, sfr; +Cc: Linux PPC dev

We can't compile a kernel with CONFIG_ALTIVEC=n when
CONFIG_PPC_TRANSACTIONAL_MEM=y.  We currently get:

arch/powerpc/kernel/tm.S:320: Error: unsupported relocation against THREAD_VSCR
arch/powerpc/kernel/tm.S:323: Error: unsupported relocation against THREAD_VR0
arch/powerpc/kernel/tm.S:323: Error: unsupported relocation against THREAD_VR0
etc.

The below fixes this with a sprinkling of #ifdefs.

This was found by mpe with kisskb:
  http://kisskb.ellerman.id.au/kisskb/buildresult/8539442/

Signed-off-by: Michael Neuling <mikey@neuling.org>
---
sfr: this would be nice to get in 3.9.

diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 59dd545..16e77a8 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -555,10 +555,12 @@ static inline void tm_recheckpoint_new_task(struct task_struct *new)
 		new->thread.regs->msr |=
 			(MSR_FP | new->thread.fpexc_mode);
 	}
+#ifdef CONFIG_ALTIVEC
 	if (msr & MSR_VEC) {
 		do_load_up_transact_altivec(&new->thread);
 		new->thread.regs->msr |= MSR_VEC;
 	}
+#endif
 	/* We may as well turn on VSX too since all the state is restored now */
 	if (msr & MSR_VSX)
 		new->thread.regs->msr |= MSR_VSX;
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 3acb28e..95068bf 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -866,10 +866,12 @@ static long restore_tm_user_regs(struct pt_regs *regs,
 		do_load_up_transact_fpu(&current->thread);
 		regs->msr |= (MSR_FP | current->thread.fpexc_mode);
 	}
+#ifdef CONFIG_ALTIVEC
 	if (msr & MSR_VEC) {
 		do_load_up_transact_altivec(&current->thread);
 		regs->msr |= MSR_VEC;
 	}
+#endif
 
 	return 0;
 }
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 995f854..c179428 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -522,10 +522,12 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
 		do_load_up_transact_fpu(&current->thread);
 		regs->msr |= (MSR_FP | current->thread.fpexc_mode);
 	}
+#ifdef CONFIG_ALTIVEC
 	if (msr & MSR_VEC) {
 		do_load_up_transact_altivec(&current->thread);
 		regs->msr |= MSR_VEC;
 	}
+#endif
 
 	return err;
 }
diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S
index 84dbace..2da67e7 100644
--- a/arch/powerpc/kernel/tm.S
+++ b/arch/powerpc/kernel/tm.S
@@ -309,6 +309,7 @@ _GLOBAL(tm_recheckpoint)
 	or	r5, r6, r5			/* Set MSR.FP+.VSX/.VEC */
 	mtmsr	r5
 
+#ifdef CONFIG_ALTIVEC
 	/* FP and VEC registers:  These are recheckpointed from thread.fpr[]
 	 * and thread.vr[] respectively.  The thread.transact_fpr[] version
 	 * is more modern, and will be loaded subsequently by any FPUnavailable
@@ -323,6 +324,7 @@ _GLOBAL(tm_recheckpoint)
 	REST_32VRS(0, r5, r3)			/* r5 scratch, r3 THREAD ptr */
 	ld	r5, THREAD_VRSAVE(r3)
 	mtspr	SPRN_VRSAVE, r5
+#endif
 
 dont_restore_vec:
 	andi.	r0, r4, MSR_FP

^ permalink raw reply related

* [PATCH] of: remove the unnecessary of_node_put for of_parse_phandle_with_args()
From: Yuantian.Tang @ 2013-04-09  6:56 UTC (permalink / raw)
  To: grant.likely
  Cc: Tang Yuantian, devicetree-discuss, linuxppc-dev, linux-kernel,
	rob.herring

From: Tang Yuantian <yuantian.tang@freescale.com>

As the function itself says it is caller's responsibility to call the
of_node_put().  So, remove it on success to keep the reference count
correct.

Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com>
---
 drivers/of/base.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 321d3ef..e8b4c28 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1168,9 +1168,6 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
 					out_args->args[i] = be32_to_cpup(list++);
 			}
 
-			/* Found it! return success */
-			if (node)
-				of_node_put(node);
 			return 0;
 		}
 
-- 
1.8.0

^ permalink raw reply related

* Re: [PATCH 17/18] cpufreq: powerpc: move cpufreq driver to drivers/cpufreq
From: Viresh Kumar @ 2013-04-09  8:35 UTC (permalink / raw)
  To: rjw, deepthi
  Cc: robin.randhawa, linux-pm, Viresh Kumar, patches, Liviu.Dudau,
	linux-kernel, cpufreq, Steve.Bannister, Paul Mackerras,
	Olof Johansson, arvind.chauhan, linuxppc-dev, linaro-kernel,
	charles.garcia-tobin
In-Reply-To: <CAKohpokGkZ9m0v1QaoXEv1m0mZqY70adWpXf3edQGmZnToRRcg@mail.gmail.com>

On 5 April 2013 12:16, Viresh Kumar <viresh.kumar@linaro.org> wrote:
> On 4 April 2013 18:24, Viresh Kumar <viresh.kumar@linaro.org> wrote:
>> This patch moves cpufreq driver of powerpc platform to drivers/cpufreq.
>>
>> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> Cc: Paul Mackerras <paulus@samba.org>
>> Cc: Olof Johansson <olof@lixom.net>
>> Cc: linuxppc-dev@lists.ozlabs.org
>> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
>> ---
>> Compile Tested only.
>>
>>  arch/powerpc/platforms/Kconfig                     | 31 ----------------------
>>  arch/powerpc/platforms/pasemi/Makefile             |  1 -
>>  arch/powerpc/platforms/powermac/Makefile           |  2 --
>>  drivers/cpufreq/Kconfig.powerpc                    | 26 ++++++++++++++++++
>>  drivers/cpufreq/Makefile                           |  3 +++
>>  .../cpufreq.c => drivers/cpufreq/pasemi-cpufreq.c  |  0
>>  .../cpufreq/pmac32-cpufreq.c                       |  0
>>  .../cpufreq/pmac64-cpufreq.c                       |  0
>>  8 files changed, 29 insertions(+), 34 deletions(-)
>>  rename arch/powerpc/platforms/pasemi/cpufreq.c => drivers/cpufreq/pasemi-cpufreq.c (100%)
>>  rename arch/powerpc/platforms/powermac/cpufreq_32.c => drivers/cpufreq/pmac32-cpufreq.c (100%)
>>  rename arch/powerpc/platforms/powermac/cpufreq_64.c => drivers/cpufreq/pmac64-cpufreq.c (100%)
>
> Hi Deepthi,
>
> Can you help testing this please?

Ping!!

^ permalink raw reply

* [PATCH v3] clk: add PowerPC corenet clock driver support
From: Yuantian.Tang @ 2013-04-09  8:46 UTC (permalink / raw)
  To: mturquette
  Cc: ulf.hansson, linux-doc, viresh.kumar, devicetree-discuss,
	linux-kernel, Tang Yuantian, shawn.guo, linuxppc-dev,
	linus.walleij

From: Tang Yuantian <yuantian.tang@freescale.com>

This adds the clock driver for Freescale PowerPC corenet
series SoCs using common clock infrastructure.

Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
v3:
	- remove the module author and description
v2:
	- add the document for device tree clock bindings

 arch/powerpc/platforms/Kconfig.cputype |   1 +
 drivers/clk/Kconfig                    |   7 +
 drivers/clk/Makefile                   |   1 +
 drivers/clk/clk-ppc-corenet.c          | 280 +++++++++++++++++++++++++++++++++
 4 files changed, 289 insertions(+)
 create mode 100644 drivers/clk/clk-ppc-corenet.c

diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 18e3b76..cf065b8 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -158,6 +158,7 @@ config E500
 config PPC_E500MC
 	bool "e500mc Support"
 	select PPC_FPU
+	select COMMON_CLK
 	depends on E500
 	help
 	  This must be enabled for running on e500mc (and derivatives
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index a47e6ee..6e2fd9c 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -63,6 +63,13 @@ config CLK_TWL6040
 	  McPDM. McPDM module is using the external bit clock on the McPDM bus
 	  as functional clock.
 
+config CLK_PPC_CORENET
+	bool "Clock driver for PowerPC corenet platforms"
+	depends on PPC_E500MC && OF
+	---help---
+	  This adds the clock driver support for Freescale PowerPC corenet
+	  platforms using common clock framework.
+
 endmenu
 
 source "drivers/clk/mvebu/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 300d477..6720319 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_X86)		+= x86/
 obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
 obj-$(CONFIG_CLK_TWL6040)	+= clk-twl6040.o
+obj-$(CONFIG_CLK_PPC_CORENET)	+= clk-ppc-corenet.o
diff --git a/drivers/clk/clk-ppc-corenet.c b/drivers/clk/clk-ppc-corenet.c
new file mode 100644
index 0000000..a2d483f
--- /dev/null
+++ b/drivers/clk/clk-ppc-corenet.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * clock driver for Freescale PowerPC corenet SoCs.
+ */
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+struct cmux_clk {
+	struct clk_hw hw;
+	void __iomem *reg;
+	u32 flags;
+};
+
+#define PLL_KILL			BIT(31)
+#define	CLKSEL_SHIFT		27
+#define CLKSEL_ADJUST		BIT(0)
+#define to_cmux_clk(p)		container_of(p, struct cmux_clk, hw)
+
+static void __iomem *base;
+static unsigned int clocks_per_pll;
+
+static int cmux_set_parent(struct clk_hw *hw, u8 idx)
+{
+	struct cmux_clk *clk = to_cmux_clk(hw);
+	u32 clksel;
+
+	clksel = ((idx / clocks_per_pll) << 2) + idx % clocks_per_pll;
+	if (clk->flags & CLKSEL_ADJUST)
+		clksel += 8;
+	clksel = (clksel & 0xf) << CLKSEL_SHIFT;
+	iowrite32be(clksel, clk->reg);
+
+	return 0;
+}
+
+static u8 cmux_get_parent(struct clk_hw *hw)
+{
+	struct cmux_clk *clk = to_cmux_clk(hw);
+	u32 clksel;
+
+	clksel = ioread32be(clk->reg);
+	clksel = (clksel >> CLKSEL_SHIFT) & 0xf;
+	if (clk->flags & CLKSEL_ADJUST)
+		clksel -= 8;
+	clksel = (clksel >> 2) * clocks_per_pll + clksel % 4;
+
+	return clksel;
+}
+
+const struct clk_ops cmux_ops = {
+	.get_parent = cmux_get_parent,
+	.set_parent = cmux_set_parent,
+};
+
+static void __init core_mux_init(struct device_node *np)
+{
+	struct clk *clk;
+	struct clk_init_data init;
+	struct cmux_clk *cmux_clk;
+	struct device_node *node;
+	int rc, count, i;
+	u32	offset;
+	const char *clk_name;
+	const char **parent_names;
+
+	rc = of_property_read_u32(np, "reg", &offset);
+	if (rc) {
+		pr_err("%s: could not get reg property\n", np->name);
+		return;
+	}
+
+	/* get the input clock source count */
+	count = of_property_count_strings(np, "clock-names");
+	if (count < 0) {
+		pr_err("%s: get clock count error\n", np->name);
+		return;
+	}
+	parent_names = kzalloc((sizeof(char *) * count), GFP_KERNEL);
+	if (!parent_names) {
+		pr_err("%s: could not allocate parent_names\n", __func__);
+		return;
+	}
+
+	for (i = 0; i < count; i++)
+		parent_names[i] = of_clk_get_parent_name(np, i);
+
+	cmux_clk = kzalloc(sizeof(struct cmux_clk), GFP_KERNEL);
+	if (!cmux_clk) {
+		pr_err("%s: could not allocate cmux_clk\n", __func__);
+		goto err_name;
+	}
+	cmux_clk->reg = base + offset;
+
+	node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
+	if (node && (offset >= 0x80))
+		cmux_clk->flags = CLKSEL_ADJUST;
+
+	rc = of_property_read_string_index(np, "clock-output-names",
+			0, &clk_name);
+	if (rc) {
+		pr_err("%s: read clock names error\n", np->name);
+		goto err_clk;
+	}
+
+	init.name = clk_name;
+	init.ops = &cmux_ops;
+	init.parent_names = parent_names;
+	init.num_parents = count;
+	init.flags = 0;
+	cmux_clk->hw.init = &init;
+
+	clk = clk_register(NULL, &cmux_clk->hw);
+	if (IS_ERR(clk)) {
+		pr_err("%s: could not register clock\n", clk_name);
+		goto err_clk;
+	}
+
+	rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	if (rc) {
+		pr_err("Could not register clock provider for node:%s\n",
+			 np->name);
+		goto err_clk;
+	}
+	goto err_name;
+
+err_clk:
+	kfree(cmux_clk);
+err_name:
+	/* free *_names because they are reallocated when registered */
+	kfree(parent_names);
+}
+
+static void __init core_pll_init(struct device_node *np)
+{
+	u32 offset, mult;
+	int i, rc, count;
+	const char *clk_name, *parent_name;
+	struct clk_onecell_data *onecell_data;
+	struct clk      **subclks;
+
+	rc = of_property_read_u32(np, "reg", &offset);
+	if (rc) {
+		pr_err("%s: could not get reg property\n", np->name);
+		return;
+	}
+
+	/* get the multiple of PLL */
+	mult = ioread32be(base + offset);
+
+	/* check if this PLL is disabled */
+	if (mult & PLL_KILL) {
+		pr_debug("PLL:%s is disabled\n", np->name);
+		return;
+	}
+	mult = (mult >> 1) & 0x3f;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name) {
+		pr_err("PLL: %s must have a parent\n", np->name);
+		return;
+	}
+
+	count = of_property_count_strings(np, "clock-output-names");
+	if (count < 0 || count > 4) {
+		pr_err("%s: clock is not supported\n", np->name);
+		return;
+	}
+
+	/* output clock number per PLL */
+	clocks_per_pll = count;
+
+	subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL);
+	if (!subclks) {
+		pr_err("%s: could not allocate subclks\n", __func__);
+		return;
+	}
+
+	onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+	if (!onecell_data) {
+		pr_err("%s: could not allocate onecell_data\n", __func__);
+		goto err_clks;
+	}
+
+	for (i = 0; i < count; i++) {
+		rc = of_property_read_string_index(np, "clock-output-names",
+				i, &clk_name);
+		if (rc) {
+			pr_err("%s: could not get clock names\n", np->name);
+			goto err_cell;
+		}
+
+		/*
+		 * when count == 4, there are 4 output clocks:
+		 * /1, /2, /3, /4 respectively
+		 * when count < 4, there are at least 2 output clocks:
+		 * /1, /2, (/4, if count == 3) respectively.
+		 */
+		if (count == 4)
+			subclks[i] = clk_register_fixed_factor(NULL, clk_name,
+					parent_name, 0, mult, 1 + i);
+		else
+
+			subclks[i] = clk_register_fixed_factor(NULL, clk_name,
+					parent_name, 0, mult, 1 << i);
+
+		if (IS_ERR(subclks[i])) {
+			pr_err("%s: could not register clock\n", clk_name);
+			goto err_cell;
+		}
+	}
+
+	onecell_data->clks = subclks;
+	onecell_data->clk_num = count;
+
+	rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
+	if (rc) {
+		pr_err("Could not register clk provider for node:%s\n",
+			 np->name);
+		goto err_cell;
+	}
+
+	return;
+err_cell:
+	kfree(onecell_data);
+err_clks:
+	kfree(subclks);
+}
+
+static const struct of_device_id clk_match[] __initconst = {
+	{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
+	{ .compatible = "fsl,core-pll-clock", .data = core_pll_init, },
+	{ .compatible = "fsl,core-mux-clock", .data = core_mux_init, },
+	{}
+};
+
+static int __init ppc_corenet_clk_probe(struct platform_device *pdev)
+{
+	struct device_node *np;
+
+	np = pdev->dev.of_node;
+	base = of_iomap(np, 0);
+	if (!base) {
+		dev_err(&pdev->dev, "iomap error\n");
+		return -ENOMEM;
+	}
+	of_clk_init(clk_match);
+
+	return 0;
+}
+
+static const struct of_device_id ppc_clk_ids[] __initconst = {
+	{ .compatible = "fsl,qoriq-clockgen-1.0", },
+	{ .compatible = "fsl,qoriq-clockgen-2", },
+	{}
+};
+
+static struct platform_driver ppc_corenet_clk_driver = {
+	.driver = {
+		.name = "ppc_corenet_clock",
+		.owner = THIS_MODULE,
+		.of_match_table = ppc_clk_ids,
+	},
+	.probe = ppc_corenet_clk_probe,
+};
+
+static int __init ppc_corenet_clk_init(void)
+{
+	return platform_driver_register(&ppc_corenet_clk_driver);
+}
+subsys_initcall(ppc_corenet_clk_init);
-- 
1.8.0

^ permalink raw reply related

* [PATCH] powerpc/mpc85xx: Update the clock device tree nodes
From: Yuantian.Tang @ 2013-04-09  8:46 UTC (permalink / raw)
  To: mturquette
  Cc: ulf.hansson, linux-doc, viresh.kumar, devicetree-discuss,
	linux-kernel, Tang Yuantian, shawn.guo, linuxppc-dev,
	linus.walleij
In-Reply-To: <1365497187-8305-1-git-send-email-Yuantian.Tang@freescale.com>

From: Tang Yuantian <yuantian.tang@freescale.com>

The following SoCs will be affected: p2041, p3041, p4080,
p5020, p5040

Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
* resend for review

 arch/powerpc/boot/dts/fsl/p2041si-post.dtsi |  62 ++++++++++++++++-
 arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi  |   4 ++
 arch/powerpc/boot/dts/fsl/p3041si-post.dtsi |  62 ++++++++++++++++-
 arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi  |   4 ++
 arch/powerpc/boot/dts/fsl/p4080si-post.dtsi | 100 +++++++++++++++++++++++++++-
 arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi  |   8 +++
 arch/powerpc/boot/dts/fsl/p5020si-post.dtsi |  42 +++++++++++-
 arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi  |   2 +
 arch/powerpc/boot/dts/fsl/p5040si-post.dtsi |  54 ++++++++++++++-
 arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi  |   4 ++
 10 files changed, 337 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
index 69ac1ac..d83de62 100644
--- a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
@@ -305,9 +305,69 @@
 	};
 
 	clockgen: global-utilities@e1000 {
-		compatible = "fsl,p2041-clockgen", "fsl,qoriq-clockgen-1.0";
+		compatible = "fsl,p2041-clockgen", "fsl,qoriq-clockgen-1.0",
+				   "fixed-clock";
 		reg = <0xe1000 0x1000>;
 		clock-frequency = <0>;
+		clock-output-names = "sysclk";
+		#clock-cells = <0>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pll0: pll0@800 {
+			#clock-cells = <1>;
+			reg = <0x800>;
+			compatible = "fsl,core-pll-clock";
+			clocks = <&clockgen>;
+			clock-output-names = "pll0", "pll0-div2", "pll0-div4";
+		};
+		pll1: pll1@820 {
+			#clock-cells = <1>;
+			reg = <0x820>;
+			compatible = "fsl,core-pll-clock";
+			clocks = <&clockgen>;
+			clock-output-names = "pll1", "pll1-div2", "pll1-div4";
+		};
+		mux0: mux0@0 {
+			#clock-cells = <0>;
+			reg = <0x0>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+				   <&pll1 0>, <&pll1 1>, <&pll1 2>;
+			clock-names = "pll0_0", "pll0_1", "pll0_2",
+				"pll1_0", "pll1_1", "pll1_2";
+			clock-output-names = "cmux0";
+		};
+		mux1: mux1@20 {
+			#clock-cells = <0>;
+			reg = <0x20>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+				   <&pll1 0>, <&pll1 1>, <&pll1 2>;
+			clock-names = "pll0_0", "pll0_1", "pll0_2",
+				"pll1_0", "pll1_1", "pll1_2";
+			clock-output-names = "cmux1";
+		};
+		mux2: mux2@40 {
+			#clock-cells = <0>;
+			reg = <0x40>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+				   <&pll1 0>, <&pll1 1>, <&pll1 2>;
+			clock-names = "pll0_0", "pll0_1", "pll0_2",
+				"pll1_0", "pll1_1", "pll1_2";
+			clock-output-names = "cmux2";
+		};
+		mux3: mux3@60 {
+			#clock-cells = <0>;
+			reg = <0x60>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+				   <&pll1 0>, <&pll1 1>, <&pll1 2>;
+			clock-names = "pll0_0", "pll0_1", "pll0_2",
+				"pll1_0", "pll1_1", "pll1_2";
+			clock-output-names = "cmux3";
+		};
 	};
 
 	rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
index 7a2697d..22f3b14 100644
--- a/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
@@ -81,6 +81,7 @@
 		cpu0: PowerPC,e500mc@0 {
 			device_type = "cpu";
 			reg = <0>;
+			clocks = <&mux0>;
 			next-level-cache = <&L2_0>;
 			L2_0: l2-cache {
 				next-level-cache = <&cpc>;
@@ -89,6 +90,7 @@
 		cpu1: PowerPC,e500mc@1 {
 			device_type = "cpu";
 			reg = <1>;
+			clocks = <&mux1>;
 			next-level-cache = <&L2_1>;
 			L2_1: l2-cache {
 				next-level-cache = <&cpc>;
@@ -97,6 +99,7 @@
 		cpu2: PowerPC,e500mc@2 {
 			device_type = "cpu";
 			reg = <2>;
+			clocks = <&mux2>;
 			next-level-cache = <&L2_2>;
 			L2_2: l2-cache {
 				next-level-cache = <&cpc>;
@@ -105,6 +108,7 @@
 		cpu3: PowerPC,e500mc@3 {
 			device_type = "cpu";
 			reg = <3>;
+			clocks = <&mux3>;
 			next-level-cache = <&L2_3>;
 			L2_3: l2-cache {
 				next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
index 9b5a81a..25b19cc 100644
--- a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
@@ -332,9 +332,69 @@
 	};
 
 	clockgen: global-utilities@e1000 {
-		compatible = "fsl,p3041-clockgen", "fsl,qoriq-clockgen-1.0";
+		compatible = "fsl,p3041-clockgen", "fsl,qoriq-clockgen-1.0",
+				   "fixed-clock";
 		reg = <0xe1000 0x1000>;
 		clock-frequency = <0>;
+		clock-output-names = "sysclk";
+		#clock-cells = <0>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pll0: pll1@800 {
+			#clock-cells = <1>;
+			reg = <0x800>;
+			compatible = "fsl,core-pll-clock";
+			clocks = <&clockgen>;
+			clock-output-names = "pll0", "pll0-div2", "pll0-div4";
+		};
+		pll1: pll1@820 {
+			#clock-cells = <1>;
+			reg = <0x820>;
+			compatible = "fsl,core-pll-clock";
+			clocks = <&clockgen>;
+			clock-output-names = "pll1", "pll1-div2", "pll1-div4";
+		};
+		mux0: mux0@0 {
+			#clock-cells = <0>;
+			reg = <0x0>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+				 <&pll1 0>, <&pll1 1>, <&pll1 2>;
+			clock-names = "pll0_0", "pll0_1", "pll0_2",
+				"pll1_0", "pll1_1", "pll1_2";
+			clock-output-names = "cmux0";
+		};
+		mux1: mux1@20 {
+			#clock-cells = <0>;
+			reg = <0x20>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+				 <&pll1 0>, <&pll1 1>, <&pll1 2>;
+			clock-names = "pll0_0", "pll0_1", "pll0_2",
+				"pll1_0", "pll1_1", "pll1_2";
+			clock-output-names = "cmux1";
+		};
+		mux2: mux2@40 {
+			#clock-cells = <0>;
+			reg = <0x40>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+				 <&pll1 0>, <&pll1 1>, <&pll1 2>;
+			clock-names = "pll0_0", "pll0_1", "pll0_2",
+				"pll1_0", "pll1_1", "pll1_2";
+			clock-output-names = "cmux2";
+		};
+		mux3: mux3@60 {
+			#clock-cells = <0>;
+			reg = <0x60>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+				 <&pll1 0>, <&pll1 1>, <&pll1 2>;
+			clock-names = "pll0_0", "pll0_1", "pll0_2",
+				"pll1_0", "pll1_1", "pll1_2";
+			clock-output-names = "cmux3";
+		};
 	};
 
 	rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
index c9ca2c3..468e8be 100644
--- a/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
@@ -82,6 +82,7 @@
 		cpu0: PowerPC,e500mc@0 {
 			device_type = "cpu";
 			reg = <0>;
+			clocks = <&mux0>;
 			next-level-cache = <&L2_0>;
 			L2_0: l2-cache {
 				next-level-cache = <&cpc>;
@@ -90,6 +91,7 @@
 		cpu1: PowerPC,e500mc@1 {
 			device_type = "cpu";
 			reg = <1>;
+			clocks = <&mux1>;
 			next-level-cache = <&L2_1>;
 			L2_1: l2-cache {
 				next-level-cache = <&cpc>;
@@ -98,6 +100,7 @@
 		cpu2: PowerPC,e500mc@2 {
 			device_type = "cpu";
 			reg = <2>;
+			clocks = <&mux2>;
 			next-level-cache = <&L2_2>;
 			L2_2: l2-cache {
 				next-level-cache = <&cpc>;
@@ -106,6 +109,7 @@
 		cpu3: PowerPC,e500mc@3 {
 			device_type = "cpu";
 			reg = <3>;
+			clocks = <&mux3>;
 			next-level-cache = <&L2_3>;
 			L2_3: l2-cache {
 				next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
index 19859ad..3596f05 100644
--- a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
@@ -352,9 +352,107 @@
 	};
 
 	clockgen: global-utilities@e1000 {
-		compatible = "fsl,p4080-clockgen", "fsl,qoriq-clockgen-1.0";
+		compatible = "fsl,p4080-clockgen", "fsl,qoriq-clockgen-1.0",
+				   "fixed-clock";
 		reg = <0xe1000 0x1000>;
 		clock-frequency = <0>;
+		clock-output-names = "sysclk";
+		#clock-cells = <0>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pll0: pll0@800 {
+			#clock-cells = <1>;
+			reg = <0x800>;
+			compatible = "fsl,core-pll-clock";
+			clocks = <&clockgen>;
+			clock-output-names = "pll0", "pll0-div2";
+		};
+		pll1: pll1@820 {
+			#clock-cells = <1>;
+			reg = <0x820>;
+			compatible = "fsl,core-pll-clock";
+			clocks = <&clockgen>;
+			clock-output-names = "pll1", "pll1-div2";
+		};
+		pll2: pll2@840 {
+			#clock-cells = <1>;
+			reg = <0x840>;
+			compatible = "fsl,core-pll-clock";
+			clocks = <&clockgen>;
+			clock-output-names = "pll2", "pll2-div2";
+		};
+		pll3: pll2@860 {
+			#clock-cells = <1>;
+			reg = <0x860>;
+			compatible = "fsl,core-pll-clock";
+			clocks = <&clockgen>;
+			clock-output-names = "pll3", "pll3-div2";
+		};
+		mux0: mux0@0 {
+			#clock-cells = <0>;
+			reg = <0x0>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+			clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+			clock-output-names = "cmux0";
+		};
+		mux1: mux1@20 {
+			#clock-cells = <0>;
+			reg = <0x20>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+			clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+			clock-output-names = "cmux1";
+		};
+		mux2: mux2@40 {
+			#clock-cells = <0>;
+			reg = <0x40>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+			clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+			clock-output-names = "cmux2";
+		};
+		mux3: mux3@60 {
+			#clock-cells = <0>;
+			reg = <0x60>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+			clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+			clock-output-names = "cmux3";
+		};
+		mux4: mux4@80 {
+			#clock-cells = <0>;
+			reg = <0x80>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+			clock-names = "pll2_0", "pll2_1", "pll3_0", "pll3_1";
+			clock-output-names = "cmux4";
+		};
+		mux5: mux5@a0 {
+			#clock-cells = <0>;
+			reg = <0xa0>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+			clock-names = "pll2_0", "pll2_1", "pll3_0", "pll3_1";
+			clock-output-names = "cmux5";
+		};
+		mux6: mux6@c0 {
+			#clock-cells = <0>;
+			reg = <0xc0>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+			clock-names = "pll2_0", "pll2_1", "pll3_0", "pll3_1";
+			clock-output-names = "cmux6";
+		};
+		mux7: mux7@e0 {
+			#clock-cells = <0>;
+			reg = <0xe0>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+			clock-names = "pll2_0", "pll2_1", "pll3_0", "pll3_1";
+			clock-output-names = "cmux7";
+		};
 	};
 
 	rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
index 493d9a0..0040b5a 100644
--- a/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
@@ -81,6 +81,7 @@
 		cpu0: PowerPC,e500mc@0 {
 			device_type = "cpu";
 			reg = <0>;
+			clocks = <&mux0>;
 			next-level-cache = <&L2_0>;
 			L2_0: l2-cache {
 				next-level-cache = <&cpc>;
@@ -89,6 +90,7 @@
 		cpu1: PowerPC,e500mc@1 {
 			device_type = "cpu";
 			reg = <1>;
+			clocks = <&mux1>;
 			next-level-cache = <&L2_1>;
 			L2_1: l2-cache {
 				next-level-cache = <&cpc>;
@@ -97,6 +99,7 @@
 		cpu2: PowerPC,e500mc@2 {
 			device_type = "cpu";
 			reg = <2>;
+			clocks = <&mux2>;
 			next-level-cache = <&L2_2>;
 			L2_2: l2-cache {
 				next-level-cache = <&cpc>;
@@ -105,6 +108,7 @@
 		cpu3: PowerPC,e500mc@3 {
 			device_type = "cpu";
 			reg = <3>;
+			clocks = <&mux3>;
 			next-level-cache = <&L2_3>;
 			L2_3: l2-cache {
 				next-level-cache = <&cpc>;
@@ -113,6 +117,7 @@
 		cpu4: PowerPC,e500mc@4 {
 			device_type = "cpu";
 			reg = <4>;
+			clocks = <&mux4>;
 			next-level-cache = <&L2_4>;
 			L2_4: l2-cache {
 				next-level-cache = <&cpc>;
@@ -121,6 +126,7 @@
 		cpu5: PowerPC,e500mc@5 {
 			device_type = "cpu";
 			reg = <5>;
+			clocks = <&mux5>;
 			next-level-cache = <&L2_5>;
 			L2_5: l2-cache {
 				next-level-cache = <&cpc>;
@@ -129,6 +135,7 @@
 		cpu6: PowerPC,e500mc@6 {
 			device_type = "cpu";
 			reg = <6>;
+			clocks = <&mux6>;
 			next-level-cache = <&L2_6>;
 			L2_6: l2-cache {
 				next-level-cache = <&cpc>;
@@ -137,6 +144,7 @@
 		cpu7: PowerPC,e500mc@7 {
 			device_type = "cpu";
 			reg = <7>;
+			clocks = <&mux7>;
 			next-level-cache = <&L2_7>;
 			L2_7: l2-cache {
 				next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
index 9ea77c3..3c662bd 100644
--- a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
@@ -337,9 +337,49 @@
 	};
 
 	clockgen: global-utilities@e1000 {
-		compatible = "fsl,p5020-clockgen", "fsl,qoriq-clockgen-1.0";
+		compatible = "fsl,p5020-clockgen", "fsl,qoriq-clockgen-1.0",
+				   "fixed-clock";
 		reg = <0xe1000 0x1000>;
 		clock-frequency = <0>;
+		clock-output-names = "sysclk";
+		#clock-cells = <0>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pll0: pll0@800 {
+			#clock-cells = <1>;
+			reg = <0x800>;
+			compatible = "fsl,core-pll-clock";
+			clocks = <&clockgen>;
+			clock-output-names = "pll0", "pll0-div2", "pll0-div4";
+		};
+		pll1: pll1@820 {
+			#clock-cells = <1>;
+			reg = <0x820>;
+			compatible = "fsl,core-pll-clock";
+			clocks = <&clockgen>;
+			clock-output-names = "pll1", "pll1-div2", "pll1-div4";
+		};
+		mux0: mux0@0 {
+			#clock-cells = <0>;
+			reg = <0x0>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+				 <&pll1 0>, <&pll1 1>, <&pll1 2>;
+			clock-names = "pll0_0", "pll0_1", "pll0_2",
+				"pll1_0", "pll1_1", "pll1_2";
+			clock-output-names = "cmux0";
+		};
+		mux1: mux1@20 {
+			#clock-cells = <0>;
+			reg = <0x20>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+				 <&pll1 0>, <&pll1 1>, <&pll1 2>;
+			clock-names = "pll0_0", "pll0_1", "pll0_2",
+				"pll1_0", "pll1_1", "pll1_2";
+			clock-output-names = "cmux1";
+		};
 	};
 
 	rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
index 8df47fc..fe1a2e6 100644
--- a/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
@@ -88,6 +88,7 @@
 		cpu0: PowerPC,e5500@0 {
 			device_type = "cpu";
 			reg = <0>;
+			clocks = <&mux0>;
 			next-level-cache = <&L2_0>;
 			L2_0: l2-cache {
 				next-level-cache = <&cpc>;
@@ -96,6 +97,7 @@
 		cpu1: PowerPC,e5500@1 {
 			device_type = "cpu";
 			reg = <1>;
+			clocks = <&mux1>;
 			next-level-cache = <&L2_1>;
 			L2_1: l2-cache {
 				next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
index 97f8c26..3870b22 100644
--- a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
@@ -297,9 +297,61 @@
 	};
 
 	clockgen: global-utilities@e1000 {
-		compatible = "fsl,p5040-clockgen", "fsl,qoriq-clockgen-1.0";
+		compatible = "fsl,p5040-clockgen", "fsl,qoriq-clockgen-1.0",
+				   "fixed-clock";
 		reg = <0xe1000 0x1000>;
 		clock-frequency = <0>;
+		clock-output-names = "sysclk";
+		#clock-cells = <0>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pll0: pll0@800 {
+			#clock-cells = <1>;
+			reg = <0x800>;
+			compatible = "fsl,core-pll-clock";
+			clocks = <&clockgen>;
+			clock-output-names = "pll0", "pll0-div2";
+		};
+		pll1: pll1@820 {
+			#clock-cells = <1>;
+			reg = <0x820>;
+			compatible = "fsl,core-pll-clock";
+			clocks = <&clockgen>;
+			clock-output-names = "pll1", "pll1-div2";
+		};
+		mux0: mux0@0 {
+			#clock-cells = <0>;
+			reg = <0x0>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+			clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+			clock-output-names = "cmux0";
+		};
+		mux1: mux1@20 {
+			#clock-cells = <0>;
+			reg = <0x20>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+			clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+			clock-output-names = "cmux1";
+		};
+		mux2: mux2@40 {
+			#clock-cells = <0>;
+			reg = <0x40>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+			clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+			clock-output-names = "cmux2";
+		};
+		mux3: mux3@60 {
+			#clock-cells = <0>;
+			reg = <0x60>;
+			compatible = "fsl,core-mux-clock";
+			clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+			clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+			clock-output-names = "cmux3";
+		};
 	};
 
 	rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
index 40ca943..3674686 100644
--- a/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
@@ -81,6 +81,7 @@
 		cpu0: PowerPC,e5500@0 {
 			device_type = "cpu";
 			reg = <0>;
+			clocks = <&mux0>;
 			next-level-cache = <&L2_0>;
 			L2_0: l2-cache {
 				next-level-cache = <&cpc>;
@@ -89,6 +90,7 @@
 		cpu1: PowerPC,e5500@1 {
 			device_type = "cpu";
 			reg = <1>;
+			clocks = <&mux1>;
 			next-level-cache = <&L2_1>;
 			L2_1: l2-cache {
 				next-level-cache = <&cpc>;
@@ -97,6 +99,7 @@
 		cpu2: PowerPC,e5500@2 {
 			device_type = "cpu";
 			reg = <2>;
+			clocks = <&mux2>;
 			next-level-cache = <&L2_2>;
 			L2_2: l2-cache {
 				next-level-cache = <&cpc>;
@@ -105,6 +108,7 @@
 		cpu3: PowerPC,e5500@3 {
 			device_type = "cpu";
 			reg = <3>;
+			clocks = <&mux3>;
 			next-level-cache = <&L2_3>;
 			L2_3: l2-cache {
 				next-level-cache = <&cpc>;
-- 
1.8.0

^ permalink raw reply related

* [PATCH v4] cpufreq: powerpc: Add cpufreq driver for Freescale e500mc SoCs
From: Yuantian.Tang @ 2013-04-09  8:32 UTC (permalink / raw)
  To: rjw
  Cc: linux-pm, viresh.kumar, linux-kernel, cpufreq, Tang Yuantian,
	linuxppc-dev

From: Tang Yuantian <yuantian.tang@freescale.com>

Add cpufreq driver for Freescale e500mc, e5500 and e6500 SoCs
which are capable of changing the CPU frequency dynamically

Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
v4:
	- rebase on bleeding-edge branch of Rafael's linux-pm.git 
	- #define pr_fmt() for better debug prints
	- use newest cpufreq_notify_transition()
	- support CPU hotplug
	- remove table[i].index as it is not used
	- remove cpus_per_cluster
v3:
	- change sizeof(struct name).. to sizeof(*p)
	- remove the struct cpufreq_data, use global variable instead
	- resolve setting policy->cpus incorrectly
	- add CPUFREQ_POSTCHANGE notifier when setting frequency error
v2:
	- add depends on OF and COMMON_CLK in Kconfig
	- use clk.h instead of clk-provider.h
	- change per_cpu variable from struct to pointer

 drivers/cpufreq/Kconfig.powerpc       |  10 ++
 drivers/cpufreq/Makefile              |   1 +
 drivers/cpufreq/ppc-corenet-cpufreq.c | 254 ++++++++++++++++++++++++++++++++++
 3 files changed, 265 insertions(+)
 create mode 100644 drivers/cpufreq/ppc-corenet-cpufreq.c

diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc
index 9c926ca..88f629e 100644
--- a/drivers/cpufreq/Kconfig.powerpc
+++ b/drivers/cpufreq/Kconfig.powerpc
@@ -23,3 +23,13 @@ config CPU_FREQ_MAPLE
 	help
 	  This adds support for frequency switching on Maple 970FX
 	  Evaluation Board and compatible boards (IBM JS2x blades).
+
+config PPC_CORENET_CPUFREQ
+	tristate "CPU frequency scaling driver for Freescale E500MC SoCs"
+	depends on PPC_E500MC && OF && COMMON_CLK
+	select CPU_FREQ_TABLE
+	select CLK_PPC_CORENET
+	help
+	  This adds the CPUFreq driver support for Freescale e500mc,
+	  e5500 and e6500 series SoCs which are capable of changing
+	  the CPU's frequency dynamically.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 6ad0b91..5125034 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_CPU_FREQ_CBE)		+= ppc-cbe-cpufreq.o
 ppc-cbe-cpufreq-y			+= ppc_cbe_cpufreq_pervasive.o ppc_cbe_cpufreq.o
 obj-$(CONFIG_CPU_FREQ_CBE_PMI)		+= ppc_cbe_cpufreq_pmi.o
 obj-$(CONFIG_CPU_FREQ_MAPLE)		+= maple-cpufreq.o
+obj-$(CONFIG_PPC_CORENET_CPUFREQ)   += ppc-corenet-cpufreq.o
 
 ##################################################################################
 # Other platform drivers
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c
new file mode 100644
index 0000000..e230282
--- /dev/null
+++ b/drivers/cpufreq/ppc-corenet-cpufreq.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * CPU Frequency Scaling driver for Freescale PowerPC corenet SoCs.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+/**
+ * struct cpu_data - per CPU data struct
+ * @clk: the clk of CPU
+ * @parent: the parent node of cpu clock
+ * @table: frequency table
+ */
+struct cpu_data {
+	struct clk *clk;
+	struct device_node *parent;
+	struct cpufreq_frequency_table *table;
+};
+
+/* serialize frequency changes  */
+static DEFINE_MUTEX(cpufreq_lock);
+static DEFINE_PER_CPU(struct cpu_data *, cpu_data);
+
+static unsigned int corenet_cpufreq_get_speed(unsigned int cpu)
+{
+	struct cpu_data *data = per_cpu(cpu_data, cpu);
+
+	return clk_get_rate(data->clk) / 1000;
+}
+
+/* reduce the duplicated frequency in frequency table */
+static void freq_table_redup(struct cpufreq_frequency_table *freq_table,
+		int count)
+{
+	int i, j;
+
+	for (i = 1; i < count; i++) {
+		for (j = 0; j < i; j++) {
+			if (freq_table[j].frequency == CPUFREQ_ENTRY_INVALID ||
+					freq_table[j].frequency !=
+					freq_table[i].frequency)
+				continue;
+
+			freq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+			break;
+		}
+	}
+}
+
+static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+	struct device_node *np;
+	int i, count, ret;
+	struct clk *clk;
+	struct cpufreq_frequency_table *table;
+	struct cpu_data *data;
+	unsigned int cpu = policy->cpu;
+
+	np = of_get_cpu_node(cpu, NULL);
+	if (!np)
+		return -ENODEV;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		pr_err("%s: no memory\n", __func__);
+		goto err_np;
+	}
+
+	data->clk = of_clk_get(np, 0);
+	if (IS_ERR(data->clk)) {
+		pr_err("%s: no clock information\n", __func__);
+		goto err_nomem2;
+	}
+
+	data->parent = of_parse_phandle(np, "clocks", 0);
+	if (!data->parent) {
+		pr_err("%s: could not get clock information\n", __func__);
+		goto err_nomem2;
+	}
+
+	count = of_property_count_strings(data->parent, "clock-names");
+	table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL);
+	if (!table) {
+		pr_err("%s: no memory\n", __func__);
+		goto err_node;
+	}
+
+	for (i = 0; i < count; i++) {
+		clk = of_clk_get(data->parent, i);
+		table[i].frequency = clk_get_rate(clk) / 1000;
+	}
+	freq_table_redup(table, count);
+	table[i].frequency = CPUFREQ_TABLE_END;
+
+	/* set the min and max frequency properly */
+	ret = cpufreq_frequency_table_cpuinfo(policy, table);
+	if (ret) {
+		pr_err("invalid frequency table: %d\n", ret);
+		goto err_nomem1;
+	}
+
+	data->table = table;
+	per_cpu(cpu_data, cpu) = data;
+
+#ifdef CONFIG_SMP
+	/* update ->cpus if we have cluster, no harm if not */
+	cpumask_copy(policy->cpus, cpu_core_mask(cpu));
+#endif
+
+	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+	policy->cur = corenet_cpufreq_get_speed(policy->cpu);
+
+	cpufreq_frequency_table_get_attr(table, cpu);
+	of_node_put(np);
+
+	return 0;
+
+err_nomem1:
+	kfree(table);
+err_node:
+	of_node_put(data->parent);
+err_nomem2:
+	per_cpu(cpu_data, cpu) = NULL;
+	kfree(data);
+err_np:
+	of_node_put(np);
+
+	return -ENODEV;
+}
+
+static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+	struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
+
+	cpufreq_frequency_table_put_attr(policy->cpu);
+	of_node_put(data->parent);
+	kfree(data->table);
+	kfree(data);
+	per_cpu(cpu_data, policy->cpu) = NULL;
+
+	return 0;
+}
+
+static int corenet_cpufreq_verify(struct cpufreq_policy *policy)
+{
+	struct cpufreq_frequency_table *table =
+		per_cpu(cpu_data, policy->cpu)->table;
+
+	return cpufreq_frequency_table_verify(policy, table);
+}
+
+static int corenet_cpufreq_target(struct cpufreq_policy *policy,
+		unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	unsigned int new;
+	struct clk *parent;
+	int ret;
+	struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
+
+	cpufreq_frequency_table_target(policy, data->table,
+			target_freq, relation, &new);
+
+	if (policy->cur == data->table[new].frequency)
+		return 0;
+
+	freqs.old = policy->cur;
+	freqs.new = data->table[new].frequency;
+	freqs.cpu = policy->cpu;
+
+	mutex_lock(&cpufreq_lock);
+	cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+
+	parent = of_clk_get(data->parent, new);
+	ret = clk_set_parent(data->clk, parent);
+	if (ret) {
+		freqs.new = freqs.old;
+		cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+		mutex_unlock(&cpufreq_lock);
+		return ret;
+	}
+
+	cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+	mutex_unlock(&cpufreq_lock);
+
+	return 0;
+}
+
+static struct freq_attr *corenet_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver ppc_corenet_cpufreq_driver = {
+	.name		= "ppc_cpufreq",
+	.owner		= THIS_MODULE,
+	.flags		= CPUFREQ_CONST_LOOPS,
+	.init		= corenet_cpufreq_cpu_init,
+	.exit		= __exit_p(corenet_cpufreq_cpu_exit),
+	.verify		= corenet_cpufreq_verify,
+	.target		= corenet_cpufreq_target,
+	.get		= corenet_cpufreq_get_speed,
+	.attr		= corenet_cpufreq_attr,
+};
+
+static const struct of_device_id node_matches[] __initconst = {
+	{ .compatible = "fsl,qoriq-clockgen-1.0", },
+	{ .compatible = "fsl,qoriq-clockgen-2", },
+	{}
+};
+
+static int __init ppc_corenet_cpufreq_init(void)
+{
+	int ret = 0;
+	struct device_node  *np;
+
+	np = of_find_matching_node(NULL, node_matches);
+	if (!np)
+		return -ENODEV;
+
+	of_node_put(np);
+
+	ret = cpufreq_register_driver(&ppc_corenet_cpufreq_driver);
+	if (!ret)
+		pr_info("Freescale PowerPC corenet CPU frequency scaling driver\n");
+
+	return ret;
+}
+module_init(ppc_corenet_cpufreq_init);
+
+static void __exit ppc_corenet_cpufreq_exit(void)
+{
+	cpufreq_unregister_driver(&ppc_corenet_cpufreq_driver);
+}
+module_exit(ppc_corenet_cpufreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>");
+MODULE_DESCRIPTION("cpufreq driver for Freescale e500mc series SoCs");
-- 
1.8.0

^ permalink raw reply related

* Re: [PATCH v4] cpufreq: powerpc: Add cpufreq driver for Freescale e500mc SoCs
From: Viresh Kumar @ 2013-04-09  9:47 UTC (permalink / raw)
  To: Yuantian.Tang; +Cc: linux-pm, linux-kernel, cpufreq, rjw, linuxppc-dev
In-Reply-To: <1365496365-28450-1-git-send-email-Yuantian.Tang@freescale.com>

Mostly good now, V5 should be the final one.

On 9 April 2013 14:02,  <Yuantian.Tang@freescale.com> wrote:
> diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c

> +static int corenet_cpufreq_target(struct cpufreq_policy *policy,
> +               unsigned int target_freq, unsigned int relation)
> +{
> +       struct cpufreq_freqs freqs;
> +       unsigned int new;
> +       struct clk *parent;
> +       int ret;
> +       struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
> +
> +       cpufreq_frequency_table_target(policy, data->table,
> +                       target_freq, relation, &new);
> +
> +       if (policy->cur == data->table[new].frequency)
> +               return 0;
> +
> +       freqs.old = policy->cur;
> +       freqs.new = data->table[new].frequency;
> +       freqs.cpu = policy->cpu;

You don't need to set freqs.cpu..

> +       mutex_lock(&cpufreq_lock);
> +       cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
> +
> +       parent = of_clk_get(data->parent, new);
> +       ret = clk_set_parent(data->clk, parent);
> +       if (ret) {
> +               freqs.new = freqs.old;
> +               cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
> +               mutex_unlock(&cpufreq_lock);
> +               return ret;
> +       }
> +
> +       cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
> +       mutex_unlock(&cpufreq_lock);

What about writing it as:

+       ret = clk_set_parent(data->clk, parent);
+       if (ret)
+               freqs.new = freqs.old;
+
+       cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+       mutex_unlock(&cpufreq_lock);

return ret;

> +       return 0;
> +}

^ permalink raw reply

* RE: [PATCH v4] cpufreq: powerpc: Add cpufreq driver for Freescale e500mc SoCs
From: Tang Yuantian-B29983 @ 2013-04-09 10:04 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: Li Yang-R58472, linux-pm@vger.kernel.org,
	linux-kernel@vger.kernel.org, cpufreq@vger.kernel.org,
	rjw@sisk.pl, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <CAKohpokVf0hCokDL62WeaUdYEBycf+Kh_cRgWxTR--_12xjEBA@mail.gmail.com>

VGhhbmtzLCB5b3UgbWFrZSBteSBjb2RlIGxvb2sgYmV0dGVyIGVhY2ggcmV2aWV3Lg0KDQpUaGFu
a3MsDQpZdWFudGlhbg0KDQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTog
VmlyZXNoIEt1bWFyIFttYWlsdG86dmlyZXNoLmt1bWFyQGxpbmFyby5vcmddDQo+IFNlbnQ6IDIw
MTPE6jTUwjnI1SAxNzo0Nw0KPiBUbzogVGFuZyBZdWFudGlhbi1CMjk5ODMNCj4gQ2M6IHJqd0Bz
aXNrLnBsOyBjcHVmcmVxQHZnZXIua2VybmVsLm9yZzsgbGludXgtcG1Admdlci5rZXJuZWwub3Jn
Ow0KPiBsaW51eC1rZXJuZWxAdmdlci5rZXJuZWwub3JnOyBsaW51eHBwYy1kZXZAbGlzdHMub3ps
YWJzLm9yZzsgTGkgWWFuZy0NCj4gUjU4NDcyDQo+IFN1YmplY3Q6IFJlOiBbUEFUQ0ggdjRdIGNw
dWZyZXE6IHBvd2VycGM6IEFkZCBjcHVmcmVxIGRyaXZlciBmb3INCj4gRnJlZXNjYWxlIGU1MDBt
YyBTb0NzDQo+IA0KPiBNb3N0bHkgZ29vZCBub3csIFY1IHNob3VsZCBiZSB0aGUgZmluYWwgb25l
Lg0KPiANCj4gT24gOSBBcHJpbCAyMDEzIDE0OjAyLCAgPFl1YW50aWFuLlRhbmdAZnJlZXNjYWxl
LmNvbT4gd3JvdGU6DQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvY3B1ZnJlcS9wcGMtY29yZW5l
dC1jcHVmcmVxLmMNCj4gPiBiL2RyaXZlcnMvY3B1ZnJlcS9wcGMtY29yZW5ldC1jcHVmcmVxLmMN
Cj4gDQo+ID4gK3N0YXRpYyBpbnQgY29yZW5ldF9jcHVmcmVxX3RhcmdldChzdHJ1Y3QgY3B1ZnJl
cV9wb2xpY3kgKnBvbGljeSwNCj4gPiArICAgICAgICAgICAgICAgdW5zaWduZWQgaW50IHRhcmdl
dF9mcmVxLCB1bnNpZ25lZCBpbnQgcmVsYXRpb24pIHsNCj4gPiArICAgICAgIHN0cnVjdCBjcHVm
cmVxX2ZyZXFzIGZyZXFzOw0KPiA+ICsgICAgICAgdW5zaWduZWQgaW50IG5ldzsNCj4gPiArICAg
ICAgIHN0cnVjdCBjbGsgKnBhcmVudDsNCj4gPiArICAgICAgIGludCByZXQ7DQo+ID4gKyAgICAg
ICBzdHJ1Y3QgY3B1X2RhdGEgKmRhdGEgPSBwZXJfY3B1KGNwdV9kYXRhLCBwb2xpY3ktPmNwdSk7
DQo+ID4gKw0KPiA+ICsgICAgICAgY3B1ZnJlcV9mcmVxdWVuY3lfdGFibGVfdGFyZ2V0KHBvbGlj
eSwgZGF0YS0+dGFibGUsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0X2ZyZXEs
IHJlbGF0aW9uLCAmbmV3KTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAocG9saWN5LT5jdXIgPT0g
ZGF0YS0+dGFibGVbbmV3XS5mcmVxdWVuY3kpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiAw
Ow0KPiA+ICsNCj4gPiArICAgICAgIGZyZXFzLm9sZCA9IHBvbGljeS0+Y3VyOw0KPiA+ICsgICAg
ICAgZnJlcXMubmV3ID0gZGF0YS0+dGFibGVbbmV3XS5mcmVxdWVuY3k7DQo+ID4gKyAgICAgICBm
cmVxcy5jcHUgPSBwb2xpY3ktPmNwdTsNCj4gDQo+IFlvdSBkb24ndCBuZWVkIHRvIHNldCBmcmVx
cy5jcHUuLg0KPiANCj4gPiArICAgICAgIG11dGV4X2xvY2soJmNwdWZyZXFfbG9jayk7DQo+ID4g
KyAgICAgICBjcHVmcmVxX25vdGlmeV90cmFuc2l0aW9uKHBvbGljeSwgJmZyZXFzLCBDUFVGUkVR
X1BSRUNIQU5HRSk7DQo+ID4gKw0KPiA+ICsgICAgICAgcGFyZW50ID0gb2ZfY2xrX2dldChkYXRh
LT5wYXJlbnQsIG5ldyk7DQo+ID4gKyAgICAgICByZXQgPSBjbGtfc2V0X3BhcmVudChkYXRhLT5j
bGssIHBhcmVudCk7DQo+ID4gKyAgICAgICBpZiAocmV0KSB7DQo+ID4gKyAgICAgICAgICAgICAg
IGZyZXFzLm5ldyA9IGZyZXFzLm9sZDsNCj4gPiArICAgICAgICAgICAgICAgY3B1ZnJlcV9ub3Rp
ZnlfdHJhbnNpdGlvbihwb2xpY3ksICZmcmVxcywNCj4gQ1BVRlJFUV9QT1NUQ0hBTkdFKTsNCj4g
PiArICAgICAgICAgICAgICAgbXV0ZXhfdW5sb2NrKCZjcHVmcmVxX2xvY2spOw0KPiA+ICsgICAg
ICAgICAgICAgICByZXR1cm4gcmV0Ow0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAg
IGNwdWZyZXFfbm90aWZ5X3RyYW5zaXRpb24ocG9saWN5LCAmZnJlcXMsIENQVUZSRVFfUE9TVENI
QU5HRSk7DQo+ID4gKyAgICAgICBtdXRleF91bmxvY2soJmNwdWZyZXFfbG9jayk7DQo+IA0KPiBX
aGF0IGFib3V0IHdyaXRpbmcgaXQgYXM6DQo+IA0KPiArICAgICAgIHJldCA9IGNsa19zZXRfcGFy
ZW50KGRhdGEtPmNsaywgcGFyZW50KTsNCj4gKyAgICAgICBpZiAocmV0KQ0KPiArICAgICAgICAg
ICAgICAgZnJlcXMubmV3ID0gZnJlcXMub2xkOw0KPiArDQo+ICsgICAgICAgY3B1ZnJlcV9ub3Rp
ZnlfdHJhbnNpdGlvbihwb2xpY3ksICZmcmVxcywgQ1BVRlJFUV9QT1NUQ0hBTkdFKTsNCj4gKyAg
ICAgICBtdXRleF91bmxvY2soJmNwdWZyZXFfbG9jayk7DQo+IA0KPiByZXR1cm4gcmV0Ow0KPiAN
Cj4gPiArICAgICAgIHJldHVybiAwOw0KPiA+ICt9DQoNCg==

^ permalink raw reply

* [PATCH] powerpc/crypto: Add property for 'era' in SEC dts crypto node
From: Vakul Garg @ 2013-04-09 11:50 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Shaveta Leekha, linux-kernel, Paul Mackerras, Andy Fleming

The crypto node now contains a new property 'fsl,sec-era'.
This is required so that applications can retrieve era info without
having to be able to read SEC's register space.

Signed-off-by: Vakul Garg <vakul@freescale.com>
---
 arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi   |    1 +
 arch/powerpc/boot/dts/fsl/qoriq-sec4.0-0.dtsi |    1 +
 arch/powerpc/boot/dts/fsl/qoriq-sec4.2-0.dtsi |    1 +
 arch/powerpc/boot/dts/fsl/qoriq-sec5.0-0.dtsi |    1 +
 arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi |    1 +
 arch/powerpc/boot/dts/fsl/qoriq-sec5.3-0.dtsi |    1 +
 6 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi
index ffadcb5..bb3d826 100644
--- a/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi
+++ b/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi
@@ -34,6 +34,7 @@
 
 crypto@30000 {
 	compatible = "fsl,sec-v4.4", "fsl,sec-v4.0";
+	fsl,sec-era = <3>;
 	#address-cells = <1>;
 	#size-cells = <1>;
 	ranges		 = <0x0 0x30000 0x10000>;
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-sec4.0-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-sec4.0-0.dtsi
index 0cbbac3..02bee5f 100644
--- a/arch/powerpc/boot/dts/fsl/qoriq-sec4.0-0.dtsi
+++ b/arch/powerpc/boot/dts/fsl/qoriq-sec4.0-0.dtsi
@@ -34,6 +34,7 @@
 
 crypto: crypto@300000 {
 	compatible = "fsl,sec-v4.0";
+	fsl,sec-era = <1>;
 	#address-cells = <1>;
 	#size-cells = <1>;
 	reg = <0x300000 0x10000>;
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-sec4.2-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-sec4.2-0.dtsi
index 7990e0d..7f7574e 100644
--- a/arch/powerpc/boot/dts/fsl/qoriq-sec4.2-0.dtsi
+++ b/arch/powerpc/boot/dts/fsl/qoriq-sec4.2-0.dtsi
@@ -34,6 +34,7 @@
 
 crypto: crypto@300000 {
 	compatible = "fsl,sec-v4.2", "fsl,sec-v4.0";
+	fsl,sec-era = <3>;
 	#address-cells = <1>;
 	#size-cells = <1>;
 	reg		 = <0x300000 0x10000>;
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-sec5.0-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-sec5.0-0.dtsi
index ffd458f..e298efb 100644
--- a/arch/powerpc/boot/dts/fsl/qoriq-sec5.0-0.dtsi
+++ b/arch/powerpc/boot/dts/fsl/qoriq-sec5.0-0.dtsi
@@ -34,6 +34,7 @@
 
 crypto: crypto@300000 {
 	compatible = "fsl,sec-v5.0", "fsl,sec-v4.0";
+	fsl,sec-era = <5>;
 	#address-cells = <1>;
 	#size-cells = <1>;
 	reg		 = <0x300000 0x10000>;
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi
index 7b2ab8a..33ff09d 100644
--- a/arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi
+++ b/arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi
@@ -34,6 +34,7 @@
 
 crypto: crypto@300000 {
 	compatible = "fsl,sec-v5.2", "fsl,sec-v5.0", "fsl,sec-v4.0";
+	fsl,sec-era = <5>;
 	#address-cells = <1>;
 	#size-cells = <1>;
 	reg		 = <0x300000 0x10000>;
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-sec5.3-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-sec5.3-0.dtsi
index 0339825..0877822 100644
--- a/arch/powerpc/boot/dts/fsl/qoriq-sec5.3-0.dtsi
+++ b/arch/powerpc/boot/dts/fsl/qoriq-sec5.3-0.dtsi
@@ -34,6 +34,7 @@
 
 crypto: crypto@300000 {
 	compatible = "fsl,sec-v5.3", "fsl,sec-v5.0", "fsl,sec-v4.0";
+	fsl,sec-era = <4>;
 	#address-cells = <1>;
 	#size-cells = <1>;
 	reg		 = <0x300000 0x10000>;
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH] powerpc/perf: Add an explict flag indicating presence of SLOT field
From: Michael Ellerman @ 2013-04-09 13:41 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: sukadev, Paul Mackerras, Anton Blanchard

In perf_ip_adjust() we potentially use the MMCRA[SLOT] field to adjust
the reported IP of a sampled instruction.

Currently the logic is written so that if the backend does NOT have
the PPMU_ALT_SIPR flag set then we assume MMCRA[SLOT] exists.

This is wrong on power7, where we have SIPR in the "alternate" location,
but also have the MMCRA[SLOT] field. Furthermore on power8 we do not
want to set ALT_SIPR (it's in a third location), and we also do not have
MMCRA[SLOT].

So add a new flag which only indicates whether MMCRA[SLOT] exists.

Naively we'd set it on everything except power6/7, because they set
ALT_SIPR, and we've reversed the polarity of the flag. But it's more
complicated than that.

mpc7450 is 32-bit, and uses its own version of perf_ip_adjust()
which doesn't use MMCRA[SLOT], so it doesn't need the new flag set and
the behaviour is unchanged.

PPC970 (and I assume power4) don't have MMCRA[SLOT], so shouldn't have
the new flag set. This is a behaviour change on those cpus, though we
were probably getting lucky and the bits in question were 0.

power5 and power5+ set the new flag, behaviour unchanged.

power6 does not set the new flag, behaviour unchanged.

power7 sets the new flag, which is a behaviour change.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

I went mildly insane working out all the different cases in this patch, so
any review appreciated.

 arch/powerpc/include/asm/perf_event_server.h |    1 +
 arch/powerpc/perf/core-book3s.c              |    3 ++-
 arch/powerpc/perf/power5+-pmu.c              |    2 +-
 arch/powerpc/perf/power5-pmu.c               |    1 +
 arch/powerpc/perf/power7-pmu.c               |    2 +-
 5 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h
index d0aec72..7074aec 100644
--- a/arch/powerpc/include/asm/perf_event_server.h
+++ b/arch/powerpc/include/asm/perf_event_server.h
@@ -52,6 +52,7 @@ struct power_pmu {
 #define PPMU_NO_SIPR		0x00000004 /* no SIPR/HV in MMCRA at all */
 #define PPMU_NO_CONT_SAMPLING	0x00000008 /* no continuous sampling */
 #define PPMU_SIAR_VALID		0x00000010 /* Processor has SIAR Valid bit */
+#define PPMU_HAS_SSLOT		0x00000020 /* Has sampled slot in MMCRA */
 
 /*
  * Values for flags to get_alternatives()
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 65362e9..eb64480 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -98,11 +98,12 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
 {
 	unsigned long mmcra = regs->dsisr;
 
-	if ((mmcra & MMCRA_SAMPLE_ENABLE) && !(ppmu->flags & PPMU_ALT_SIPR)) {
+	if ((ppmu->flags & PPMU_HAS_SSLOT) && (mmcra & MMCRA_SAMPLE_ENABLE)) {
 		unsigned long slot = (mmcra & MMCRA_SLOT) >> MMCRA_SLOT_SHIFT;
 		if (slot > 1)
 			return 4 * (slot - 1);
 	}
+
 	return 0;
 }
 
diff --git a/arch/powerpc/perf/power5+-pmu.c b/arch/powerpc/perf/power5+-pmu.c
index a8757ba..b03b6dc 100644
--- a/arch/powerpc/perf/power5+-pmu.c
+++ b/arch/powerpc/perf/power5+-pmu.c
@@ -671,7 +671,7 @@ static struct power_pmu power5p_pmu = {
 	.get_alternatives	= power5p_get_alternatives,
 	.disable_pmc		= power5p_disable_pmc,
 	.limited_pmc_event	= power5p_limited_pmc_event,
-	.flags			= PPMU_LIMITED_PMC5_6,
+	.flags			= PPMU_LIMITED_PMC5_6 | PPMU_HAS_SSLOT,
 	.n_generic		= ARRAY_SIZE(power5p_generic_events),
 	.generic_events		= power5p_generic_events,
 	.cache_events		= &power5p_cache_events,
diff --git a/arch/powerpc/perf/power5-pmu.c b/arch/powerpc/perf/power5-pmu.c
index e7f06eb..1e8ce42 100644
--- a/arch/powerpc/perf/power5-pmu.c
+++ b/arch/powerpc/perf/power5-pmu.c
@@ -615,6 +615,7 @@ static struct power_pmu power5_pmu = {
 	.n_generic		= ARRAY_SIZE(power5_generic_events),
 	.generic_events		= power5_generic_events,
 	.cache_events		= &power5_cache_events,
+	.flags			= PPMU_HAS_SSLOT,
 };
 
 static int __init init_power5_pmu(void)
diff --git a/arch/powerpc/perf/power7-pmu.c b/arch/powerpc/perf/power7-pmu.c
index 3c475d6..744a5cf 100644
--- a/arch/powerpc/perf/power7-pmu.c
+++ b/arch/powerpc/perf/power7-pmu.c
@@ -448,7 +448,7 @@ static struct power_pmu power7_pmu = {
 	.get_constraint		= power7_get_constraint,
 	.get_alternatives	= power7_get_alternatives,
 	.disable_pmc		= power7_disable_pmc,
-	.flags			= PPMU_ALT_SIPR,
+	.flags			= PPMU_ALT_SIPR | PPMU_HAS_SSLOT,
 	.attr_groups		= power7_pmu_attr_groups,
 	.n_generic		= ARRAY_SIZE(power7_generic_events),
 	.generic_events		= power7_generic_events,
-- 
1.7.10.4

^ permalink raw reply related

* Re: powerpc userspace address space layout information
From: Chris Friesen @ 2013-04-09 14:30 UTC (permalink / raw)
  To: David Gibson; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <20130407055844.GB17787@truffula.fritz.box>

On 04/06/2013 11:58 PM, David Gibson wrote:
> On Thu, Apr 04, 2013 at 10:53:58PM -0600, Chris Friesen wrote:

>> Third, what's the most reliable way to ensure a block of addresses around
>> 0xf6000000 don't get used for shared libraries?  (We want to preserve
>> those addresses for emulating hardware in a virtual machine.)  We have
>> this working on an older system but after upgrading to new software the
>> libraries now extend further down the address space.
>
> The only reliable method I can think of would be to use a custom
> linker script to give your binary an extra program header specifying
> that virtual region to map.

Thanks for your help.  We had started working on the custom linker 
script while waiting to see if anyone would respond, so it's good to get 
some validation that we picked the right solution.

Chris

^ permalink raw reply

* [PATCH] powerpc/fsl-booke: Minor fixes to T4240 Si device tree
From: Kumar Gala @ 2013-04-09 14:53 UTC (permalink / raw)
  To: linuxppc-dev

* Fix cpu unit address to match reg
* Update compatible for rcpm & clockgen to be 2.0 instead of 2

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/boot/dts/fsl/t4240si-post.dtsi |    4 ++--
 arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi  |   22 +++++++++++-----------
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi b/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
index 1d72926..e77e6ad 100644
--- a/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t4240si-post.dtsi
@@ -364,12 +364,12 @@
 	};
 
 	clockgen: global-utilities@e1000 {
-		compatible = "fsl,t4240-clockgen", "fsl,qoriq-clockgen-2";
+		compatible = "fsl,t4240-clockgen", "fsl,qoriq-clockgen-2.0";
 		reg = <0xe1000 0x1000>;
 	};
 
 	rcpm: global-utilities@e2000 {
-		compatible = "fsl,t4240-rcpm", "fsl,qoriq-rcpm-2";
+		compatible = "fsl,t4240-rcpm", "fsl,qoriq-rcpm-2.0";
 		reg = <0xe2000 0x1000>;
 	};
 
diff --git a/arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi b/arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi
index 9b39a43..a93c55a 100644
--- a/arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/t4240si-pre.dtsi
@@ -69,57 +69,57 @@
 			reg = <0 1>;
 			next-level-cache = <&L2_1>;
 		};
-		cpu1: PowerPC,e6500@1 {
+		cpu1: PowerPC,e6500@2 {
 			device_type = "cpu";
 			reg = <2 3>;
 			next-level-cache = <&L2_1>;
 		};
-		cpu2: PowerPC,e6500@2 {
+		cpu2: PowerPC,e6500@4 {
 			device_type = "cpu";
 			reg = <4 5>;
 			next-level-cache = <&L2_1>;
 		};
-		cpu3: PowerPC,e6500@3 {
+		cpu3: PowerPC,e6500@6 {
 			device_type = "cpu";
 			reg = <6 7>;
 			next-level-cache = <&L2_1>;
 		};
-		cpu4: PowerPC,e6500@4 {
+		cpu4: PowerPC,e6500@8 {
 			device_type = "cpu";
 			reg = <8 9>;
 			next-level-cache = <&L2_2>;
 		};
-		cpu5: PowerPC,e6500@5 {
+		cpu5: PowerPC,e6500@10 {
 			device_type = "cpu";
 			reg = <10 11>;
 			next-level-cache = <&L2_2>;
 		};
-		cpu6: PowerPC,e6500@6 {
+		cpu6: PowerPC,e6500@12 {
 			device_type = "cpu";
 			reg = <12 13>;
 			next-level-cache = <&L2_2>;
 		};
-		cpu7: PowerPC,e6500@7 {
+		cpu7: PowerPC,e6500@14 {
 			device_type = "cpu";
 			reg = <14 15>;
 			next-level-cache = <&L2_2>;
 		};
-		cpu8: PowerPC,e6500@8 {
+		cpu8: PowerPC,e6500@16 {
 			device_type = "cpu";
 			reg = <16 17>;
 			next-level-cache = <&L2_3>;
 		};
-		cpu9: PowerPC,e6500@9 {
+		cpu9: PowerPC,e6500@18 {
 			device_type = "cpu";
 			reg = <18 19>;
 			next-level-cache = <&L2_3>;
 		};
-		cpu10: PowerPC,e6500@10 {
+		cpu10: PowerPC,e6500@20 {
 			device_type = "cpu";
 			reg = <20 21>;
 			next-level-cache = <&L2_3>;
 		};
-		cpu11: PowerPC,e6500@11 {
+		cpu11: PowerPC,e6500@22 {
 			device_type = "cpu";
 			reg = <22 23>;
 			next-level-cache = <&L2_3>;
-- 
1.7.9.7

^ permalink raw reply related

* Re: Build regressions/improvements in v3.9-rc6
From: Geert Uytterhoeven @ 2013-04-09 21:07 UTC (permalink / raw)
  To: Linux Kernel Development; +Cc: Linux/PPC Development, linux-sh
In-Reply-To: <alpine.DEB.2.00.1304092304220.23715@ayla.of.borg>

On Tue, 9 Apr 2013, Geert Uytterhoeven wrote:
> JFYI, when comparing v3.9-rc6 to v3.9-rc5[3], the summaries are:
>   - build errors: +8/-13

Ignoring R_PPC64_REL24 truncated relocations, as usual:

  + error: binder.c: undefined reference to `get_vm_area':  => .text+0x2fe8b8)
  + error: binder.c: undefined reference to `map_vm_area':  => .text+0x2fa11c) 
  + error: binder.c: undefined reference to `zap_page_range':  => .text+0x2fa354)

sh4/sh-randconfig

  + error: cuboot-pq2.c: undefined reference to `fsl_get_immr':  => .text+0x314)

powerpc-randconfig

> [1] http://kisskb.ellerman.id.au/kisskb/head/6063/ (all 118 configs)
> [3] http://kisskb.ellerman.id.au/kisskb/head/6041/ (all 118 configs)

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH] powerpc/crypto: Add property for 'era' in SEC dts crypto node
From: Kim Phillips @ 2013-04-09 22:31 UTC (permalink / raw)
  To: Vakul Garg
  Cc: Shaveta Leekha, linux-kernel, Andy Fleming, Paul Mackerras,
	linuxppc-dev
In-Reply-To: <1365508233-26292-1-git-send-email-vakul@freescale.com>

On Tue, 9 Apr 2013 17:20:33 +0530
Vakul Garg <vakul@freescale.com> wrote:

> The crypto node now contains a new property 'fsl,sec-era'.
> This is required so that applications can retrieve era info without
> having to be able to read SEC's register space.
> 
> Signed-off-by: Vakul Garg <vakul@freescale.com>
> ---
>  arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi   |    1 +
>  arch/powerpc/boot/dts/fsl/qoriq-sec4.0-0.dtsi |    1 +
>  arch/powerpc/boot/dts/fsl/qoriq-sec4.2-0.dtsi |    1 +
>  arch/powerpc/boot/dts/fsl/qoriq-sec5.0-0.dtsi |    1 +
>  arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi |    1 +
>  arch/powerpc/boot/dts/fsl/qoriq-sec5.3-0.dtsi |    1 +
>  6 files changed, 6 insertions(+), 0 deletions(-)

missing p1023si-post.dtsi and qoriq-sec4.1-0.dtsi files.

Kim

^ permalink raw reply

* [PATCH] fadump: allow duplicate assignment to /sys/kernel/fadump_registered when it's assigned the desired value already
From: Wang Sheng-Hui @ 2013-04-10  0:46 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras, Suzuki K. Poulose,
	linuxppc-dev

When the fadump is enabled, we have /sys/kernel/fadump_enabled assigned 1.
But sometimes we need to restart the fadump service by 'service kdump restart',
in case the kdump script has added the fadump detect/support already.
In current implementation, we cannot re-assign 1 to /sys/kernel/fadump_enabled
if 1 is already set and we have added more logic check in the user space script.

I think we can enable the duplicate assignment to ease the user space tools,
as long as the value is the right 1 or 0.

Signed-off-by: Wang Sheng-Hui <shhuiw@gmail.com>
---
  arch/powerpc/kernel/fadump.c |    8 ++------
  1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index 06c8202..e1347e5 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -1140,18 +1140,14 @@ static ssize_t fadump_register_store(struct kobject *kobj,

  	switch (buf[0]) {
  	case '0':
-		if (fw_dump.dump_registered == 0) {
-			ret = -EINVAL;
+		if (fw_dump.dump_registered == 0)
  			goto unlock_out;
-		}
  		/* Un-register Firmware-assisted dump */
  		fadump_unregister_dump(&fdm);
  		break;
  	case '1':
-		if (fw_dump.dump_registered == 1) {
-			ret = -EINVAL;
+		if (fw_dump.dump_registered == 1)
  			goto unlock_out;
-		}
  		/* Register Firmware-assisted dump */
  		register_fadump();
  		break;
-- 
1.7.10.4

^ permalink raw reply related

* Re: [PATCH] fadump: allow duplicate assignment to /sys/kernel/fadump_registered when it's assigned the desired value already
From: Mahesh Jagannath Salgaonkar @ 2013-04-10  1:43 UTC (permalink / raw)
  To: Wang Sheng-Hui; +Cc: Paul Mackerras, linuxppc-dev, Suzuki K. Poulose
In-Reply-To: <5164B664.6070306@gmail.com>

On 04/10/2013 06:16 AM, Wang Sheng-Hui wrote:
> When the fadump is enabled, we have /sys/kernel/fadump_enabled assigned 1.
> But sometimes we need to restart the fadump service by 'service kdump
> restart',
> in case the kdump script has added the fadump detect/support already.
> In current implementation, we cannot re-assign 1 to
> /sys/kernel/fadump_enabled

I assume you meant /sys/kernel/fadump_registered here. Ideally service
kdump restart should first echo 0 to /sys/kernel/fadump_registered to
un-register fadump before echo 1 to /sys/kernel/fadump_registered for
re-registration. I would fix the user space tool than changing the
kernel code.

> if 1 is already set and we have added more logic check in the user space
> script.
> 
> I think we can enable the duplicate assignment to ease the user space
> tools,
> as long as the value is the right 1 or 0.
> 
> Signed-off-by: Wang Sheng-Hui <shhuiw@gmail.com>
> ---
>  arch/powerpc/kernel/fadump.c |    8 ++------
>  1 file changed, 2 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
> index 06c8202..e1347e5 100644
> --- a/arch/powerpc/kernel/fadump.c
> +++ b/arch/powerpc/kernel/fadump.c
> @@ -1140,18 +1140,14 @@ static ssize_t fadump_register_store(struct
> kobject *kobj,
> 
>      switch (buf[0]) {
>      case '0':
> -        if (fw_dump.dump_registered == 0) {
> -            ret = -EINVAL;
> +        if (fw_dump.dump_registered == 0)
>              goto unlock_out;
> -        }
>          /* Un-register Firmware-assisted dump */
>          fadump_unregister_dump(&fdm);
>          break;
>      case '1':
> -        if (fw_dump.dump_registered == 1) {
> -            ret = -EINVAL;
> +        if (fw_dump.dump_registered == 1)
>              goto unlock_out;
> -        }
>          /* Register Firmware-assisted dump */
>          register_fadump();
>          break;

^ permalink raw reply

* Re: [RFC PATCH powerpc] try secondary hash before BUG in kernel_map_linear_page()
From: Michael Ellerman @ 2013-04-10  2:21 UTC (permalink / raw)
  To: Li Zhong; +Cc: Paul Mackerras, PowerPC email list
In-Reply-To: <1361784575.3001.5.camel@ThinkPad-T5421.cn.ibm.com>

On Mon, Feb 25, 2013 at 05:29:35PM +0800, Li Zhong wrote:
> This patch tries to fix following issue when CONFIG_DEBUG_PAGEALLOC
> is enabled:
> 
> [  543.075675] ------------[ cut here ]------------
> [  543.075701] kernel BUG at arch/powerpc/mm/hash_utils_64.c:1239!
> [  543.075714] Oops: Exception in kernel mode, sig: 5 [#1]

So the issue is that kernel_map_linear_page() doesn't try the secondary
hash slot.

> The code is borrowed from that in __hash_page_huge().

It is, and in fact there is another copy in hash_low_64.S - in assembler.

So I think we should at least try and keep ourselves to two
implementations, one in asm and one in C. So can you split it out into a
helper routine called by both kernel_map_linear_page() and
__hash_page_huge() ?

cheers

^ permalink raw reply

* RE: [PATCH V4] powerpc/MPIC: Add get_version API both for internal and external use
From: Jia Hongtao-B38951 @ 2013-04-10  2:22 UTC (permalink / raw)
  To: Wood Scott-B07421, galak@kernel.crashing.org
  Cc: linuxppc-dev@lists.ozlabs.org, Li Yang-R58472, Jia Hongtao-B38951
In-Reply-To: <1365386514-14647-1-git-send-email-hongtao.jia@freescale.com>

Hi Kumar and Scott,

Any more comments for this patch and MSI-X erratum patch?

Thanks.
-Hongtao.



> -----Original Message-----
> From: Jia Hongtao-B38951
> Sent: Monday, April 08, 2013 10:02 AM
> To: linuxppc-dev@lists.ozlabs.org; galak@kernel.crashing.org
> Cc: Wood Scott-B07421; Li Yang-R58472; Jia Hongtao-B38951
> Subject: [PATCH V4] powerpc/MPIC: Add get_version API both for internal
> and external use
>=20
> MPIC version is useful information for both mpic_alloc() and mpic_init().
> The patch provide an API to get MPIC version for reusing the code.
> Also, some other IP block may need MPIC version for their own use.
> The API for external use is also provided.
>=20
> Signed-off-by: Jia Hongtao <hongtao.jia@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
> ---
> Changes for V4:
> * change the name of function from mpic_get_version() to
>   fsl_mpic_get_version().
>=20
> Changes for V3:
> * change the name of function from mpic_primary_get_version() to
>   fsl_mpic_primary_get_version().
> * return 0 if mpic_primary is null.
>=20
> Changes for V2:
> * Using mpic_get_version() to implement mpic_primary_get_version()
>=20
>  arch/powerpc/include/asm/mpic.h |  3 +++
>  arch/powerpc/sysdev/mpic.c      | 29 ++++++++++++++++++++++-------
>  2 files changed, 25 insertions(+), 7 deletions(-)
>=20
> diff --git a/arch/powerpc/include/asm/mpic.h
> b/arch/powerpc/include/asm/mpic.h index c0f9ef9..ea6bf72 100644
> --- a/arch/powerpc/include/asm/mpic.h
> +++ b/arch/powerpc/include/asm/mpic.h
> @@ -393,6 +393,9 @@ struct mpic
>  #define	MPIC_REGSET_STANDARD		MPIC_REGSET(0)	/* Original
> MPIC */
>  #define	MPIC_REGSET_TSI108		MPIC_REGSET(1)	/* Tsi108/109
> PIC */
>=20
> +/* Get the version of primary MPIC */
> +extern u32 fsl_mpic_primary_get_version(void);
> +
>  /* Allocate the controller structure and setup the linux irq descs
>   * for the range if interrupts passed in. No HW initialization is
>   * actually performed.
> diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
> index d30e6a6..48c8fae 100644
> --- a/arch/powerpc/sysdev/mpic.c
> +++ b/arch/powerpc/sysdev/mpic.c
> @@ -1165,10 +1165,30 @@ static struct irq_domain_ops mpic_host_ops =3D {
>  	.xlate =3D mpic_host_xlate,
>  };
>=20
> +static u32 fsl_mpic_get_version(struct mpic *mpic) {
> +	u32 brr1;
> +
> +	brr1 =3D _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
> +			MPIC_FSL_BRR1);
> +
> +	return brr1 & MPIC_FSL_BRR1_VER;
> +}
> +
>  /*
>   * Exported functions
>   */
>=20
> +u32 fsl_mpic_primary_get_version(void)
> +{
> +	struct mpic *mpic =3D mpic_primary;
> +
> +	if (mpic)
> +		return fsl_mpic_get_version(mpic);
> +
> +	return 0;
> +}
> +
>  struct mpic * __init mpic_alloc(struct device_node *node,
>  				phys_addr_t phys_addr,
>  				unsigned int flags,
> @@ -1315,7 +1335,6 @@ struct mpic * __init mpic_alloc(struct device_node
> *node,
>  	mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE),
> 0x1000);
>=20
>  	if (mpic->flags & MPIC_FSL) {
> -		u32 brr1;
>  		int ret;
>=20
>  		/*
> @@ -1326,9 +1345,7 @@ struct mpic * __init mpic_alloc(struct device_node
> *node,
>  		mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs,
>  			 MPIC_CPU_THISBASE, 0x1000);
>=20
> -		brr1 =3D _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
> -				MPIC_FSL_BRR1);
> -		fsl_version =3D brr1 & MPIC_FSL_BRR1_VER;
> +		fsl_version =3D fsl_mpic_get_version(mpic);
>=20
>  		/* Error interrupt mask register (EIMR) is required for
>  		 * handling individual device error interrupts. EIMR @@ -
> 1518,9 +1535,7 @@ void __init mpic_init(struct mpic *mpic)
>  	mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
>=20
>  	if (mpic->flags & MPIC_FSL) {
> -		u32 brr1 =3D _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
> -				      MPIC_FSL_BRR1);
> -		u32 version =3D brr1 & MPIC_FSL_BRR1_VER;
> +		u32 version =3D fsl_mpic_get_version(mpic);
>=20
>  		/*
>  		 * Timer group B is present at the latest in MPIC 3.1 (e.g.
> --
> 1.8.0

^ permalink raw reply

* RE: [PATCH V5] powerpc/85xx: Add machine check handler to fix PCIe erratum on mpc85xx
From: Jia Hongtao-B38951 @ 2013-04-10  2:27 UTC (permalink / raw)
  To: Wood Scott-B07421
  Cc: Jia Hongtao-B38951, linuxppc-dev@lists.ozlabs.org, Li Yang-R58472
In-Reply-To: <1365409614-2634-1-git-send-email-hongtao.jia@freescale.com>

Hi Scott,

I added load instruction handler for the skipped instruction.
For now most common load instructions are handled in this patch.

Any advice for this?

Thanks.
-Hongtao.

> -----Original Message-----
> From: Jia Hongtao-B38951
> Sent: Monday, April 08, 2013 4:27 PM
> To: linuxppc-dev@lists.ozlabs.org; galak@kernel.crashing.org
> Cc: Wood Scott-B07421; Li Yang-R58472; Jia Hongtao-B38951
> Subject: [PATCH V5] powerpc/85xx: Add machine check handler to fix PCIe
> erratum on mpc85xx
>=20
> A PCIe erratum of mpc85xx may causes a core hang when a link of PCIe goes
> down. when the link goes down, Non-posted transactions issued via the
> ATMU requiring completion result in an instruction stall.
> At the same time a machine-check exception is generated to the core to
> allow further processing by the handler. We implements the handler which
> skips the instruction caused the stall.
>=20
> This patch depends on patch:
> powerpc/85xx: Add platform_device declaration to fsl_pci.h
>=20
> Signed-off-by: Zhao Chenhui <b35336@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
> Signed-off-by: Liu Shuo <soniccat.liu@gmail.com>
> Signed-off-by: Jia Hongtao <hongtao.jia@freescale.com>
> ---
> Changes for V4:
> * Fill rd with all-Fs if the skipped instruction is load and emulate the
>   instruction.
> * Let KVM/QEMU deal with the exception if the machine check comes from
> KVM.
>=20
>  arch/powerpc/kernel/cpu_setup_fsl_booke.S |   2 +-
>  arch/powerpc/kernel/traps.c               |   3 +
>  arch/powerpc/sysdev/fsl_pci.c             | 121
> ++++++++++++++++++++++++++++++
>  arch/powerpc/sysdev/fsl_pci.h             |   6 ++
>  4 files changed, 131 insertions(+), 1 deletion(-)
>=20
> diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> index dcd8819..f1bde90 100644
> --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> @@ -66,7 +66,7 @@ _GLOBAL(__setup_cpu_e500v2)
>  	bl	__e500_icache_setup
>  	bl	__e500_dcache_setup
>  	bl	__setup_e500_ivors
> -#ifdef CONFIG_FSL_RIO
> +#if defined(CONFIG_FSL_RIO) || defined(CONFIG_FSL_PCI)
>  	/* Ensure that RFXE is set */
>  	mfspr	r3,SPRN_HID1
>  	oris	r3,r3,HID1_RFXE@h
> diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
> index a008cf5..dd275a4 100644
> --- a/arch/powerpc/kernel/traps.c
> +++ b/arch/powerpc/kernel/traps.c
> @@ -59,6 +59,7 @@
>  #include <asm/fadump.h>
>  #include <asm/switch_to.h>
>  #include <asm/debug.h>
> +#include <sysdev/fsl_pci.h>
>=20
>  #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)  int
> (*__debugger)(struct pt_regs *regs) __read_mostly; @@ -556,6 +557,8 @@
> int machine_check_e500(struct pt_regs *regs)
>  	if (reason & MCSR_BUS_RBERR) {
>  		if (fsl_rio_mcheck_exception(regs))
>  			return 1;
> +		if (fsl_pci_mcheck_exception(regs))
> +			return 1;
>  	}
>=20
>  	printk("Machine check in kernel mode.\n"); diff --git
> a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index
> 682084d..48326cd 100644
> --- a/arch/powerpc/sysdev/fsl_pci.c
> +++ b/arch/powerpc/sysdev/fsl_pci.c
> @@ -26,11 +26,14 @@
>  #include <linux/memblock.h>
>  #include <linux/log2.h>
>  #include <linux/slab.h>
> +#include <linux/uaccess.h>
>=20
>  #include <asm/io.h>
>  #include <asm/prom.h>
>  #include <asm/pci-bridge.h>
> +#include <asm/ppc-pci.h>
>  #include <asm/machdep.h>
> +#include <asm/disassemble.h>
>  #include <sysdev/fsl_soc.h>
>  #include <sysdev/fsl_pci.h>
>=20
> @@ -826,6 +829,124 @@ u64 fsl_pci_immrbar_base(struct pci_controller
> *hose)
>  	return 0;
>  }
>=20
> +#ifdef CONFIG_E500
> +
> +#define OP_LWZ  32
> +#define OP_LWZU 33
> +#define OP_LBZ  34
> +#define OP_LBZU 35
> +#define OP_LHZ  40
> +#define OP_LHZU 41
> +#define OP_LHA  42
> +#define OP_LHAU 43
> +
> +static int mcheck_handle_load(struct pt_regs *regs, u32 inst) {
> +	unsigned int rd, ra, d;
> +
> +	rd =3D get_rt(inst);
> +	ra =3D get_ra(inst);
> +	d =3D get_d(inst);
> +
> +	switch (get_op(inst)) {
> +	case OP_LWZ:
> +		regs->gpr[rd] =3D 0xffffffff;
> +		break;
> +
> +	case OP_LWZU:
> +		regs->gpr[rd] =3D 0xffffffff;
> +		regs->gpr[ra] +=3D (s16)d;
> +		break;
> +
> +	case OP_LBZ:
> +		regs->gpr[rd] =3D 0xff;
> +		break;
> +
> +	case OP_LBZU:
> +		regs->gpr[rd] =3D 0xff;
> +		regs->gpr[ra] +=3D (s16)d;
> +		break;
> +
> +	case OP_LHZ:
> +		regs->gpr[rd] =3D 0xffff;
> +		break;
> +
> +	case OP_LHZU:
> +		regs->gpr[rd] =3D 0xffff;
> +		regs->gpr[ra] +=3D (s16)d;
> +		break;
> +
> +	case OP_LHA:
> +		regs->gpr[rd] =3D 0xffff;
> +		break;
> +
> +	case OP_LHAU:
> +		regs->gpr[rd] =3D 0xffff;
> +		regs->gpr[ra] +=3D (s16)d;
> +		break;
> +
> +	default:
> +		return 0;
> +	}
> +
> +	return 1;
> +}
> +
> +static int is_in_pci_mem_space(phys_addr_t addr) {
> +	struct pci_controller *hose;
> +	struct resource *res;
> +	int i;
> +
> +	list_for_each_entry(hose, &hose_list, list_node) {
> +		if (!early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP))
> +			continue;
> +
> +		for (i =3D 0; i < 3; i++) {
> +			res =3D &hose->mem_resources[i];
> +			if ((res->flags & IORESOURCE_MEM) &&
> +				addr >=3D res->start && addr <=3D res->end)
> +				return 1;
> +		}
> +	}
> +	return 0;
> +}
> +
> +int fsl_pci_mcheck_exception(struct pt_regs *regs) {
> +	u32 inst;
> +	int ret;
> +	phys_addr_t addr =3D 0;
> +
> +	/* Let KVM/QEMU deal with the exception */
> +	if (regs->msr & MSR_GS)
> +		return 0;
> +
> +#ifdef CONFIG_PHYS_64BIT
> +	addr =3D mfspr(SPRN_MCARU);
> +	addr <<=3D 32;
> +#endif
> +	addr +=3D mfspr(SPRN_MCAR);
> +
> +	if (is_in_pci_mem_space(addr)) {
> +		if (user_mode(regs)) {
> +			pagefault_disable();
> +			ret =3D get_user(regs->nip, &inst);
> +			pagefault_enable();
> +		} else {
> +			ret =3D probe_kernel_address(regs->nip, inst);
> +		}
> +
> +		if (mcheck_handle_load(regs, inst)) {
> +			regs->nip +=3D 4;
> +			return 1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +#endif
> +
>  #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)  static
> const struct of_device_id pci_ids[] =3D {
>  	{ .compatible =3D "fsl,mpc8540-pci", },
> diff --git a/arch/powerpc/sysdev/fsl_pci.h
> b/arch/powerpc/sysdev/fsl_pci.h index 851dd56..b0d01ea 100644
> --- a/arch/powerpc/sysdev/fsl_pci.h
> +++ b/arch/powerpc/sysdev/fsl_pci.h
> @@ -115,5 +115,11 @@ static inline int mpc85xx_pci_err_probe(struct
> platform_device *op)  }  #endif
>=20
> +#ifdef CONFIG_FSL_PCI
> +extern int fsl_pci_mcheck_exception(struct pt_regs *); #else static
> +inline int fsl_pci_mcheck_exception(struct pt_regs *regs) {return 0; }
> +#endif
> +
>  #endif /* __POWERPC_FSL_PCI_H */
>  #endif /* __KERNEL__ */
> --
> 1.8.0

^ permalink raw reply


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