* Re: [PATCH] powerpc/booke64: Configurable lazy interrupt disabling
From: Stuart Yoder @ 2012-01-19 19:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Laurentiu Tudor, linuxppc-dev
In-Reply-To: <CALRxmdC_E4Z==4R_2MGHAi3T7mdF9oHx3rBE6Meb+3R1gWF5VQ@mail.gmail.com>
On Thu, Jan 19, 2012 at 1:21 PM, Stuart Yoder <b08248@gmail.com> wrote:
> On Wed, Jan 18, 2012 at 3:10 PM, Benjamin Herrenschmidt
> <benh@kernel.crashing.org> wrote:
>> On Wed, 2012-01-18 at 16:35 +0200, Laurentiu Tudor wrote:
>>> This patch adds a menuconfig option that allows controlling
>>> the lazy interrupt disabling feature implemented by this
>>> commit:
>>>
>>> commit d04c56f73c30a5e593202ecfcf25ed43d42363a2
>>> Author: Paul Mackerras
>>> Date: =A0 Wed Oct 4 16:47:49 2006 +1000
>>>
>>> =A0 =A0 [POWERPC] Lazy interrupt disabling for 64-bit machines
>>>
>>> The code in 'powerpc/include/asm/hw_irq.h' was rearranged and
>>> cleaned-up a bit in order to reduce the number of needed #ifdef's.
>>
>> It's still nasty. Do you have numbers showing that it's worth disabling
>> on BookE ?
>
> It's not just about bare metal performance-- some platforms such as
> the Freescale
> Topaz hypervisor don't provide legacy IACK type interrupt
> acknowledgment, and expect
> the guest to support the external proxy mechanism.
>
> With Topaz, interrupts go directly to guests and we don't want to require=
a
> trap/hcall to do an IACK, as that adds potentially thousands of cycles of
> latency to every interrupt.
>
> As you know, with external proxy interrupts are acknowledged by the
> hardware and it becomes problematic to replay the interrupt in
> the context of lazy EE when interrupts are re-enabled. =A0 The interrupt
> will not fire again when you enable EE.
>
> That is currently the issue, as we can't run the 64-bit kernel on Topaz.
> Our option are:
> =A01) to provide an option to disable lazy EE
> =A02) do some kind of hack to replay interrupts with lazy EE
> =A03) change Topaz to support legacy IACK, but this gets ugly for
> =A0 =A0 =A0various reasons.
>
> Providing a config option to disable lazy EE seemed to be a good
> approach.
Also, Scott had posted an approach to do option #2 a while back,
but as I recall there was some negative feedback about this. See:
<http://lists.ozlabs.org/pipermail/linuxppc-dev/2011-August/092103.html>
Stuart
^ permalink raw reply
* ata/ide driver for MPC512x
From: Matthias Fuchs @ 2012-01-19 21:28 UTC (permalink / raw)
To: linuxppc-dev
Hi,
do we have an ata/ide driver for MPC512x internal ATA controller?
So something that is compatible to "fsl,mpc5121-pata"?
Matthias
^ permalink raw reply
* [PATCH] powerpc/85xx: fix Kconfig warning about missing 8250 dependency
From: Paul Gortmaker @ 2012-01-20 1:23 UTC (permalink / raw)
To: galak, benh, paulus; +Cc: Paul Gortmaker, linuxppc-dev
The SERIAL_8250_EXTENDED option just enables access to other
less regularly used options, like SERIAL_8250_SHARE_IRQ.
Select it to get rid of this warning when selecting the child
option living underneath it.
warning: (FSL_SOC_BOOKE && SERIAL_8250_RM9K) selects
SERIAL_8250_SHARE_IRQ which has unmet direct dependencies
(HAS_IOMEM && SERIAL_8250_EXTENDED)
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index d7946be..b221236 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -6,6 +6,7 @@ menuconfig FSL_SOC_BOOKE
select MPIC
select PPC_PCI_CHOICE
select FSL_PCI if PCI
+ select SERIAL_8250_EXTENDED if SERIAL_8250
select SERIAL_8250_SHARE_IRQ if SERIAL_8250
default y
--
1.7.7.2
^ permalink raw reply related
* [PATCH V2] fsl-sata: I/O load balancing
From: qiang.liu @ 2012-01-20 2:19 UTC (permalink / raw)
To: jgarzik, linux-ide; +Cc: Qiang Liu, linuxppc-dev, linux-kernel
From: Qiang Liu <qiang.liu@freescale.com>
Reduce interrupt signals through reset Interrupt Coalescing Control Reg.
Provide dynamic method to adjust interrupt signals and timer ticks by sysfs.
It is a tradeoff for different applications.
Signed-off-by: Qiang Liu <qiang.liu@freescale.com>
---
change for V2
support dynamic config interrupt coalescing register by /sysfs
test random small file with iometer
Description:
1. fsl-sata interrupt will be raised 130 thousand times when write 8G file
(dd if=/dev/zero of=/dev/sda2 bs=128K count=65536);
2. most of interrupts raised because of only 1-4 commands completed;
3. only 30 thousand times will be raised after set max interrupt threshold,
more interrupts are coalesced as the description of ICC;
Test methods and results:
1. test sequential large file performance,
[root@p2020ds root]# echo 31 524287 > \
/sys/devices/soc.0/ffe18000.sata/intr_coalescing
[root@p2020ds root]# dd if=/dev/zero of=/dev/sda2 bs=128K count=65536 &
[root@p2020ds root]# top
CPU % | dd | flush-8:0 | softirq
---------------------------------------
before | 20-22 | 17-19 | 7
---------------------------------------
after | 18-21 | 15-16 | 5
---------------------------------------
2. test random small file with iometer,
iometer paramters:
4 I/Os burst length, 1MB transfer request size, 100% write, 2MB file size
as default configuration of interrupt coalescing register, 1 interrupts and
no timeout config, total write performance is 119MB per second,
after config with the maximum value, write performance is 110MB per second.
After compare the test results, a configuable interrupt coalescing should be
better when cope with flexible context.
drivers/ata/sata_fsl.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 107 insertions(+), 4 deletions(-)
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 3547000..41ca495 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -6,7 +6,7 @@
* Author: Ashish Kalra <ashish.kalra@freescale.com>
* Li Yang <leoli@freescale.com>
*
- * Copyright (c) 2006-2007, 2011 Freescale Semiconductor, Inc.
+ * Copyright (c) 2006-2007, 2011-2012 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
@@ -26,6 +26,15 @@
#include <asm/io.h>
#include <linux/of_platform.h>
+static unsigned int intr_coalescing_count;
+module_param(intr_coalescing_count, int, S_IRUGO);
+MODULE_PARM_DESC(intr_coalescing_count,
+ "INT coalescing count threshold (1..31)");
+
+static unsigned int intr_coalescing_ticks;
+module_param(intr_coalescing_ticks, int, S_IRUGO);
+MODULE_PARM_DESC(intr_coalescing_ticks,
+ "INT coalescing timer threshold in AHB ticks");
/* Controller information */
enum {
SATA_FSL_QUEUE_DEPTH = 16,
@@ -83,6 +92,16 @@ enum {
};
/*
+ * Interrupt Coalescing Control Register bitdefs */
+enum {
+ ICC_MIN_INT_COUNT_THRESHOLD = 1,
+ ICC_MAX_INT_COUNT_THRESHOLD = ((1 << 5) - 1),
+ ICC_MIN_INT_TICKS_THRESHOLD = 0,
+ ICC_MAX_INT_TICKS_THRESHOLD = ((1 << 19) - 1),
+ ICC_SAFE_INT_TICKS = 1,
+};
+
+/*
* Host Controller command register set - per port
*/
enum {
@@ -263,9 +282,66 @@ struct sata_fsl_host_priv {
int irq;
int data_snoop;
u32 quirks;
+ struct device_attribute intr_coalescing;
#define SATA_FSL_QUIRK_P3P5_ERRATA (1 << 0)
};
+static void fsl_sata_set_irq_coalescing(struct ata_host *host,
+ unsigned int count, unsigned int ticks)
+{
+ struct sata_fsl_host_priv *host_priv = host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+
+ if (count > ICC_MAX_INT_COUNT_THRESHOLD)
+ count = ICC_MAX_INT_COUNT_THRESHOLD;
+ else if (count < ICC_MIN_INT_COUNT_THRESHOLD)
+ count = ICC_MIN_INT_COUNT_THRESHOLD;
+
+ if (ticks > ICC_MAX_INT_TICKS_THRESHOLD)
+ ticks = ICC_MAX_INT_TICKS_THRESHOLD;
+ else if ((ICC_MIN_INT_TICKS_THRESHOLD == ticks) &&
+ (count > ICC_MIN_INT_COUNT_THRESHOLD))
+ ticks = ICC_SAFE_INT_TICKS;
+
+ spin_lock(&host->lock);
+ iowrite32((count << 24 | ticks), hcr_base + ICC);
+
+ intr_coalescing_count = count;
+ intr_coalescing_ticks = ticks;
+ spin_unlock(&host->lock);
+
+ DPRINTK("intrrupt coalescing, count = 0x%x, ticks = %x\n",
+ intr_coalescing_count, intr_coalescing_ticks);
+ DPRINTK("ICC register status: (hcr base: 0x%x) = 0x%x\n",
+ hcr_base, ioread32(hcr_base + ICC));
+}
+
+static ssize_t fsl_sata_intr_coalescing_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d %d\n",
+ intr_coalescing_count, intr_coalescing_ticks);
+}
+
+static ssize_t fsl_sata_intr_coalescing_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned int coalescing_count, coalescing_ticks;
+
+ if (sscanf(buf, "%d%d",
+ &coalescing_count,
+ &coalescing_ticks) != 2) {
+ printk(KERN_ERR "fsl-sata: wrong parameter format.\n");
+ return -EINVAL;
+ }
+
+ fsl_sata_set_irq_coalescing(dev_get_drvdata(dev),
+ coalescing_count, coalescing_ticks);
+
+ return strlen(buf);
+}
+
static void sata_fsl_dev_config(struct ata_device *dev)
{
dev->max_sectors = 16;
@@ -352,11 +428,11 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
(unsigned long long)sg_addr, sg_len);
/* warn if each s/g element is not dword aligned */
- if (sg_addr & 0x03)
+ if (unlikely(sg_addr & 0x03))
ata_port_printk(qc->ap, KERN_ERR,
"s/g addr unaligned : 0x%llx\n",
(unsigned long long)sg_addr);
- if (sg_len & 0x03)
+ if (unlikely(sg_len & 0x03))
ata_port_printk(qc->ap, KERN_ERR,
"s/g len unaligned : 0x%x\n", sg_len);
@@ -1305,6 +1381,13 @@ static int sata_fsl_init_controller(struct ata_host *host)
iowrite32(0x00000FFFF, hcr_base + DE);
/*
+ * reset the number of command complete bits which will cause the
+ * interrupt to be signaled
+ */
+ fsl_sata_set_irq_coalescing(host, intr_coalescing_count,
+ intr_coalescing_ticks);
+
+ /*
* host controller will be brought on-line, during xx_port_start()
* callback, that should also initiate the OOB, COMINIT sequence
*/
@@ -1368,7 +1451,7 @@ static int sata_fsl_probe(struct platform_device *ofdev)
void __iomem *csr_base = NULL;
struct sata_fsl_host_priv *host_priv = NULL;
int irq;
- struct ata_host *host;
+ struct ata_host *host = NULL;
u32 temp;
struct ata_port_info pi = sata_fsl_port_info[0];
@@ -1430,6 +1513,10 @@ static int sata_fsl_probe(struct platform_device *ofdev)
/* allocate host structure */
host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_FSL_MAX_PORTS);
+ if (!host) {
+ retval = -ENOMEM;
+ goto error_exit_with_cleanup;
+ }
/* host->iomap is not used currently */
host->private_data = host_priv;
@@ -1447,10 +1534,24 @@ static int sata_fsl_probe(struct platform_device *ofdev)
dev_set_drvdata(&ofdev->dev, host);
+ host_priv->intr_coalescing.show = fsl_sata_intr_coalescing_show;
+ host_priv->intr_coalescing.store = fsl_sata_intr_coalescing_store;
+ sysfs_attr_init(&host_priv->intr_coalescing.attr);
+ host_priv->intr_coalescing.attr.name = "intr_coalescing";
+ host_priv->intr_coalescing.attr.mode = S_IRUGO | S_IWUSR;
+ retval = device_create_file(host->dev, &host_priv->intr_coalescing);
+ if (retval)
+ goto error_exit_with_cleanup;
+
return 0;
error_exit_with_cleanup:
+ if (host) {
+ dev_set_drvdata(&ofdev->dev, NULL);
+ ata_host_detach(host);
+ }
+
if (hcr_base)
iounmap(hcr_base);
if (host_priv)
@@ -1464,6 +1565,8 @@ static int sata_fsl_remove(struct platform_device *ofdev)
struct ata_host *host = dev_get_drvdata(&ofdev->dev);
struct sata_fsl_host_priv *host_priv = host->private_data;
+ device_remove_file(&ofdev->dev, &host_priv->intr_coalescing);
+
ata_host_detach(host);
dev_set_drvdata(&ofdev->dev, NULL);
--
1.7.5.1
^ permalink raw reply related
* [PATCH 2/2] powerpc: Abstract common define of signal multiplex control for qe
From: Zhicheng Fan @ 2012-01-20 5:00 UTC (permalink / raw)
To: galak, linuxppc-dev; +Cc: Fanzc
In-Reply-To: <1327035611-22794-1-git-send-email-B32736@freescale.com>
From: Fanzc <b32736@freeescale.com>
The mpc85xx_rdb and mpc85xx_mds have commom define of signal multiplex for qe ,so
they need to go in common header, the patch abstract them to fsl_guts.h
Signed-off-by: Fanzc <b32736@freeescale.com>
---
arch/powerpc/include/asm/fsl_guts.h | 19 +++++++++++++++++++
arch/powerpc/platforms/85xx/mpc85xx_mds.c | 7 ++-----
2 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h
index bebd124..efacfe3 100644
--- a/arch/powerpc/include/asm/fsl_guts.h
+++ b/arch/powerpc/include/asm/fsl_guts.h
@@ -114,6 +114,25 @@ struct ccsr_guts_86xx {
__be32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */
} __attribute__ ((packed));
+#ifdef CONFIG_PPC_85xx
+
+/* Alternate function signal multiplex control */
+#define MPC85xx_PMUXCR_OFFSET 0x60
+#define MPC85xx_PMUXCR_QE0 0x00008000
+#define MPC85xx_PMUXCR_QE2 0x00002000
+#define MPC85xx_PMUXCR_QE3 0x00001000
+#define MPC85xx_PMUXCR_QE4 0x00000800
+#define MPC85xx_PMUXCR_QE5 0x00000400
+#define MPC85xx_PMUXCR_QE6 0x00000200
+#define MPC85xx_PMUXCR_QE7 0x00000100
+#define MPC85xx_PMUXCR_QE8 0x00000080
+#define MPC85xx_PMUXCR_QE9 0x00000040
+#define MPC85xx_PMUXCR_QE10 0x00000020
+#define MPC85xx_PMUXCR_QE11 0x00000010
+#define MPC85xx_PMUXCR_QE12 0x00000008
+
+#endif
+
#ifdef CONFIG_PPC_86xx
#define CCSR_GUTS_DMACR_DEV_SSI 0 /* DMA controller/channel set to SSI */
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 1d15a0c..1bd339a 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -51,6 +51,7 @@
#include <asm/qe_ic.h>
#include <asm/mpic.h>
#include <asm/swiotlb.h>
+#include <asm/fsl_guts.h>
#include "smp.h"
#include "mpc85xx.h"
@@ -268,11 +269,7 @@ static void __init mpc85xx_mds_qe_init(void)
mpc85xx_mds_reset_ucc_phys();
if (machine_is(p1021_mds)) {
-#define MPC85xx_PMUXCR_OFFSET 0x60
-#define MPC85xx_PMUXCR_QE0 0x00008000
-#define MPC85xx_PMUXCR_QE3 0x00001000
-#define MPC85xx_PMUXCR_QE9 0x00000040
-#define MPC85xx_PMUXCR_QE12 0x00000008
+
static __be32 __iomem *pmuxcr;
np = of_find_node_by_name(NULL, "global-utilities");
--
1.7.0.4
^ permalink raw reply related
* [PATCH 1/2] P1025RDB: add Quicc Engine support
From: Zhicheng Fan @ 2012-01-20 5:00 UTC (permalink / raw)
To: galak, linuxppc-dev; +Cc: Fanzc
From: Fanzc <b32736@freeescale.com>
Signed-off-by: Fanzc <b32736@freeescale.com>
---
arch/powerpc/platforms/85xx/mpc85xx_rdb.c | 79 ++++++++++++++++++++++++++++-
1 files changed, 78 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
index 1950076..1ba67aa 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
@@ -26,6 +26,9 @@
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/mpic.h>
+#include <asm/qe.h>
+#include <asm/qe_ic.h>
+#include <asm/fsl_guts.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
@@ -47,6 +50,10 @@ void __init mpc85xx_rdb_pic_init(void)
struct mpic *mpic;
unsigned long root = of_get_flat_dt_root();
+#ifdef CONFIG_QUICC_ENGINE
+ struct device_node *np;
+#endif
+
if (of_flat_dt_is_compatible(root, "fsl,MPC85XXRDB-CAMP")) {
mpic = mpic_alloc(NULL, 0,
MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
@@ -62,6 +69,18 @@ void __init mpc85xx_rdb_pic_init(void)
BUG_ON(mpic == NULL);
mpic_init(mpic);
+
+#ifdef CONFIG_QUICC_ENGINE
+ np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
+ if (np) {
+ qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
+ qe_ic_cascade_high_mpic);
+ of_node_put(np);
+
+ } else
+ printk(KERN_ERR "Could not find qe-ic node\n");
+#endif
+
}
/*
@@ -69,7 +88,7 @@ void __init mpc85xx_rdb_pic_init(void)
*/
static void __init mpc85xx_rdb_setup_arch(void)
{
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) || defined(CONFIG_QUICC_ENGINE)
struct device_node *np;
#endif
@@ -85,6 +104,64 @@ static void __init mpc85xx_rdb_setup_arch(void)
#endif
mpc85xx_smp_init();
+
+#ifdef CONFIG_QUICC_ENGINE
+ np = of_find_compatible_node(NULL, NULL, "fsl,qe");
+ if (!np) {
+ printk(KERN_ERR "Could not find Quicc Engine node\n");
+ goto qe_fail;
+ }
+
+ qe_reset();
+ of_node_put(np);
+
+ np = of_find_node_by_name(NULL, "par_io");
+ if (np) {
+ struct device_node *ucc;
+
+ par_io_init(np);
+ of_node_put(np);
+
+ for_each_node_by_name(ucc, "ucc")
+ par_io_of_config(ucc);
+
+ }
+ if (machine_is(p1025_rdb)) {
+
+ __be32 __iomem *pmuxcr;
+
+ np = of_find_node_by_name(NULL, "global-utilities");
+
+ if (np) {
+ pmuxcr = of_iomap(np, 0) + MPC85xx_PMUXCR_OFFSET;
+
+ if (!pmuxcr)
+ pr_err(KERN_EMERG "Error: Alternate function"
+ " signal multiplex control register not"
+ " mapped!\n");
+ else {
+#if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE)
+ /* P1025 has pins muxed for QE and other functions. To
+ * enable QE UEC mode, we need to set bit QE0 for UCC1
+ * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9
+ * and QE12 for QE MII management singals in PMUXCR
+ * register.
+ */
+ setbits32(pmuxcr, MPC85xx_PMUXCR_QE0 |
+ MPC85xx_PMUXCR_QE3 |
+ MPC85xx_PMUXCR_QE9 |
+ MPC85xx_PMUXCR_QE12);
+#endif
+ }
+
+ of_node_put(np);
+ }
+
+ }
+
+qe_fail:
+#endif /* CONFIG_QUICC_ENGINE */
+
printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n");
}
--
1.7.0.4
^ permalink raw reply related
* linux-next: build failure after merge of the final tree
From: Stephen Rothwell @ 2012-01-20 7:21 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev
Cc: Deepthi Dharwar, Arun R Bharadwaj, linux-next, linux-kernel,
Trinabh Gupta
[-- Attachment #1: Type: text/plain, Size: 750 bytes --]
Hi all,
After merging the final tree, today's linux-next build (powerpc
allmodconfig) failed like this:
arch/powerpc/platforms/pseries/processor_idle.c:35:6: error: redefinition of 'update_smt_snooze_delay'
arch/powerpc/include/asm/system.h:230:20: note: previous definition of 'update_smt_snooze_delay' was here
arch/powerpc/platforms/pseries/processor_idle.c:175:5: error: redefinition of 'pseries_notify_cpuidle_add_cpu'
arch/powerpc/include/asm/system.h:231:19: note: previous definition of 'pseries_notify_cpuidle_add_cpu' was here
Caused by commit 707827f3387d ("powerpc/cpuidle: cpuidle driver for
pSeries"). For this build, CONFIG_PSERIES_IDLE is "m".
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: linux-next: build failure after merge of the final tree
From: Deepthi Dharwar @ 2012-01-20 9:08 UTC (permalink / raw)
To: Stephen Rothwell
Cc: Trinabh Gupta, Arun R Bharadwaj, linux-kernel, linux-next,
Paul Mackerras, linuxppc-dev
In-Reply-To: <20120120182117.01a6eb5d3cfb3f2bdfb32ae4@canb.auug.org.au>
On 01/20/2012 12:51 PM, Stephen Rothwell wrote:
> Hi all,
>
> After merging the final tree, today's linux-next build (powerpc
> allmodconfig) failed like this:
>
> arch/powerpc/platforms/pseries/processor_idle.c:35:6: error: redefinition of 'update_smt_snooze_delay'
> arch/powerpc/include/asm/system.h:230:20: note: previous definition of 'update_smt_snooze_delay' was here
> arch/powerpc/platforms/pseries/processor_idle.c:175:5: error: redefinition of 'pseries_notify_cpuidle_add_cpu'
> arch/powerpc/include/asm/system.h:231:19: note: previous definition of 'pseries_notify_cpuidle_add_cpu' was here
>
> Caused by commit 707827f3387d ("powerpc/cpuidle: cpuidle driver for
> pSeries"). For this build, CONFIG_PSERIES_IDLE is "m".
>
>
>
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
Hi Stephen,
We had a discussion on this particular problem on ppcdev list a few
days back and concluded that it is best not have pseries_idle
as a module.
http://old.nabble.com/-PATCH--cpuidle%3A-Default-y-for-pseries-to33118294.html#a33127587
The following patch disables pseries cpuidle driver to be loaded as a
module as there are build problems reported when one is trying to do so.
arch/powerpc/platforms/pseries/processor_idle.c:35:6: error:
redefinition of 'update_smt_snooze_delay'
arch/powerpc/include/asm/system.h:230:20: note:
previous definition of 'update_smt_snooze_delay' was here
arch/powerpc/platforms/pseries/processor_idle.c:175:5:
error: redefinition of 'pseries_notify_cpuidle_add_cpu'
arch/powerpc/include/asm/system.h:231:19: note:
previous definition of 'pseries_notify_cpuidle_add_cpu' was here
Since the above two functions
are used in core power architecture functions (store_smt_snooze_delay
at kernel/sysfs.c and smp_xics_setup_cpu at platforms/pseries/smp.c),
this requires some rework in these interactions. For now please
disable PSERIES_IDLE to be built as a module for now.
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
arch/powerpc/platforms/pseries/Kconfig | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/Kconfig
b/arch/powerpc/platforms/pseries/Kconfig
index ae7b6d4..31f22c1 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -122,7 +122,7 @@ config DTL
Say N if you are unsure.
config PSERIES_IDLE
- tristate "Cpuidle driver for pSeries platforms"
+ bool "Cpuidle driver for pSeries platforms"
depends on CPU_IDLE
depends on PPC_PSERIES
default y
Regards,
Deepthi
^ permalink raw reply related
* [PATCH][v3] NAND Machine support for Integrated Flash Controller
From: Prabhakar Kushwaha @ 2012-01-20 12:52 UTC (permalink / raw)
To: linuxppc-dev, linux-mtd
Cc: Poonam Aggrwal, Liu Shuo, Scott Wood, Dipen Dudhat,
Prabhakar Kushwaha
Integrated Flash Controller(IFC) can be used to hook NAND Flash
chips using NAND Flash Machine available on it.
Signed-off-by: Dipen Dudhat <Dipen.Dudhat@freescale.com>
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Liu Shuo <b35362@freescale.com>
Signed-off-by: Poonam Aggrwal <poonam.aggrwal@freescale.com>
Signed-off-by: Prabhakar Kushwaha <prabhakar@freescale.com>
---
Based upon git://git.kernel.org/pub/scm/linux/kernel/git/galak/powerpc.git (branch next)
Tested on P1010RDB
Changes for v2: Ported IFC driver for linux-3.2.0-rc3
- Use chip->bbt_options for BBT
- Use mtd_device_parse_register instead of old parse_mtd_partitions
Changes for v3: Squashed following patch to make singe NAND driver patch
- mtd/nand:Fix wrong usage of is_blank() in fsl_ifc_run_command
http://patchwork.ozlabs.org/patch/136547/
- mtd/nand: Fix IFC driver to support 2K NAND page
http://patchwork.ozlabs.org/patch/135010/
drivers/mtd/nand/Kconfig | 10 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/fsl_ifc_nand.c | 1071 +++++++++++++++++++++++++++++++++++++++
3 files changed, 1082 insertions(+), 0 deletions(-)
create mode 100644 drivers/mtd/nand/fsl_ifc_nand.c
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index cce7b70..2fff5c7 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -463,6 +463,16 @@ config MTD_NAND_FSL_ELBC
Enabling this option will enable you to use this to control
external NAND devices.
+config MTD_NAND_FSL_IFC
+ tristate "NAND support for Freescale IFC controller"
+ depends on MTD_NAND && FSL_SOC
+ select FSL_IFC
+ help
+ Various Freescale chips e.g P1010, include a NAND Flash machine
+ with built-in hardware ECC capabilities.
+ Enabling this option will enable you to use this to control
+ external NAND devices.
+
config MTD_NAND_FSL_UPM
tristate "Support for NAND on Freescale UPM"
depends on PPC_83xx || PPC_85xx
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 618f4ba..19bc8cb 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_MTD_ALAUDA) += alauda.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
new file mode 100644
index 0000000..33b55d2
--- /dev/null
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -0,0 +1,1071 @@
+/*
+ * Freescale Integrated Flash Controller NAND driver
+ *
+ * Copyright 2011,2012 Freescale Semiconductor, Inc
+ *
+ * Author: Dipen Dudhat <Dipen.Dudhat@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand_ecc.h>
+#include <asm/fsl_ifc.h>
+
+#define ERR_BYTE 0xFF /* Value returned for read
+ bytes when read failed */
+#define IFC_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait
+ for IFC NAND Machine */
+
+struct fsl_ifc_ctrl;
+
+/* mtd information per set */
+struct fsl_ifc_mtd {
+ struct mtd_info mtd;
+ struct nand_chip chip;
+ struct fsl_ifc_ctrl *ctrl;
+
+ struct device *dev;
+ int bank; /* Chip select bank number */
+ unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */
+ u8 __iomem *vbase; /* Chip select base virtual address */
+};
+
+/* overview of the fsl ifc controller */
+struct fsl_ifc_nand_ctrl {
+ struct nand_hw_control controller;
+ struct fsl_ifc_mtd *chips[FSL_IFC_BANK_COUNT];
+
+ u8 __iomem *addr; /* Address of assigned IFC buffer */
+ unsigned int page; /* Last page written to / read from */
+ unsigned int read_bytes;/* Number of bytes read during command */
+ unsigned int column; /* Saved column from SEQIN */
+ unsigned int index; /* Pointer to next byte to 'read' */
+ unsigned int oob; /* Non zero if operating on OOB data */
+ unsigned int eccread; /* Non zero for a full-page ECC read */
+ unsigned int counter; /* counter for the initializations */
+};
+
+static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl;
+
+/* 512-byte page with 4-bit ECC, 8-bit */
+static struct nand_ecclayout oob_512_8bit_ecc4 = {
+ .eccbytes = 8,
+ .eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
+ .oobfree = { {0, 5}, {6, 2} },
+};
+
+/* 512-byte page with 4-bit ECC, 16-bit */
+static struct nand_ecclayout oob_512_16bit_ecc4 = {
+ .eccbytes = 8,
+ .eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
+ .oobfree = { {2, 6}, },
+};
+
+/* 2048-byte page size with 4-bit ECC */
+static struct nand_ecclayout oob_2048_ecc4 = {
+ .eccbytes = 32,
+ .eccpos = {
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ },
+ .oobfree = { {2, 6}, {40, 24} },
+};
+
+/* 4096-byte page size with 4-bit ECC */
+static struct nand_ecclayout oob_4096_ecc4 = {
+ .eccbytes = 64,
+ .eccpos = {
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ },
+ .oobfree = { {2, 6}, {72, 56} },
+};
+
+/* 4096-byte page size with 8-bit ECC -- requires 218-byte OOB */
+static struct nand_ecclayout oob_4096_ecc8 = {
+ .eccbytes = 128,
+ .eccpos = {
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135,
+ },
+ .oobfree = { {2, 6}, {136, 82} },
+};
+
+
+/*
+ * Generic flash bbt descriptors
+ */
+static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+ NAND_BBT_2BIT | NAND_BBT_VERSION,
+ .offs = 2, /* 0 on 8-bit small page */
+ .len = 4,
+ .veroffs = 6,
+ .maxblocks = 4,
+ .pattern = bbt_pattern,
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+ .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+ NAND_BBT_2BIT | NAND_BBT_VERSION,
+ .offs = 2, /* 0 on 8-bit small page */
+ .len = 4,
+ .veroffs = 6,
+ .maxblocks = 4,
+ .pattern = mirror_pattern,
+};
+
+/*
+ * Set up the IFC hardware block and page address fields, and the ifc nand
+ * structure addr field to point to the correct IFC buffer in memory
+ */
+static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_ifc_mtd *priv = chip->priv;
+ struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+ struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+ int buf_num;
+
+ ifc_nand_ctrl->page = page_addr;
+ /* Program ROW0/COL0 */
+ out_be32(&ifc->ifc_nand.row0, page_addr);
+ out_be32(&ifc->ifc_nand.col0, (oob ? IFC_NAND_COL_MS : 0) | column);
+
+ buf_num = page_addr & priv->bufnum_mask;
+
+ ifc_nand_ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2);
+ ifc_nand_ctrl->index = column;
+
+ /* for OOB data point to the second half of the buffer */
+ if (oob)
+ ifc_nand_ctrl->index += mtd->writesize;
+}
+
+static int is_blank(struct mtd_info *mtd, unsigned int bufnum)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_ifc_mtd *priv = chip->priv;
+ u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2);
+ u32 __iomem *mainarea = (u32 *)addr;
+ u8 __iomem *oob = addr + mtd->writesize;
+ int i;
+
+ for (i = 0; i < mtd->writesize / 4; i++) {
+ if (__raw_readl(&mainarea[i]) != 0xffffffff)
+ return 0;
+ }
+
+ for (i = 0; i < chip->ecc.layout->eccbytes; i++) {
+ int pos = chip->ecc.layout->eccpos[i];
+
+ if (__raw_readb(&oob[pos]) != 0xff)
+ return 0;
+ }
+
+ return 1;
+}
+
+/* returns nonzero if entire page is blank */
+static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
+ u32 *eccstat, unsigned int bufnum)
+{
+ u32 reg = eccstat[bufnum / 4];
+ int errors;
+
+ errors = (reg >> ((3 - bufnum % 4) * 8)) & 15;
+
+ return errors;
+}
+
+/*
+ * execute IFC NAND command and wait for it to complete
+ */
+static void fsl_ifc_run_command(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_ifc_mtd *priv = chip->priv;
+ struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+ struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
+ struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+ u32 eccstat[4];
+ int i;
+
+ /* set the chip select for NAND Transaction */
+ out_be32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT);
+
+ dev_vdbg(priv->dev,
+ "%s: fir0=%08x fcr0=%08x\n",
+ __func__,
+ in_be32(&ifc->ifc_nand.nand_fir0),
+ in_be32(&ifc->ifc_nand.nand_fcr0));
+
+ ctrl->nand_stat = 0;
+
+ /* start read/write seq */
+ out_be32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT);
+
+ /* wait for command complete flag or timeout */
+ wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
+ IFC_TIMEOUT_MSECS * HZ/1000);
+
+ if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_FTOER)
+ dev_err(priv->dev, "NAND Flash Timeout Error\n");
+ if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER)
+ dev_err(priv->dev, "NAND Flash Write Protect Error\n");
+
+ if (nctrl->eccread) {
+ int errors;
+ int bufnum = nctrl->page & priv->bufnum_mask;
+ int sector = bufnum * chip->ecc.steps;
+ int sector_end = sector + chip->ecc.steps - 1;
+
+ for (i = sector / 4; i <= sector_end / 4; i++)
+ eccstat[i] = in_be32(&ifc->ifc_nand.nand_eccstat[i]);
+
+ for (i = sector; i <= sector_end; i++) {
+ errors = check_read_ecc(mtd, ctrl, eccstat, i);
+
+ if (errors == 15) {
+ /*
+ * Uncorrectable error.
+ * OK only if the whole page is blank.
+ *
+ * We disable ECCER reporting due to...
+ * erratum IFC-A002770 -- so report it now if we
+ * see an uncorrectable error in ECCSTAT.
+ */
+ if (!is_blank(mtd, bufnum))
+ ctrl->nand_stat |=
+ IFC_NAND_EVTER_STAT_ECCER;
+ break;
+ }
+
+ mtd->ecc_stats.corrected += errors;
+ }
+
+ nctrl->eccread = 0;
+ }
+}
+
+static void fsl_ifc_do_read(struct nand_chip *chip,
+ int oob,
+ struct mtd_info *mtd)
+{
+ struct fsl_ifc_mtd *priv = chip->priv;
+ struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+ struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+
+ /* Program FIR/IFC_NAND_FCR0 for Small/Large page */
+ if (mtd->writesize > 512) {
+ out_be32(&ifc->ifc_nand.nand_fir0,
+ (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+ (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+ (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+ (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) |
+ (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT));
+ out_be32(&ifc->ifc_nand.nand_fir1, 0x0);
+
+ out_be32(&ifc->ifc_nand.nand_fcr0,
+ (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) |
+ (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT));
+ } else {
+ out_be32(&ifc->ifc_nand.nand_fir0,
+ (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+ (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+ (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+ (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT));
+ out_be32(&ifc->ifc_nand.nand_fir1, 0x0);
+
+ if (oob)
+ out_be32(&ifc->ifc_nand.nand_fcr0,
+ NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT);
+ else
+ out_be32(&ifc->ifc_nand.nand_fcr0,
+ NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT);
+ }
+}
+
+/* cmdfunc send commands to the IFC NAND Machine */
+static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr) {
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_ifc_mtd *priv = chip->priv;
+ struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+ struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+
+ /* clear the read buffer */
+ ifc_nand_ctrl->read_bytes = 0;
+ if (command != NAND_CMD_PAGEPROG)
+ ifc_nand_ctrl->index = 0;
+
+ switch (command) {
+ /* READ0 read the entire buffer to use hardware ECC. */
+ case NAND_CMD_READ0:
+ out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+ set_addr(mtd, 0, page_addr, 0);
+
+ ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+ ifc_nand_ctrl->index += column;
+
+ if (chip->ecc.mode == NAND_ECC_HW)
+ ifc_nand_ctrl->eccread = 1;
+
+ fsl_ifc_do_read(chip, 0, mtd);
+ fsl_ifc_run_command(mtd);
+ return;
+
+ /* READOOB reads only the OOB because no ECC is performed. */
+ case NAND_CMD_READOOB:
+ out_be32(&ifc->ifc_nand.nand_fbcr, mtd->oobsize - column);
+ set_addr(mtd, column, page_addr, 1);
+
+ ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+
+ fsl_ifc_do_read(chip, 1, mtd);
+ fsl_ifc_run_command(mtd);
+
+ return;
+
+ /* READID must read all 8 possible bytes */
+ case NAND_CMD_READID:
+ out_be32(&ifc->ifc_nand.nand_fir0,
+ (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
+ (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) |
+ (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
+ out_be32(&ifc->ifc_nand.nand_fcr0,
+ NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT);
+ /* 8 bytes for manuf, device and exts */
+ out_be32(&ifc->ifc_nand.nand_fbcr, 8);
+ ifc_nand_ctrl->read_bytes = 8;
+
+ set_addr(mtd, 0, 0, 0);
+ fsl_ifc_run_command(mtd);
+ return;
+
+ /* ERASE1 stores the block and page address */
+ case NAND_CMD_ERASE1:
+ set_addr(mtd, 0, page_addr, 0);
+ return;
+
+ /* ERASE2 uses the block and page address from ERASE1 */
+ case NAND_CMD_ERASE2:
+ out_be32(&ifc->ifc_nand.nand_fir0,
+ (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+ (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+ (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT));
+
+ out_be32(&ifc->ifc_nand.nand_fcr0,
+ (NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) |
+ (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT));
+
+ out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+ ifc_nand_ctrl->read_bytes = 0;
+ fsl_ifc_run_command(mtd);
+ return;
+
+ /* SEQIN sets up the addr buffer and all registers except the length */
+ case NAND_CMD_SEQIN: {
+ u32 nand_fcr0;
+ ifc_nand_ctrl->column = column;
+ ifc_nand_ctrl->oob = 0;
+
+ if (mtd->writesize > 512) {
+ nand_fcr0 =
+ (NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) |
+ (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD1_SHIFT);
+
+ out_be32(&ifc->ifc_nand.nand_fir0,
+ (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+ (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+ (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+ (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) |
+ (IFC_FIR_OP_CW1 << IFC_NAND_FIR0_OP4_SHIFT));
+ } else {
+ nand_fcr0 = ((NAND_CMD_PAGEPROG <<
+ IFC_NAND_FCR0_CMD1_SHIFT) |
+ (NAND_CMD_SEQIN <<
+ IFC_NAND_FCR0_CMD2_SHIFT));
+
+ out_be32(&ifc->ifc_nand.nand_fir0,
+ (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+ (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) |
+ (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+ (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
+ (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT));
+ out_be32(&ifc->ifc_nand.nand_fir1,
+ (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT));
+
+ if (column >= mtd->writesize)
+ nand_fcr0 |=
+ NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT;
+ else
+ nand_fcr0 |=
+ NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT;
+ }
+
+ if (column >= mtd->writesize) {
+ /* OOB area --> READOOB */
+ column -= mtd->writesize;
+ ifc_nand_ctrl->oob = 1;
+ }
+ out_be32(&ifc->ifc_nand.nand_fcr0, nand_fcr0);
+ set_addr(mtd, column, page_addr, ifc_nand_ctrl->oob);
+ return;
+ }
+
+ /* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+ case NAND_CMD_PAGEPROG: {
+ int full_page;
+ if (ifc_nand_ctrl->oob) {
+ out_be32(&ifc->ifc_nand.nand_fbcr,
+ ifc_nand_ctrl->index - ifc_nand_ctrl->column);
+ full_page = 0;
+ } else {
+ out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+ full_page = 1;
+ }
+
+ fsl_ifc_run_command(mtd);
+ return;
+ }
+
+ case NAND_CMD_STATUS:
+ out_be32(&ifc->ifc_nand.nand_fir0,
+ (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+ (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT));
+ out_be32(&ifc->ifc_nand.nand_fcr0,
+ NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT);
+ out_be32(&ifc->ifc_nand.nand_fbcr, 1);
+ set_addr(mtd, 0, 0, 0);
+ ifc_nand_ctrl->read_bytes = 1;
+
+ fsl_ifc_run_command(mtd);
+
+ /*
+ * The chip always seems to report that it is
+ * write-protected, even when it is not.
+ */
+ setbits8(ifc_nand_ctrl->addr, NAND_STATUS_WP);
+ return;
+
+ case NAND_CMD_RESET:
+ out_be32(&ifc->ifc_nand.nand_fir0,
+ IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT);
+ out_be32(&ifc->ifc_nand.nand_fcr0,
+ NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT);
+ fsl_ifc_run_command(mtd);
+ return;
+
+ default:
+ dev_err(priv->dev, "%s: error, unsupported command 0x%x.\n",
+ __func__, command);
+ }
+}
+
+static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
+{
+ /* The hardware does not seem to support multiple
+ * chips per bank.
+ */
+}
+
+/*
+ * Write buf to the IFC NAND Controller Data Buffer
+ */
+static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_ifc_mtd *priv = chip->priv;
+ unsigned int bufsize = mtd->writesize + mtd->oobsize;
+
+ if (len <= 0) {
+ dev_err(priv->dev, "%s: len %d bytes", __func__, len);
+ return;
+ }
+
+ if ((unsigned int)len > bufsize - ifc_nand_ctrl->index) {
+ dev_err(priv->dev,
+ "%s: beyond end of buffer (%d requested, %u available)\n",
+ __func__, len, bufsize - ifc_nand_ctrl->index);
+ len = bufsize - ifc_nand_ctrl->index;
+ }
+
+ memcpy_toio(&ifc_nand_ctrl->addr[ifc_nand_ctrl->index], buf, len);
+ ifc_nand_ctrl->index += len;
+}
+
+/*
+ * Read a byte from either the IFC hardware buffer
+ * read function for 8-bit buswidth
+ */
+static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_ifc_mtd *priv = chip->priv;
+
+ /*
+ * If there are still bytes in the IFC buffer, then use the
+ * next byte.
+ */
+ if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes)
+ return in_8(&ifc_nand_ctrl->addr[ifc_nand_ctrl->index++]);
+
+ dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
+ return ERR_BYTE;
+}
+
+/*
+ * Read two bytes from the IFC hardware buffer
+ * read function for 16-bit buswith
+ */
+static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_ifc_mtd *priv = chip->priv;
+ uint16_t data;
+
+ /*
+ * If there are still bytes in the IFC buffer, then use the
+ * next byte.
+ */
+ if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) {
+ data = in_be16((uint16_t *)&ifc_nand_ctrl->
+ addr[ifc_nand_ctrl->index]);
+ ifc_nand_ctrl->index += 2;
+ return (uint8_t) data;
+ }
+
+ dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
+ return ERR_BYTE;
+}
+
+/*
+ * Read from the IFC Controller Data Buffer
+ */
+static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_ifc_mtd *priv = chip->priv;
+ int avail;
+
+ if (len < 0) {
+ dev_err(priv->dev, "%s: len %d bytes", __func__, len);
+ return;
+ }
+
+ avail = min((unsigned int)len,
+ ifc_nand_ctrl->read_bytes - ifc_nand_ctrl->index);
+ memcpy_fromio(buf, &ifc_nand_ctrl->addr[ifc_nand_ctrl->index], avail);
+ ifc_nand_ctrl->index += avail;
+
+ if (len > avail)
+ dev_err(priv->dev,
+ "%s: beyond end of buffer (%d requested, %d available)\n",
+ __func__, len, avail);
+}
+
+/*
+ * Verify buffer against the IFC Controller Data Buffer
+ */
+static int fsl_ifc_verify_buf(struct mtd_info *mtd,
+ const u_char *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_ifc_mtd *priv = chip->priv;
+ struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+ struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
+ int i;
+
+ if (len < 0) {
+ dev_err(priv->dev, "%s: write_buf of %d bytes", __func__, len);
+ return -EINVAL;
+ }
+
+ if ((unsigned int)len > nctrl->read_bytes - nctrl->index) {
+ dev_err(priv->dev,
+ "%s: beyond end of buffer (%d requested, %u available)\n",
+ __func__, len, nctrl->read_bytes - nctrl->index);
+
+ nctrl->index = nctrl->read_bytes;
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len; i++)
+ if (in_8(&nctrl->addr[nctrl->index + i]) != buf[i])
+ break;
+
+ nctrl->index += len;
+
+ if (i != len)
+ return -EIO;
+ if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
+ return -EIO;
+
+ return 0;
+}
+
+/*
+ * This function is called after Program and Erase Operations to
+ * check for success or failure.
+ */
+static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+ struct fsl_ifc_mtd *priv = chip->priv;
+ struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+ struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+ u32 nand_fsr;
+
+ /* Use READ_STATUS command, but wait for the device to be ready */
+ out_be32(&ifc->ifc_nand.nand_fir0,
+ (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+ (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT));
+ out_be32(&ifc->ifc_nand.nand_fcr0, NAND_CMD_STATUS <<
+ IFC_NAND_FCR0_CMD0_SHIFT);
+ out_be32(&ifc->ifc_nand.nand_fbcr, 1);
+ set_addr(mtd, 0, 0, 0);
+ ifc_nand_ctrl->read_bytes = 1;
+
+ fsl_ifc_run_command(mtd);
+
+ nand_fsr = in_be32(&ifc->ifc_nand.nand_fsr);
+
+ /*
+ * The chip always seems to report that it is
+ * write-protected, even when it is not.
+ */
+ return nand_fsr | NAND_STATUS_WP;
+}
+
+static int fsl_ifc_read_page(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ uint8_t *buf, int page)
+{
+ struct fsl_ifc_mtd *priv = chip->priv;
+ struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+
+ fsl_ifc_read_buf(mtd, buf, mtd->writesize);
+ fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) {
+ dev_err(priv->dev, "NAND Flash Write Protect Error\n");
+ mtd->ecc_stats.failed++;
+ }
+
+ return 0;
+}
+
+/* ECC will be calculated automatically, and errors will be detected in
+ * waitfunc.
+ */
+static void fsl_ifc_write_page(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ const uint8_t *buf)
+{
+ fsl_ifc_write_buf(mtd, buf, mtd->writesize);
+ fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+}
+
+static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_ifc_mtd *priv = chip->priv;
+
+ dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
+ chip->numchips);
+ dev_dbg(priv->dev, "%s: nand->chipsize = %lld\n", __func__,
+ chip->chipsize);
+ dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__,
+ chip->pagemask);
+ dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__,
+ chip->chip_delay);
+ dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__,
+ chip->badblockpos);
+ dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__,
+ chip->chip_shift);
+ dev_dbg(priv->dev, "%s: nand->page_shift = %d\n", __func__,
+ chip->page_shift);
+ dev_dbg(priv->dev, "%s: nand->phys_erase_shift = %d\n", __func__,
+ chip->phys_erase_shift);
+ dev_dbg(priv->dev, "%s: nand->ecclayout = %p\n", __func__,
+ chip->ecclayout);
+ dev_dbg(priv->dev, "%s: nand->ecc.mode = %d\n", __func__,
+ chip->ecc.mode);
+ dev_dbg(priv->dev, "%s: nand->ecc.steps = %d\n", __func__,
+ chip->ecc.steps);
+ dev_dbg(priv->dev, "%s: nand->ecc.bytes = %d\n", __func__,
+ chip->ecc.bytes);
+ dev_dbg(priv->dev, "%s: nand->ecc.total = %d\n", __func__,
+ chip->ecc.total);
+ dev_dbg(priv->dev, "%s: nand->ecc.layout = %p\n", __func__,
+ chip->ecc.layout);
+ dev_dbg(priv->dev, "%s: mtd->flags = %08x\n", __func__, mtd->flags);
+ dev_dbg(priv->dev, "%s: mtd->size = %lld\n", __func__, mtd->size);
+ dev_dbg(priv->dev, "%s: mtd->erasesize = %d\n", __func__,
+ mtd->erasesize);
+ dev_dbg(priv->dev, "%s: mtd->writesize = %d\n", __func__,
+ mtd->writesize);
+ dev_dbg(priv->dev, "%s: mtd->oobsize = %d\n", __func__,
+ mtd->oobsize);
+
+ return 0;
+}
+
+static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
+{
+ struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+ struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+ struct nand_chip *chip = &priv->chip;
+ struct nand_ecclayout *layout;
+ u32 csor;
+
+ /* Fill in fsl_ifc_mtd structure */
+ priv->mtd.priv = chip;
+ priv->mtd.owner = THIS_MODULE;
+
+ /* fill in nand_chip structure */
+ /* set up function call table */
+ if ((in_be32(&ifc->cspr_cs[priv->bank].cspr)) & CSPR_PORT_SIZE_16)
+ chip->read_byte = fsl_ifc_read_byte16;
+ else
+ chip->read_byte = fsl_ifc_read_byte;
+
+ chip->write_buf = fsl_ifc_write_buf;
+ chip->read_buf = fsl_ifc_read_buf;
+ chip->verify_buf = fsl_ifc_verify_buf;
+ chip->select_chip = fsl_ifc_select_chip;
+ chip->cmdfunc = fsl_ifc_cmdfunc;
+ chip->waitfunc = fsl_ifc_wait;
+
+ chip->bbt_td = &bbt_main_descr;
+ chip->bbt_md = &bbt_mirror_descr;
+
+ out_be32(&ifc->ifc_nand.ncfgr, 0x0);
+
+ /* set up nand options */
+ chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR;
+ chip->bbt_options = NAND_BBT_USE_FLASH;
+
+
+ if (in_be32(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) {
+ chip->read_byte = fsl_ifc_read_byte16;
+ chip->options |= NAND_BUSWIDTH_16;
+ } else {
+ chip->read_byte = fsl_ifc_read_byte;
+ }
+
+ chip->controller = &ifc_nand_ctrl->controller;
+ chip->priv = priv;
+
+ chip->ecc.read_page = fsl_ifc_read_page;
+ chip->ecc.write_page = fsl_ifc_write_page;
+
+ csor = in_be32(&ifc->csor_cs[priv->bank].csor);
+
+ /* Hardware generates ECC per 512 Bytes */
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 8;
+
+ switch (csor & CSOR_NAND_PGS_MASK) {
+ case CSOR_NAND_PGS_512:
+ if (chip->options & NAND_BUSWIDTH_16) {
+ layout = &oob_512_16bit_ecc4;
+ } else {
+ layout = &oob_512_8bit_ecc4;
+
+ /* Avoid conflict with bad block marker */
+ bbt_main_descr.offs = 0;
+ bbt_mirror_descr.offs = 0;
+ }
+
+ priv->bufnum_mask = 15;
+ break;
+
+ case CSOR_NAND_PGS_2K:
+ layout = &oob_2048_ecc4;
+ priv->bufnum_mask = 3;
+ break;
+
+ case CSOR_NAND_PGS_4K:
+ if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
+ CSOR_NAND_ECC_MODE_4) {
+ layout = &oob_4096_ecc4;
+ } else {
+ layout = &oob_4096_ecc8;
+ chip->ecc.bytes = 16;
+ }
+
+ priv->bufnum_mask = 1;
+ break;
+
+ default:
+ dev_err(priv->dev, "bad csor %#x: bad page size\n", csor);
+ return -ENODEV;
+ }
+
+ /* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */
+ if (csor & CSOR_NAND_ECC_DEC_EN) {
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.layout = layout;
+ } else {
+ chip->ecc.mode = NAND_ECC_SOFT;
+ }
+
+ return 0;
+}
+
+static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
+{
+ nand_release(&priv->mtd);
+
+ kfree(priv->mtd.name);
+
+ if (priv->vbase)
+ iounmap(priv->vbase);
+
+ ifc_nand_ctrl->chips[priv->bank] = NULL;
+ dev_set_drvdata(priv->dev, NULL);
+ kfree(priv);
+
+ return 0;
+}
+
+static int match_bank(struct fsl_ifc_regs __iomem *ifc, int bank,
+ phys_addr_t addr)
+{
+ u32 cspr = in_be32(&ifc->cspr_cs[bank].cspr);
+
+ if (!(cspr & CSPR_V))
+ return 0;
+ if ((cspr & CSPR_MSEL) != CSPR_MSEL_NAND)
+ return 0;
+
+ return (cspr & CSPR_BA) == convert_ifc_address(addr);
+}
+
+static DEFINE_MUTEX(fsl_ifc_nand_mutex);
+
+static int __devinit fsl_ifc_nand_probe(struct platform_device *dev)
+{
+ struct fsl_ifc_regs __iomem *ifc;
+ struct fsl_ifc_mtd *priv;
+ struct resource res;
+ static const char *part_probe_types[]
+ = { "cmdlinepart", "RedBoot", "ofpart", NULL };
+ int ret;
+ int bank;
+ struct device_node *node = dev->dev.of_node;
+ struct mtd_part_parser_data ppdata;
+
+ ppdata.of_node = dev->dev.of_node;
+ if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs)
+ return -ENODEV;
+ ifc = fsl_ifc_ctrl_dev->regs;
+
+ /* get, allocate and map the memory resource */
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret) {
+ dev_err(&dev->dev, "%s: failed to get resource\n", __func__);
+ return ret;
+ }
+
+ /* find which chip select it is connected to */
+ for (bank = 0; bank < FSL_IFC_BANK_COUNT; bank++) {
+ if (match_bank(ifc, bank, res.start))
+ break;
+ }
+
+ if (bank >= FSL_IFC_BANK_COUNT) {
+ dev_err(&dev->dev, "%s: address did not match any chip selects\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ mutex_lock(&fsl_ifc_nand_mutex);
+ if (!fsl_ifc_ctrl_dev->nand) {
+ ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL);
+ if (!ifc_nand_ctrl) {
+ dev_err(&dev->dev, "failed to allocate memory\n");
+ mutex_unlock(&fsl_ifc_nand_mutex);
+ return -ENOMEM;
+ }
+
+ ifc_nand_ctrl->read_bytes = 0;
+ ifc_nand_ctrl->index = 0;
+ ifc_nand_ctrl->addr = NULL;
+ fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
+
+ spin_lock_init(&ifc_nand_ctrl->controller.lock);
+ init_waitqueue_head(&ifc_nand_ctrl->controller.wq);
+ } else {
+ ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
+ }
+ mutex_unlock(&fsl_ifc_nand_mutex);
+
+ ifc_nand_ctrl->chips[bank] = priv;
+ priv->bank = bank;
+ priv->ctrl = fsl_ifc_ctrl_dev;
+ priv->dev = &dev->dev;
+
+ priv->vbase = ioremap(res.start, resource_size(&res));
+ if (!priv->vbase) {
+ dev_err(priv->dev, "%s: failed to map chip region\n", __func__);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ dev_set_drvdata(priv->dev, priv);
+
+ out_be32(&ifc->ifc_nand.nand_evter_en,
+ IFC_NAND_EVTER_EN_OPC_EN |
+ IFC_NAND_EVTER_EN_FTOER_EN |
+ IFC_NAND_EVTER_EN_WPER_EN);
+
+ /* enable NAND Machine Interrupts */
+ out_be32(&ifc->ifc_nand.nand_evter_intr_en,
+ IFC_NAND_EVTER_INTR_OPCIR_EN |
+ IFC_NAND_EVTER_INTR_FTOERIR_EN |
+ IFC_NAND_EVTER_INTR_WPERIR_EN);
+
+ priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start);
+ if (!priv->mtd.name) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = fsl_ifc_chip_init(priv);
+ if (ret)
+ goto err;
+
+ ret = nand_scan_ident(&priv->mtd, 1, NULL);
+ if (ret)
+ goto err;
+
+ ret = fsl_ifc_chip_init_tail(&priv->mtd);
+ if (ret)
+ goto err;
+
+ ret = nand_scan_tail(&priv->mtd);
+ if (ret)
+ goto err;
+
+ /* First look for RedBoot table or partitions on the command
+ * line, these take precedence over device tree information */
+ mtd_device_parse_register(&priv->mtd, part_probe_types, &ppdata,
+ NULL, 0);
+
+ dev_info(priv->dev, "IFC NAND device at 0x%llx, bank %d\n",
+ (unsigned long long)res.start, priv->bank);
+ return 0;
+
+err:
+ fsl_ifc_chip_remove(priv);
+ return ret;
+}
+
+static int fsl_ifc_nand_remove(struct platform_device *dev)
+{
+ struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev);
+
+ fsl_ifc_chip_remove(priv);
+
+ mutex_lock(&fsl_ifc_nand_mutex);
+ ifc_nand_ctrl->counter--;
+ if (!ifc_nand_ctrl->counter) {
+ fsl_ifc_ctrl_dev->nand = NULL;
+ kfree(ifc_nand_ctrl);
+ }
+ mutex_unlock(&fsl_ifc_nand_mutex);
+
+ return 0;
+}
+
+static const struct of_device_id fsl_ifc_nand_match[] = {
+ {
+ .compatible = "fsl,ifc-nand",
+ },
+ {}
+};
+
+static struct platform_driver fsl_ifc_nand_driver = {
+ .driver = {
+ .name = "fsl,ifc-nand",
+ .owner = THIS_MODULE,
+ .of_match_table = fsl_ifc_nand_match,
+ },
+ .probe = fsl_ifc_nand_probe,
+ .remove = fsl_ifc_nand_remove,
+};
+
+static int __init fsl_ifc_nand_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&fsl_ifc_nand_driver);
+ if (ret)
+ printk(KERN_ERR "fsl-ifc: Failed to register platform"
+ "driver\n");
+
+ return ret;
+}
+
+static void __exit fsl_ifc_nand_exit(void)
+{
+ platform_driver_unregister(&fsl_ifc_nand_driver);
+}
+
+module_init(fsl_ifc_nand_init);
+module_exit(fsl_ifc_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale");
+MODULE_DESCRIPTION("Freescale Integrated Flash Controller MTD NAND driver");
--
1.7.5.4
^ permalink raw reply related
* Re: Cannot wake-up from standby with MPC8313
From: Scott Wood @ 2012-01-20 20:05 UTC (permalink / raw)
To: Norbert van Bolhuis; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <4F169BE3.30102@aimvalley.nl>
On 01/18/2012 04:16 AM, Norbert van Bolhuis wrote:
> Yes this is it!
> You mentioned mpc8313erdb bug before, I guess you had to mention it
> twice before
> I looked at mpc8313erdb bug description.
>=20
> The mpc8313erdb bug is described as follows:
>=20
> 3.5 Power management control (PMC) registers cannot be
> accessed?
> The PMC registers range from IMMR + 0x0B00 to IMMR + 0x0BFF. When this
> area is accessed in u-boot,
> the RDB hangs up. It appears that the PMC block is related to the JTAG
> interface; TRST must not be pulled
> down for normal operation of the PMC block. Possible workarounds are as
> follows:
> =95 Attach a debugger to drive TRST high during normal operation.
> =95 Remove the pull-down resistor (R37) for TRST. Although this tested =
on
> some RDBs without any
> problem, it violates the hardware specification. If it does not work on
> your RDB, use another workaround.
>=20
>=20
> I guess this is an MPC8313 problem rather than an MPC8313E-RDB problem =
?
> and I would expect it to be mentioned in MPC8313E Errata (which isn't t=
he
> case).
It is mentioned in the MPC8313E manual (4.2.2 step #10) that TRST must
not be asserted except when PORESET is asserted. The mpc8313erdb bug
was that the board was not complying with this.
-Scott
^ permalink raw reply
* Re: [PATCH] mtd/nand:Fix wrong usage of is_blank() in fsl_ifc_run_command
From: Scott Wood @ 2012-01-20 20:20 UTC (permalink / raw)
To: Prabhakar Kushwaha; +Cc: linux-mtd, linuxppc-dev, Poonam Aggrwal
In-Reply-To: <1326859991-7469-1-git-send-email-prabhakar@freescale.com>
On 01/17/2012 10:13 PM, Prabhakar Kushwaha wrote:
> + for (i = sector; i <= sector_end; i++) {
> + errors = check_read_ecc(mtd, ctrl, eccstat, i);
> +
> + if (errors == 15) {
> + /*
> + * Uncorrectable error.
> + * OK only if the whole page is blank.
> + *
> + * We disable ECCER reporting due to...
s/due to.../due to/
Otherwise looks good.
-Scott
^ permalink raw reply
* Re: [PATCH 1/2] P1025RDB: add Quicc Engine support
From: Tabi Timur-B04825 @ 2012-01-20 20:50 UTC (permalink / raw)
To: Fan Zhicheng-B32736; +Cc: linuxppc-dev@lists.ozlabs.org, Fanzc
In-Reply-To: <1327035611-22794-1-git-send-email-B32736@freescale.com>
On Thu, Jan 19, 2012 at 11:00 PM, Zhicheng Fan <B32736@freescale.com> wrote=
:
> From: Fanzc <b32736@freeescale.com>
>
> Signed-off-by: Fanzc <b32736@freeescale.com>
Please use your full name (first and last name)
> ---
> =A0arch/powerpc/platforms/85xx/mpc85xx_rdb.c | =A0 79 +++++++++++++++++++=
+++++++++-
> =A01 files changed, 78 insertions(+), 1 deletions(-)
>
> diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/pla=
tforms/85xx/mpc85xx_rdb.c
> index 1950076..1ba67aa 100644
> --- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
> +++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
> @@ -26,6 +26,9 @@
> =A0#include <asm/prom.h>
> =A0#include <asm/udbg.h>
> =A0#include <asm/mpic.h>
> +#include <asm/qe.h>
> +#include <asm/qe_ic.h>
> +#include <asm/fsl_guts.h>
>
> =A0#include <sysdev/fsl_soc.h>
> =A0#include <sysdev/fsl_pci.h>
> @@ -47,6 +50,10 @@ void __init mpc85xx_rdb_pic_init(void)
> =A0 =A0 =A0 =A0struct mpic *mpic;
> =A0 =A0 =A0 =A0unsigned long root =3D of_get_flat_dt_root();
>
> +#ifdef CONFIG_QUICC_ENGINE
> + =A0 =A0 =A0 struct device_node *np;
> +#endif
> +
> =A0 =A0 =A0 =A0if (of_flat_dt_is_compatible(root, "fsl,MPC85XXRDB-CAMP"))=
{
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mpic =3D mpic_alloc(NULL, 0,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0MPIC_BIG_ENDIAN | MPIC_BRO=
KEN_FRR_NIRQS |
> @@ -62,6 +69,18 @@ void __init mpc85xx_rdb_pic_init(void)
>
> =A0 =A0 =A0 =A0BUG_ON(mpic =3D=3D NULL);
> =A0 =A0 =A0 =A0mpic_init(mpic);
> +
> +#ifdef CONFIG_QUICC_ENGINE
> + =A0 =A0 =A0 np =3D of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
> + =A0 =A0 =A0 if (np) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 qe_ic_casca=
de_high_mpic);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(np);
> +
> + =A0 =A0 =A0 } else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "Could not find qe-ic node\=
n");
Use pr_err instead of printk(KERN_ERR
> +#endif
> +
> =A0}
>
> =A0/*
> @@ -69,7 +88,7 @@ void __init mpc85xx_rdb_pic_init(void)
> =A0*/
> =A0static void __init mpc85xx_rdb_setup_arch(void)
> =A0{
> -#ifdef CONFIG_PCI
> +#if defined(CONFIG_PCI) || defined(CONFIG_QUICC_ENGINE)
> =A0 =A0 =A0 =A0struct device_node *np;
> =A0#endif
>
> @@ -85,6 +104,64 @@ static void __init mpc85xx_rdb_setup_arch(void)
> =A0#endif
>
> =A0 =A0 =A0 =A0mpc85xx_smp_init();
> +
> +#ifdef CONFIG_QUICC_ENGINE
> + =A0 =A0 =A0 np =3D of_find_compatible_node(NULL, NULL, "fsl,qe");
> + =A0 =A0 =A0 if (!np) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "Could not find Quicc Engin=
e node\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto qe_fail;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 qe_reset();
> + =A0 =A0 =A0 of_node_put(np);
> +
> + =A0 =A0 =A0 np =3D of_find_node_by_name(NULL, "par_io");
> + =A0 =A0 =A0 if (np) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct device_node *ucc;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 par_io_init(np);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(np);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 for_each_node_by_name(ucc, "ucc")
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 par_io_of_config(ucc);
> +
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 if (machine_is(p1025_rdb)) {
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 __be32 __iomem *pmuxcr;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 np =3D of_find_node_by_name(NULL, "global-u=
tilities");
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (np) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pmuxcr =3D of_iomap(np, 0) =
+ MPC85xx_PMUXCR_OFFSET;
You're missing the iounmap().
--=20
Timur Tabi
Linux kernel developer at Freescale=
^ permalink raw reply
* Re: [PATCH] powerpc/booke64: Configurable lazy interrupt disabling
From: Benjamin Herrenschmidt @ 2012-01-20 23:02 UTC (permalink / raw)
To: Stuart Yoder; +Cc: Laurentiu Tudor, linuxppc-dev
In-Reply-To: <CALRxmdC_E4Z==4R_2MGHAi3T7mdF9oHx3rBE6Meb+3R1gWF5VQ@mail.gmail.com>
> With Topaz, interrupts go directly to guests and we don't want to require a
> trap/hcall to do an IACK, as that adds potentially thousands of cycles of
> latency to every interrupt.
>
> As you know, with external proxy interrupts are acknowledged by the
> hardware and it becomes problematic to replay the interrupt in
> the context of lazy EE when interrupts are re-enabled. The interrupt
> will not fire again when you enable EE.
So you have a broken HW and broken HV design to start with ... :-)
> That is currently the issue, as we can't run the 64-bit kernel on Topaz.
> Our option are:
> 1) to provide an option to disable lazy EE
> 2) do some kind of hack to replay interrupts with lazy EE
> 3) change Topaz to support legacy IACK, but this gets ugly for
> various reasons.
>
> Providing a config option to disable lazy EE seemed to be a good
> approach.
A config option is bad because it gets us yet another step toward
non-generic kernels.
Why don't you look into what would be needed to do a replay ? There are
many ways to achieve this, using the DEC is one that wouldn't involve
the hypervisor for example. But the case of an interrupt occurring while
masked is actually pretty low key so the overhead of an hcall at that
point wouldn't be too bad I beleive, so you could also implement some
kind of retry hcall which can internally be implemented using a guest
doorbell or something similar.
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH] powerpc/booke64: Configurable lazy interrupt disabling
From: Benjamin Herrenschmidt @ 2012-01-20 23:05 UTC (permalink / raw)
To: Stuart Yoder; +Cc: Laurentiu Tudor, linuxppc-dev
In-Reply-To: <CALRxmdA9mh6x5YGK1oFHvgmV-RsnN6WkxhpZbcRJv1S8Y0RH1w@mail.gmail.com>
On Thu, 2012-01-19 at 13:29 -0600, Stuart Yoder wrote:
> Also, Scott had posted an approach to do option #2 a while back,
> but as I recall there was some negative feedback about this. See:
> <http://lists.ozlabs.org/pipermail/linuxppc-dev/2011-August/092103.html>
I see... the problems with doorbells are workable tho. A reject hcall
could also raise the CPU priority to avoid lower priority interrupts for
example. The decrementer option works too.
Another approach is to do an hcall into the interrupt re-enable path
when an interrupt occurred while masked, which is what we do on i or
ps3, which could then trigger a replay.
Traditionally EE's have always been "level sensitive" on PowerPC, the
way you changed that is arguably an utterly broken HW design and I am
not too keen on changing our core interrupt handling to deal with it via
ifdef's if we can find a less invasive solution.
Cheers,
Ben.
^ permalink raw reply
* Re: error: 'cpus_in_crash' defined but not used
From: Christian Kujau @ 2012-01-21 0:45 UTC (permalink / raw)
To: LKML; +Cc: linuxppc-dev
In-Reply-To: <alpine.DEB.2.01.1201172104410.2895@trent.utfs.org>
> On Tue, 17 Jan 2012 at 20:13, Christian Kujau wrote:
> >
> > compiling today's git (mainline, a25a2b8) on powerpc32 gives:
> >
> > CC arch/powerpc/kernel/crash.o
> > cc1: warnings being treated as errors
> > /usr/local/src/linux-2.6-git/arch/powerpc/kernel/crash.c:49: error:
> > ‘cpus_in_crash’ defined but not used
> > make[2]: *** [arch/powerpc/kernel/crash.o] Error 1
> > make[1]: *** [arch/powerpc/kernel] Error 2
> > make: *** [sub-make] Error 2
This still happens in 3.3.0-rc1 and is fixed by the patch below.
.config is here: http://nerdbynature.de/bits/3.2.0/
Thoughts?
Thanks,
Christian.
> I could not find cpus_in_crash anywhere in the sourcetree, except for
> arch/powerpc/kernel/crash.c. Moving the definition into the CONFIG_SMP
> ifdef helps on my UP system, of course - not sure about other machines
> though:
>
> diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
> index 28be345..abef751 100644
> --- a/arch/powerpc/kernel/crash.c
> +++ b/arch/powerpc/kernel/crash.c
> @@ -46,7 +46,6 @@
>
> /* This keeps a track of which one is the crashing cpu. */
> int crashing_cpu = -1;
> -static atomic_t cpus_in_crash;
> static int time_to_dump;
>
> #define CRASH_HANDLER_MAX 3
> @@ -66,6 +65,7 @@ static int handle_fault(struct pt_regs *regs)
>
> #ifdef CONFIG_SMP
>
> +static atomic_t cpus_in_crash;
> void crash_ipi_callback(struct pt_regs *regs)
> {
> static cpumask_t cpus_state_saved = CPU_MASK_NONE;
>
>
> Christian.
> --
> BOFH excuse #272:
>
> Netscape has crashed
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
--
BOFH excuse #51:
Cosmic ray particles crashed through the hard disk platter
^ permalink raw reply
* [PATCH] powerpc: dont include 8250 pre-setup if 8250 driver isn't enabled.
From: Paul Gortmaker @ 2012-01-21 3:50 UTC (permalink / raw)
To: benh, paulus; +Cc: Paul Gortmaker, linuxppc-dev
The legacy_serial code was setting things up based on the assumption
that the main 8250 driver would be loaded shortly after. But some
randconfigs exposed an issue where early debug (UDB) UART support was
enabled, yet the core UART 8250 support was disabled.
In theory a person could care about _really_ early UART output for
early debug, but not care about generic console output via UART on
embedded devices, so fix things so it is a valid combination.
While this might seem like a pointless randconfig change, there are
some existing default configs that actually reflect the above setup.
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
index 3fea368..9a82a49 100644
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -413,6 +413,14 @@ void __init find_legacy_serial_ports(void)
DBG(" <- find_legacy_serial_port()\n");
}
+/*
+ * In theory, one could have the early debugging enabled, but yet not care
+ * about 8250 after that, i.e. PPC_UDBG_16550=y but "SERIAL_8250 is not set".
+ * Mostly appears in randconfig builds, but some defconfigs have this.
+ */
+
+#ifdef CONFIG_SERIAL_8250
+
static struct platform_device serial_device = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM,
@@ -523,6 +531,7 @@ static int __init serial_dev_init(void)
}
device_initcall(serial_dev_init);
+#endif /* CONFIG_SERIAL_8250 */
#ifdef CONFIG_SERIAL_8250_CONSOLE
/*
--
1.7.7.2
^ permalink raw reply related
* [PATCH] powerpc/85xx: fix build failure from p1022 in SMP defconfig
From: Paul Gortmaker @ 2012-01-21 14:52 UTC (permalink / raw)
To: galak; +Cc: paulus, linuxppc-dev, Paul Gortmaker
Using the configs/mpc85xx_smp_defconfig shows this build error:
arch/powerpc/platforms/85xx/p1022_ds.c:341: error: 'udbg_progress' undeclared here (not in a function)
Adding in the obvious missing header <asm/udbg.h> fixes it.
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c
index bb3d84f..aa4022e 100644
--- a/arch/powerpc/platforms/85xx/p1022_ds.c
+++ b/arch/powerpc/platforms/85xx/p1022_ds.c
@@ -26,6 +26,7 @@
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
#include <asm/fsl_guts.h>
+#include <asm/udbg.h>
#include "smp.h"
#include "mpc85xx.h"
--
1.7.7.2
^ permalink raw reply related
* Re: [PATCH] powerpc/85xx: fix build failure from p1022 in SMP defconfig
From: Paul Gortmaker @ 2012-01-21 15:50 UTC (permalink / raw)
To: galak; +Cc: linuxppc-dev, paulus
In-Reply-To: <1327157528-12312-1-git-send-email-paul.gortmaker@windriver.com>
On Sat, Jan 21, 2012 at 9:52 AM, Paul Gortmaker
<paul.gortmaker@windriver.com> wrote:
> Using the configs/mpc85xx_smp_defconfig shows this build error:
>
> arch/powerpc/platforms/85xx/p1022_ds.c:341: error: 'udbg_progress' undecl=
ared here (not in a function)
>
> Adding in the obvious missing header <asm/udbg.h> fixes it.
I just noticed this fix is a duplicate, it seems that it was already
queued back in Dec 11th last year:
http://patchwork.ozlabs.org/patch/130620/
...but for one reason or another didn't make it into 3.3-rc1.
P.
>
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
>
> diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platfo=
rms/85xx/p1022_ds.c
> index bb3d84f..aa4022e 100644
> --- a/arch/powerpc/platforms/85xx/p1022_ds.c
> +++ b/arch/powerpc/platforms/85xx/p1022_ds.c
> @@ -26,6 +26,7 @@
> =A0#include <sysdev/fsl_soc.h>
> =A0#include <sysdev/fsl_pci.h>
> =A0#include <asm/fsl_guts.h>
> +#include <asm/udbg.h>
> =A0#include "smp.h"
>
> =A0#include "mpc85xx.h"
> --
> 1.7.7.2
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* Searching TLB entry for a page frame number.
From: Arshad, Farrukh @ 2012-01-23 7:49 UTC (permalink / raw)
To: linuxppc-dev@lists.ozlabs.org
[-- Attachment #1: Type: text/plain, Size: 614 bytes --]
Greetings All,
I have a quick question regarding TLB dump for P1022. Please excuse me for being naïve. I want to dump the TLB entry for a page number. I know my page frame number. If I read TLB0 dump using tlbre instruction, the instruction output TLB0 entries in MAS0 - MAS3 registers. After the tlbre instruction the value of MAS3 register [32-51] RPN, Is this Real Page Number is the page frame number for which I am searching the TLB entry.
Best Regards
Farrukh Arshad
Sr. Software Development Engineer
Mentor Graphics Pakistan
Ph: +92 - 423 - 609 - 92 - 09
Cell: +92 - 303 - 444 - 77 - 05
[-- Attachment #2: Type: text/html, Size: 3035 bytes --]
^ permalink raw reply
* Re: Cannot wake-up from standby with MPC8313
From: ehodys @ 2012-01-23 10:08 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <4F19C8F8.1090801@freescale.com>
Hello al,
I am newbie about porting Linux on a ADS512101 Dev tool and I don't
know how to put the video display at work. The only thing that works
is the serial interface and I find no information to switch to the LCD
display.
Can some one help me please, thank you.
Best regards
Edgar
^ permalink raw reply
* Cannot wake-up from standby with MPC8313
From: nvbolhuis @ 2012-01-23 9:34 UTC (permalink / raw)
To: scottwood; +Cc: linuxppc-dev
>
> It is mentioned in the MPC8313E manual (4.2.2 step #10) that TRST must
> not be asserted except when PORESET is asserted. The mpc8313erdb bug
> was that the board was not complying with this.
>
ok, I see.
The board did not comply to the spec and as a side-effect PMC
registers could not be accessed.
Thanks again for all help!
---
NvBolhuis
^ permalink raw reply
* Problem with ADS512101 : Switch from serial I/O to LCD
From: ehodys @ 2012-01-23 18:01 UTC (permalink / raw)
To: linuxppc-dev
Hello all,
I am newbie about porting Linux on a ADS512101 Dev tool and I don't
know how to put the video display at work. The only thing that works
is the serial interface and I find no information to switch to the LCD
display.
Can some one help me please, thank you.
Best regards
Edgar
^ permalink raw reply
* Re: [PATCH] powerpc/booke64: Configurable lazy interrupt disabling
From: Scott Wood @ 2012-01-23 19:21 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Laurentiu Tudor, linuxppc-dev, Stuart Yoder
In-Reply-To: <1327100755.2923.6.camel@pasglop>
On 01/20/2012 05:05 PM, Benjamin Herrenschmidt wrote:
> On Thu, 2012-01-19 at 13:29 -0600, Stuart Yoder wrote:
>> Also, Scott had posted an approach to do option #2 a while back,
>> but as I recall there was some negative feedback about this. See:
>> <http://lists.ozlabs.org/pipermail/linuxppc-dev/2011-August/092103.html>
>
> I see... the problems with doorbells are workable tho. A reject hcall
> could also raise the CPU priority to avoid lower priority interrupts for
> example. The decrementer option works too.
>
> Another approach is to do an hcall into the interrupt re-enable path
> when an interrupt occurred while masked, which is what we do on i or
> ps3, which could then trigger a replay.
Here's what I previously wrote to you about this:
> If we never hard-enable with a pending interrupt (go straight to the
> exception entry), we can leave the interrupt in EPR. If we hard-enable
> even briefly, we can't guarantee that another (higher priority)
> interrupt won't come in before the doorbell, so we need to be able to
> queue up a number of interrupts equal to the number of priorities in use.
>
> Care will need to be taken to dequeue in proper order, whether the
> interrupt comes in via extirq or doorbell (e.g. if we take an extirq on
> hard-enable, and then the doorbell fires when that interrupt
> hard-enables, we don't want to run the lower-priority queued interrupt
> until after the high prio handler is done).
>
> BTW, for non-booke, when is DEC checked when interrupts are hard-enabled
> as part of exception return? Likewise with the PS3 HV thing. I only
> see the iseries check in the exception path.
Perhaps the issues with a higher priority interrupt intervening can be
addressed by messing around with current task priority at the MPIC (with
an hcall introduced for the hv case, since currently task priority is
not exposed to the guest). I haven't had time to revisit this, and
don't expect to soon. If someone else wants to try, fine. In the
meantime, lazy EE is causing problems.
I'd still like to know the answer to that last question. It's difficult
to determine how to correctly implement this stuff for our hardware if
it looks like there are holes in the scheme for hardware that this is
supposed to already work with.
> Traditionally EE's have always been "level sensitive" on PowerPC,
You mean besides the places you already have to work around, such as
doorbells and book3s decrementers and other hypervisors... and you force
all functions that enable interrupts to create a stack frame to deal
with this.
> the way you changed that is arguably an utterly broken HW design
Just because you don't like it, and it doesn't play well with your hack,
doesn't make it "utterly broken".
> and I am not too keen on changing our core interrupt handling to deal with it via
> ifdef's if we can find a less invasive solution.
Wheras having to significantly change the way interrupts work because
the register size doubled is so totally reasonable...
What is the compelling reason for forcing lazy EE on us? Why is it tied
to 64-bit?
-Scott
^ permalink raw reply
* Re: [PATCH] powerpc/booke64: Configurable lazy interrupt disabling
From: Scott Wood @ 2012-01-23 19:31 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Laurentiu Tudor, linuxppc-dev, Stuart Yoder
In-Reply-To: <1327100531.2923.3.camel@pasglop>
On 01/20/2012 05:02 PM, Benjamin Herrenschmidt wrote:
>
>> With Topaz, interrupts go directly to guests and we don't want to require a
>> trap/hcall to do an IACK, as that adds potentially thousands of cycles of
>> latency to every interrupt.
>>
>> As you know, with external proxy interrupts are acknowledged by the
>> hardware and it becomes problematic to replay the interrupt in
>> the context of lazy EE when interrupts are re-enabled. The interrupt
>> will not fire again when you enable EE.
>
> So you have a broken HW and broken HV design to start with ... :-)
That "breakage" significantly reduces the overhead of handling
interrupts in a guest, since we don't need to involve the hypervisor (at
least on the entry side -- there's a hack to avoid it on EOI as well,
though that involves exposing some MPIC registers directly; users can
decide whether it's worth enabling for their use case).
-Scott
^ permalink raw reply
* Re: Searching TLB entry for a page frame number.
From: Scott Wood @ 2012-01-23 19:33 UTC (permalink / raw)
To: Arshad, Farrukh; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <93CD5F41FDBC6042A6B449764F3B35CC050CDFE1@EU-MBX-03.mgc.mentorg.com>
On 01/23/2012 01:49 AM, Arshad, Farrukh wrote:
> Greetings All,
>=20
> =20
>=20
> I have a quick question regarding TLB dump for P1022. Please excuse me
> for being na=EFve. I want to dump the TLB entry for a page number. I kn=
ow
> my page frame number. If I read TLB0 dump using tlbre instruction, the
> instruction output TLB0 entries in MAS0 =96 MAS3 registers. After the
> tlbre instruction the value of MAS3 register [32-51] RPN, Is this Real
> Page Number is the page frame number for which I am searching the TLB e=
ntry.
Yes, and MAS7 contains the upper 4 bits.
-Scott
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox