* [PATCH 2/2] P4080/mtd: Fix the freescale lbc issue with 36bit mode
From: Roy Zang @ 2010-10-18 7:22 UTC (permalink / raw)
To: linux-mtd; +Cc: B07421, dedekind1, B25806, linuxppc-dev, akpm, dwmw2, B11780
In-Reply-To: <1287386552-10647-1-git-send-email-tie-fei.zang@freescale.com>
From: Lan Chunhe-B25806 <b25806@freescale.com>
When system uses 36bit physical address, res.start is 36bit
physical address. But the function of in_be32 returns 32bit
physical address. Then both of them compared each other is
wrong. So by converting the address of res.start into
the right format fixes this issue.
Signed-off-by: Lan Chunhe-B25806 <b25806@freescale.com>
Signed-off-by: Roy Zang <tie-fei.zang@freescale.com>
Reviewed-by: Anton Vorontsov <cbouatmailru@gmail.com>
---
arch/powerpc/include/asm/fsl_lbc.h | 1 +
arch/powerpc/sysdev/fsl_lbc.c | 23 ++++++++++++++++++++++-
drivers/mtd/nand/fsl_elbc_nand.c | 2 +-
3 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h
index 0c40c05..7639cbd 100644
--- a/arch/powerpc/include/asm/fsl_lbc.h
+++ b/arch/powerpc/include/asm/fsl_lbc.h
@@ -248,6 +248,7 @@ struct fsl_upm {
int width;
};
+extern u32 fsl_lbc_addr(phys_addr_t addr_base);
extern int fsl_lbc_find(phys_addr_t addr_base);
extern int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm);
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
index 4bb0336..29ba867 100644
--- a/arch/powerpc/sysdev/fsl_lbc.c
+++ b/arch/powerpc/sysdev/fsl_lbc.c
@@ -34,6 +34,27 @@ struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
EXPORT_SYMBOL(fsl_lbc_ctrl_dev);
/**
+ * fsl_lbc_addr - convert the base address
+ * @addr_base: base address of the memory bank
+ *
+ * This function converts a base address of lbc into the right format for the
+ * BR register. If the SOC has eLBC then it returns 32bit physical address
+ * else it convers a 34bit local bus physical address to correct format of
+ * 32bit address for BR register (Example: MPC8641).
+ */
+u32 fsl_lbc_addr(phys_addr_t addr_base)
+{
+ struct device_node *np = fsl_lbc_ctrl_dev->dev->of_node;
+ u32 addr = addr_base & 0xffff8000;
+
+ if (of_device_is_compatible(np, "fsl,elbc"))
+ return addr;
+
+ return addr | ((addr_base & 0x300000000ull) >> 19);
+}
+EXPORT_SYMBOL(fsl_lbc_addr);
+
+/**
* fsl_lbc_find - find Localbus bank
* @addr_base: base address of the memory bank
*
@@ -55,7 +76,7 @@ int fsl_lbc_find(phys_addr_t addr_base)
__be32 br = in_be32(&lbc->bank[i].br);
__be32 or = in_be32(&lbc->bank[i].or);
- if (br & BR_V && (br & or & BR_BA) == addr_base)
+ if (br & BR_V && (br & or & BR_BA) == fsl_lbc_addr(addr_base))
return i;
}
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 400f01f..8785317 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -868,7 +868,7 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)
(in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM &&
(in_be32(&lbc->bank[bank].br) &
in_be32(&lbc->bank[bank].or) & BR_BA)
- == res.start)
+ == fsl_lbc_addr(res.start))
break;
if (bank >= MAX_BANKS) {
--
1.5.6.5
^ permalink raw reply related
* [PATCH 1/2] P4080/eLBC: Make Freescale elbc interrupt common to elbc devices
From: Roy Zang @ 2010-10-18 7:22 UTC (permalink / raw)
To: linux-mtd; +Cc: B07421, dedekind1, B25806, linuxppc-dev, akpm, dwmw2, B11780
Move Freescale elbc interrupt from nand dirver to elbc driver.
Then all elbc devices can use the interrupt instead of ONLY nand.
For former nand driver, it had the two functions:
1. detecting nand flash partitions;
2. registering elbc interrupt.
Now, second function is removed to fsl_lbc.c.
Signed-off-by: Lan Chunhe-B25806 <b25806@freescale.com>
Signed-off-by: Roy Zang <tie-fei.zang@freescale.com>
Reviewed-by: Anton Vorontsov <cbouatmailru@gmail.com>
Cc: Wood Scott-B07421 <B07421@freescale.com>
---
These two patches are based on the following commits:
1. http://lists.infradead.org/pipermail/linux-mtd/2010-September/032112.html
2. http://lists.infradead.org/pipermail/linux-mtd/2010-September/032110.html
3. http://lists.infradead.org/pipermail/linux-mtd/2010-September/032111.html
According to Anton's comment, I merge 1 & 2 together and start a new thread.
Comparing the provided link:
1. Merge 1 & 2 together.
2. Some code style updates
3. Add counter protect for elbc driver remove
4. Rebase to 2.6.36-rc7
Other histories from the links:
V2: Comparing with v1, according to the feedback, add some decorations.
V3: Comparing with v2:
1. according to the feedback, add some decorations.
2. change of_platform_driver to platform_driver
3. rebase to 2.6.36-rc4
V4: Comparing with v3
1. minor fix from type unsigned int to u32
2. fix platform_driver issue.
3. add mutex for nand probe
arch/powerpc/Kconfig | 7 +-
arch/powerpc/include/asm/fsl_lbc.h | 33 +++-
arch/powerpc/sysdev/fsl_lbc.c | 229 ++++++++++++++---
drivers/mtd/nand/Kconfig | 1 +
drivers/mtd/nand/fsl_elbc_nand.c | 482 +++++++++++++++---------------------
5 files changed, 425 insertions(+), 327 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 631e5a0..44df1ba 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -687,9 +687,12 @@ config 4xx_SOC
bool
config FSL_LBC
- bool
+ bool "Freescale Local Bus support"
+ depends on FSL_SOC
help
- Freescale Localbus support
+ Enables reporting of errors from the Freescale local bus
+ controller. Also contains some common code used by
+ drivers for specific local bus peripherals.
config FSL_GTM
bool
diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h
index 1b5a210..0c40c05 100644
--- a/arch/powerpc/include/asm/fsl_lbc.h
+++ b/arch/powerpc/include/asm/fsl_lbc.h
@@ -1,9 +1,10 @@
/* Freescale Local Bus Controller
*
- * Copyright (c) 2006-2007 Freescale Semiconductor
+ * Copyright (c) 2006-2007, 2010 Freescale Semiconductor
*
* Authors: Nick Spence <nick.spence@freescale.com>,
* Scott Wood <scottwood@freescale.com>
+ * Jack Lan <jack.lan@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
@@ -26,6 +27,8 @@
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
struct fsl_lbc_bank {
__be32 br; /**< Base Register */
@@ -125,13 +128,23 @@ struct fsl_lbc_regs {
#define LTESR_ATMW 0x00800000
#define LTESR_ATMR 0x00400000
#define LTESR_CS 0x00080000
+#define LTESR_UPM 0x00000002
#define LTESR_CC 0x00000001
#define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC)
+#define LTESR_MASK (LTESR_BM | LTESR_FCT | LTESR_PAR | LTESR_WP \
+ | LTESR_ATMW | LTESR_ATMR | LTESR_CS | LTESR_UPM \
+ | LTESR_CC)
+#define LTESR_CLEAR 0xFFFFFFFF
+#define LTECCR_CLEAR 0xFFFFFFFF
+#define LTESR_STATUS LTESR_MASK
+#define LTEIR_ENABLE LTESR_MASK
+#define LTEDR_ENABLE 0x00000000
__be32 ltedr; /**< Transfer Error Disable Register */
__be32 lteir; /**< Transfer Error Interrupt Register */
__be32 lteatr; /**< Transfer Error Attributes Register */
__be32 ltear; /**< Transfer Error Address Register */
- u8 res6[0xC];
+ __be32 lteccr; /**< Transfer Error ECC Register */
+ u8 res6[0x8];
__be32 lbcr; /**< Configuration Register */
#define LBCR_LDIS 0x80000000
#define LBCR_LDIS_SHIFT 31
@@ -265,7 +278,23 @@ static inline void fsl_upm_end_pattern(struct fsl_upm *upm)
cpu_relax();
}
+/* overview of the fsl lbc controller */
+
+struct fsl_lbc_ctrl {
+ /* device info */
+ struct device *dev;
+ struct fsl_lbc_regs __iomem *regs;
+ int irq;
+ wait_queue_head_t irq_wait;
+ spinlock_t lock;
+ void *nand;
+
+ /* status read from LTESR by irq handler */
+ unsigned int irq_status;
+};
+
extern int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base,
u32 mar);
+extern struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
#endif /* __ASM_FSL_LBC_H */
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
index dceb8d1..4bb0336 100644
--- a/arch/powerpc/sysdev/fsl_lbc.c
+++ b/arch/powerpc/sysdev/fsl_lbc.c
@@ -2,8 +2,11 @@
* Freescale LBC and UPM routines.
*
* Copyright (c) 2007-2008 MontaVista Software, Inc.
+ * Copyright (c) 2010 Freescale Semiconductor
*
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ * Author: Jack Lan <Jack.Lan@freescale.com>
+ * Author: Roy Zang <tie-fei.zang@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
@@ -19,39 +22,16 @@
#include <linux/types.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
#include <asm/prom.h>
#include <asm/fsl_lbc.h>
static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
-static struct fsl_lbc_regs __iomem *fsl_lbc_regs;
-
-static char __initdata *compat_lbc[] = {
- "fsl,pq2-localbus",
- "fsl,pq2pro-localbus",
- "fsl,pq3-localbus",
- "fsl,elbc",
-};
-
-static int __init fsl_lbc_init(void)
-{
- struct device_node *lbus;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) {
- lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]);
- if (lbus)
- goto found;
- }
- return -ENODEV;
-
-found:
- fsl_lbc_regs = of_iomap(lbus, 0);
- of_node_put(lbus);
- if (!fsl_lbc_regs)
- return -ENOMEM;
- return 0;
-}
-arch_initcall(fsl_lbc_init);
+struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
+EXPORT_SYMBOL(fsl_lbc_ctrl_dev);
/**
* fsl_lbc_find - find Localbus bank
@@ -65,13 +45,15 @@ arch_initcall(fsl_lbc_init);
int fsl_lbc_find(phys_addr_t addr_base)
{
int i;
+ struct fsl_lbc_regs __iomem *lbc;
- if (!fsl_lbc_regs)
+ if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
return -ENODEV;
- for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) {
- __be32 br = in_be32(&fsl_lbc_regs->bank[i].br);
- __be32 or = in_be32(&fsl_lbc_regs->bank[i].or);
+ lbc = fsl_lbc_ctrl_dev->regs;
+ for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) {
+ __be32 br = in_be32(&lbc->bank[i].br);
+ __be32 or = in_be32(&lbc->bank[i].or);
if (br & BR_V && (br & or & BR_BA) == addr_base)
return i;
@@ -94,22 +76,27 @@ int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm)
{
int bank;
__be32 br;
+ struct fsl_lbc_regs __iomem *lbc;
bank = fsl_lbc_find(addr_base);
if (bank < 0)
return bank;
- br = in_be32(&fsl_lbc_regs->bank[bank].br);
+ if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
+ return -ENODEV;
+
+ lbc = fsl_lbc_ctrl_dev->regs;
+ br = in_be32(&lbc->bank[bank].br);
switch (br & BR_MSEL) {
case BR_MS_UPMA:
- upm->mxmr = &fsl_lbc_regs->mamr;
+ upm->mxmr = &lbc->mamr;
break;
case BR_MS_UPMB:
- upm->mxmr = &fsl_lbc_regs->mbmr;
+ upm->mxmr = &lbc->mbmr;
break;
case BR_MS_UPMC:
- upm->mxmr = &fsl_lbc_regs->mcmr;
+ upm->mxmr = &lbc->mcmr;
break;
default:
return -EINVAL;
@@ -148,9 +135,12 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
int ret = 0;
unsigned long flags;
+ if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
+ return -ENODEV;
+
spin_lock_irqsave(&fsl_lbc_lock, flags);
- out_be32(&fsl_lbc_regs->mar, mar);
+ out_be32(&fsl_lbc_ctrl_dev->regs->mar, mar);
switch (upm->width) {
case 8:
@@ -172,3 +162,166 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
return ret;
}
EXPORT_SYMBOL(fsl_upm_run_pattern);
+
+static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl)
+{
+ struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+
+ /* clear event registers */
+ setbits32(&lbc->ltesr, LTESR_CLEAR);
+ out_be32(&lbc->lteatr, 0);
+ out_be32(&lbc->ltear, 0);
+ out_be32(&lbc->lteccr, LTECCR_CLEAR);
+ out_be32(&lbc->ltedr, LTEDR_ENABLE);
+
+ /* Enable interrupts for any detected events */
+ out_be32(&lbc->lteir, LTEIR_ENABLE);
+
+ return 0;
+}
+
+/*
+ * NOTE: This interrupt is used to report localbus events of various kinds,
+ * such as transaction errors on the chipselects.
+ */
+
+static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data)
+{
+ struct fsl_lbc_ctrl *ctrl = data;
+ struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+ u32 status;
+
+ status = in_be32(&lbc->ltesr);
+ if (!status)
+ return IRQ_NONE;
+
+ out_be32(&lbc->ltesr, LTESR_CLEAR);
+ out_be32(&lbc->lteatr, 0);
+ out_be32(&lbc->ltear, 0);
+ ctrl->irq_status = status;
+
+ if (status & LTESR_BM)
+ dev_err(ctrl->dev, "Local bus monitor time-out: "
+ "LTESR 0x%08X\n", status);
+ if (status & LTESR_WP)
+ dev_err(ctrl->dev, "Write protect error: "
+ "LTESR 0x%08X\n", status);
+ if (status & LTESR_ATMW)
+ dev_err(ctrl->dev, "Atomic write error: "
+ "LTESR 0x%08X\n", status);
+ if (status & LTESR_ATMR)
+ dev_err(ctrl->dev, "Atomic read error: "
+ "LTESR 0x%08X\n", status);
+ if (status & LTESR_CS)
+ dev_err(ctrl->dev, "Chip select error: "
+ "LTESR 0x%08X\n", status);
+ if (status & LTESR_UPM)
+ ;
+ if (status & LTESR_FCT) {
+ dev_err(ctrl->dev, "FCM command time-out: "
+ "LTESR 0x%08X\n", status);
+ smp_wmb();
+ wake_up(&ctrl->irq_wait);
+ }
+ if (status & LTESR_PAR) {
+ dev_err(ctrl->dev, "Parity or Uncorrectable ECC error: "
+ "LTESR 0x%08X\n", status);
+ smp_wmb();
+ wake_up(&ctrl->irq_wait);
+ }
+ if (status & LTESR_CC) {
+ smp_wmb();
+ wake_up(&ctrl->irq_wait);
+ }
+ if (status & ~LTESR_MASK)
+ dev_err(ctrl->dev, "Unknown error: "
+ "LTESR 0x%08X\n", status);
+ return IRQ_HANDLED;
+}
+
+/*
+ * fsl_lbc_ctrl_probe
+ *
+ * called by device layer when it finds a device matching
+ * one our driver can handled. This code allocates all of
+ * the resources needed for the controller only. The
+ * resources for the NAND banks themselves are allocated
+ * in the chip probe function.
+*/
+
+static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev)
+{
+ int ret;
+
+ if (!dev->dev.of_node) {
+ dev_err(&dev->dev, "Device OF-Node is NULL");
+ return -EFAULT;
+ }
+
+ fsl_lbc_ctrl_dev = kzalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL);
+ if (!fsl_lbc_ctrl_dev)
+ return -ENOMEM;
+
+ dev_set_drvdata(&dev->dev, fsl_lbc_ctrl_dev);
+
+ spin_lock_init(&fsl_lbc_ctrl_dev->lock);
+ init_waitqueue_head(&fsl_lbc_ctrl_dev->irq_wait);
+
+ fsl_lbc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
+ if (!fsl_lbc_ctrl_dev->regs) {
+ dev_err(&dev->dev, "failed to get memory region\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ fsl_lbc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
+ if (fsl_lbc_ctrl_dev->irq == NO_IRQ) {
+ dev_err(&dev->dev, "failed to get irq resource\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ fsl_lbc_ctrl_dev->dev = &dev->dev;
+
+ ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev);
+ if (ret < 0)
+ goto err;
+
+ ret = request_irq(fsl_lbc_ctrl_dev->irq, fsl_lbc_ctrl_irq, 0,
+ "fsl-lbc", fsl_lbc_ctrl_dev);
+ if (ret != 0) {
+ dev_err(&dev->dev, "failed to install irq (%d)\n",
+ fsl_lbc_ctrl_dev->irq);
+ ret = fsl_lbc_ctrl_dev->irq;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ iounmap(fsl_lbc_ctrl_dev->regs);
+ kfree(fsl_lbc_ctrl_dev);
+ return ret;
+}
+
+static const struct of_device_id fsl_lbc_match[] = {
+ { .compatible = "fsl,elbc", },
+ { .compatible = "fsl,pq3-localbus", },
+ { .compatible = "fsl,pq2-localbus", },
+ { .compatible = "fsl,pq2pro-localbus", },
+ {},
+};
+
+static struct platform_driver fsl_lbc_ctrl_driver = {
+ .driver = {
+ .name = "fsl-lbc",
+ .of_match_table = fsl_lbc_match,
+ },
+ .probe = fsl_lbc_ctrl_probe,
+};
+
+static int __init fsl_lbc_init(void)
+{
+ return platform_driver_register(&fsl_lbc_ctrl_driver);
+}
+module_init(fsl_lbc_init);
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 8b4b67c..4132c46 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -458,6 +458,7 @@ config MTD_NAND_ORION
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on PPC_OF
+ select FSL_LBC
help
Various Freescale chips, including the 8313, include a NAND Flash
Controller Module with built-in hardware ECC capabilities.
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 80de0bf..400f01f 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -1,9 +1,11 @@
/* Freescale Enhanced Local Bus Controller NAND driver
*
- * Copyright (c) 2006-2007 Freescale Semiconductor
+ * Copyright (c) 2006-2007, 2010 Freescale Semiconductor
*
* Authors: Nick Spence <nick.spence@freescale.com>,
* Scott Wood <scottwood@freescale.com>
+ * Jack Lan <jack.lan@freescale.com>
+ * Roy Zang <tie-fei.zang@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
@@ -27,6 +29,7 @@
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
@@ -42,14 +45,12 @@
#define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
#define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
-struct fsl_elbc_ctrl;
-
/* mtd information per set */
struct fsl_elbc_mtd {
struct mtd_info mtd;
struct nand_chip chip;
- struct fsl_elbc_ctrl *ctrl;
+ struct fsl_lbc_ctrl *ctrl;
struct device *dev;
int bank; /* Chip select bank number */
@@ -58,18 +59,12 @@ struct fsl_elbc_mtd {
unsigned int fmr; /* FCM Flash Mode Register value */
};
-/* overview of the fsl elbc controller */
+/* Freescale eLBC FCM controller infomation */
-struct fsl_elbc_ctrl {
+struct fsl_elbc_fcm_ctrl {
struct nand_hw_control controller;
struct fsl_elbc_mtd *chips[MAX_BANKS];
- /* device info */
- struct device *dev;
- struct fsl_lbc_regs __iomem *regs;
- int irq;
- wait_queue_head_t irq_wait;
- unsigned int irq_status; /* status read from LTESR by irq handler */
u8 __iomem *addr; /* Address of assigned FCM buffer */
unsigned int page; /* Last page written to / read from */
unsigned int read_bytes; /* Number of bytes read during command */
@@ -79,6 +74,7 @@ struct fsl_elbc_ctrl {
unsigned int mdr; /* UPM/FCM Data Register value */
unsigned int use_mdr; /* Non zero if the MDR is to be set */
unsigned int oob; /* Non zero if operating on OOB data */
+ unsigned int counter; /* counter for the initializations */
char *oob_poi; /* Place to write ECC after read back */
};
@@ -164,11 +160,12 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
int buf_num;
- ctrl->page = page_addr;
+ elbc_fcm_ctrl->page = page_addr;
out_be32(&lbc->fbar,
page_addr >> (chip->phys_erase_shift - chip->page_shift));
@@ -185,16 +182,18 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
buf_num = page_addr & 7;
}
- ctrl->addr = priv->vbase + buf_num * 1024;
- ctrl->index = column;
+ elbc_fcm_ctrl->addr = priv->vbase + buf_num * 1024;
+ elbc_fcm_ctrl->index = column;
/* for OOB data point to the second half of the buffer */
if (oob)
- ctrl->index += priv->page_size ? 2048 : 512;
+ elbc_fcm_ctrl->index += priv->page_size ? 2048 : 512;
- dev_vdbg(ctrl->dev, "set_addr: bank=%d, ctrl->addr=0x%p (0x%p), "
+ dev_vdbg(priv->dev, "set_addr: bank=%d, "
+ "elbc_fcm_ctrl->addr=0x%p (0x%p), "
"index %x, pes %d ps %d\n",
- buf_num, ctrl->addr, priv->vbase, ctrl->index,
+ buf_num, elbc_fcm_ctrl->addr, priv->vbase,
+ elbc_fcm_ctrl->index,
chip->phys_erase_shift, chip->page_shift);
}
@@ -205,18 +204,19 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_lbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
/* Setup the FMR[OP] to execute without write protection */
out_be32(&lbc->fmr, priv->fmr | 3);
- if (ctrl->use_mdr)
- out_be32(&lbc->mdr, ctrl->mdr);
+ if (elbc_fcm_ctrl->use_mdr)
+ out_be32(&lbc->mdr, elbc_fcm_ctrl->mdr);
- dev_vdbg(ctrl->dev,
+ dev_vdbg(priv->dev,
"fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
- dev_vdbg(ctrl->dev,
+ dev_vdbg(priv->dev,
"fsl_elbc_run_command: fbar=%08x fpar=%08x "
"fbcr=%08x bank=%d\n",
in_be32(&lbc->fbar), in_be32(&lbc->fpar),
@@ -229,19 +229,18 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
/* wait for FCM complete flag or timeout */
wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
FCM_TIMEOUT_MSECS * HZ/1000);
- ctrl->status = ctrl->irq_status;
-
+ elbc_fcm_ctrl->status = ctrl->irq_status;
/* store mdr value in case it was needed */
- if (ctrl->use_mdr)
- ctrl->mdr = in_be32(&lbc->mdr);
+ if (elbc_fcm_ctrl->use_mdr)
+ elbc_fcm_ctrl->mdr = in_be32(&lbc->mdr);
- ctrl->use_mdr = 0;
+ elbc_fcm_ctrl->use_mdr = 0;
- if (ctrl->status != LTESR_CC) {
- dev_info(ctrl->dev,
+ if (elbc_fcm_ctrl->status != LTESR_CC) {
+ dev_info(priv->dev,
"command failed: fir %x fcr %x status %x mdr %x\n",
in_be32(&lbc->fir), in_be32(&lbc->fcr),
- ctrl->status, ctrl->mdr);
+ elbc_fcm_ctrl->status, elbc_fcm_ctrl->mdr);
return -EIO;
}
@@ -251,7 +250,7 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
{
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
if (priv->page_size) {
@@ -284,15 +283,16 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_lbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
- ctrl->use_mdr = 0;
+ elbc_fcm_ctrl->use_mdr = 0;
/* clear the read buffer */
- ctrl->read_bytes = 0;
+ elbc_fcm_ctrl->read_bytes = 0;
if (command != NAND_CMD_PAGEPROG)
- ctrl->index = 0;
+ elbc_fcm_ctrl->index = 0;
switch (command) {
/* READ0 and READ1 read the entire buffer to use hardware ECC. */
@@ -301,7 +301,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* fall-through */
case NAND_CMD_READ0:
- dev_dbg(ctrl->dev,
+ dev_dbg(priv->dev,
"fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
" 0x%x, column: 0x%x.\n", page_addr, column);
@@ -309,8 +309,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
set_addr(mtd, 0, page_addr, 0);
- ctrl->read_bytes = mtd->writesize + mtd->oobsize;
- ctrl->index += column;
+ elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+ elbc_fcm_ctrl->index += column;
fsl_elbc_do_read(chip, 0);
fsl_elbc_run_command(mtd);
@@ -318,14 +318,14 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* READOOB reads only the OOB because no ECC is performed. */
case NAND_CMD_READOOB:
- dev_vdbg(ctrl->dev,
+ dev_vdbg(priv->dev,
"fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
" 0x%x, column: 0x%x.\n", page_addr, column);
out_be32(&lbc->fbcr, mtd->oobsize - column);
set_addr(mtd, column, page_addr, 1);
- ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+ elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
fsl_elbc_do_read(chip, 1);
fsl_elbc_run_command(mtd);
@@ -333,7 +333,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* READID must read all 5 possible bytes while CEB is active */
case NAND_CMD_READID:
- dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
+ dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) |
(FIR_OP_UA << FIR_OP1_SHIFT) |
@@ -341,9 +341,9 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT);
/* 5 bytes for manuf, device and exts */
out_be32(&lbc->fbcr, 5);
- ctrl->read_bytes = 5;
- ctrl->use_mdr = 1;
- ctrl->mdr = 0;
+ elbc_fcm_ctrl->read_bytes = 5;
+ elbc_fcm_ctrl->use_mdr = 1;
+ elbc_fcm_ctrl->mdr = 0;
set_addr(mtd, 0, 0, 0);
fsl_elbc_run_command(mtd);
@@ -351,7 +351,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* ERASE1 stores the block and page address */
case NAND_CMD_ERASE1:
- dev_vdbg(ctrl->dev,
+ dev_vdbg(priv->dev,
"fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
"page_addr: 0x%x.\n", page_addr);
set_addr(mtd, 0, page_addr, 0);
@@ -359,7 +359,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* ERASE2 uses the block and page address from ERASE1 */
case NAND_CMD_ERASE2:
- dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
+ dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
out_be32(&lbc->fir,
(FIR_OP_CM0 << FIR_OP0_SHIFT) |
@@ -374,8 +374,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
(NAND_CMD_ERASE2 << FCR_CMD2_SHIFT));
out_be32(&lbc->fbcr, 0);
- ctrl->read_bytes = 0;
- ctrl->use_mdr = 1;
+ elbc_fcm_ctrl->read_bytes = 0;
+ elbc_fcm_ctrl->use_mdr = 1;
fsl_elbc_run_command(mtd);
return;
@@ -383,14 +383,12 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* SEQIN sets up the addr buffer and all registers except the length */
case NAND_CMD_SEQIN: {
__be32 fcr;
- dev_vdbg(ctrl->dev,
- "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
+ dev_vdbg(priv->dev,
+ "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
"page_addr: 0x%x, column: 0x%x.\n",
page_addr, column);
- ctrl->column = column;
- ctrl->oob = 0;
- ctrl->use_mdr = 1;
+ elbc_fcm_ctrl->use_mdr = 1;
fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
(NAND_CMD_SEQIN << FCR_CMD2_SHIFT) |
@@ -420,7 +418,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* OOB area --> READOOB */
column -= mtd->writesize;
fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
- ctrl->oob = 1;
+ elbc_fcm_ctrl->oob = 1;
} else {
WARN_ON(column != 0);
/* First 256 bytes --> READ0 */
@@ -429,24 +427,24 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
}
out_be32(&lbc->fcr, fcr);
- set_addr(mtd, column, page_addr, ctrl->oob);
+ set_addr(mtd, column, page_addr, elbc_fcm_ctrl->oob);
return;
}
/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
case NAND_CMD_PAGEPROG: {
int full_page;
- dev_vdbg(ctrl->dev,
+ dev_vdbg(priv->dev,
"fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
- "writing %d bytes.\n", ctrl->index);
+ "writing %d bytes.\n", elbc_fcm_ctrl->index);
/* if the write did not start at 0 or is not a full page
* then set the exact length, otherwise use a full page
* write so the HW generates the ECC.
*/
- if (ctrl->oob || ctrl->column != 0 ||
- ctrl->index != mtd->writesize + mtd->oobsize) {
- out_be32(&lbc->fbcr, ctrl->index);
+ if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 ||
+ elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) {
+ out_be32(&lbc->fbcr, elbc_fcm_ctrl->index);
full_page = 0;
} else {
out_be32(&lbc->fbcr, 0);
@@ -458,21 +456,21 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* Read back the page in order to fill in the ECC for the
* caller. Is this really needed?
*/
- if (full_page && ctrl->oob_poi) {
+ if (full_page && elbc_fcm_ctrl->oob_poi) {
out_be32(&lbc->fbcr, 3);
set_addr(mtd, 6, page_addr, 1);
- ctrl->read_bytes = mtd->writesize + 9;
+ elbc_fcm_ctrl->read_bytes = mtd->writesize + 9;
fsl_elbc_do_read(chip, 1);
fsl_elbc_run_command(mtd);
- memcpy_fromio(ctrl->oob_poi + 6,
- &ctrl->addr[ctrl->index], 3);
- ctrl->index += 3;
+ memcpy_fromio(elbc_fcm_ctrl->oob_poi + 6,
+ &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], 3);
+ elbc_fcm_ctrl->index += 3;
}
- ctrl->oob_poi = NULL;
+ elbc_fcm_ctrl->oob_poi = NULL;
return;
}
@@ -485,26 +483,26 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
out_be32(&lbc->fbcr, 1);
set_addr(mtd, 0, 0, 0);
- ctrl->read_bytes = 1;
+ elbc_fcm_ctrl->read_bytes = 1;
fsl_elbc_run_command(mtd);
/* The chip always seems to report that it is
* write-protected, even when it is not.
*/
- setbits8(ctrl->addr, NAND_STATUS_WP);
+ setbits8(elbc_fcm_ctrl->addr, NAND_STATUS_WP);
return;
/* RESET without waiting for the ready line */
case NAND_CMD_RESET:
- dev_dbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
+ dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
fsl_elbc_run_command(mtd);
return;
default:
- dev_err(ctrl->dev,
+ dev_err(priv->dev,
"fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
command);
}
@@ -524,24 +522,24 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
unsigned int bufsize = mtd->writesize + mtd->oobsize;
if (len <= 0) {
- dev_err(ctrl->dev, "write_buf of %d bytes", len);
- ctrl->status = 0;
+ dev_err(priv->dev, "write_buf of %d bytes", len);
+ elbc_fcm_ctrl->status = 0;
return;
}
- if ((unsigned int)len > bufsize - ctrl->index) {
- dev_err(ctrl->dev,
+ if ((unsigned int)len > bufsize - elbc_fcm_ctrl->index) {
+ dev_err(priv->dev,
"write_buf beyond end of buffer "
"(%d requested, %u available)\n",
- len, bufsize - ctrl->index);
- len = bufsize - ctrl->index;
+ len, bufsize - elbc_fcm_ctrl->index);
+ len = bufsize - elbc_fcm_ctrl->index;
}
- memcpy_toio(&ctrl->addr[ctrl->index], buf, len);
+ memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], buf, len);
/*
* This is workaround for the weird elbc hangs during nand write,
* Scott Wood says: "...perhaps difference in how long it takes a
@@ -549,9 +547,9 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
* is causing problems, and sync isn't helping for some reason."
* Reading back the last byte helps though.
*/
- in_8(&ctrl->addr[ctrl->index] + len - 1);
+ in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index] + len - 1);
- ctrl->index += len;
+ elbc_fcm_ctrl->index += len;
}
/*
@@ -562,13 +560,13 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
/* If there are still bytes in the FCM, then use the next byte. */
- if (ctrl->index < ctrl->read_bytes)
- return in_8(&ctrl->addr[ctrl->index++]);
+ if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes)
+ return in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index++]);
- dev_err(ctrl->dev, "read_byte beyond end of buffer\n");
+ dev_err(priv->dev, "read_byte beyond end of buffer\n");
return ERR_BYTE;
}
@@ -579,18 +577,19 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
int avail;
if (len < 0)
return;
- avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index);
- memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail);
- ctrl->index += avail;
+ avail = min((unsigned int)len,
+ elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
+ memcpy_fromio(buf, &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], avail);
+ elbc_fcm_ctrl->index += avail;
if (len > avail)
- dev_err(ctrl->dev,
+ dev_err(priv->dev,
"read_buf beyond end of buffer "
"(%d requested, %d available)\n",
len, avail);
@@ -603,30 +602,32 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
int i;
if (len < 0) {
- dev_err(ctrl->dev, "write_buf of %d bytes", len);
+ dev_err(priv->dev, "write_buf of %d bytes", len);
return -EINVAL;
}
- if ((unsigned int)len > ctrl->read_bytes - ctrl->index) {
- dev_err(ctrl->dev,
- "verify_buf beyond end of buffer "
- "(%d requested, %u available)\n",
- len, ctrl->read_bytes - ctrl->index);
+ if ((unsigned int)len >
+ elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index) {
+ dev_err(priv->dev,
+ "verify_buf beyond end of buffer "
+ "(%d requested, %u available)\n",
+ len, elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
- ctrl->index = ctrl->read_bytes;
+ elbc_fcm_ctrl->index = elbc_fcm_ctrl->read_bytes;
return -EINVAL;
}
for (i = 0; i < len; i++)
- if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i])
+ if (in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index + i])
+ != buf[i])
break;
- ctrl->index += len;
- return i == len && ctrl->status == LTESR_CC ? 0 : -EIO;
+ elbc_fcm_ctrl->index += len;
+ return i == len && elbc_fcm_ctrl->status == LTESR_CC ? 0 : -EIO;
}
/* This function is called after Program and Erase Operations to
@@ -635,22 +636,22 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
{
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
- if (ctrl->status != LTESR_CC)
+ if (elbc_fcm_ctrl->status != LTESR_CC)
return NAND_STATUS_FAIL;
/* The chip always seems to report that it is
* write-protected, even when it is not.
*/
- return (ctrl->mdr & 0xff) | NAND_STATUS_WP;
+ return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
}
static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
unsigned int al;
@@ -665,41 +666,41 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
priv->fmr |= (12 << FMR_CWTO_SHIFT) | /* Timeout > 12 ms */
(al << FMR_AL_SHIFT);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->numchips = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n",
chip->numchips);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
chip->chipsize);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
chip->pagemask);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
chip->chip_delay);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
chip->badblockpos);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
chip->chip_shift);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->page_shift = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n",
chip->page_shift);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
chip->phys_erase_shift);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecclayout = %p\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->ecclayout = %p\n",
chip->ecclayout);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
chip->ecc.mode);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
chip->ecc.steps);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
chip->ecc.bytes);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
chip->ecc.total);
- dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
chip->ecc.layout);
- dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
- dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
- dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
+ dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
+ dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
mtd->erasesize);
- dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->writesize = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n",
mtd->writesize);
- dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
+ dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
mtd->oobsize);
/* adjust Option Register and ECC to match Flash page size */
@@ -719,7 +720,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
chip->badblock_pattern = &largepage_memorybased;
}
} else {
- dev_err(ctrl->dev,
+ dev_err(priv->dev,
"fsl_elbc_init: page size %d is not supported\n",
mtd->writesize);
return -1;
@@ -750,18 +751,19 @@ static void fsl_elbc_write_page(struct mtd_info *mtd,
const uint8_t *buf)
{
struct fsl_elbc_mtd *priv = chip->priv;
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
fsl_elbc_write_buf(mtd, buf, mtd->writesize);
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
- ctrl->oob_poi = chip->oob_poi;
+ elbc_fcm_ctrl->oob_poi = chip->oob_poi;
}
static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
{
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
+ struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
struct nand_chip *chip = &priv->chip;
dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
@@ -790,7 +792,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR |
NAND_USE_FLASH_BBT;
- chip->controller = &ctrl->controller;
+ chip->controller = &elbc_fcm_ctrl->controller;
chip->priv = priv;
chip->ecc.read_page = fsl_elbc_read_page;
@@ -815,8 +817,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
{
- struct fsl_elbc_ctrl *ctrl = priv->ctrl;
-
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
nand_release(&priv->mtd);
kfree(priv->mtd.name);
@@ -824,18 +825,21 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
if (priv->vbase)
iounmap(priv->vbase);
- ctrl->chips[priv->bank] = NULL;
+ elbc_fcm_ctrl->chips[priv->bank] = NULL;
kfree(priv);
-
+ kfree(elbc_fcm_ctrl);
return 0;
}
-static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
- struct device_node *node)
+static DEFINE_MUTEX(fsl_elbc_nand_mutex);
+
+static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)
{
- struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+ struct fsl_lbc_regs __iomem *lbc;
struct fsl_elbc_mtd *priv;
struct resource res;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl;
+
#ifdef CONFIG_MTD_PARTITIONS
static const char *part_probe_types[]
= { "cmdlinepart", "RedBoot", NULL };
@@ -843,11 +847,18 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
#endif
int ret;
int bank;
+ struct device *dev;
+ struct device_node *node = pdev->dev.of_node;
+
+ if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
+ return -ENODEV;
+ lbc = fsl_lbc_ctrl_dev->regs;
+ dev = fsl_lbc_ctrl_dev->dev;
/* get, allocate and map the memory resource */
ret = of_address_to_resource(node, 0, &res);
if (ret) {
- dev_err(ctrl->dev, "failed to get resource\n");
+ dev_err(dev, "failed to get resource\n");
return ret;
}
@@ -861,7 +872,7 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
break;
if (bank >= MAX_BANKS) {
- dev_err(ctrl->dev, "address did not match any chip selects\n");
+ dev_err(dev, "address did not match any chip selects\n");
return -ENODEV;
}
@@ -869,14 +880,33 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
if (!priv)
return -ENOMEM;
- ctrl->chips[bank] = priv;
+ mutex_lock(&fsl_elbc_nand_mutex);
+ if (!fsl_lbc_ctrl_dev->nand) {
+ elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL);
+ if (!elbc_fcm_ctrl) {
+ dev_err(dev, "failed to allocate memory\n");
+ mutex_unlock(&fsl_elbc_nand_mutex);
+ ret = -ENOMEM;
+ goto err;
+ }
+ elbc_fcm_ctrl->counter++;
+
+ spin_lock_init(&elbc_fcm_ctrl->controller.lock);
+ init_waitqueue_head(&elbc_fcm_ctrl->controller.wq);
+ fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
+ } else {
+ elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
+ }
+ mutex_unlock(&fsl_elbc_nand_mutex);
+
+ elbc_fcm_ctrl->chips[bank] = priv;
priv->bank = bank;
- priv->ctrl = ctrl;
- priv->dev = ctrl->dev;
+ priv->ctrl = fsl_lbc_ctrl_dev;
+ priv->dev = dev;
priv->vbase = ioremap(res.start, resource_size(&res));
if (!priv->vbase) {
- dev_err(ctrl->dev, "failed to map chip region\n");
+ dev_err(dev, "failed to map chip region\n");
ret = -ENOMEM;
goto err;
}
@@ -933,171 +963,53 @@ err:
return ret;
}
-static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl)
+static int fsl_elbc_nand_remove(struct platform_device *pdev)
{
- struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
-
- /*
- * NAND transactions can tie up the bus for a long time, so set the
- * bus timeout to max by clearing LBCR[BMT] (highest base counter
- * value) and setting LBCR[BMTPS] to the highest prescaler value.
- */
- clrsetbits_be32(&lbc->lbcr, LBCR_BMT, 15);
-
- /* clear event registers */
- setbits32(&lbc->ltesr, LTESR_NAND_MASK);
- out_be32(&lbc->lteatr, 0);
-
- /* Enable interrupts for any detected events */
- out_be32(&lbc->lteir, LTESR_NAND_MASK);
-
- ctrl->read_bytes = 0;
- ctrl->index = 0;
- ctrl->addr = NULL;
-
- return 0;
-}
-
-static int fsl_elbc_ctrl_remove(struct platform_device *ofdev)
-{
- struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev);
int i;
-
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
for (i = 0; i < MAX_BANKS; i++)
- if (ctrl->chips[i])
- fsl_elbc_chip_remove(ctrl->chips[i]);
-
- if (ctrl->irq)
- free_irq(ctrl->irq, ctrl);
-
- if (ctrl->regs)
- iounmap(ctrl->regs);
-
- dev_set_drvdata(&ofdev->dev, NULL);
- kfree(ctrl);
- return 0;
-}
-
-/* NOTE: This interrupt is also used to report other localbus events,
- * such as transaction errors on other chipselects. If we want to
- * capture those, we'll need to move the IRQ code into a shared
- * LBC driver.
- */
-
-static irqreturn_t fsl_elbc_ctrl_irq(int irqno, void *data)
-{
- struct fsl_elbc_ctrl *ctrl = data;
- struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
- __be32 status = in_be32(&lbc->ltesr) & LTESR_NAND_MASK;
-
- if (status) {
- out_be32(&lbc->ltesr, status);
- out_be32(&lbc->lteatr, 0);
-
- ctrl->irq_status = status;
- smp_wmb();
- wake_up(&ctrl->irq_wait);
-
- return IRQ_HANDLED;
+ if (elbc_fcm_ctrl->chips[i])
+ fsl_elbc_chip_remove(elbc_fcm_ctrl->chips[i]);
+
+ mutex_lock(&fsl_elbc_nand_mutex);
+ elbc_fcm_ctrl->counter--;
+ if (!elbc_fcm_ctrl->counter) {
+ fsl_lbc_ctrl_dev->nand = NULL;
+ kfree(elbc_fcm_ctrl);
}
-
- return IRQ_NONE;
-}
-
-/* fsl_elbc_ctrl_probe
- *
- * called by device layer when it finds a device matching
- * one our driver can handled. This code allocates all of
- * the resources needed for the controller only. The
- * resources for the NAND banks themselves are allocated
- * in the chip probe function.
-*/
-
-static int __devinit fsl_elbc_ctrl_probe(struct platform_device *ofdev,
- const struct of_device_id *match)
-{
- struct device_node *child;
- struct fsl_elbc_ctrl *ctrl;
- int ret;
-
- ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
- if (!ctrl)
- return -ENOMEM;
-
- dev_set_drvdata(&ofdev->dev, ctrl);
-
- spin_lock_init(&ctrl->controller.lock);
- init_waitqueue_head(&ctrl->controller.wq);
- init_waitqueue_head(&ctrl->irq_wait);
-
- ctrl->regs = of_iomap(ofdev->dev.of_node, 0);
- if (!ctrl->regs) {
- dev_err(&ofdev->dev, "failed to get memory region\n");
- ret = -ENODEV;
- goto err;
- }
-
- ctrl->irq = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
- if (ctrl->irq == NO_IRQ) {
- dev_err(&ofdev->dev, "failed to get irq resource\n");
- ret = -ENODEV;
- goto err;
- }
-
- ctrl->dev = &ofdev->dev;
-
- ret = fsl_elbc_ctrl_init(ctrl);
- if (ret < 0)
- goto err;
-
- ret = request_irq(ctrl->irq, fsl_elbc_ctrl_irq, 0, "fsl-elbc", ctrl);
- if (ret != 0) {
- dev_err(&ofdev->dev, "failed to install irq (%d)\n",
- ctrl->irq);
- ret = ctrl->irq;
- goto err;
- }
-
- for_each_child_of_node(ofdev->dev.of_node, child)
- if (of_device_is_compatible(child, "fsl,elbc-fcm-nand"))
- fsl_elbc_chip_probe(ctrl, child);
+ mutex_unlock(&fsl_elbc_nand_mutex);
return 0;
-err:
- fsl_elbc_ctrl_remove(ofdev);
- return ret;
}
-static const struct of_device_id fsl_elbc_match[] = {
- {
- .compatible = "fsl,elbc",
- },
+static const struct of_device_id fsl_elbc_nand_match[] = {
+ { .compatible = "fsl,elbc-fcm-nand", },
{}
};
-static struct of_platform_driver fsl_elbc_ctrl_driver = {
+static struct platform_driver fsl_elbc_nand_driver = {
.driver = {
- .name = "fsl-elbc",
+ .name = "fsl,elbc-fcm-nand",
.owner = THIS_MODULE,
- .of_match_table = fsl_elbc_match,
+ .of_match_table = fsl_elbc_nand_match,
},
- .probe = fsl_elbc_ctrl_probe,
- .remove = fsl_elbc_ctrl_remove,
+ .probe = fsl_elbc_nand_probe,
+ .remove = fsl_elbc_nand_remove,
};
-static int __init fsl_elbc_init(void)
+static int __init fsl_elbc_nand_init(void)
{
- return of_register_platform_driver(&fsl_elbc_ctrl_driver);
+ return platform_driver_register(&fsl_elbc_nand_driver);
}
-static void __exit fsl_elbc_exit(void)
+static void __exit fsl_elbc_nand_exit(void)
{
- of_unregister_platform_driver(&fsl_elbc_ctrl_driver);
+ platform_driver_unregister(&fsl_elbc_nand_driver);
}
-module_init(fsl_elbc_init);
-module_exit(fsl_elbc_exit);
+module_init(fsl_elbc_nand_init);
+module_exit(fsl_elbc_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Freescale");
--
1.5.6.5
^ permalink raw reply related
* Re: Freescale P2020 CPU Freeze over PCIe abort signal
From: Bin Meng @ 2010-10-18 5:26 UTC (permalink / raw)
To: Eran Liberty; +Cc: linuxppc-dev, linux-pci
In-Reply-To: <4CBB4D80.3030007@extricom.com>
On Mon, Oct 18, 2010 at 3:24 AM, Eran Liberty <liberty@extricom.com> wrote:
<snip>
> In P2020 if I do any of those the CPU is left hung over the transaction.
>
> something like:
> in_le32(addr)
>
> is turned into:
> 7c 00 04 ac =A0 =A0 sync =A0 7c 00 4c 2c =A0 =A0 lwbrx =A0 r0,0,r9
> 0c 00 00 00 =A0 =A0 twi =A0 =A0 0,r0,0
> 4c 00 01 2c =A0 =A0 isync
>
> assembly code, where in r9 (in this example) hold an address which is
> physically mapped into the PCIe resource space.
>
> The CPU will hang over the load instruction.
>
> Just for the fun of it, I have wrote my own assembly function omitting
> everything but the load instruction; still freeze.
> Replace "lwbrx" with a simple "lwz"; still freeze.
>
> It looks like the CPU snoozes till the PCIe transaction is done with no
> timeouts, ignoring any abort signal.
>
It sounds like a similar issue I got with the 83xx PCIe host controller.
If there is no valid link established under the PCIe host controller
(ie: no device connected), or the device under the PCIe host
controller does not respond the configuration access correctly,
the host will hang at the instruction of "lwz" when trying to access
the PCIe configuration space (in 83xx, it's memory mapped)
And I remember the same issue exists in 8548, not sure if it is fixed in P2=
020.
<snip>
Bin
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>
^ permalink raw reply
* BUG: dead loop in PowerPC hcall tracepoint (Was: [LTP] [PATCH v2] Add ftrace-stress-test to LTP)
From: Li Zefan @ 2010-10-18 3:19 UTC (permalink / raw)
To: subrata
Cc: ltp-list, Peter Zijlstra, LKML, Steven Rostedt, Paul Mackerras,
Anton Blanchard, Ingo Molnar, linuxppc-dev
In-Reply-To: <1286995066.4893.17.camel@subratamodak.linux.ibm.com>
Cc: Steven
Cc: Ingo
Cc: Peter
Cc: Anton Blanchard <anton@samba.org>
Cc: Paul Mackerras <paulus@samba.org>
For those Cced, More information here:
http://marc.info/?l=ltp-list&m=128569007015044&w=2
http://marc.info/?l=ltp-list&m=128696942432669&w=2
02:37, Subrata Modak wrote:
> I get a bigger trace with this patch:
>
> Unable to handle kernel paging request for data at address 0x00000000
> Faulting instruction address: 0xc0000000002133f0
> cpu 0x2: Vector: 300 (Data Access) at [c0000000d9f8b560]
> pc: c0000000002133f0: .trace_clock_global+0xb4/0x2a0
> lr: c000000000213458: .trace_clock_global+0x11c/0x2a0
> sp: c0000000d9f8b7e0
> msr: 800000000200b032
> dar: 0
> dsisr: 40000000
> current = 0xc0000000d9f7d100
> paca = 0xc000000007fc8e00
> pid = 1667, comm = ftrace_stack_tr
> Unrecoverable FP Unavailable Exception 800 at c0000000016a9540
> cpu 0x0: Vector: 8Unable to handle0 kernel paging r0 equest for data (at
> address 0xbffFffffe0175b688
> PU UnavaFaulting instruciltion address: 0xac0000000001017fcb
> le) at [c0000000d9f8a6a0]
> p pc: c0000000016a9540: etnetre r? ?f ofro rh ehlepl
>
>
> lr: [c000000000016a9540: key_type_dns_resolver+0x15110/0x365f8
> sp: c0000000018804e8
> msr: 8000000000001032
> current = 0xc0000000d838d100
> paca = 0xc000000007fc8000
> pid = 1668, comm = ftrace_stack_ma
> pid = 1668, cc0000000002226b0 .rb_reserve_next_event+0x20c/0x804
> [c0000000d9f8b9b0] c000000000223178 .ring_buffer_lock_reserve
> +0x24c/0x2a4
> [c0000000d9f8ba40] c00000000022d6f4 .trace_buffer_lock_reserve+0x58/0xe4
> [c0000000d9f8baf0] c00000000022ec9c .trace_current_buffer_lock_reserve
> +0x44/0x6c
> [c0000000d9f8bb80] c000000000011c5c .ftrace_raw_event_hcall_entry
> +0x7c/0x144
> [c0000000d9f8bc40] c000000000096624 .__trace_hcall_entry+0xa0/0xec
> [c0000000d9f8bcd0] c00000000009786c .plpar_hcall_norets+0x50/0xd0
> [c0000000d9f8bd40] c0000000000749c8 .__spin_yield+0x130/0x15c
> [c0000000d9f8bdd0] c000000000213458 .trace_clock_global+0x11c/0x2a0
This is a dead loop:
trace_hcall_entry() -> trace_clock_global() -> trace_hcall_entry() ..
And this is a PPC specific bug. Hope some ppc guys will fix it?
Or we kill trace_clock_global() if no one actually uses it..
--
Li Zefan
> [c0000000d9f8be90] c0000000002226b0 .rb_reserve_next_event+0x20c/0x804
> [c0000000d9f8bfa0] c000000000223178 .ring_buffer_lock_reserve
> +0x24c/0x2a4
> [c0000000d9f8c030] c00000000022d6f4 .trace_buffer_lock_reserve+0x58/0xe4
> [c0000000d9f8c0e0] c00000000022ec9c .trace_current_buffer_lock_reserve
> +0x44/0x6c
> [c0000000d9f8c170] c000000000011c5c .ftrace_raw_event_hcall_entry
> +0x7c/0x144
> [c0000000d9f8c230] c000000000096624 .__trace_hcall_entry+0xa0/0xec
> [c0000000d9f8c2c0] c00000000009786c .plpar_hcall_norets+0x50/0xd0
> [c0000000d9f8c330] c0000000000749c8 .__spin_yield+0x130/0x15c
> [c0000000d9f8c3c0] c000000000213458 .trace_clock_global+0x11c/0x2a0
> [c0000000d9f8c480] c0000000002226b0 .rb_reserve_next_event+0x20c/0x804
> [c0000000d9f8c590] c000000000223178 .ring_buffer_lock_reserve
> +0x24c/0x2a4
> [c0000000d9f8c620] c00000000022d6f4 .trace_buffer_lock_reserve+0x58/0xe4
> [c0000000d9f8c6d0] c00000000022ec9c .trace_current_buffer_lock_reserve
> +0x44/0x6c
> [c0000000d9f8c760] c000000000011c5c .ftrace_raw_event_hcall_entry
> +0x7c/0x144
> [c0000000d9f8c820] c000000000096624 .__trace_hcall_entry+0xa0/0xec
> [c0000000d9f8c8b0] c00000000009786c .plpar_hcall_norets+0x50/0xd0
> [c0000000d9f8c920] c0000000000749c8 .__spin_yield+0x130/0x15c
> [c0000000d9f8c9b0] c000000000213458 .trace_clock_global+0x11c/0x2a0
> [c0000000d9f8ca70] c0000000002226b0 .rb_reserve_next_event+0x20c/0x804
> [c0000000d9f8cb80] c000000000223178 .ring_buffer_lock_reserve
> +0x24c/0x2a4
> [c0000000d9f8cc10] c00000000022d6f4 .trace_buffer_lock_reserve+0x58/0xe4
> [c0000000d9f8ccc0] c00000000022ec9c .trace_current_buffer_lock_reserve
> +0x44/0x6c
> [c0000000d9f8cd50] c000000000011c5c .ftrace_raw_event_hcall_entry
> +0x7c/0x144
> [c0000000d9f8ce10] c000000000096624 .__trace_hcall_entry+0xa0/0xec
> [c0000000d9f8cea0] c00000000009786c .plpar_hcall_norets+0x50/0xd0
> [c0000000d9f8cf10] c0000000000749c8 .__spin_yield+0x130/0x15c
> [c0000000d9f8cfa0] c000000000213458 .trace_clock_global+0x11c/0x2a0
> [c0000000d9f8d060] c0000000002226b0 .rb_reserve_next_event+0x20c/0x804
> [c0000000d9f8d170] c000000000223178 .ring_buffer_lock_reserve
> +0x24c/0x2a4
> [c0000000d9f8d200] c00000000022d6f4 .trace_buffer_lock_reserve+0x58/0xe4
> [c0000000d9f8d2b0] c00000000022ec9c .trace_current_buffer_lock_reserve
> +0x44/0x6c
> [c0000000d9f8d340] c000000000011c5c .ftrace_raw_event_hcall_entry
> +0x7c/0x144
> [c0000000d9f8d400] c000000000096624 .__trace_hcall_entry+0xa0/0xec
> [c0000000d9f8d490] c00000000009786c .plpar_hcall_norets+0x50/0xd0
> [c0000000d9f8d500] c0000000000749c8 .__spin_yield+0x130/0x15c
> [c0000000d9f8d590] c000000000213458 .trace_clock_global+0x11c/0x2a0
> [c0000000d9f8d650] c0000000002226b0 .rb_reserve_next_event+0x20c/0x804
> [c0000000d9f8d760] c000000000223178 .ring_buffer_lock_reserve
> +0x24c/0x2a4
> [c0000000d9f8d7f0] c00000000022d6f4 .trace_buffer_lock_reserve+0x58/0xe4
> [c0000000d9f8d8a0] c00000000022ec9c .trace_current_buffer_lock_reserve
> +0x44/0x6c
> [c0000000d9f8d930] c000000000011c5c .ftrace_raw_event_hcall_entry
> +0x7c/0x144
> [c0000000d9f8d9f0] c000000000096624 .__trace_hcall_entry+0xa0/0xec
> [c0000000d9f8da80] c00000000009786c .plpar_hcall_norets+0x50/0xd0
> [c0000000d9f8daf0] c0000000000749c8 .__spin_yield+0x130/0x15c
> [c0000000d9f8db80] c000000000213458 .trace_clock_global+0x11c/0x2a0
> [c0000000d9f8dc40] c0000000002226b0 .rb_reserve_next_event+0x20c/0x804
> [c0000000d9f8dd50] c000000000223178 .ring_buffer_lock_reserve
> +0x24c/0x2a4
> [c0000000d9f8dde0] c00000000022d6f4 .trace_buffer_lock_reserve+0x58/0xe4
> [c0000000d9f8de90] c00000000022ec9c .trace_current_buffer_lock_reserve
> +0x44/0x6c
> [c0000000d9f8df20] c000000000011c5c .ftrace_raw_event_hcall_entry
> +0x7c/0x144
> [c0000000d9f8dfe0] c000000000096624 .__trace_hcall_entry+0xa0/0xec
> [c0000000d9f8e070] c00000000009786c .plpar_hcall_norets+0x50/0xd0
> [c0000000d9f8e0e0] c0000000000749c8 .__spin_yield+0x130/0x15c
> [c0000000d9f8e170] c000000000213458 .trace_clock_global+0x11c/0x2a0
> [c0000000d9f8e230] c0000000002226b0 .rb_reserve_next_event+0x20c/0x804
>
> Regards--
> Subrata
>
> On Wed, 2010-10-13 at 19:29 +0800, Li Zefan wrote:
>> Li Zefan wrote:
>>> Li Zefan wrote:
>>>> Subrata Modak wrote:
>>>>> Li,
>>>>>
>>>>> Can you kindly fix the below issues and send me a new patch ?
>>>>>
>>>> Sure, I will.
>>>>
>>> At a first glance, the kernel bug doesn't seem to come from ftrace,
>>> at least not directly from it.
>>>
>>> Question:
>>>
>>> Can you trigger this bug in latest kernel (2.6.36-rc7)? If you
>>> haven't tried it, could you test it? Thanks!
>>>
>> I got a patch from Peter, though he's not sure about the bug yet.
>> So could you try this?
>>
>> Note, I don't know if this patch can be applied to 2.6.35-4..
>>
>> ======================
>>
>> (From Peter)
>>
>> Hrmm, not something I've seen before.. but since the migration thread
>> and stop_machine are involved, does the below patch which rewrites the
>> migration-thread/stop_macehine/scheduler interaction cure this?
>>
>> This patch is probably .37 fodder, but who knows..
>>
>> ---
>> Subject: sched: Create special class for stop/migrate work
>> From: Peter Zijlstra <a.p.zijlstra@chello.nl>
>> Date: Wed Sep 22 13:53:15 CEST 2010
>>
>> In order to separate the stop/migrate work thread from the SCHED_FIFO
>> implementation, create a special class for it that is of higher priority
>> than SCHED_FIFO itself.
>>
>> This currently solves a problem where cpu-hotplug consumes so much cpu-time
>> that the SCHED_FIFO class gets throttled, but has the bandwidth replenishment
>> timer pending on the now dead cpu.
>>
>> It is also required for when we add the planned deadline scheduling class
>> above SCHED_FIFO, as the stop/migrate thread still needs to transcent those
>> tasks.
>>
>> Tested-by: Heiko Carstens <heiko.carstens@de.ibm.com>
>> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
>> LKML-Reference: <1285165776.2275.1022.camel@laptop>
>> ---
>> kernel/sched.c | 54 ++++++++++++++++++++----
>> kernel/sched_stoptask.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++
>> kernel/stop_machine.c | 8 ++-
>> 3 files changed, 158 insertions(+), 12 deletions(-)
>>
>> Index: linux-2.6/kernel/sched.c
>> ===================================================================
>> --- linux-2.6.orig/kernel/sched.c
>> +++ linux-2.6/kernel/sched.c
>> @@ -486,7 +486,7 @@ struct rq {
>> */
>> unsigned long nr_uninterruptible;
>>
>> - struct task_struct *curr, *idle;
>> + struct task_struct *curr, *idle, *stop;
>> unsigned long next_balance;
>> struct mm_struct *prev_mm;
>>
>> @@ -1837,7 +1837,7 @@ static inline void __set_task_cpu(struct
>>
>> static const struct sched_class rt_sched_class;
>>
>> -#define sched_class_highest (&rt_sched_class)
>> +#define sched_class_highest (&stop_sched_class)
>> #define for_each_class(class) \
>> for (class = sched_class_highest; class; class = class->next)
>>
>> @@ -1917,10 +1917,41 @@ static void deactivate_task(struct rq *r
>> #include "sched_idletask.c"
>> #include "sched_fair.c"
>> #include "sched_rt.c"
>> +#include "sched_stoptask.c"
>> #ifdef CONFIG_SCHED_DEBUG
>> # include "sched_debug.c"
>> #endif
>>
>> +void sched_set_stop_task(int cpu, struct task_struct *stop)
>> +{
>> + struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
>> + struct task_struct *old_stop = cpu_rq(cpu)->stop;
>> +
>> + if (stop) {
>> + /*
>> + * Make it appear like a SCHED_FIFO task, its something
>> + * userspace knows about and won't get confused about.
>> + *
>> + * Also, it will make PI more or less work without too
>> + * much confusion -- but then, stop work should not
>> + * rely on PI working anyway.
>> + */
>> + sched_setscheduler_nocheck(stop, SCHED_FIFO, ¶m);
>> +
>> + stop->sched_class = &stop_sched_class;
>> + }
>> +
>> + cpu_rq(cpu)->stop = stop;
>> +
>> + if (old_stop) {
>> + /*
>> + * Reset it back to a normal scheduling class so that
>> + * it can die in pieces.
>> + */
>> + old_stop->sched_class = &rt_sched_class;
>> + }
>> +}
>> +
>> /*
>> * __normal_prio - return the priority that is based on the static prio
>> */
>> @@ -3720,17 +3751,13 @@ pick_next_task(struct rq *rq)
>> return p;
>> }
>>
>> - class = sched_class_highest;
>> - for ( ; ; ) {
>> + for_each_class(class) {
>> p = class->pick_next_task(rq);
>> if (p)
>> return p;
>> - /*
>> - * Will never be NULL as the idle class always
>> - * returns a non-NULL p:
>> - */
>> - class = class->next;
>> }
>> +
>> + BUG(); /* the idle class will always have a runnable task */
>> }
>>
>> /*
>> @@ -4659,6 +4686,15 @@ static int __sched_setscheduler(struct t
>> */
>> rq = __task_rq_lock(p);
>>
>> + /*
>> + * Changing the policy of the stop threads its a very bad idea
>> + */
>> + if (p == rq->stop) {
>> + __task_rq_unlock(rq);
>> + raw_spin_unlock_irqrestore(&p->pi_lock, flags);
>> + return -EINVAL;
>> + }
>> +
>> #ifdef CONFIG_RT_GROUP_SCHED
>> if (user) {
>> /*
>> Index: linux-2.6/kernel/stop_machine.c
>> ===================================================================
>> --- linux-2.6.orig/kernel/stop_machine.c
>> +++ linux-2.6/kernel/stop_machine.c
>> @@ -287,11 +287,12 @@ static int cpu_stopper_thread(void *data
>> goto repeat;
>> }
>>
>> +extern void sched_set_stop_task(int cpu, struct task_struct *stop);
>> +
>> /* manage stopper for a cpu, mostly lifted from sched migration thread mgmt */
>> static int __cpuinit cpu_stop_cpu_callback(struct notifier_block *nfb,
>> unsigned long action, void *hcpu)
>> {
>> - struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
>> unsigned int cpu = (unsigned long)hcpu;
>> struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
>> struct task_struct *p;
>> @@ -304,13 +305,13 @@ static int __cpuinit cpu_stop_cpu_callba
>> cpu);
>> if (IS_ERR(p))
>> return NOTIFY_BAD;
>> - sched_setscheduler_nocheck(p, SCHED_FIFO, ¶m);
>> get_task_struct(p);
>> + kthread_bind(p, cpu);
>> + sched_set_stop_task(cpu, p);
>> stopper->thread = p;
>> break;
>>
>> case CPU_ONLINE:
>> - kthread_bind(stopper->thread, cpu);
>> /* strictly unnecessary, as first user will wake it */
>> wake_up_process(stopper->thread);
>> /* mark enabled */
>> @@ -325,6 +326,7 @@ static int __cpuinit cpu_stop_cpu_callba
>> {
>> struct cpu_stop_work *work;
>>
>> + sched_set_stop_task(cpu, NULL);
>> /* kill the stopper */
>> kthread_stop(stopper->thread);
>> /* drain remaining works */
>> Index: linux-2.6/kernel/sched_stoptask.c
>> ===================================================================
>> --- /dev/null
>> +++ linux-2.6/kernel/sched_stoptask.c
>> @@ -0,0 +1,108 @@
>> +/*
>> + * stop-task scheduling class.
>> + *
>> + * The stop task is the highest priority task in the system, it preempts
>> + * everything and will be preempted by nothing.
>> + *
>> + * See kernel/stop_machine.c
>> + */
>> +
>> +#ifdef CONFIG_SMP
>> +static int
>> +select_task_rq_stop(struct rq *rq, struct task_struct *p,
>> + int sd_flag, int flags)
>> +{
>> + return task_cpu(p); /* stop tasks as never migrate */
>> +}
>> +#endif /* CONFIG_SMP */
>> +
>> +static void
>> +check_preempt_curr_stop(struct rq *rq, struct task_struct *p, int flags)
>> +{
>> + resched_task(rq->curr); /* we preempt everything */
>> +}
>> +
>> +static struct task_struct *pick_next_task_stop(struct rq *rq)
>> +{
>> + struct task_struct *stop = rq->stop;
>> +
>> + if (stop && stop->state == TASK_RUNNING)
>> + return stop;
>> +
>> + return NULL;
>> +}
>> +
>> +static void
>> +enqueue_task_stop(struct rq *rq, struct task_struct *p, int flags)
>> +{
>> +}
>> +
>> +static void
>> +dequeue_task_stop(struct rq *rq, struct task_struct *p, int flags)
>> +{
>> +}
>> +
>> +static void yield_task_stop(struct rq *rq)
>> +{
>> + BUG(); /* the stop task should never yield, its pointless. */
>> +}
>> +
>> +static void put_prev_task_stop(struct rq *rq, struct task_struct *prev)
>> +{
>> +}
>> +
>> +static void task_tick_stop(struct rq *rq, struct task_struct *curr, int queued)
>> +{
>> +}
>> +
>> +static void set_curr_task_stop(struct rq *rq)
>> +{
>> +}
>> +
>> +static void switched_to_stop(struct rq *rq, struct task_struct *p,
>> + int running)
>> +{
>> + BUG(); /* its impossible to change to this class */
>> +}
>> +
>> +static void prio_changed_stop(struct rq *rq, struct task_struct *p,
>> + int oldprio, int running)
>> +{
>> + BUG(); /* how!?, what priority? */
>> +}
>> +
>> +static unsigned int
>> +get_rr_interval_stop(struct rq *rq, struct task_struct *task)
>> +{
>> + return 0;
>> +}
>> +
>> +/*
>> + * Simple, special scheduling class for the per-CPU stop tasks:
>> + */
>> +static const struct sched_class stop_sched_class = {
>> + .next = &rt_sched_class,
>> +
>> + .enqueue_task = enqueue_task_stop,
>> + .dequeue_task = dequeue_task_stop,
>> + .yield_task = yield_task_stop,
>> +
>> + .check_preempt_curr = check_preempt_curr_stop,
>> +
>> + .pick_next_task = pick_next_task_stop,
>> + .put_prev_task = put_prev_task_stop,
>> +
>> +#ifdef CONFIG_SMP
>> + .select_task_rq = select_task_rq_stop,
>> +#endif
>> +
>> + .set_curr_task = set_curr_task_stop,
>> + .task_tick = task_tick_stop,
>> +
>> + .get_rr_interval = get_rr_interval_stop,
>> +
>> + .prio_changed = prio_changed_stop,
>> + .switched_to = switched_to_stop,
>> +
>> + /* no .task_new for stop tasks */
>> +};
>>
>>
>>
>
>
>
^ permalink raw reply
* Re: 64K PAGE_SIZE and arch/powerpc/kernel/vdso.c
From: Michael Neuling @ 2010-10-17 23:44 UTC (permalink / raw)
To: Nicholas A. Bellinger; +Cc: Brian King, Tim Abbott, linuxppc-dev
In-Reply-To: <1287216239.9909.234.camel@haakon2.linux-iscsi.org>
> Greetings Linux-ppc64 folks,
>=20
> While trying to compile v2.6.36-rc8 with PAGE_SIZE=3D65536 I run into the
> following compile failure w/ strict checking on a RHEL5.4 / gcc (GCC)
> 4.1.2 20080704 (Red Hat 4.1.2-46) system:
>=20
> cc1: warnings being treated as errors
> arch/powerpc/kernel/vdso.c:81: warning: alignment of =E2=80=98vdso_data_s=
tore=E2=80=99
> is greater than maximum object file alignment. Using 32768
> CC arch/powerpc/sysdev/msi_bitmap.o
> make[1]: *** [arch/powerpc/kernel/vdso.o] Error 1
> make[1]: *** Waiting for unfinished jobs....
>=20
> Any ideas folks..?
It seems this broke it:
commit abe1ee3a221d53778c3e58747bbec6e518e5471b
Author: Tim Abbott <tabbott@ksplice.com>
Date: Sun Sep 20 18:14:15 2009 -0400
Use macros for .data.page_aligned section.
=20=20=20=20
This patch changes the remaining direct references to
.data.page_aligned in C and assembly code to use the macros in
include/linux/linkage.h.
Backing out just that part of the change (see below) fixes it.
FYI the error only occurs on gcc 4.1 and 4.2. 4.3 and greater is fine.=20=
=20
Mikey
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index 13002fe..c140fce 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -78,7 +78,7 @@ static int vdso_ready;
static union {
struct vdso_data data;
u8 page[PAGE_SIZE];
-} vdso_data_store __page_aligned_data;
+} vdso_data_store __attribute__((__section__(".data.page_aligned")));
struct vdso_data *vdso_data =3D &vdso_data_store.data;
=20
/* Format of the patch table */
^ permalink raw reply related
* Freescale P2020 CPU Freeze over PCIe abort signal
From: Eran Liberty @ 2010-10-17 19:24 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linux-pci, linuxppc-dev
In-Reply-To: <1286796721.5220.2.camel@pasglop>
This should probably go to the Freescale support, as it feels like a
hardware issue yet the end result is a very frozen Linux kernel so I
post here first...
I have a programmable FPGA PCIe device connected to a Freescale's P2020
PCIe port. As part of the bring-up tests, we are testing two faulty
scenarios:
1. The FPGA totally ignores the PCIe transaction.
2. The FPGA return a transaction abort.
Both are plausible PCIe behavior and their should be outcome is
documented in the PCIe spec. The first should be terminated by the
transaction requestor timeout mechanism and raise an error, the second
should abort the transaction and raise and error.
In P2020 if I do any of those the CPU is left hung over the transaction.
something like:
in_le32(addr)
is turned into:
7c 00 04 ac sync
7c 00 4c 2c lwbrx r0,0,r9
0c 00 00 00 twi 0,r0,0
4c 00 01 2c isync
assembly code, where in r9 (in this example) hold an address which is
physically mapped into the PCIe resource space.
The CPU will hang over the load instruction.
Just for the fun of it, I have wrote my own assembly function omitting
everything but the load instruction; still freeze.
Replace "lwbrx" with a simple "lwz"; still freeze.
It looks like the CPU snoozes till the PCIe transaction is done with no
timeouts, ignoring any abort signal.
I am going to:
A. Try to reach the Freescale support.
B. Asked the FPGA designed to give me a new behavior that will stall the
PCIe transaction replay for 10 sec, but after those return ok.
C. report back here with either A or B.
If you have any ideas I would love to hear them.
-- Liberty
^ permalink raw reply
* [PATCH] powerpc: sysdev: fix signedness bug
From: Vasiliy Kulikov @ 2010-10-17 14:51 UTC (permalink / raw)
To: kernel-janitors
Cc: Harninder Rai, devicetree-discuss, linux-kernel, Paul Mackerras,
linuxppc-dev, Vivek Mahajan
sram_params.sram_size and sram_params.sram_offset were unsigned.
If get_cache_sram_size() or get_cache_sram_offset() returns error code
then it is not seen to the caller. Made sram_size and sram_offset signed.
Signed-off-by: Vasiliy Kulikov <segooon@gmail.com>
---
arch/powerpc/sysdev/fsl_85xx_l2ctlr.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
index cc8d655..23b85ac 100644
--- a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
+++ b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
@@ -94,14 +94,14 @@ static int __devinit mpc85xx_l2ctlr_of_probe(struct platform_device *dev,
l2cache_size = *prop;
sram_params.sram_size = get_cache_sram_size();
- if (sram_params.sram_size <= 0) {
+ if ((int)sram_params.sram_size <= 0) {
dev_err(&dev->dev,
"Entire L2 as cache, Aborting Cache-SRAM stuff\n");
return -EINVAL;
}
sram_params.sram_offset = get_cache_sram_offset();
- if (sram_params.sram_offset <= 0) {
+ if ((int64_t)sram_params.sram_offset <= 0) {
dev_err(&dev->dev,
"Entire L2 as cache, provide a valid sram offset\n");
return -EINVAL;
--
1.7.0.4
^ permalink raw reply related
* Re: [patch] ps3disk: passing wrong variable to bvec_kunmap_irq()
From: Geert Uytterhoeven @ 2010-10-17 11:36 UTC (permalink / raw)
To: Jens Axboe
Cc: cbe-oss-dev@lists.ozlabs.org, Dan Carpenter, Martin K. Petersen,
Geoff Levand, kernel-janitors@vger.kernel.org, FUJITA Tomonori,
linuxppc-dev@lists.ozlabs.org
In-Reply-To: <4CBA9C79.7050908@fusionio.com>
On Sun, Oct 17, 2010 at 08:49, Jens Axboe <jaxboe@fusionio.com> wrote:
> On 2010-10-16 21:39, Geert Uytterhoeven wrote:
>> On Mon, Oct 11, 2010 at 21:42, Jens Axboe <jaxboe@fusionio.com> wrote:
>>> On 2010-10-11 21:13, Dan Carpenter wrote:
>>>> This should pass "buf" to bvec_kunmap_irq() instead of "bv". =C2=A0The=
api is
>>>> like kmap_atomic() instead of kmap().
>>>>
>>>> Signed-off-by: Dan Carpenter <error27@gmail.com>
>>>>
>>>> diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
>>>> index e9da874..03688c2 100644
>>>> --- a/drivers/block/ps3disk.c
>>>> +++ b/drivers/block/ps3disk.c
>>>> @@ -113,7 +113,7 @@ static void ps3disk_scatter_gather(struct ps3_stor=
age_device *dev,
>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 memcpy(buf, dev->bounce_buf+offset, size);
>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 offset +=3D size;
>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 flush_kernel_dcache_p=
age(bvec->bv_page);
>>>> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bvec_kunmap_irq(bvec, &fla=
gs);
>>>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bvec_kunmap_irq(buf, &flag=
s);
>>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 i++;
>>>> =C2=A0 =C2=A0 =C2=A0 }
>>>> =C2=A0}
>>>
>>> Thanks applied, that bug is all too common.
>>
>> Because =C2=A0bvec_kunmap_irq() is a macro if !CONFIG_HIGHMEM, and thus =
there's no
>> argument type checking on e.g. pp64, which doesn't support HIGHMEM?
>
> It's a generic problem, not isolated to this case. The problem is that
> the API isn't symmetric, and the unmap parts take a void * pointer.
No, the unmap takes a char *:
static inline void bvec_kunmap_irq(char *buffer, unsigned long *flags)
So it could be detected. Patch will follow.
Gr{oetje,eeting}s,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 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. Bu=
t
when I'm talking to journalists I just say "programmer" or something like t=
hat.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0=C2=A0 =C2=A0=C2=A0 -- Linus Torvalds
^ permalink raw reply
* Re: [PATCH v4 5/5] mtd: m25p80: add support to parse the partitions by OF node
From: Artem Bityutskiy @ 2010-10-17 7:44 UTC (permalink / raw)
To: Grant Likely
Cc: kumar.gala, david-b, linuxppc-dev, linux-mtd, spi-devel-general,
Mingkai Hu
In-Reply-To: <AANLkTimr03KAKnz5sfwm19=KzB-ik95WM_qQO0YP9qVs@mail.gmail.com>
On Sat, 2010-10-16 at 19:05 -0600, Grant Likely wrote:
> On Sat, Oct 16, 2010 at 1:17 PM, Artem Bityutskiy <dedekind1@gmail.com> wrote:
> > On Tue, 2010-10-12 at 18:18 +0800, Mingkai Hu wrote:
> >> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> >> Acked-by: Grant Likely <grant.likely@secretlab.ca>
> >> ---
> >> v4:
> >> - Updated to latest kernel base(Linux 2.6.36-rc7).
> >> - Made changes according to Grant's comments.
> >
> > Looks good to me, pushed to l2-mtd-2.6.git, thanks.
>
> Wait! It will break whenever CONFIG_OF is not set. I broke
> linux-next with this patch. It can be solved by wrapping the block
> with #ifdef CONFIG_OF, but I'd like to find a better solution.
OK, removed.
--
Best Regards,
Artem Bityutskiy (Артём Битюцкий)
^ permalink raw reply
* Re: [patch] ps3disk: passing wrong variable to bvec_kunmap_irq()
From: Jens Axboe @ 2010-10-17 6:49 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: cbe-oss-dev@lists.ozlabs.org, Dan Carpenter, Martin K. Petersen,
Geoff Levand, kernel-janitors@vger.kernel.org, FUJITA Tomonori,
linuxppc-dev@lists.ozlabs.org
In-Reply-To: <AANLkTi=wQDgAHC0Zm+psdP2g+B7JZJ8ot1NPCE+AAqU0@mail.gmail.com>
On 2010-10-16 21:39, Geert Uytterhoeven wrote:
> On Mon, Oct 11, 2010 at 21:42, Jens Axboe <jaxboe@fusionio.com> wrote:
>> On 2010-10-11 21:13, Dan Carpenter wrote:
>>> This should pass "buf" to bvec_kunmap_irq() instead of "bv". The api is
>>> like kmap_atomic() instead of kmap().
>>>
>>> Signed-off-by: Dan Carpenter <error27@gmail.com>
>>>
>>> diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
>>> index e9da874..03688c2 100644
>>> --- a/drivers/block/ps3disk.c
>>> +++ b/drivers/block/ps3disk.c
>>> @@ -113,7 +113,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
>>> memcpy(buf, dev->bounce_buf+offset, size);
>>> offset += size;
>>> flush_kernel_dcache_page(bvec->bv_page);
>>> - bvec_kunmap_irq(bvec, &flags);
>>> + bvec_kunmap_irq(buf, &flags);
>>> i++;
>>> }
>>> }
>>
>> Thanks applied, that bug is all too common.
>
> Because bvec_kunmap_irq() is a macro if !CONFIG_HIGHMEM, and thus there's no
> argument type checking on e.g. pp64, which doesn't support HIGHMEM?
It's a generic problem, not isolated to this case. The problem is that
the API isn't symmetric, and the unmap parts take a void * pointer.
--
Jens Axboe
^ permalink raw reply
* Re: [PATCH v4 5/5] mtd: m25p80: add support to parse the partitions by OF node
From: Grant Likely @ 2010-10-17 1:05 UTC (permalink / raw)
To: dedekind1
Cc: kumar.gala, david-b, linuxppc-dev, linux-mtd, spi-devel-general,
Mingkai Hu
In-Reply-To: <1287256647.1781.34.camel@brekeke>
On Sat, Oct 16, 2010 at 1:17 PM, Artem Bityutskiy <dedekind1@gmail.com> wro=
te:
> On Tue, 2010-10-12 at 18:18 +0800, Mingkai Hu wrote:
>> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
>> Acked-by: Grant Likely <grant.likely@secretlab.ca>
>> ---
>> v4:
>> =A0- Updated to latest kernel base(Linux 2.6.36-rc7).
>> =A0- Made changes according to Grant's comments.
>
> Looks good to me, pushed to l2-mtd-2.6.git, thanks.
Wait! It will break whenever CONFIG_OF is not set. I broke
linux-next with this patch. It can be solved by wrapping the block
with #ifdef CONFIG_OF, but I'd like to find a better solution.
g.
^ permalink raw reply
* [PATCH] powerpc: Add support for Virtual Processor Home Node (VPHN)
From: Jesse Larrew @ 2010-10-16 19:45 UTC (permalink / raw)
To: linuxppc-dev
Cc: markn, antonb, pmac, Tony Breeds, lkessler, jlarrew,
Michael J Wolf
[-- Attachment #1: Type: text/plain, Size: 1 bytes --]
[-- Attachment #2: 0001-powerpc-Add-support-for-Virtual-Processor-Home-Node-.patch --]
[-- Type: text/plain, Size: 15865 bytes --]
From: Jesse Larrew <jlarrew@linux.vnet.ibm.com>
The SPLPAR option allows the platform to dispatch virtual processors on
physical processors that, due to the variable nature of work loads, are
temporarily free, thus improving the utilization of computing resources.
However, SPLPAR implies inconsistent mapping of virtual to physical
processors, thus defeating resource allocation software that attempts to
optimize performance on platforms that implement the NUMA option.
To bridge the gap between these two options, the VPHN option maintain a
substantially consistent mapping of a given virtual processor to a physical
processor or set of processors within a given associativity domain. When
allocating computing resources, the kernel can take advantage of this
statistically consistent mapping to improve processing performance.
VPHN mappings are substantially consistent but not static. For any given
dispatch cycle, a best effort is made by the hypervisor to dispatch the
virtual processor on a physical processor within a targeted associativity
domain (the virtual processor's home node). However, if processing capacity
within the home node is not available, some other physical processor is
assigned to meet the processing capacity entitlement. From time to time,
to optimize the total platform performance, it may be necessary for the
platform to change the home node of a given virtual processor.
The Virtual Processor Home Node feature addresses this by adding the
H_HOME_NODE_ASSOCIATIVITY hcall to retrieve the current associativity
domain information directly from the hypervisor for a given virtual
processor's home node. It also exposes a set of associativity change
counters in the Virtual Processor Area (VPA) of each processor to indicate
when associativity changes occur.
This patch sets a timer during boot that will periodically poll the
associativity change counters. When a change in associativity is detected,
it retrieves the new associativity domain information via the
H_HOME_NODE_ASSOCIATIVITY hcall and updates the NUMA node maps and sysfs
entries accordingly. The polling mechanism is also tied into the
ibm,suspend-me rtas call to stop/restart polling before/after a suspend,
hibernate, migrate, or checkpoint restart operation.
Signed-off-by: Jesse Larrew <jlarrew@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/firmware.h | 3 +-
arch/powerpc/include/asm/hvcall.h | 3 +-
arch/powerpc/include/asm/lppaca.h | 5 +-
arch/powerpc/include/asm/topology.h | 6 +-
arch/powerpc/kernel/rtas.c | 15 ++
arch/powerpc/mm/numa.c | 274 +++++++++++++++++++++++++++-
arch/powerpc/platforms/pseries/firmware.c | 1 +
7 files changed, 293 insertions(+), 14 deletions(-)
diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h
index 20778a4..4ef662e 100644
--- a/arch/powerpc/include/asm/firmware.h
+++ b/arch/powerpc/include/asm/firmware.h
@@ -46,6 +46,7 @@
#define FW_FEATURE_PS3_LV1 ASM_CONST(0x0000000000800000)
#define FW_FEATURE_BEAT ASM_CONST(0x0000000001000000)
#define FW_FEATURE_CMO ASM_CONST(0x0000000002000000)
+#define FW_FEATURE_VPHN ASM_CONST(0x0000000004000000)
#ifndef __ASSEMBLY__
@@ -59,7 +60,7 @@ enum {
FW_FEATURE_VIO | FW_FEATURE_RDMA | FW_FEATURE_LLAN |
FW_FEATURE_BULK_REMOVE | FW_FEATURE_XDABR |
FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR |
- FW_FEATURE_CMO,
+ FW_FEATURE_CMO | FW_FEATURE_VPHN,
FW_FEATURE_PSERIES_ALWAYS = 0,
FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index de03ca5..6de1e5f 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -232,7 +232,8 @@
#define H_GET_EM_PARMS 0x2B8
#define H_SET_MPP 0x2D0
#define H_GET_MPP 0x2D4
-#define MAX_HCALL_OPCODE H_GET_MPP
+#define H_HOME_NODE_ASSOCIATIVITY 0x2EC
+#define MAX_HCALL_OPCODE H_HOME_NODE_ASSOCIATIVITY
#ifndef __ASSEMBLY__
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h
index 14b592d..cc07d7f 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -62,7 +62,10 @@ struct lppaca {
volatile u32 dyn_pir; // Dynamic ProcIdReg value x20-x23
u32 dsei_data; // DSEI data x24-x27
u64 sprg3; // SPRG3 value x28-x2F
- u8 reserved3[80]; // Reserved x30-x7F
+ u8 reserved3[40]; // Reserved x30-x57
+ volatile u8 vphn_assoc_counts[8]; // Virtual processor home node
+ // associativity change counters x58-x5F
+ u8 reserved4[32]; // Reserved x60-x7F
//=============================================================================
// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index afe4aaa..1747d27 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -49,7 +49,7 @@ static inline int pcibus_to_node(struct pci_bus *bus)
{
return -1;
}
-#endif
+#endif /* CONFIG_PCI */
#define cpumask_of_pcibus(bus) (pcibus_to_node(bus) == -1 ? \
cpu_all_mask : \
@@ -93,6 +93,8 @@ extern void __init dump_numa_cpu_topology(void);
extern int sysfs_add_device_to_node(struct sys_device *dev, int nid);
extern void sysfs_remove_device_from_node(struct sys_device *dev, int nid);
+extern int __init init_topology_update(void);
+extern int stop_topology_update(void);
#else
static inline void dump_numa_cpu_topology(void) {}
@@ -107,6 +109,8 @@ static inline void sysfs_remove_device_from_node(struct sys_device *dev,
{
}
+static int __init init_topology_update(void) {}
+static int stop_topology_update(void) {}
#endif /* CONFIG_NUMA */
#include <asm-generic/topology.h>
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 41048de..abfcdc7 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -41,6 +41,7 @@
#include <asm/atomic.h>
#include <asm/time.h>
#include <asm/mmu.h>
+#include <asm/topology.h>
struct rtas_t rtas = {
.lock = __ARCH_SPIN_LOCK_UNLOCKED
@@ -706,6 +707,18 @@ void rtas_os_term(char *str)
static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE;
#ifdef CONFIG_PPC_PSERIES
+static void pre_suspend_work(void)
+{
+ stop_topology_update();
+ return;
+}
+
+static void post_suspend_work(void)
+{
+ init_topology_update();
+ return;
+}
+
static int __rtas_suspend_last_cpu(struct rtas_suspend_me_data *data, int wake_when_done)
{
u16 slb_size = mmu_slb_size;
@@ -713,6 +726,7 @@ static int __rtas_suspend_last_cpu(struct rtas_suspend_me_data *data, int wake_w
int cpu;
slb_set_size(SLB_MIN_SIZE);
+ pre_suspend_work();
printk(KERN_DEBUG "calling ibm,suspend-me on cpu %i\n", smp_processor_id());
while (rc == H_MULTI_THREADS_ACTIVE && !atomic_read(&data->done) &&
@@ -728,6 +742,7 @@ static int __rtas_suspend_last_cpu(struct rtas_suspend_me_data *data, int wake_w
rc = atomic_read(&data->error);
atomic_set(&data->error, rc);
+ post_suspend_work();
if (wake_when_done) {
atomic_set(&data->done, 1);
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 002878c..c182c2d 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -20,10 +20,14 @@
#include <linux/memblock.h>
#include <linux/of.h>
#include <linux/pfn.h>
+#include <linux/cpuset.h>
+#include <linux/node.h>
#include <asm/sparsemem.h>
#include <asm/prom.h>
#include <asm/system.h>
#include <asm/smp.h>
+#include <asm/firmware.h>
+#include <asm/paca.h>
static int numa_enabled = 1;
@@ -246,32 +250,41 @@ static void initialize_distance_lookup_table(int nid,
/* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
* info is found.
*/
-static int of_node_to_nid_single(struct device_node *device)
+static int associativity_to_nid(const unsigned int *associativity)
{
int nid = -1;
- const unsigned int *tmp;
if (min_common_depth == -1)
goto out;
- tmp = of_get_associativity(device);
- if (!tmp)
- goto out;
-
- if (tmp[0] >= min_common_depth)
- nid = tmp[min_common_depth];
+ if (associativity[0] >= min_common_depth)
+ nid = associativity[min_common_depth];
/* POWER4 LPAR uses 0xffff as invalid node */
if (nid == 0xffff || nid >= MAX_NUMNODES)
nid = -1;
- if (nid > 0 && tmp[0] >= distance_ref_points_depth)
- initialize_distance_lookup_table(nid, tmp);
+ if (nid > 0 && associativity[0] >= distance_ref_points_depth)
+ initialize_distance_lookup_table(nid, associativity);
out:
return nid;
}
+/* Returns the nid associated with the given device tree node,
+ * or -1 if not found.
+ */
+static int of_node_to_nid_single(struct device_node *device)
+{
+ int nid = -1;
+ const unsigned int *tmp;
+
+ tmp = of_get_associativity(device);
+ if (tmp)
+ nid = associativity_to_nid(tmp);
+ return nid;
+}
+
/* Walk the device tree upwards, looking for an associativity id */
int of_node_to_nid(struct device_node *device)
{
@@ -1247,3 +1260,244 @@ int hot_add_scn_to_nid(unsigned long scn_addr)
}
#endif /* CONFIG_MEMORY_HOTPLUG */
+
+/* Vrtual Processor Home Node (VPHN) support */
+#define VPHN_NR_CHANGE_CTRS (8)
+static u8 vphn_cpu_change_counts[NR_CPUS][VPHN_NR_CHANGE_CTRS];
+static cpumask_t cpu_associativity_changes_mask;
+static void topology_work_fn(struct work_struct *work);
+static DECLARE_WORK(topology_work, topology_work_fn);
+static void topology_timer_fn(unsigned long ignored);
+static struct timer_list topology_timer =
+ TIMER_INITIALIZER(topology_timer_fn, 0, 0);
+
+static void set_topology_timer(void);
+int stop_topology_update(void);
+
+/*
+ * Store the current values of the associativity change counters in the
+ * hypervisor.
+ */
+static void setup_cpu_associativity_change_counters(void)
+{
+ int cpu = 0;
+
+ for_each_possible_cpu(cpu) {
+ int i = 0;
+ u8 *counts = vphn_cpu_change_counts[cpu];
+ volatile u8 *hypervisor_counts = lppaca[cpu].vphn_assoc_counts;
+
+ for (i = 0; i < VPHN_NR_CHANGE_CTRS; i++) {
+ counts[i] = hypervisor_counts[i];
+ }
+ }
+
+ return;
+}
+
+/*
+ * The hypervisor maintains a set of 8 associativity change counters in
+ * the VPA of each cpu that correspond to the associativity levels in the
+ * ibm,associativity-reference-points property. When an associativity
+ * level changes, the corresponding counter is incremented.
+ *
+ * Set a bit in cpu_associativity_changes_mask for each cpu whose home
+ * node associativity levels have changed.
+ */
+static void update_cpu_associativity_changes_mask(void)
+{
+ int cpu = 0;
+ cpumask_t *changes = &cpu_associativity_changes_mask;
+
+ cpumask_clear(changes);
+
+ for_each_possible_cpu(cpu) {
+ int i;
+ u8 *counts = vphn_cpu_change_counts[cpu];
+ volatile u8 *hypervisor_counts = lppaca[cpu].vphn_assoc_counts;
+
+ for (i = 0; i < VPHN_NR_CHANGE_CTRS; i++) {
+ if (hypervisor_counts[i] > counts[i]) {
+ counts[i] = hypervisor_counts[i];
+
+ if (!(cpumask_test_cpu(cpu, changes)))
+ cpumask_set_cpu(cpu, changes);
+ }
+ }
+ }
+
+ return;
+}
+
+/* 6 64-bit registers unpacked into 12 32-bit associativity values */
+#define VPHN_ASSOC_BUFSIZE (6*sizeof(u64)/sizeof(u32))
+
+/*
+ * Convert the associativity domain numbers returned from the hypervisor
+ * to the sequence they would appear in the ibm,associativity property.
+ */
+static int vphn_unpack_associativity(const long *packed, unsigned int *unpacked)
+{
+ int i = 0;
+ int nr_assoc_doms = 0;
+ const u16 *field = (const u16*) packed;
+
+#define VPHN_FIELD_UNUSED (0xffff)
+#define VPHN_FIELD_MSB (0x8000)
+#define VPHN_FIELD_MASK (~VPHN_FIELD_MSB)
+
+ for (i = 0; i < VPHN_ASSOC_BUFSIZE; i++) {
+ if (*field == VPHN_FIELD_UNUSED) {
+ /* All significant fields processed, and remaining
+ * fields contain the reserved value of all 1's.
+ * Just store them.
+ */
+ unpacked[i] = *((u32*)field);
+ field += 2;
+ }
+ else if (*field & VPHN_FIELD_MSB) {
+ /* Data is in the lower 15 bits of this field */
+ unpacked[i] = *field & VPHN_FIELD_MASK;
+ field++;
+ nr_assoc_doms++;
+ }
+ else {
+ /* Data is in the lower 15 bits of this field
+ * concatenated with the next 16 bit field
+ */
+ unpacked[i] = *((u32*)field);
+ field += 2;
+ nr_assoc_doms++;
+ }
+ }
+
+ return nr_assoc_doms;
+}
+
+/*
+ * Retrieve the new associativity information for a virtual processor's
+ * home node.
+ */
+static long hcall_vphn(unsigned long cpu, unsigned int *associativity)
+{
+ long rc = 0;
+ long retbuf[PLPAR_HCALL9_BUFSIZE] = {0};
+ u64 flags = 1;
+ int hwcpu = get_hard_smp_processor_id(cpu);
+
+ rc = plpar_hcall9(H_HOME_NODE_ASSOCIATIVITY, retbuf, flags, hwcpu);
+ vphn_unpack_associativity(retbuf, associativity);
+
+ return rc;
+}
+
+static long
+vphn_get_associativity(unsigned long cpu, unsigned int *associativity)
+{
+ long rc = 0;
+
+ rc = hcall_vphn(cpu, associativity);
+
+ switch (rc) {
+ case H_FUNCTION:
+ printk(KERN_INFO
+ "VPHN is not supported. Disabling polling...\n");
+ stop_topology_update();
+ break;
+ case H_HARDWARE:
+ printk(KERN_ERR
+ "hcall_vphn() experienced a hardware fault "
+ "preventing VPHN. Disabling polling...\n");
+ stop_topology_update();
+ }
+
+ return rc;
+}
+
+/*
+ * Update the node maps and sysfs entries for each cpu whose home node
+ * has changed.
+ */
+int arch_update_cpu_topology(void)
+{
+ int cpu = 0, nid = 0, old_nid = 0;
+ unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0};
+ struct sys_device *sysdev = NULL;
+
+ for_each_cpu_mask(cpu, cpu_associativity_changes_mask) {
+ vphn_get_associativity(cpu, associativity);
+ nid = associativity_to_nid(associativity);
+
+ if (nid < 0 || !node_online(nid))
+ nid = first_online_node;
+
+ old_nid = numa_cpu_lookup_table[cpu];
+
+ /* Disable hotplug while we update the cpu
+ * masks and sysfs.
+ */
+ get_online_cpus();
+ unregister_cpu_under_node(cpu, old_nid);
+ unmap_cpu_from_node(cpu);
+ map_cpu_to_node(cpu, nid);
+ register_cpu_under_node(cpu, nid);
+ put_online_cpus();
+
+ sysdev = get_cpu_sysdev(cpu);
+ if (sysdev)
+ kobject_uevent(&sysdev->kobj, KOBJ_CHANGE);
+ }
+
+ return 1;
+}
+
+static void topology_work_fn(struct work_struct *work)
+{
+ rebuild_sched_domains();
+}
+
+void topology_schedule_update(void)
+{
+ schedule_work(&topology_work);
+}
+
+static void topology_timer_fn(unsigned long ignored)
+{
+ update_cpu_associativity_changes_mask();
+ if (!cpumask_empty(&cpu_associativity_changes_mask))
+ topology_schedule_update();
+ set_topology_timer();
+}
+
+static void set_topology_timer(void)
+{
+ topology_timer.data = 0;
+ topology_timer.expires = jiffies + 60 * HZ;
+ add_timer(&topology_timer);
+}
+
+/*
+ * Start polling for VPHN associativity changes.
+ */
+int __init init_topology_update(void)
+{
+ int rc = 0;
+
+ if (firmware_has_feature(FW_FEATURE_VPHN)) {
+ setup_cpu_associativity_change_counters();
+ init_timer_deferrable(&topology_timer);
+ set_topology_timer();
+ rc = 1;
+ }
+
+ return rc;
+}
+__initcall(init_topology_update);
+
+/*
+ * Disable polling for VPHN associativity changes.
+ */
+int stop_topology_update(void)
+{
+ return del_timer(&topology_timer);
+}
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index 0a14d8c..0b0eff0 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -55,6 +55,7 @@ firmware_features_table[FIRMWARE_MAX_FEATURES] = {
{FW_FEATURE_XDABR, "hcall-xdabr"},
{FW_FEATURE_MULTITCE, "hcall-multi-tce"},
{FW_FEATURE_SPLPAR, "hcall-splpar"},
+ {FW_FEATURE_VPHN, "hcall-vphn"},
};
/* Build up the firmware features bitmask using the contents of
--
1.7.2.3
^ permalink raw reply related
* Re: [patch] ps3disk: passing wrong variable to bvec_kunmap_irq()
From: Geert Uytterhoeven @ 2010-10-16 19:39 UTC (permalink / raw)
To: Jens Axboe
Cc: cbe-oss-dev@lists.ozlabs.org, Dan Carpenter, Martin K. Petersen,
Geoff Levand, kernel-janitors@vger.kernel.org, FUJITA Tomonori,
linuxppc-dev@lists.ozlabs.org
In-Reply-To: <4CB3689F.1050601@fusionio.com>
On Mon, Oct 11, 2010 at 21:42, Jens Axboe <jaxboe@fusionio.com> wrote:
> On 2010-10-11 21:13, Dan Carpenter wrote:
>> This should pass "buf" to bvec_kunmap_irq() instead of "bv". =C2=A0The a=
pi is
>> like kmap_atomic() instead of kmap().
>>
>> Signed-off-by: Dan Carpenter <error27@gmail.com>
>>
>> diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
>> index e9da874..03688c2 100644
>> --- a/drivers/block/ps3disk.c
>> +++ b/drivers/block/ps3disk.c
>> @@ -113,7 +113,7 @@ static void ps3disk_scatter_gather(struct ps3_storag=
e_device *dev,
>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 memcpy(buf, dev->bounce_buf+offset, size);
>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 offset +=3D size;
>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 flush_kernel_dcache_pag=
e(bvec->bv_page);
>> - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bvec_kunmap_irq(bvec, &flags=
);
>> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bvec_kunmap_irq(buf, &flags)=
;
>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 i++;
>> =C2=A0 =C2=A0 =C2=A0 }
>> =C2=A0}
>
> Thanks applied, that bug is all too common.
Because bvec_kunmap_irq() is a macro if !CONFIG_HIGHMEM, and thus there's =
no
argument type checking on e.g. pp64, which doesn't support HIGHMEM?
What about turning it into an inline function?
Gr{oetje,eeting}s,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 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. Bu=
t
when I'm talking to journalists I just say "programmer" or something like t=
hat.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0=C2=A0 =C2=A0=C2=A0 -- Linus Torvalds
^ permalink raw reply
* Re: [PATCH v4 5/5] mtd: m25p80: add support to parse the partitions by OF node
From: Artem Bityutskiy @ 2010-10-16 19:17 UTC (permalink / raw)
To: Mingkai Hu
Cc: david-b, kumar.gala, linuxppc-dev, linux-mtd, spi-devel-general
In-Reply-To: <1286878714-13090-6-git-send-email-Mingkai.hu@freescale.com>
On Tue, 2010-10-12 at 18:18 +0800, Mingkai Hu wrote:
> Signed-off-by: Mingkai Hu <Mingkai.hu@freescale.com>
> Acked-by: Grant Likely <grant.likely@secretlab.ca>
> ---
> v4:
> - Updated to latest kernel base(Linux 2.6.36-rc7).
> - Made changes according to Grant's comments.
Looks good to me, pushed to l2-mtd-2.6.git, thanks.
--
Best Regards,
Artem Bityutskiy (Битюцкий Артём)
^ permalink raw reply
* Wher to find gcc-3.3.1-crossppc.diff
From: Ramón Frutos Sánchez @ 2010-10-16 19:13 UTC (permalink / raw)
To: linuxppc-dev
Thank you very much, Lorenz
^ permalink raw reply
* Re: Wher to find gcc-3.3.1-crossppc.diff
From: Lorenz Kolb @ 2010-10-16 17:00 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1287246649.10014.1.camel@linux-oduc.site>
Asking google came up with:
http://osdir.com/ml/linux.ports.ppc.embedded/2004-02/msg00040.html
Which again points to: http://osdir.com/ml/attachments/txtvjVqHGcB6G.txt
Hope this helps.
Am 16.10.2010 18:30, schrieb Ramón Frutos Sánchez:
> Helo, I'm looking for the patch gcc-3.3.1-crossppc.diff but it seems to
> be disapeared from penguinppc web, does anybody know where to find it?
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>
^ permalink raw reply
* Wher to find gcc-3.3.1-crossppc.diff
From: Ramón Frutos Sánchez @ 2010-10-16 16:30 UTC (permalink / raw)
To: linuxppc-dev
Helo, I'm looking for the patch gcc-3.3.1-crossppc.diff but it seems to
be disapeared from penguinppc web, does anybody know where to find it?
^ permalink raw reply
* Help about chip select on SPI slave devices
From: WANG YiFei @ 2010-10-16 10:35 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <BAY158-ds2BEE228C7E27E7CE0C28BF5550@phx.gbl>
Hi,
We have a board which has 1 SPI master controller and 4 SPI slave =
devices, and we'd like to use 2 GPIOs to demux to chip select these =
slave devices.
Can anyone tell me if current powerpc dts support demuxer for chip =
select for spi slave devices? So far as I know, in dts, SPI master can =
only use 1 to 1 GPIO to CS(then needs 4 GPIOs).
Thanks in advance,
YiFei
^ permalink raw reply
* 64K PAGE_SIZE and arch/powerpc/kernel/vdso.c
From: Nicholas A. Bellinger @ 2010-10-16 8:03 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Brian King
Greetings Linux-ppc64 folks,
While trying to compile v2.6.36-rc8 with PAGE_SIZE=65536 I run into the
following compile failure w/ strict checking on a RHEL5.4 / gcc (GCC)
4.1.2 20080704 (Red Hat 4.1.2-46) system:
cc1: warnings being treated as errors
arch/powerpc/kernel/vdso.c:81: warning: alignment of ‘vdso_data_store’
is greater than maximum object file alignment. Using 32768
CC arch/powerpc/sysdev/msi_bitmap.o
make[1]: *** [arch/powerpc/kernel/vdso.o] Error 1
make[1]: *** Waiting for unfinished jobs....
Any ideas folks..?
TIA,
--nab
^ permalink raw reply
* Re: [PATCH] powerpc/5121: pdm360ng: fix touch irq if 8xxx gpio driver is enabled
From: Grant Likely @ 2010-10-16 3:52 UTC (permalink / raw)
To: Anatolij Gustschin; +Cc: linuxppc-dev
In-Reply-To: <20101014165549.473d71ab@wker>
On Thu, Oct 14, 2010 at 04:55:49PM +0200, Anatolij Gustschin wrote:
> Hi Grant,
>
> On Wed, 15 Sep 2010 22:12:57 +0200
> Anatolij Gustschin <agust@denx.de> wrote:
>
> > Enabling the MPC8xxx GPIO driver with MPC512x GPIO extension
> > breaks touch screen support on this board since the GPIO
> > interrupt will be mapped to 8xxx GPIO irq host resulting in
> > a not requestable interrupt in the touch screen driver. Fix
> > it by mapping the touch interrupt on 8xxx GPIO irq host.
> >
> > Signed-off-by: Anatolij Gustschin <agust@denx.de>
> > ---
> > arch/powerpc/platforms/512x/pdm360ng.c | 26 ++++++++++++++++++++++----
> > 1 files changed, 22 insertions(+), 4 deletions(-)
>
> Can this patch go in for 2.6.37 ?
I hope so, but I haven't looked at it properly yet and I'm trying to
dig myself out of a patch backlog.
g.
^ permalink raw reply
* [PATCH] Drivers: ps3: Makefile: replace the use of <module>-objs with <module>-y
From: Tracey Dent @ 2010-10-16 3:30 UTC (permalink / raw)
To: geoff; +Cc: Tracey Dent, linuxppc-dev, linux-kernel
Changed <module>-objs to <module>-y in Makefile.
Signed-off-by: Tracey Dent <tdent48227@gmail.com>
---
drivers/ps3/Makefile | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile
index ccea15c..50cb1e1 100644
--- a/drivers/ps3/Makefile
+++ b/drivers/ps3/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_PS3_VUART) += ps3-vuart.o
obj-$(CONFIG_PS3_PS3AV) += ps3av_mod.o
-ps3av_mod-objs += ps3av.o ps3av_cmd.o
+ps3av_mod-y := ps3av.o ps3av_cmd.o
obj-$(CONFIG_PPC_PS3) += sys-manager-core.o
obj-$(CONFIG_PS3_SYS_MANAGER) += ps3-sys-manager.o
obj-$(CONFIG_PS3_STORAGE) += ps3stor_lib.o
--
1.7.3.1.104.gc752e
^ permalink raw reply related
* Re: [PATCH] mxc_udc: add workaround for ENGcm09152 for i.MX35
From: Eric Bénard @ 2010-10-15 19:24 UTC (permalink / raw)
To: Greg KH
Cc: dbrownell, Dinh.Nguyen, linux-usb, linux-kernel, linuxppc-dev,
gregkh, linux-arm-kernel
In-Reply-To: <20101015191005.GB8098@kroah.com>
Hi Greg,
Le 15/10/2010 21:10, Greg KH a écrit :
> On Fri, Oct 15, 2010 at 02:30:58PM +0200, Eric Bénard wrote:
>> this patch gives the possibility to workaround bug ENGcm09152
>> on i.MX35 when the hardware workaround is also implemented on
>> the board.
>> It covers the workaround described on page 25 of the following Errata :
>> http://cache.freescale.com/files/dsp/doc/errata/IMX35CE.pdf
>>
>> Signed-off-by: Eric Bénard<eric@eukrea.com>
>> ---
>> arch/arm/mach-mx3/mach-cpuimx35.c | 1 +
>> drivers/usb/gadget/fsl_mxc_udc.c | 15 +++++++++++++++
>> include/linux/fsl_devices.h | 3 +++
>> 3 files changed, 19 insertions(+), 0 deletions(-)
>
> Do you want me to take this through my usb tree, or will it go through
> some other developer's tree?
>
as most of the changes are in drivers/usb that would be great if you can take it.
Thanks
Eric
^ permalink raw reply
* Re: [PATCH] mxc_udc: add workaround for ENGcm09152 for i.MX35
From: Greg KH @ 2010-10-15 19:10 UTC (permalink / raw)
To: Eric Bénard
Cc: dbrownell, Dinh.Nguyen, linux-usb, linux-kernel, linuxppc-dev,
gregkh, linux-arm-kernel
In-Reply-To: <1287145858-10239-1-git-send-email-eric@eukrea.com>
On Fri, Oct 15, 2010 at 02:30:58PM +0200, Eric Bénard wrote:
> this patch gives the possibility to workaround bug ENGcm09152
> on i.MX35 when the hardware workaround is also implemented on
> the board.
> It covers the workaround described on page 25 of the following Errata :
> http://cache.freescale.com/files/dsp/doc/errata/IMX35CE.pdf
>
> Signed-off-by: Eric Bénard <eric@eukrea.com>
> ---
> arch/arm/mach-mx3/mach-cpuimx35.c | 1 +
> drivers/usb/gadget/fsl_mxc_udc.c | 15 +++++++++++++++
> include/linux/fsl_devices.h | 3 +++
> 3 files changed, 19 insertions(+), 0 deletions(-)
Do you want me to take this through my usb tree, or will it go through
some other developer's tree?
Either is fine with me.
thanks,
greg k-h
^ permalink raw reply
* Re: Possible kernel stack overflow due to fast interrupts
From: Rick Tao @ 2010-10-15 19:13 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1287100633.2205.80.camel@pasglop>
You are exactly right! Ensuring interrupts would not cause more preemptions=
. =0AThanks for pointing it out.=0ARick=0A=0A--- On Thu, 10/14/10, Benjamin=
Herrenschmidt <benh@kernel.crashing.org> wrote:=0A=0A> From: Benjamin Herr=
enschmidt <benh@kernel.crashing.org>=0A> Subject: Re: Possible kernel stack=
overflow due to fast interrupts=0A> To: "Rick Tao" <tao_rick@yahoo.com>=0A=
> Cc: linuxppc-dev@lists.ozlabs.org=0A> Date: Thursday, October 14, 2010, 4=
:57 PM=0A> On Thu, 2010-10-14 at 13:45 -0700,=0A> Rick Tao wrote:=0A> > Hi,=
all,=0A> =0A> .../...=0A> =0A> > In the context of task A=0A> > a. NIP wo=
uld point to the instruction after=0A> switch_to(). =0A> > b. MSR_EE is ena=
bled in the call trace=0A> (finish_task_switch=0A> -->finish_lock_switch-->=
spin_unlock_irq)=0A> > c. do something that would trigger an interrupt late=
r=0A> on (such as timer)=0A> > d. call schedule() for context switch to tas=
k B.=0A> >=A0 =A0 In this step, =0A> >=A0 =A0 =A0 task B's stack is popped=
=0A> INT_FRAME_SIZE size for context restore.=A0 =0A> >=A0 =A0 Note that ta=
sk B's ksp =3D X -=0A> INT_FRAME_SIZE=0A> > =0A> > In the context of task B=
again=0A> > a1. similar to step "a" above=0A> >=0A> > b1. similar to step =
"b" above =0A> > c1. interrupt occurs, go to step "1" above, and=0A> repeat=
!!!=0A> > =0A> > As you can see, task B's kernel stack space is reduced=0A>=
by INT_FRAME_SIZE=0A> > on each loop. It will eventually overflow.=0A> =0A=
> So if I follow you correctly, you are worried that by the=0A> time execut=
ion=0A> resumes in B, and before it pops the second frame off, it=0A> might=
get=0A> another interrupt and re-preempt...=0A> =0A> Now unless I missed s=
omething, that cannot happen because=0A> preempt_schedule_irq() does increm=
ent the preempt count:=0A> =0A> =A0=A0=A0 add_preempt_count(PREEMPT_ACTIVE)=
;=0A> =A0=A0=A0 local_irq_enable();=0A> =A0=A0=A0 schedule();=0A> =A0=A0=A0=
local_irq_disable();=0A> =A0=A0=A0 sub_preempt_count(PREEMPT_ACTIVE);=0A> =
=0A> Which means that it won't preempt again in=0A> finish_task_switch, and=
so=0A> will eventually come back, turn EE back off, and pop off=0A> the st=
ack=0A> frame.=0A> =0A> Or am I missing something ?=0A> =0A> Cheers,=0A> Be=
n.=0A> =0A> =0A> _______________________________________________=0A> Linuxp=
pc-dev mailing list=0A> Linuxppc-dev@lists.ozlabs.org=0A> https://lists.ozl=
abs.org/listinfo/linuxppc-dev=0A> =0A=0A=0A
^ permalink raw reply
* [RFC PATCH v3] 476: Set CCR2[DSTI] to prevent isync from flushing shadow TLB
From: Dave Kleikamp @ 2010-10-15 17:33 UTC (permalink / raw)
To: Josh Boyer, Benjamin Herrenschmidt; +Cc: linuxppc-dev list, Dave Kleikamp
Josh, don't pick this up yet. It needs a bit more testing, but I think I
got it right this time.
When the DSTI (Disable Shadow TLB Invalidate) bit is set in the CCR2
register, the isync command does not flush the shadow TLB (iTLB & dTLB).
However, since the shadow TLB does not contain context information, we
want the shadow TLB flushed in situations where we are switching context.
In those situations, we explicitly clear the DSTI bit before performing
isync, and set it again afterward. We also need to do the same when we
perform isync after explicitly flushing the TLB.
The 476 requires an isync following a write to certain SPRs in order for
their changes to be effective. Such is the case with the DSTI bit, so
the first isync may not be affected by an immediate change to CCR2, but
a second isync instruction will repect the setting.
Signed-off-by: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/reg_booke.h | 4 ++++
arch/powerpc/kernel/head_44x.S | 28 ++++++++++++++++++++++++++++
arch/powerpc/mm/tlb_nohash_low.S | 24 +++++++++++++++++++++++-
arch/powerpc/platforms/44x/misc_44x.S | 28 ++++++++++++++++++++++++++++
4 files changed, 83 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index 667a498..a7ecbfe 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -120,6 +120,7 @@
#define SPRN_TLB3CFG 0x2B3 /* TLB 3 Config Register */
#define SPRN_EPR 0x2BE /* External Proxy Register */
#define SPRN_CCR1 0x378 /* Core Configuration Register 1 */
+#define SPRN_CCR2_476 0x379 /* Core Configuration Register 2 (476)*/
#define SPRN_ZPR 0x3B0 /* Zone Protection Register (40x) */
#define SPRN_MAS7 0x3B0 /* MMU Assist Register 7 */
#define SPRN_MMUCR 0x3B2 /* MMU Control Register */
@@ -188,6 +189,9 @@
#define CCR1_DPC 0x00000100 /* Disable L1 I-Cache/D-Cache parity checking */
#define CCR1_TCS 0x00000080 /* Timer Clock Select */
+/* Bit definitions for CCR2. */
+#define CCR2_476_DSTI 0x08000000 /* Disable Shadow TLB Invalidate */
+
/* Bit definitions for the MCSR. */
#define MCSR_MCS 0x80000000 /* Machine Check Summary */
#define MCSR_IB 0x40000000 /* Instruction PLB Error */
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index 562305b..df1ef80 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -38,6 +38,7 @@
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>
#include <asm/synch.h>
+#include <asm/bug.h>
#include "head_booke.h"
@@ -703,8 +704,29 @@ _GLOBAL(set_context)
stw r4, 0x4(r5)
#endif
mtspr SPRN_PID,r3
+BEGIN_MMU_FTR_SECTION
+ b 1f
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
isync /* Force context change */
blr
+1:
+#ifdef CONFIG_PPC_47x
+ mfspr r10,SPRN_CCR2_476
+ rlwinm r11,r10,0,~CCR2_476_DSTI
+ mtspr SPRN_CCR2_476,r11
+ /*
+ * The first isync may not respect the change to CCR2, but its
+ * completion will ensure that the second isync does.
+ */
+ isync
+ isync /* Force context change */
+ mtspr SPRN_CCR2_476,r10
+ isync
+#else /* CONFIG_PPC_47x */
+2: trap
+ EMIT_BUG_ENTRY 2b,__FILE__,__LINE__,0;
+#endif /* CONFIG_PPC_47x */
+ blr
/*
* Init CPU state. This is called at boot time or for secondary CPUs
@@ -1083,6 +1105,12 @@ clear_utlb_entry:
isync
#endif /* CONFIG_PPC_EARLY_DEBUG_44x */
+ mfspr r3,SPRN_CCR2_476
+ /* With CCR2(DSTI) set, isync does not invalidate the shadow TLB */
+ oris r3,r3,CCR2_476_DSTI@h
+ mtspr SPRN_CCR2_476,r3
+ isync
+
/* Establish the interrupt vector offsets */
SET_IVOR(0, CriticalInput);
SET_IVOR(1, MachineCheckA);
diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S
index b9d9fed..8e318ed 100644
--- a/arch/powerpc/mm/tlb_nohash_low.S
+++ b/arch/powerpc/mm/tlb_nohash_low.S
@@ -112,6 +112,16 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
clrrwi r4,r3,12 /* get an EPN for the hashing with V = 0 */
ori r4,r4,PPC47x_TLBE_SIZE
tlbwe r4,r7,0 /* write it */
+ mfspr r8,SPRN_CCR2_476
+ rlwinm r9,r8,0,~CCR2_476_DSTI
+ mtspr SPRN_CCR2_476,r9
+ /*
+ * The first isync may not respect the change to CCR2, but its
+ * completion will ensure that the second isync does.
+ */
+ isync
+ isync
+ mtspr SPRN_CCR2_476,r8
isync
wrtee r10
blr
@@ -180,7 +190,13 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
lwz r8,0(r10) /* Load boltmap entry */
addi r10,r10,4 /* Next word */
b 1b /* Then loop */
-1: isync /* Sync shadows */
+1: mfspr r9,SPRN_CCR2_476
+ rlwinm r10,r9,0,~CCR2_476_DSTI
+ mtspr SPRN_CCR2_476,r10
+ isync
+ isync /* Sync shadows */
+ mtspr SPRN_CCR2_476,r9
+ isync
wrtee r11
#else /* CONFIG_PPC_47x */
1: trap
@@ -203,6 +219,12 @@ _GLOBAL(_tlbivax_bcast)
isync
/* tlbivax 0,r3 - use .long to avoid binutils deps */
.long 0x7c000624 | (r3 << 11)
+ mfspr r8,SPRN_CCR2_476
+ rlwinm r9,r8,0,~CCR2_476_DSTI
+ mtspr SPRN_CCR2_476,r9
+ isync
+ isync
+ mtspr SPRN_CCR2_476,r8
isync
eieio
tlbsync
diff --git a/arch/powerpc/platforms/44x/misc_44x.S b/arch/powerpc/platforms/44x/misc_44x.S
index dc12b80..2422dd3 100644
--- a/arch/powerpc/platforms/44x/misc_44x.S
+++ b/arch/powerpc/platforms/44x/misc_44x.S
@@ -9,15 +9,40 @@
*
*/
+#include <asm/mmu.h>
#include <asm/reg.h>
#include <asm/ppc_asm.h>
.text
+#ifdef CONFIG_PPC_47x
+
+#define LOAD_CLEAR_CCR2_DSTI(REG1, REG2) \
+BEGIN_MMU_FTR_SECTION \
+ mfspr REG1,SPRN_CCR2_476; \
+ rlwinm REG2,REG1,0,~CCR2_476_DSTI; \
+ mtspr SPRN_CCR2_476,REG2; \
+ isync; \
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
+
+#define RESTORE_CCR2_DSTI(REG) \
+BEGIN_MMU_FTR_SECTION \
+ mtspr SPRN_CCR2_476,REG; \
+ isync; \
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
+
+#else /* CONFIG_PPC_47x */
+
+#define LOAD_CLEAR_CCR2_DSTI(REG1, REG2)
+#define RESTORE_CCR2_DSTI(REG)
+
+#endif /* CONFIG_PPC_47x */
+
/*
* Do an IO access in AS1
*/
_GLOBAL(as1_readb)
+ LOAD_CLEAR_CCR2_DSTI(r8, r9)
mfmsr r7
ori r0,r7,MSR_DS
sync
@@ -29,9 +54,11 @@ _GLOBAL(as1_readb)
mtmsr r7
sync
isync
+ RESTORE_CCR2_DSTI(r8)
blr
_GLOBAL(as1_writeb)
+ LOAD_CLEAR_CCR2_DSTI(r8, r9)
mfmsr r7
ori r0,r7,MSR_DS
sync
@@ -43,4 +70,5 @@ _GLOBAL(as1_writeb)
mtmsr r7
sync
isync
+ RESTORE_CCR2_DSTI(r8)
blr
--
1.7.2.2
^ permalink raw reply related
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