* [PATCH 8/8] sdhci: Use jiffies instead of a timeout counter
From: Anton Vorontsov @ 2010-07-14 13:08 UTC (permalink / raw)
To: Andrew Morton
Cc: Matt Fleming, Albert Herranz, linux-mmc, linux-kernel,
linuxppc-dev, Ben Dooks, Pierre Ossman
In-Reply-To: <20100714130728.GA27339@oksana.dev.rtsoft.ru>
Just a cosmetic change, should not affect functionality.
Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
---
drivers/mmc/host/sdhci.c | 11 +++++------
1 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index e6adda8..c754df1 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/scatterlist.h>
+#include <linux/jiffies.h>
#include <linux/leds.h>
@@ -160,17 +161,16 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
host->clock = 0;
/* Wait max 100 ms */
- timeout = 100;
+ timeout = jiffies + msecs_to_jiffies(100);
/* hw clears the bit when it's done */
while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
- if (timeout == 0) {
+ if (time_after(jiffies, timeout)) {
printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
mmc_hostname(host->mmc), (int)mask);
sdhci_dumpregs(host);
return;
}
- timeout--;
msleep(1);
}
@@ -884,7 +884,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
WARN_ON(host->cmd);
/* Wait max 10 ms */
- timeout = 10;
+ timeout = jiffies + msecs_to_jiffies(10);
mask = SDHCI_CMD_INHIBIT;
if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
@@ -896,7 +896,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
mask &= ~SDHCI_DATA_INHIBIT;
while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
- if (timeout == 0) {
+ if (time_after(jiffies, timeout)) {
printk(KERN_ERR "%s: Controller never released "
"inhibit bit(s).\n", mmc_hostname(host->mmc));
sdhci_dumpregs(host);
@@ -904,7 +904,6 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
schedule_work(&host->finish_work);
return;
}
- timeout--;
mdelay(1);
}
--
1.7.0.5
^ permalink raw reply related
* [PATCH 7/8] sdhci: Get rid of mdelay()s where it is safe and makes sense
From: Anton Vorontsov @ 2010-07-14 13:08 UTC (permalink / raw)
To: Andrew Morton
Cc: Matt Fleming, Albert Herranz, linux-mmc, linux-kernel,
linuxppc-dev, Ben Dooks, Pierre Ossman
In-Reply-To: <20100714130728.GA27339@oksana.dev.rtsoft.ru>
Since we don't run in the atomic context any longer, we can
turn mdelay()s into msleep()s.
The only place where the driver is still using mdelay() is
sdhci_send_command(). There it is possible to use sleepable
delays too, but we don't actually want to force rescheduling
in a hot path.
Sure, we might end up calling msleep() there too, just not
via this safe patch.
Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
---
drivers/mmc/host/sdhci-of-esdhc.c | 2 +-
drivers/mmc/host/sdhci.c | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index c8623de..e9f99fe 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -94,7 +94,7 @@ static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
setbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
div << ESDHC_DIVIDER_SHIFT | pre_div << ESDHC_PREDIV_SHIFT);
- mdelay(100);
+ msleep(100);
out:
host->clock = clock;
}
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 56d5c56..e6adda8 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -171,7 +171,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
return;
}
timeout--;
- mdelay(1);
+ msleep(1);
}
if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
@@ -1019,7 +1019,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
return;
}
timeout--;
- mdelay(1);
+ msleep(1);
}
clk |= SDHCI_CLOCK_CARD_EN;
@@ -1086,7 +1086,7 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
* can apply clock after applying power
*/
if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
- mdelay(10);
+ msleep(10);
}
/*****************************************************************************\
--
1.7.0.5
^ permalink raw reply related
* [PATCH 6/8] sdhci: Get rid of card detect work
From: Anton Vorontsov @ 2010-07-14 13:08 UTC (permalink / raw)
To: Andrew Morton
Cc: Matt Fleming, Albert Herranz, linux-mmc, linux-kernel,
linuxppc-dev, Ben Dooks, Pierre Ossman
In-Reply-To: <20100714130728.GA27339@oksana.dev.rtsoft.ru>
Nowadays we can just call the card detection handler directly,
no need for the separate work struct.
We still need host->finish_work as sdhci_finish_work() calls
mmc_request_done(), which tries to re-enter the driver.
Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
---
drivers/mmc/host/sdhci.c | 14 ++------------
drivers/mmc/host/sdhci.h | 1 -
2 files changed, 2 insertions(+), 13 deletions(-)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 5eddbdb..56d5c56 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1239,14 +1239,8 @@ static const struct mmc_host_ops sdhci_ops = {
* *
\*****************************************************************************/
-static void sdhci_card_detect_work(struct work_struct *wk)
+static void sdhci_card_detect(struct sdhci_host *host)
{
- struct sdhci_host *host;
-
- host = container_of(wk, struct sdhci_host, card_detect_work);
-
- mutex_lock(&host->lock);
-
if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
if (host->mrq) {
printk(KERN_ERR "%s: Card removed during transfer!\n",
@@ -1262,8 +1256,6 @@ static void sdhci_card_detect_work(struct work_struct *wk)
}
}
- mutex_unlock(&host->lock);
-
mmc_detect_change(host->mmc, msecs_to_jiffies(200));
}
@@ -1511,7 +1503,7 @@ static irqreturn_t sdhci_irq_thread(int irq, void *dev_id)
sdhci_writel(host, intmask, SDHCI_INT_STATUS);
if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE))
- schedule_work(&host->card_detect_work);
+ sdhci_card_detect(host);
intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
@@ -1865,7 +1857,6 @@ int sdhci_add_host(struct sdhci_host *host)
/*
* Init work structs.
*/
- INIT_WORK(&host->card_detect_work, sdhci_card_detect_work);
INIT_WORK(&host->finish_work, sdhci_finish_work);
INIT_DELAYED_WORK(&host->timeout_work, sdhci_timeout_work);
@@ -1950,7 +1941,6 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
flush_delayed_work(&host->timeout_work);
- flush_work(&host->card_detect_work);
flush_work(&host->finish_work);
kfree(host->adma_desc);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 364d4e8..5f7d649 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -289,7 +289,6 @@ struct sdhci_host {
dma_addr_t adma_addr; /* Mapped ADMA descr. table */
dma_addr_t align_addr; /* Mapped bounce buffer */
- struct work_struct card_detect_work;
struct work_struct finish_work;
struct delayed_work timeout_work; /* Work for timeouts */
--
1.7.0.5
^ permalink raw reply related
* [PATCH 5/8] sdhci: Turn host->lock into a mutex
From: Anton Vorontsov @ 2010-07-14 13:08 UTC (permalink / raw)
To: Andrew Morton
Cc: Matt Fleming, Albert Herranz, linux-mmc, linux-kernel,
linuxppc-dev, Ben Dooks, Pierre Ossman
In-Reply-To: <20100714130728.GA27339@oksana.dev.rtsoft.ru>
Finally, we can get rid of the host->lock spinlock, and turn it
into a mutex.
This patch does just this.
Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
---
drivers/mmc/host/sdhci.c | 53 +++++++++++++++++++--------------------------
drivers/mmc/host/sdhci.h | 3 +-
2 files changed, 24 insertions(+), 32 deletions(-)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 0358b35..5eddbdb 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -20,6 +20,7 @@
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
#include <linux/scatterlist.h>
#include <linux/leds.h>
@@ -228,16 +229,15 @@ static void sdhci_led_control(struct led_classdev *led,
enum led_brightness brightness)
{
struct sdhci_host *host = container_of(led, struct sdhci_host, led);
- unsigned long flags;
- spin_lock_irqsave(&host->lock, flags);
+ mutex_lock(&host->lock);
if (brightness == LED_OFF)
sdhci_deactivate_led(host);
else
sdhci_activate_led(host);
- spin_unlock_irqrestore(&host->lock, flags);
+ mutex_unlock(&host->lock);
}
#endif
@@ -1099,11 +1099,10 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sdhci_host *host;
bool present;
- unsigned long flags;
host = mmc_priv(mmc);
- spin_lock_irqsave(&host->lock, flags);
+ mutex_lock(&host->lock);
WARN_ON(host->mrq != NULL);
@@ -1127,18 +1126,17 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
sdhci_send_command(host, mrq->cmd);
mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
+ mutex_unlock(&host->lock);
}
static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct sdhci_host *host;
- unsigned long flags;
u8 ctrl;
host = mmc_priv(mmc);
- spin_lock_irqsave(&host->lock, flags);
+ mutex_lock(&host->lock);
if (host->flags & SDHCI_DEVICE_DEAD)
goto out;
@@ -1183,25 +1181,24 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
out:
mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
+ mutex_unlock(&host->lock);
}
static int sdhci_get_ro(struct mmc_host *mmc)
{
struct sdhci_host *host;
- unsigned long flags;
int present;
host = mmc_priv(mmc);
- spin_lock_irqsave(&host->lock, flags);
+ mutex_lock(&host->lock);
if (host->flags & SDHCI_DEVICE_DEAD)
present = 0;
else
present = sdhci_readl(host, SDHCI_PRESENT_STATE);
- spin_unlock_irqrestore(&host->lock, flags);
+ mutex_unlock(&host->lock);
if (host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT)
return !!(present & SDHCI_WRITE_PROTECT);
@@ -1211,11 +1208,10 @@ static int sdhci_get_ro(struct mmc_host *mmc)
static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
{
struct sdhci_host *host;
- unsigned long flags;
host = mmc_priv(mmc);
- spin_lock_irqsave(&host->lock, flags);
+ mutex_lock(&host->lock);
if (host->flags & SDHCI_DEVICE_DEAD)
goto out;
@@ -1227,7 +1223,7 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
out:
mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
+ mutex_unlock(&host->lock);
}
static const struct mmc_host_ops sdhci_ops = {
@@ -1246,11 +1242,10 @@ static const struct mmc_host_ops sdhci_ops = {
static void sdhci_card_detect_work(struct work_struct *wk)
{
struct sdhci_host *host;
- unsigned long flags;
host = container_of(wk, struct sdhci_host, card_detect_work);
- spin_lock_irqsave(&host->lock, flags);
+ mutex_lock(&host->lock);
if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
if (host->mrq) {
@@ -1267,7 +1262,7 @@ static void sdhci_card_detect_work(struct work_struct *wk)
}
}
- spin_unlock_irqrestore(&host->lock, flags);
+ mutex_unlock(&host->lock);
mmc_detect_change(host->mmc, msecs_to_jiffies(200));
}
@@ -1275,12 +1270,11 @@ static void sdhci_card_detect_work(struct work_struct *wk)
static void sdhci_finish_work(struct work_struct *wk)
{
struct sdhci_host *host;
- unsigned long flags;
struct mmc_request *mrq;
host = container_of(wk, struct sdhci_host, finish_work);
- spin_lock_irqsave(&host->lock, flags);
+ mutex_lock(&host->lock);
__cancel_delayed_work(&host->timeout_work);
@@ -1321,7 +1315,7 @@ static void sdhci_finish_work(struct work_struct *wk)
#endif
mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
+ mutex_unlock(&host->lock);
mmc_request_done(host->mmc, mrq);
}
@@ -1329,11 +1323,10 @@ static void sdhci_finish_work(struct work_struct *wk)
static void sdhci_timeout_work(struct work_struct *wk)
{
struct sdhci_host *host;
- unsigned long flags;
host = container_of(wk, struct sdhci_host, timeout_work.work);
- spin_lock_irqsave(&host->lock, flags);
+ mutex_lock(&host->lock);
if (host->mrq) {
printk(KERN_ERR "%s: Timeout waiting for hardware "
@@ -1354,7 +1347,7 @@ static void sdhci_timeout_work(struct work_struct *wk)
}
mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
+ mutex_unlock(&host->lock);
}
/*****************************************************************************\
@@ -1512,7 +1505,7 @@ static irqreturn_t sdhci_irq_thread(int irq, void *dev_id)
u32 intmask;
int cardint = 0;
- spin_lock(&host->lock);
+ mutex_lock(&host->lock);
intmask = sdhci_readl(host, SDHCI_INT_STATUS);
sdhci_writel(host, intmask, SDHCI_INT_STATUS);
@@ -1551,7 +1544,7 @@ static irqreturn_t sdhci_irq_thread(int irq, void *dev_id)
mmiowb();
- spin_unlock(&host->lock);
+ mutex_unlock(&host->lock);
/*
* We have to delay this as it calls back into the driver.
@@ -1816,7 +1809,7 @@ int sdhci_add_host(struct sdhci_host *host)
return -ENODEV;
}
- spin_lock_init(&host->lock);
+ mutex_init(&host->lock);
/*
* Maximum number of segments. Depends on if the hardware
@@ -1926,10 +1919,8 @@ EXPORT_SYMBOL_GPL(sdhci_add_host);
void sdhci_remove_host(struct sdhci_host *host, int dead)
{
- unsigned long flags;
-
if (dead) {
- spin_lock_irqsave(&host->lock, flags);
+ mutex_lock(&host->lock);
host->flags |= SDHCI_DEVICE_DEAD;
@@ -1941,7 +1932,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
schedule_work(&host->finish_work);
}
- spin_unlock_irqrestore(&host->lock, flags);
+ mutex_unlock(&host->lock);
}
sdhci_disable_card_detection(host);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index d96e4dd..364d4e8 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -15,6 +15,7 @@
#include <linux/workqueue.h>
#include <linux/compiler.h>
#include <linux/types.h>
+#include <linux/mutex.h>
#include <linux/io.h>
/*
@@ -256,7 +257,7 @@ struct sdhci_host {
char led_name[32];
#endif
- spinlock_t lock; /* Mutex */
+ struct mutex lock; /* Mutex */
int flags; /* Host attributes */
#define SDHCI_USE_SDMA (1<<0) /* Host is SDMA capable */
--
1.7.0.5
^ permalink raw reply related
* [PATCH 4/8] sdhci: Use threaded IRQ handler
From: Anton Vorontsov @ 2010-07-14 13:08 UTC (permalink / raw)
To: Andrew Morton
Cc: Matt Fleming, Albert Herranz, linux-mmc, linux-kernel,
linuxppc-dev, Ben Dooks, Pierre Ossman
In-Reply-To: <20100714130728.GA27339@oksana.dev.rtsoft.ru>
We only need atomic context to disable SDHCI interrupts, after that
we can run in a kernel thread.
Note that irq handler still grabs an irqsave spinlock, we'll deal
with it in a subsequent patch.
Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
---
drivers/mmc/host/sdhci.c | 47 +++++++++++++++++++++++++++------------------
1 files changed, 28 insertions(+), 19 deletions(-)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9ec245c..0358b35 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1506,9 +1506,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
}
}
-static irqreturn_t sdhci_irq(int irq, void *dev_id)
+static irqreturn_t sdhci_irq_thread(int irq, void *dev_id)
{
- irqreturn_t result;
struct sdhci_host* host = dev_id;
u32 intmask;
int cardint = 0;
@@ -1516,17 +1515,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
spin_lock(&host->lock);
intmask = sdhci_readl(host, SDHCI_INT_STATUS);
-
- if (!intmask || intmask == 0xffffffff) {
- result = IRQ_NONE;
- goto out;
- }
-
sdhci_writel(host, intmask, SDHCI_INT_STATUS);
- DBG("*** %s got interrupt: 0x%08x\n",
- mmc_hostname(host->mmc), intmask);
-
if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE))
schedule_work(&host->card_detect_work);
@@ -1559,10 +1549,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
sdhci_dumpregs(host);
}
- result = IRQ_HANDLED;
-
mmiowb();
-out:
+
spin_unlock(&host->lock);
/*
@@ -1571,7 +1559,28 @@ out:
if (cardint)
mmc_signal_sdio_irq(host->mmc);
- return result;
+ /* Restore interrupts */
+ intmask = sdhci_readl(host, SDHCI_INT_ENABLE);
+ sdhci_writel(host, intmask, SDHCI_SIGNAL_ENABLE);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sdhci_irq(int irq, void *dev_id)
+{
+ struct sdhci_host *host = dev_id;
+ u32 intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+
+ if (!intmask || intmask == 0xffffffff)
+ return IRQ_NONE;
+
+ /* Disable interrupts */
+ sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
+
+ DBG("*** %s got interrupt: 0x%08x\n",
+ mmc_hostname(host->mmc), intmask);
+
+ return IRQ_WAKE_THREAD;
}
/*****************************************************************************\
@@ -1608,8 +1617,8 @@ int sdhci_resume_host(struct sdhci_host *host)
host->ops->enable_dma(host);
}
- ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
- mmc_hostname(host->mmc), host);
+ ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_irq_thread,
+ IRQF_SHARED, mmc_hostname(host->mmc), host);
if (ret)
return ret;
@@ -1868,8 +1877,8 @@ int sdhci_add_host(struct sdhci_host *host)
INIT_DELAYED_WORK(&host->timeout_work, sdhci_timeout_work);
- ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
- mmc_hostname(mmc), host);
+ ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_irq_thread,
+ IRQF_SHARED, mmc_hostname(host->mmc), host);
if (ret)
return ret;
--
1.7.0.5
^ permalink raw reply related
* [PATCH 3/8] sdhci: Clear interrupt status register just once
From: Anton Vorontsov @ 2010-07-14 13:08 UTC (permalink / raw)
To: Andrew Morton
Cc: Matt Fleming, Albert Herranz, linux-mmc, linux-kernel,
linuxppc-dev, Ben Dooks, Pierre Ossman
In-Reply-To: <20100714130728.GA27339@oksana.dev.rtsoft.ru>
There's no need to clear the interrupt status register bit-by-bit,
we can just clear it once. This simplifies irq handler.
Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
---
drivers/mmc/host/sdhci.c | 23 ++++++-----------------
1 files changed, 6 insertions(+), 17 deletions(-)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 748a2e3..9ec245c 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1522,38 +1522,29 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
goto out;
}
+ sdhci_writel(host, intmask, SDHCI_INT_STATUS);
+
DBG("*** %s got interrupt: 0x%08x\n",
mmc_hostname(host->mmc), intmask);
- if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
- sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
- SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
+ if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE))
schedule_work(&host->card_detect_work);
- }
intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
- if (intmask & SDHCI_INT_CMD_MASK) {
- sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
- SDHCI_INT_STATUS);
+ if (intmask & SDHCI_INT_CMD_MASK)
sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
- }
- if (intmask & SDHCI_INT_DATA_MASK) {
- sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
- SDHCI_INT_STATUS);
+ if (intmask & SDHCI_INT_DATA_MASK)
sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
- }
intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
intmask &= ~SDHCI_INT_ERROR;
- if (intmask & SDHCI_INT_BUS_POWER) {
+ if (intmask & SDHCI_INT_BUS_POWER)
printk(KERN_ERR "%s: Card is consuming too much power!\n",
mmc_hostname(host->mmc));
- sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS);
- }
intmask &= ~SDHCI_INT_BUS_POWER;
@@ -1566,8 +1557,6 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n",
mmc_hostname(host->mmc), intmask);
sdhci_dumpregs(host);
-
- sdhci_writel(host, intmask, SDHCI_INT_STATUS);
}
result = IRQ_HANDLED;
--
1.7.0.5
^ permalink raw reply related
* [PATCH 2/8] sdhci: Use work structs instead of tasklets
From: Anton Vorontsov @ 2010-07-14 13:07 UTC (permalink / raw)
To: Andrew Morton
Cc: Matt Fleming, Albert Herranz, linux-mmc, linux-kernel,
linuxppc-dev, Ben Dooks, Pierre Ossman
In-Reply-To: <20100714130728.GA27339@oksana.dev.rtsoft.ru>
The driver can happily live without an atomic context and tasklets,
so turn the tasklets into the work structs.
Tasklets handlers still grab irqsave spinlocks, but we'll deal
with it in a separate patch.
Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
---
drivers/mmc/host/sdhci.c | 48 ++++++++++++++++++++-------------------------
drivers/mmc/host/sdhci.h | 4 +-
2 files changed, 23 insertions(+), 29 deletions(-)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index dc6328c..748a2e3 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -872,7 +872,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
sdhci_send_command(host, data->stop);
} else
- tasklet_schedule(&host->finish_tasklet);
+ schedule_work(&host->finish_work);
}
static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
@@ -901,7 +901,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
"inhibit bit(s).\n", mmc_hostname(host->mmc));
sdhci_dumpregs(host);
cmd->error = -EIO;
- tasklet_schedule(&host->finish_tasklet);
+ schedule_work(&host->finish_work);
return;
}
timeout--;
@@ -922,7 +922,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
printk(KERN_ERR "%s: Unsupported response type!\n",
mmc_hostname(host->mmc));
cmd->error = -EINVAL;
- tasklet_schedule(&host->finish_tasklet);
+ schedule_work(&host->finish_work);
return;
}
@@ -973,7 +973,7 @@ static void sdhci_finish_command(struct sdhci_host *host)
sdhci_finish_data(host);
if (!host->cmd->data)
- tasklet_schedule(&host->finish_tasklet);
+ schedule_work(&host->finish_work);
host->cmd = NULL;
}
@@ -1122,7 +1122,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (!present || host->flags & SDHCI_DEVICE_DEAD) {
host->mrq->cmd->error = -ENOMEDIUM;
- tasklet_schedule(&host->finish_tasklet);
+ schedule_work(&host->finish_work);
} else
sdhci_send_command(host, mrq->cmd);
@@ -1239,16 +1239,16 @@ static const struct mmc_host_ops sdhci_ops = {
/*****************************************************************************\
* *
- * Tasklets *
+ * Work handlers *
* *
\*****************************************************************************/
-static void sdhci_tasklet_card(unsigned long param)
+static void sdhci_card_detect_work(struct work_struct *wk)
{
struct sdhci_host *host;
unsigned long flags;
- host = (struct sdhci_host*)param;
+ host = container_of(wk, struct sdhci_host, card_detect_work);
spin_lock_irqsave(&host->lock, flags);
@@ -1263,7 +1263,7 @@ static void sdhci_tasklet_card(unsigned long param)
sdhci_reset(host, SDHCI_RESET_DATA);
host->mrq->cmd->error = -ENOMEDIUM;
- tasklet_schedule(&host->finish_tasklet);
+ schedule_work(&host->finish_work);
}
}
@@ -1272,13 +1272,13 @@ static void sdhci_tasklet_card(unsigned long param)
mmc_detect_change(host->mmc, msecs_to_jiffies(200));
}
-static void sdhci_tasklet_finish(unsigned long param)
+static void sdhci_finish_work(struct work_struct *wk)
{
struct sdhci_host *host;
unsigned long flags;
struct mmc_request *mrq;
- host = (struct sdhci_host*)param;
+ host = container_of(wk, struct sdhci_host, finish_work);
spin_lock_irqsave(&host->lock, flags);
@@ -1349,7 +1349,7 @@ static void sdhci_timeout_work(struct work_struct *wk)
else
host->mrq->cmd->error = -ETIMEDOUT;
- tasklet_schedule(&host->finish_tasklet);
+ schedule_work(&host->finish_work);
}
}
@@ -1382,7 +1382,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
host->cmd->error = -EILSEQ;
if (host->cmd->error) {
- tasklet_schedule(&host->finish_tasklet);
+ schedule_work(&host->finish_work);
return;
}
@@ -1528,7 +1528,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
- tasklet_schedule(&host->card_tasklet);
+ schedule_work(&host->card_detect_work);
}
intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
@@ -1872,19 +1872,17 @@ int sdhci_add_host(struct sdhci_host *host)
mmc->max_blk_count = (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535;
/*
- * Init tasklets.
+ * Init work structs.
*/
- tasklet_init(&host->card_tasklet,
- sdhci_tasklet_card, (unsigned long)host);
- tasklet_init(&host->finish_tasklet,
- sdhci_tasklet_finish, (unsigned long)host);
+ INIT_WORK(&host->card_detect_work, sdhci_card_detect_work);
+ INIT_WORK(&host->finish_work, sdhci_finish_work);
INIT_DELAYED_WORK(&host->timeout_work, sdhci_timeout_work);
ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
mmc_hostname(mmc), host);
if (ret)
- goto untasklet;
+ return ret;
sdhci_init(host, 0);
@@ -1923,10 +1921,6 @@ reset:
sdhci_reset(host, SDHCI_RESET_ALL);
free_irq(host->irq, host);
#endif
-untasklet:
- tasklet_kill(&host->card_tasklet);
- tasklet_kill(&host->finish_tasklet);
-
return ret;
}
@@ -1946,7 +1940,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
" transfer!\n", mmc_hostname(host->mmc));
host->mrq->cmd->error = -ENOMEDIUM;
- tasklet_schedule(&host->finish_tasklet);
+ schedule_work(&host->finish_work);
}
spin_unlock_irqrestore(&host->lock, flags);
@@ -1967,8 +1961,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
flush_delayed_work(&host->timeout_work);
- tasklet_kill(&host->card_tasklet);
- tasklet_kill(&host->finish_tasklet);
+ flush_work(&host->card_detect_work);
+ flush_work(&host->finish_work);
kfree(host->adma_desc);
kfree(host->align_buffer);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 55c114d..d96e4dd 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -288,8 +288,8 @@ struct sdhci_host {
dma_addr_t adma_addr; /* Mapped ADMA descr. table */
dma_addr_t align_addr; /* Mapped bounce buffer */
- struct tasklet_struct card_tasklet; /* Tasklet structures */
- struct tasklet_struct finish_tasklet;
+ struct work_struct card_detect_work;
+ struct work_struct finish_work;
struct delayed_work timeout_work; /* Work for timeouts */
--
1.7.0.5
^ permalink raw reply related
* [PATCH 1/8] sdhci: Turn timeout timer into delayed work
From: Anton Vorontsov @ 2010-07-14 13:07 UTC (permalink / raw)
To: Andrew Morton
Cc: Matt Fleming, Albert Herranz, linux-mmc, linux-kernel,
linuxppc-dev, Ben Dooks, Pierre Ossman
In-Reply-To: <20100714130728.GA27339@oksana.dev.rtsoft.ru>
There is no need for the timeout handler to run in the atomic
context, so this patch turns timeout timeout into the delayed
work.
Note that the timeout handler still grabs an irqsave spinlock,
we'll deal with it in a separate patch.
Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
---
drivers/mmc/host/sdhci.c | 14 ++++++++------
drivers/mmc/host/sdhci.h | 3 ++-
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c6d1bd8..dc6328c 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -13,6 +13,8 @@
* - JMicron (hardware and technical support)
*/
+#include <linux/kernel.h>
+#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/highmem.h>
#include <linux/io.h>
@@ -906,7 +908,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
mdelay(1);
}
- mod_timer(&host->timer, jiffies + 10 * HZ);
+ schedule_delayed_work(&host->timeout_work, 10 * HZ);
host->cmd = cmd;
@@ -1280,7 +1282,7 @@ static void sdhci_tasklet_finish(unsigned long param)
spin_lock_irqsave(&host->lock, flags);
- del_timer(&host->timer);
+ __cancel_delayed_work(&host->timeout_work);
mrq = host->mrq;
@@ -1324,12 +1326,12 @@ static void sdhci_tasklet_finish(unsigned long param)
mmc_request_done(host->mmc, mrq);
}
-static void sdhci_timeout_timer(unsigned long data)
+static void sdhci_timeout_work(struct work_struct *wk)
{
struct sdhci_host *host;
unsigned long flags;
- host = (struct sdhci_host*)data;
+ host = container_of(wk, struct sdhci_host, timeout_work.work);
spin_lock_irqsave(&host->lock, flags);
@@ -1877,7 +1879,7 @@ int sdhci_add_host(struct sdhci_host *host)
tasklet_init(&host->finish_tasklet,
sdhci_tasklet_finish, (unsigned long)host);
- setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
+ INIT_DELAYED_WORK(&host->timeout_work, sdhci_timeout_work);
ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
mmc_hostname(mmc), host);
@@ -1963,7 +1965,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
free_irq(host->irq, host);
- del_timer_sync(&host->timer);
+ flush_delayed_work(&host->timeout_work);
tasklet_kill(&host->card_tasklet);
tasklet_kill(&host->finish_tasklet);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index c846813..55c114d 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -12,6 +12,7 @@
#define __SDHCI_H
#include <linux/scatterlist.h>
+#include <linux/workqueue.h>
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/io.h>
@@ -290,7 +291,7 @@ struct sdhci_host {
struct tasklet_struct card_tasklet; /* Tasklet structures */
struct tasklet_struct finish_tasklet;
- struct timer_list timer; /* Timer for timeouts */
+ struct delayed_work timeout_work; /* Work for timeouts */
unsigned long private[0] ____cacheline_aligned;
};
--
1.7.0.5
^ permalink raw reply related
* [PATCH 0/8] sdhci: Move real work out of an atomic context
From: Anton Vorontsov @ 2010-07-14 13:07 UTC (permalink / raw)
To: Andrew Morton
Cc: Matt Fleming, Albert Herranz, linux-mmc, linux-kernel,
linuxppc-dev, Ben Dooks, Pierre Ossman
Hi all,
Currently the sdhci driver does everything in the atomic context.
And what is worse, PIO transfers are made from the IRQ handler.
This causes huge latencies (up to 120 ms). On some P2020 SOCs,
DMA and card detection is broken, which means that kernel polls
for the card via PIO transfers every second. Needless to say
that this is quite bad.
So, this patch set reworks sdhci code to avoid atomic context,
almost completely. We only do two device memory operations
in the atomic context, and all the rest is threaded.
I noticed no throughput drop neither with PIO transfers nor
with DMA (tested on MPC8569E CPU), while latencies should be
greatly improved.
Thanks,
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH] powerpc:prom Export device tree physical address via proc
From: Segher Boessenkool @ 2010-07-14 12:51 UTC (permalink / raw)
To: Timur Tabi; +Cc: Matthew McClintock, linuxppc-dev
In-Reply-To: <4C3CB69D.4060400@freescale.com>
>> + if (prop)
>> + prom_remove_property(node, prop);
>> + prop = of_find_property(node, "linux,devietree-end", NULL);
>
> Either the indentation is wrong, or you're missing some braces here
You're missing a "c" as well (and a dash).
Segher
^ permalink raw reply
* cpm_uart_console_write() stuck in waiting for transmitter fifo ready
From: Shawn Jin @ 2010-07-14 9:05 UTC (permalink / raw)
To: ppcdev, galak, panto, Scott Wood
Hi Gurus,
Please give me some hints and directions to debug this problem. I've
been scratching my head for quite a while.
The problem is that after/when the kernel switches to the real console
from the boot console, printk() calls cpm_uart_console_write() to
print the first (?) message using the cpm_uart driver. But the
transmitter buffer never becomes ready. It's shown below with the gdb
session.
Program received signal SIGSTOP, Stopped (signal).
0xc00f3510 in cpm_uart_console_write (co=3D<value optimized out>,
s=3D0xc017703e "console [ttyCPM0] enabled, bootconsole disabled\n",
count=3D0x30) at /home/code/linux-2.6.33.5/arch/powerpc/include/asm/io.h:15=
4
(gdb) next
(gdb) x/4h bdbase
0xfddfa020: 0xffff 0xffff 0xffff 0xffff
(gdb)
Why would the TxBD be filled with all 0xF? Would it be possible that
the bdbase actually points somewhere else other than the TxBD?
The kernel boot messages are copied below. My target is MPC870, using
SMC1 as UART. I'm porting the kernel based on adder875 board.
=3D> bootm 1000000
## Booting image at 01000000 ...
Image Name: Linux-2.6.33.5
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 706700 Bytes =3D 690.1 kB
Load Address: 00400000
Entry Point: 00400554
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Memory <- <0x0 0x8000000> (128MB)
ENET0: local-mac-address <- 00:09:9b:01:58:64
CPU clock-frequency <- 0x7270e00 (120MHz)
CPU timebase-frequency <- 0x7270e0 (8MHz)
CPU bus-frequency <- 0x3938700 (60MHz)
zImage starting: loaded at 0x00400000 (sp: 0x07d1cbd0)
Allocating 0x186be5 bytes for kernel ...
gunzipping (0x00000000 <- 0x0040c000:0x005c1b78)...done 0x173b10 bytes
Linux/PowerPC load: root=3D/dev/ram
Finalizing device tree... flat tree at 0x5ce300
Probing machine type ...
My MPC870 ... match !
id mach(): done
MMU:enter
MMU:hw init
MMU:mapin
MMU:setio
MMU:exit
Using My MPC870 machine description
Linux version 2.6.33.5 (shawn@ubuntu) (gcc version 4.2.2) #17 Wed Jul
14 01:24:03 PDT 2010
bootconsole [udbg0] enabled
setup_arch: bootmem
arch: exit
Top of RAM: 0x8000000, Total RAM: 0x8000000
Memory hole size: 0MB
Zone PFN ranges:
DMA 0x00000000 -> 0x00008000
Normal 0x00008000 -> 0x00008000
Movable zone start PFN for each node
early_node_map[1] active PFN ranges
0: 0x00000000 -> 0x00008000
On node 0 totalpages: 32768
free_area_init_node: node 0, pgdat c016b5b0, node_mem_map c0189000
DMA zone: 256 pages used for memmap
DMA zone: 0 pages reserved
DMA zone: 32512 pages, LIFO batch:7
MMU: Allocated 72 bytes of context maps for 16 contexts
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 32512
Kernel command line: root=3D/dev/ram
PID hash table entries: 512 (order: -1, 2048 bytes)
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
Memory: 128096k/131072k available (1416k kernel code, 2836k reserved,
72k data, 74k bss, 76k init)
Kernel virtual memory layout:
* 0xfffdf000..0xfffff000 : fixmap
* 0xfde00000..0xfe000000 : consistent mem
* 0xfddfa000..0xfde00000 : early ioremap
* 0xc9000000..0xfddfa000 : vmalloc & ioremap
SLUB: Genslabs=3D12, HWalign=3D16, Order=3D0-3, MinObjects=3D0, CPUs=3D1, N=
odes=3D1
Hierarchical RCU implementation.
NR_IRQS:512 nr_irqs:512
irq: Allocated host of type 2 @0xc7804000
irq: irq_create_mapping(0xc7804000, 0x5)
irq: -> using host @c7804000
alloc irq_desc for 16 on node 0
alloc kstat_irqs on node 0
irq: irq 5 on host /soc@fa200000/interrupt-controller@0 mapped to virtual i=
rq 16
irq: Allocated host of type 2 @0xc7804200
irq: irq_create_mapping(0xc7804200, 0x0)
irq: -> using host @c7804200
alloc irq_desc for 17 on node 0
alloc kstat_irqs on node 0
irq: irq 0 on host /soc@fa200000/cpm@9c0/interrupt-controller@930
mapped to virtual irq 17
Decrementer Frequency =3D 0x7270e0
irq: irq_create_mapping(0xc7804000, 0xf)
irq: -> using host @c7804000
alloc irq_desc for 18 on node 0
alloc kstat_irqs on node 0
irq: irq 15 on host /soc@fa200000/interrupt-controller@0 mapped to
virtual irq 18
time_init: decrementer frequency =3D 7.500000 MHz
time_init: processor frequency =3D 120.000000 MHz
clocksource: timebase mult[21555555] shift[22] registered
clockevent: decrementer mult[1eb851e] shift[32] cpu[0]
irq: irq_create_mapping(0xc7804200, 0x4)
irq: -> using host @c7804200
alloc irq_desc for 19 on node 0
alloc kstat_irqs on node 0
irq: irq 4 on host /soc@fa200000/cpm@9c0/interrupt-controller@930
mapped to virtual irq 1=EF=BF=BD
Thanks a lot,
-Shawn.
^ permalink raw reply
* Re: [PATCH 4/7] Allow sysfs memory directories to be split
From: KAMEZAWA Hiroyuki @ 2010-07-14 8:30 UTC (permalink / raw)
To: KAMEZAWA Hiroyuki; +Cc: linuxppc-dev, linux-kernel, Dave Hansen
In-Reply-To: <20100714122503.74f746a2.kamezawa.hiroyu@jp.fujitsu.com>
On Wed, 14 Jul 2010 12:25:03 +0900
KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> wrote:
> On Tue, 13 Jul 2010 22:18:03 -0500
> Nathan Fontenot <nfont@austin.ibm.com> wrote:
>
> > On 07/13/2010 07:35 PM, KAMEZAWA Hiroyuki wrote:
> > > On Tue, 13 Jul 2010 10:51:58 -0500
> > > Nathan Fontenot <nfont@austin.ibm.com> wrote:
> > >
> > >>>
> > >>> And for what purpose this interface is ? Does this split memory block into 2 pieces
> > >>> of the same size ?? sounds __very__ strange interface to me.
> > >>
> > >> Yes, this splits the memory_block into two blocks of the same size. This was
> > >> suggested as something we may want to do. From ppc perspective I am not sure we
> > >> would use this.
> > >>
> > >> The split functionality is not required. The main goal of the patch set is to
> > >> reduce the number of memory sysfs directories created. From a ppc perspective
> > >> the split functionality is not really needed.
> > >>
> > >
> > > Okay, this is an offer from me.
> > >
> > > 1. I think you can add an boot option as "don't create memory sysfs".
> > > please do.
> >
> > I posted a patch to do that a week or so ago, it didn't go over very well.
> >
> > >
> > > 2. I'd like to write a configfs module for handling memory hotplug even when
> > > sysfs directroy is not created.
> > > Because configfs support rmdir/mkdir, the user (ppc's daemon?) has to do
> > >
> > > When offlining section X.
> > > # insmod configfs_memory.ko
> > > # mount -t configfs none /configfs
> > > # mkdir /configfs/memoryX
> > > # echo offline > /configfs/memoryX/state
> > > # rmdir /configfs/memoryX
> > >
> > > And making this operation as the default bahavior for all arch's memory hotplug may
> > > be better...
> > >
> > > Dave, how do you think ? Because ppc guys uses "probe" interface already,
> > > this can be handled... no ?
> >
> > ppc would still require the existance of the 'probe' interface.
> >
> > Are you objecting to the 'split' functionality?
> yes.
>
> > If so I do not see any reason from ppc
> > perspective that it is needed. This was something Dave suggested, unless I am missing
> > something.
> >
> > Since ppc needs the 'probe' interface in sysfs, and for ppc having mutliple
> > memory_block_sections reside under a single memory_block makes memory hotplug
> > simpler. On ppc we do emory hotplug operations on an LMB size basis. With my
> > patches this now lets us set each memory_block to span an LMB's worth of
> > memory. Now we could do emory hotplug in a single operation instead of multiple
> > operations to offline/online all of the memory sections in an LMB.
> >
>
> Why per-section memory offlining is provided is for allowing good success-rate of
> memory offlining. Because memory-hotplug has to "migrate or free" all used page
> under a section, possibility of memory unplug depends on usage of memory.
> If a section contains unmovable page(kernel page), we can't offline sectin.
>
> For example, comparing
> 1. offlining 128MB of memory at once
> 2. offlining 8 chunks of 16MB memory
> "2" can get very good possibility and system-busy time can be much reduced.
>
> IIUC, ppc's 1st requirement is "resizing" not "hot-removing some memory device",
> "2" is much welcomed. So, some fine-grained interface to section_size is
> appreciated. So, "multiple operations" is much better than single operation.
>
> As I posted show/hide patch, I'm writing it in configfs. I think it meets IBM's
> requirements.
> _But_, it's IBM's issue not Fujitsu's. So, final decistion will depend on you guys.
>
> Anyway, I don't like a too fancy interface as "split".
>
This is a sample configfs for handling memory hotplug.
I wrote this just for my fun and study. code-duplication was not as
big as expected...most of codes are for configfs management.
you can ignore this. but please avoid changing existing interace in fancy way.
==
[root@bluextal kamezawa]# mount -t configfs none /configfs/
[root@bluextal kamezawa]# mkdir /configfs/memory/72
[root@bluextal kamezawa]# cat /configfs/memory/72/phys_index
00000048
[root@bluextal kamezawa]# cat /sys/devices/system/memory/memory72/phys_index
00000048
[root@bluextal kamezawa]# echo offline > /configfs/memory/72/state
[root@bluextal kamezawa]# cat /configfs/memory/72/state
offline
[root@bluextal kamezawa]# cat /sys/devices/system/memory/memory72/state
offline
[root@bluextal kamezawa]# echo online > /configfs/memory/72/state
[root@bluextal kamezawa]# cat /sys/devices/system/memory/memory72/state
online
No sign.
---
drivers/base/Makefile | 2
drivers/base/memory.c | 87 +++++++++++++++++--
drivers/base/memory_config.c | 192 +++++++++++++++++++++++++++++++++++++++++++
include/linux/memory.h | 10 ++
mm/Kconfig | 1
5 files changed, 280 insertions(+), 12 deletions(-)
Index: mmotm-2.6.35-0701/drivers/base/memory.c
===================================================================
--- mmotm-2.6.35-0701.orig/drivers/base/memory.c
+++ mmotm-2.6.35-0701/drivers/base/memory.c
@@ -23,12 +23,15 @@
#include <linux/mutex.h>
#include <linux/stat.h>
#include <linux/slab.h>
+#include <linux/radix-tree.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
#define MEMORY_CLASS_NAME "memory"
+
+
static struct sysdev_class memory_sysdev_class = {
.name = MEMORY_CLASS_NAME,
};
@@ -104,17 +107,57 @@ unregister_memory(struct memory_block *m
sysdev_unregister(&memory->sysdev);
}
+/* routine for remember memory's status when configs is not used. */
+
+RADIX_TREE(hidden_mems, GFP_KERNEL);
+DEFINE_MUTEX(hidden_mems_mutex);
+int record_memory_state(unsigned long section_nr, int status)
+{
+ int ret = -ENOMEM;
+ long lstat = status << 8; /* for avoid radix'trees special handling */
+ mutex_lock(&hidden_mems_mutex);
+ radix_tree_delete(&hidden_mems, section_nr);
+ if (radix_tree_preload(GFP_KERNEL))
+ goto out;
+ ret = radix_tree_insert(&hidden_mems, section_nr, (void*)lstat);
+ radix_tree_preload_end();
+out:
+ mutex_unlock(&hidden_mems_mutex);
+ return ret;
+}
+
+int lookup_memory_state(unsigned long section_nr)
+{
+ void *ptr;
+ /* we already have big mutex */
+ ptr= radix_tree_lookup(&hidden_mems, section_nr);
+ /* treate not-recorded mems'state as ONLINE...? */
+ return ((long)ptr) >> 8;
+}
+
+void forget_memory_state(unsigned long section_nr)
+{
+ radix_tree_delete(&hidden_mems, section_nr);
+}
+
+
/*
* use this as the physical section index that this memsection
* uses.
*/
+ssize_t show_memoryblock_phys_index(struct memory_block *mem,
+ char *buf)
+{
+ return sprintf(buf, "%08lx\n", mem->phys_index);
+}
+
static ssize_t show_mem_phys_index(struct sys_device *dev,
struct sysdev_attribute *attr, char *buf)
{
struct memory_block *mem =
container_of(dev, struct memory_block, sysdev);
- return sprintf(buf, "%08lx\n", mem->phys_index);
+ return show_memoryblock_phys_index(mem, buf);
}
/*
@@ -136,11 +179,8 @@ static ssize_t show_mem_removable(struct
/*
* online, offline, going offline, etc.
*/
-static ssize_t show_mem_state(struct sys_device *dev,
- struct sysdev_attribute *attr, char *buf)
+ssize_t show_memoryblock_state(struct memory_block *mem, char *buf)
{
- struct memory_block *mem =
- container_of(dev, struct memory_block, sysdev);
ssize_t len = 0;
/*
@@ -167,6 +207,15 @@ static ssize_t show_mem_state(struct sys
return len;
}
+ssize_t show_mem_state(struct sys_device *dev,
+ struct sysdev_attribute *attr, char *buf)
+{
+ struct memory_block *mem =
+ container_of(dev, struct memory_block, sysdev);
+ mem->state = lookup_memory_state(mem->phys_index);
+ return show_memoryblock_state(mem, buf);
+}
+
int memory_notify(unsigned long val, void *v)
{
return blocking_notifier_call_chain(&memory_chain, val, v);
@@ -218,11 +267,14 @@ memory_block_action(struct memory_block
break;
case MEM_OFFLINE:
mem->state = MEM_GOING_OFFLINE;
+ record_memory_state(mem->phys_index, mem->state);
start_paddr = page_to_pfn(first_page) << PAGE_SHIFT;
ret = remove_memory(start_paddr,
PAGES_PER_SECTION << PAGE_SHIFT);
if (ret) {
mem->state = old_state;
+ record_memory_state(mem->phys_index,
+ mem->state);
break;
}
break;
@@ -241,6 +293,8 @@ static int memory_block_change_state(str
int ret = 0;
mutex_lock(&mem->state_mutex);
+ mem->state = lookup_memory_state(mem->phys_index);
+
if (mem->state != from_state_req) {
ret = -EINVAL;
goto out;
@@ -249,21 +303,18 @@ static int memory_block_change_state(str
ret = memory_block_action(mem, to_state);
if (!ret)
mem->state = to_state;
-
+ record_memory_state(mem->phys_index, mem->state);
out:
mutex_unlock(&mem->state_mutex);
return ret;
}
-static ssize_t
-store_mem_state(struct sys_device *dev,
- struct sysdev_attribute *attr, const char *buf, size_t count)
+ssize_t store_memoryblock_state(struct memory_block *mem,
+ const char *buf, size_t count)
{
- struct memory_block *mem;
unsigned int phys_section_nr;
int ret = -EINVAL;
- mem = container_of(dev, struct memory_block, sysdev);
phys_section_nr = mem->phys_index;
if (!present_section_nr(phys_section_nr))
@@ -279,6 +330,16 @@ out:
return count;
}
+static ssize_t
+store_mem_state(struct sys_device *dev,
+ struct sysdev_attribute *attr, const char *buf, size_t count)
+{
+ struct memory_block *mem;
+
+ mem = container_of(dev, struct memory_block, sysdev);
+ return store_memoryblock_state(mem, buf, count);
+}
+
/*
* phys_device is a bad name for this. What I really want
* is a way to differentiate between memory ranges that
@@ -451,6 +512,8 @@ static int add_memory_block(int nid, str
start_pfn = section_nr_to_pfn(mem->phys_index);
mem->phys_device = arch_get_memory_phys_device(start_pfn);
+ record_memory_state(mem->phys_index, state);
+
ret = register_memory(mem, section);
if (!ret)
ret = mem_create_simple_file(mem, phys_index);
@@ -505,6 +568,7 @@ int remove_memory_block(unsigned long no
struct memory_block *mem;
mem = find_memory_block(section);
+ forget_memory_state(mem->phys_index);
unregister_mem_sect_under_nodes(mem);
mem_remove_simple_file(mem, phys_index);
mem_remove_simple_file(mem, state);
@@ -573,3 +637,4 @@ out:
printk(KERN_ERR "%s() failed: %d\n", __func__, ret);
return ret;
}
+
Index: mmotm-2.6.35-0701/drivers/base/memory_config.c
===================================================================
--- /dev/null
+++ mmotm-2.6.35-0701/drivers/base/memory_config.c
@@ -0,0 +1,192 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/memory.h>
+#include <linux/slab.h>
+#include <linux/radix-tree.h>
+#include <linux/configfs.h>
+
+
+
+struct memory_hp_block {
+ struct config_group group;
+ struct memory_block mb;
+};
+struct memory_hp_attribute {
+ struct configfs_attribute attr;
+ ssize_t (*show)(struct memory_hp_block *, char *);
+ ssize_t (*store)(struct memory_hp_block *, const char *);
+};
+
+static struct memory_hp_block *to_mhp_block(struct config_item *item)
+{
+ if (!item)
+ return NULL;
+ return container_of(to_config_group(item),
+ struct memory_hp_block, group);
+}
+
+static ssize_t
+memory_hp_phys_index_read(struct memory_hp_block *mhb, char *page)
+{
+ return show_memoryblock_phys_index(&mhb->mb, page);
+}
+
+static struct memory_hp_attribute memory_hp_phys_index = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "phys_index",
+ .ca_mode = S_IRUGO },
+ .show = memory_hp_phys_index_read,
+};
+
+static ssize_t
+memory_hp_state_read(struct memory_hp_block *mhb, char *page)
+{
+ /* synchronize */
+ printk("lookup section %ld\n", mhb->mb.phys_index);
+ mhb->mb.state = lookup_memory_state(mhb->mb.phys_index);
+ return show_memoryblock_state(&mhb->mb, page);
+}
+
+static ssize_t
+memory_hp_state_store(struct memory_hp_block *mhb, const char *page)
+{
+ int len = strnlen(page, 8);
+ printk("length %d str %s\n", len, page);
+ if (len > 8) /* online/offline */
+ return -EINVAL;
+ /* synchronize */
+ mhb->mb.state = lookup_memory_state(mhb->mb.phys_index);
+ return store_memoryblock_state(&mhb->mb, page, len);
+}
+
+static struct memory_hp_attribute memory_hp_state = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "state",
+ .ca_mode = S_IRUGO|S_IWUSR },
+ .show = memory_hp_state_read,
+ .store = memory_hp_state_store,
+};
+
+static struct configfs_attribute *memory_hp_attrs[] = {
+ &memory_hp_phys_index.attr,
+ &memory_hp_state.attr,
+ NULL,
+};
+
+static ssize_t memory_hp_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
+{
+ struct memory_hp_block *mhb = to_mhp_block(item);
+ struct memory_hp_attribute *memhp_attr =
+ container_of(attr, struct memory_hp_attribute, attr);
+ ssize_t ret = 0;
+
+ if (memhp_attr->show)
+ ret = memhp_attr->show(mhb, page);
+ return ret;
+}
+
+static ssize_t memory_hp_attr_store(struct config_item *item,
+ struct configfs_attribute *attr,
+ const char *page, size_t count)
+{
+ struct memory_hp_block *mhb = to_mhp_block(item);
+ struct memory_hp_attribute *memhp_attr =
+ container_of(attr, struct memory_hp_attribute, attr);
+ ssize_t ret = 0;
+
+ if (memhp_attr->store)
+ ret = memhp_attr->store(mhb, page);
+ else
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct configfs_item_operations memory_hp_item_ops = {
+ .show_attribute = memory_hp_attr_show,
+ .store_attribute = memory_hp_attr_store,
+};
+
+static struct config_item_type memory_hp_type = {
+ .ct_item_ops = &memory_hp_item_ops,
+ .ct_attrs = memory_hp_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *
+memory_hp_make_group(struct config_group *group, const char *name)
+{
+ struct memory_hp_block *mhb;
+ unsigned long long section_id;
+
+
+ if (strict_strtoull(name, 10, §ion_id))
+ return ERR_PTR(-EINVAL);
+
+ if (!valid_section_nr(section_id))
+ return ERR_PTR(-EINVAL);
+
+ mhb = kzalloc(sizeof(*mhb), GFP_KERNEL);
+ if (!mhb)
+ return NULL;
+
+ config_group_init_type_name(&mhb->group, name, &memory_hp_type);
+
+ mhb->mb.phys_index = section_id;
+ mutex_init(&mhb->mb.state_mutex);
+ mhb->mb.state = lookup_memory_state(section_id);
+
+ return &mhb->group;
+}
+
+static void memory_hp_drop_item(struct config_group *group,
+ struct config_item *item)
+{
+ struct memory_hp_block *mhb;
+
+ mhb = container_of(group, struct memory_hp_block, group);
+ config_item_put(item);
+}
+
+static struct configfs_group_operations memory_hp_group_ops = {
+ .make_group = memory_hp_make_group,
+ .drop_item = memory_hp_drop_item,
+};
+
+static struct config_item_type memory_hp_subsys_type = {
+ .ct_group_ops = &memory_hp_group_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct configfs_subsystem memory_hp_subsys = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = "memory",
+ .ci_type = &memory_hp_subsys_type,
+ },
+ },
+};
+
+static int __init memory_config_init(void)
+{
+ int ret;
+
+ config_group_init(&memory_hp_subsys.su_group);
+ mutex_init(&memory_hp_subsys.su_mutex);
+ ret = configfs_register_subsystem(&memory_hp_subsys);
+ if (ret) {
+ printk(KERN_ERR "Error %d while registering memory configfs\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+#if 0
+static void __exit memory_config_exit(void)
+{
+ configfs_unregister_subsystem(&memory_hp_subsys);
+}
+#endif
+late_initcall(memory_config_init);
Index: mmotm-2.6.35-0701/drivers/base/Makefile
===================================================================
--- mmotm-2.6.35-0701.orig/drivers/base/Makefile
+++ mmotm-2.6.35-0701/drivers/base/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT)
obj-$(CONFIG_ISA) += isa.o
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
-obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o
+obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o memory_config.o
obj-$(CONFIG_SMP) += topology.o
obj-$(CONFIG_IOMMU_API) += iommu.o
ifeq ($(CONFIG_SYSFS),y)
Index: mmotm-2.6.35-0701/mm/Kconfig
===================================================================
--- mmotm-2.6.35-0701.orig/mm/Kconfig
+++ mmotm-2.6.35-0701/mm/Kconfig
@@ -138,6 +138,7 @@ config MEMORY_HOTPLUG
config MEMORY_HOTPLUG_SPARSE
def_bool y
depends on SPARSEMEM && MEMORY_HOTPLUG
+ select CONFIGFS_FS
config MEMORY_HOTREMOVE
bool "Allow for memory hot remove"
Index: mmotm-2.6.35-0701/include/linux/memory.h
===================================================================
--- mmotm-2.6.35-0701.orig/include/linux/memory.h
+++ mmotm-2.6.35-0701/include/linux/memory.h
@@ -68,6 +68,16 @@ struct memory_isolate_notify {
struct notifier_block;
struct mem_section;
+
+ssize_t show_memoryblock_phys_index(struct memory_block *mb, char *buf);
+ssize_t show_memoryblock_state(struct memory_block *mb, char *buf);
+ssize_t store_memoryblock_state(struct memory_block *mb,
+ const char *buf, size_t count);
+
+int record_memory_state(unsigned long section, int state);
+int lookup_memory_state(unsigned long section);
+void forget_memory_state(unsigned long section);
+
/*
* Priorities for the hotplug memory callback routines (stored in decreasing
* order in the callback chain)
^ permalink raw reply
* Re: [PATCH v2]460EX on-chip SATA driver<resubmisison>
From: Jeff Garzik @ 2010-07-14 7:51 UTC (permalink / raw)
To: Rupjyoti Sarmah; +Cc: linux-ide, sr, rsarmah, linux-kernel, linuxppc-dev
In-Reply-To: <201007061106.o66B631f013777@amcc.com>
On 07/06/2010 07:06 AM, Rupjyoti Sarmah wrote:
> This patch enables the on-chip DWC SATA controller of the AppliedMicro processor 460EX.
>
> Signed-off-by: Rupjyoti Sarmah<rsarmah@appliedmicro.com>
> Signed-off-by: Mark Miesfeld<mmiesfeld@appliedmicro.com>
> Signed-off-by: Prodyut Hazarika<phazarika@appliedmicro.com>
>
> ---
> This patch incorporates the changes advised in the mailing list. The device
> tree changes were submitted as a seperate patch. Kconfig file is fixed in this version.
>
> drivers/ata/Kconfig | 9 +
> drivers/ata/Makefile | 1 +
> drivers/ata/sata_dwc_460ex.c | 1756 ++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 1766 insertions(+), 0 deletions(-)
> create mode 100644 drivers/ata/sata_dwc_460ex.c
applied
^ permalink raw reply
* [git pull] Please pull powerpc.git lmb-to-memblock branch
From: Benjamin Herrenschmidt @ 2010-07-14 7:22 UTC (permalink / raw)
To: Linus Torvalds
Cc: linuxppc-dev list, Andrew Morton, Russell King, Linux Kernel list
Hi Linus !
As discussed, here's the lmb rename to memblock.
CCing Russell since I know he has some patches in -next for using lmb on ARM which
might need to be reworked on top of that.
BTW. There's another request coming your way for ppc stuff, it's not a
duplicate email :-)
Cheers,
Ben.
The following changes since commit 1c5474a65bf15a4cb162dfff86d6d0b5a08a740c:
Linus Torvalds (1):
Linux 2.6.35-rc5
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git lmb-to-memblock
Yinghai Lu (1):
lmb: rename to memblock
Documentation/kernel-parameters.txt | 2 +-
arch/microblaze/Kconfig | 2 +-
arch/microblaze/include/asm/{lmb.h => memblock.h} | 10 +-
arch/microblaze/kernel/prom.c | 14 +-
arch/microblaze/mm/init.c | 40 +-
arch/powerpc/Kconfig | 2 +-
arch/powerpc/include/asm/abs_addr.h | 2 +-
arch/powerpc/include/asm/lmb.h | 15 -
arch/powerpc/include/asm/memblock.h | 15 +
arch/powerpc/kernel/btext.c | 2 +-
arch/powerpc/kernel/crash.c | 2 +-
arch/powerpc/kernel/crash_dump.c | 4 +-
arch/powerpc/kernel/dma-swiotlb.c | 2 +-
arch/powerpc/kernel/dma.c | 4 +-
arch/powerpc/kernel/machine_kexec.c | 12 +-
arch/powerpc/kernel/paca.c | 8 +-
arch/powerpc/kernel/prom.c | 62 ++--
arch/powerpc/kernel/rtas.c | 6 +-
arch/powerpc/kernel/setup-common.c | 2 +-
arch/powerpc/kernel/setup_32.c | 16 +-
arch/powerpc/kernel/setup_64.c | 20 +-
arch/powerpc/kernel/vdso.c | 4 +-
arch/powerpc/mm/40x_mmu.c | 2 +-
arch/powerpc/mm/hash_utils_64.c | 26 +-
arch/powerpc/mm/init_32.c | 16 +-
arch/powerpc/mm/init_64.c | 2 +-
arch/powerpc/mm/mem.c | 78 ++--
arch/powerpc/mm/numa.c | 84 ++--
arch/powerpc/mm/pgtable_32.c | 6 +-
arch/powerpc/mm/pgtable_64.c | 4 +-
arch/powerpc/mm/ppc_mmu_32.c | 4 +-
arch/powerpc/mm/stab.c | 4 +-
arch/powerpc/mm/tlb_nohash.c | 4 +-
arch/powerpc/platforms/85xx/corenet_ds.c | 4 +-
arch/powerpc/platforms/85xx/mpc8536_ds.c | 4 +-
arch/powerpc/platforms/85xx/mpc85xx_ds.c | 4 +-
arch/powerpc/platforms/85xx/mpc85xx_mds.c | 4 +-
arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 4 +-
arch/powerpc/platforms/cell/iommu.c | 10 +-
arch/powerpc/platforms/embedded6xx/wii.c | 12 +-
arch/powerpc/platforms/maple/setup.c | 2 +-
arch/powerpc/platforms/pasemi/iommu.c | 4 +-
arch/powerpc/platforms/powermac/setup.c | 4 +-
arch/powerpc/platforms/ps3/htab.c | 2 +-
arch/powerpc/platforms/ps3/mm.c | 6 +-
arch/powerpc/platforms/ps3/os-area.c | 4 +-
arch/powerpc/platforms/pseries/hotplug-memory.c | 38 +-
arch/powerpc/platforms/pseries/iommu.c | 2 +-
arch/powerpc/platforms/pseries/phyp_dump.c | 4 +-
arch/powerpc/sysdev/dart_iommu.c | 8 +-
arch/powerpc/sysdev/fsl_pci.c | 4 +-
arch/sh/Kconfig | 2 +-
arch/sh/include/asm/lmb.h | 6 -
arch/sh/include/asm/memblock.h | 6 +
arch/sh/kernel/machine_kexec.c | 18 +-
arch/sh/kernel/setup.c | 8 +-
arch/sh/mm/init.c | 40 +-
arch/sh/mm/numa.c | 8 +-
arch/sparc/Kconfig | 2 +-
arch/sparc/include/asm/lmb.h | 10 -
arch/sparc/include/asm/memblock.h | 10 +
arch/sparc/kernel/mdesc.c | 16 +-
arch/sparc/kernel/prom_64.c | 4 +-
arch/sparc/mm/init_64.c | 54 +-
include/linux/lmb.h | 89 ----
include/linux/memblock.h | 89 ++++
lib/Kconfig | 3 -
lib/Makefile | 2 -
lib/lmb.c | 541 ---------------------
mm/Kconfig | 3 +
mm/Makefile | 2 +
mm/memblock.c | 541 +++++++++++++++++++++
72 files changed, 1025 insertions(+), 1025 deletions(-)
rename arch/microblaze/include/asm/{lmb.h => memblock.h} (57%)
delete mode 100644 arch/powerpc/include/asm/lmb.h
create mode 100644 arch/powerpc/include/asm/memblock.h
delete mode 100644 arch/sh/include/asm/lmb.h
create mode 100644 arch/sh/include/asm/memblock.h
delete mode 100644 arch/sparc/include/asm/lmb.h
create mode 100644 arch/sparc/include/asm/memblock.h
delete mode 100644 include/linux/lmb.h
create mode 100644 include/linux/memblock.h
delete mode 100644 lib/lmb.c
create mode 100644 mm/memblock.c
^ permalink raw reply
* [git pull] Please pull powerpc.git merge branch
From: Benjamin Herrenschmidt @ 2010-07-14 7:22 UTC (permalink / raw)
To: Linus Torvalds
Cc: linuxppc-dev list, Andrew Morton, Russell King, Linux Kernel list
Hi Linus !
Here are some late fixed for some freescale embedded platforms
for 2.6.35. A bit late but since it only touch their platform
code I don't really have an objection.
Cheers,
Ben.
The following changes since commit 1c5474a65bf15a4cb162dfff86d6d0b5a08a740c:
Linus Torvalds (1):
Linux 2.6.35-rc5
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git merge
Anton Vorontsov (3):
powerpc/cpm: Reintroduce global spi_pram struct (fixes build issue)
powerpc/cpm1: Fix build with various CONFIG_*_UCODE_PATCH combinations
powerpc/cpm1: Mark micropatch code/data static and __init
Matthew McClintock (1):
powerpc/fsl-booke: Fix address issue when using relocatable kernels
arch/powerpc/include/asm/cpm.h | 24 ++++++++++++++++++++
arch/powerpc/include/asm/cpm1.h | 3 +-
arch/powerpc/kernel/fsl_booke_entry_mapping.S | 4 +--
arch/powerpc/sysdev/micropatch.c | 30 +++++++++++++++----------
drivers/spi/spi_mpc8xxx.c | 22 ------------------
5 files changed, 45 insertions(+), 38 deletions(-)
^ permalink raw reply
* Re: [PATCH] kbuild: Enable building defconfigs from Kconfig files
From: Grant Likely @ 2010-07-14 5:47 UTC (permalink / raw)
To: Linus Torvalds
Cc: Michal Marek, Stephen Rothwell, Catalin Marinas, LKML,
Russell King, Andrew Morton, ppc-dev, linux-arm-kernel
In-Reply-To: <AANLkTik-QCXFnjma3J28B9h27uajOcDhthTGz99zKgVi@mail.gmail.com>
On Tue, Jul 13, 2010 at 10:04 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
> On Tue, Jul 13, 2010 at 7:26 PM, Grant Likely <grant.likely@secretlab.ca>=
wrote:
>>
>> I chose to use -D /dev/null (defconfig from an empty file) instead of
>> -n (allnoconfig) so that default values in Kconfig would get
>> respected. =A0For the benefit of everyone else, here's an excerpt from
>> our IRC conversation this afternoon:
>>
>> 19:49 < gcl> sfr: [...] Your patch and my patch are
>> =A0 =A0 =A0 =A0 =A0 =A0 essentially doing exactly the same thing, except=
that I used '-d'
>> =A0 =A0 =A0 =A0 =A0 =A0 and you used '-n'.
>> 19:50 < gcl> s/-d/-D/
>> 19:55 < sfr> right
>> 19:55 < sfr> Linus wanted us to use -n
>
> Just a note: Linus doesn't really care.
>
> IOW, I used -n not because of any fundamental belief that it is
> correct, but just because ti happened to be how I happened to decide
> to solve it. It's entirely possible that starting from the Kconfig
> defaults (rather than "no") is the right way to go.
>
> I think either approach is likely fine. The -D /dev/null approach
> would presumably give smaller Kconfig.xyz files, assuming our defaults
> are sane (an maybe that could be at least a partial validation of the
> defaults we do have). While the -n approach is in some ways more
> stable, in that the resulting Kconfig.xyz entires would presumably be
> more stand-alone, and there wouldn't be any subtle interactions when
> somebody changes a default value int he Kconfig file.
Okay, well I advocate for the -D /dev/null approach then. I think
that validating our defaults, and looking for the subtle interactions
are exactly what we want to be doing when it comes to defconfigs. The
fact that a defconfig does *not* want the default value is exactly
what the defconfigs should be capturing.
> So I can see advantages to either model. And either model clearly
> would want the improvements to "select" that are independent (ie warn
> about unsatisfied 'depends on' constraints, and select recursively.
> Maybe we already fixed the recursive select thing, I forget).
>
> I also think we need to allow setting of actual values. I don't know
> what the syntax would be. A "set" statement that overrides a default
> in the Kconfig file, so that you can do
>
> =A0 =A0 =A0 =A0 =A0set NODES_SHIFT 10
>
> which would basically be equivalent to a "select" of a tristate
> variable, but instead set the actual value? I dunno.
I'm partial to extending select statements myself because it fits
nicely into the existing grammer; but I can see value in having a set
statement too. It would eliminate the temporary config options that
both my and Stephen's patch would add.
> And quite frankly, maybe somebody comes up with a better model
> entirely. I like the Kconfig.xyz model, in that it should be
> human-readable/writable and shouldn't introduce any fundamentally new
> concepts (except the fairly simple extensions to the Kconfig
> language), but maybe there are better models.
Perhaps, but I can't think of anything and this one is simple,
elegant, and easy to implement.
> Regardless, I don't have anything against either set of patches
> (Grant's or Stephen's).
I think we should run with this. Since the patch has been merged to
warn on unmet Kconfig dependences, the only major hole left is being
able to do negative selects and to select specific values. Stephen,
I'm happy to either keep working on this, or drop my patch in favor of
yours. Whichever you prefer. I'll try to find some time to look at
the Kconfig grammer.
The solver would also be useful and could further reduce the size of
the Kconfig fragments, but it isn't necessary so we don't need to wait
for it to get implemented to take this approach..
Cheers,
g.
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* [PATCH v2] powerpc/book3e: Add generic 64-bit idle powersave
From: Benjamin Herrenschmidt @ 2010-07-14 4:15 UTC (permalink / raw)
To: linuxppc-dev
We use a similar technique to ppc32: We set a thread local flag
to indicate that we are about to enter or have entered the stop
state, and have fixup code in the async interrupt entry code that
reacts to this flag to make us return to a different location
(sets NIP to LINK in our case).
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
--
v2. Fix lockdep bug
Re-mask interrupts when coming back from idle
---
arch/powerpc/include/asm/machdep.h | 1 +
arch/powerpc/kernel/Makefile | 2 +-
arch/powerpc/kernel/exceptions-64e.S | 23 +++++++++
arch/powerpc/kernel/idle_book3e.S | 86 ++++++++++++++++++++++++++++++++++
4 files changed, 111 insertions(+), 1 deletions(-)
create mode 100644 arch/powerpc/kernel/idle_book3e.S
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 2bad6e5..adc8e6c 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -278,6 +278,7 @@ extern void e500_idle(void);
extern void power4_idle(void);
extern void power4_cpu_offline_powersave(void);
extern void ppc6xx_idle(void);
+extern void book3e_idle(void);
/*
* ppc_md contains a copy of the machine description structure for the
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 8a33318..77d831a 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -37,7 +37,7 @@ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o
obj64-$(CONFIG_RELOCATABLE) += reloc_64.o
-obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o
+obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o
obj-$(CONFIG_PPC64) += vdso64/
obj-$(CONFIG_ALTIVEC) += vecemu.o
obj-$(CONFIG_PPC_970_NAP) += idle_power4.o
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
index a42637c..316465a 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -204,11 +204,30 @@ exc_##n##_bad_stack: \
lis r,TSR_FIS@h; \
mtspr SPRN_TSR,r
+/* Used by asynchronous interrupt that may happen in the idle loop.
+ *
+ * This check if the thread was in the idle loop, and if yes, returns
+ * to the caller rather than the PC. This is to avoid a race if
+ * interrupts happen before the wait instruction.
+ */
+#define CHECK_NAPPING() \
+ clrrdi r11,r1,THREAD_SHIFT; \
+ ld r10,TI_LOCAL_FLAGS(r11); \
+ andi. r9,r10,_TLF_NAPPING; \
+ beq+ 1f; \
+ ld r8,_LINK(r1); \
+ rlwinm r7,r10,0,~_TLF_NAPPING; \
+ std r8,_NIP(r1); \
+ std r7,TI_LOCAL_FLAGS(r11); \
+1:
+
+
#define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack) \
START_EXCEPTION(label); \
NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE) \
EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE_ALL) \
ack(r8); \
+ CHECK_NAPPING(); \
addi r3,r1,STACK_FRAME_OVERHEAD; \
bl hdlr; \
b .ret_from_except_lite;
@@ -257,6 +276,7 @@ interrupt_end_book3e:
CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE)
// EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE_ALL)
// bl special_reg_save_crit
+// CHECK_NAPPING();
// addi r3,r1,STACK_FRAME_OVERHEAD
// bl .critical_exception
// b ret_from_crit_except
@@ -268,6 +288,7 @@ interrupt_end_book3e:
// EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE_ALL)
// bl special_reg_save_mc
// addi r3,r1,STACK_FRAME_OVERHEAD
+// CHECK_NAPPING();
// bl .machine_check_exception
// b ret_from_mc_except
b .
@@ -338,6 +359,7 @@ interrupt_end_book3e:
CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE)
// EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL)
// bl special_reg_save_crit
+// CHECK_NAPPING();
// addi r3,r1,STACK_FRAME_OVERHEAD
// bl .unknown_exception
// b ret_from_crit_except
@@ -434,6 +456,7 @@ kernel_dbg_exc:
CRIT_EXCEPTION_PROLOG(0x2080, PROLOG_ADDITION_NONE)
// EXCEPTION_COMMON(0x2080, PACA_EXCRIT, INTS_DISABLE_ALL)
// bl special_reg_save_crit
+// CHECK_NAPPING();
// addi r3,r1,STACK_FRAME_OVERHEAD
// bl .doorbell_critical_exception
// b ret_from_crit_except
diff --git a/arch/powerpc/kernel/idle_book3e.S b/arch/powerpc/kernel/idle_book3e.S
new file mode 100644
index 0000000..16c002d
--- /dev/null
+++ b/arch/powerpc/kernel/idle_book3e.S
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2010 IBM Corp, Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ * Generic idle routine for Book3E processors
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/threads.h>
+#include <asm/reg.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/ppc-opcode.h>
+#include <asm/processor.h>
+#include <asm/thread_info.h>
+
+/* 64-bit version only for now */
+#ifdef CONFIG_PPC64
+
+_GLOBAL(book3e_idle)
+ /* Save LR for later */
+ mflr r0
+ std r0,16(r1)
+
+ /* Hard disable interrupts */
+ wrteei 0
+
+ /* Now check if an interrupt came in while we were soft disabled
+ * since we may otherwise lose it (doorbells etc...). We know
+ * that since PACAHARDIRQEN will have been cleared in that case.
+ */
+ lbz r3,PACAHARDIRQEN(r13)
+ cmpwi cr0,r3,0
+ beqlr
+
+ /* Now we are going to mark ourselves as soft and hard enables in
+ * order to be able to take interrupts while asleep. We inform lockdep
+ * of that. We don't actually turn interrupts on just yet tho.
+ */
+#ifdef CONFIG_TRACE_IRQFLAGS
+ stdu r1,-128(r1)
+ bl .trace_hardirqs_on
+#endif
+ li r0,1
+ stb r0,PACASOFTIRQEN(r13)
+ stb r0,PACAHARDIRQEN(r13)
+
+ /* Interrupts will make use return to LR, so get something we want
+ * in there
+ */
+ bl 1f
+
+ /* Hard disable interrupts again */
+ wrteei 0
+
+ /* Mark them off again in the PACA as well */
+ li r0,0
+ stb r0,PACASOFTIRQEN(r13)
+ stb r0,PACAHARDIRQEN(r13)
+
+ /* Tell lockdep about it */
+#ifdef CONFIG_TRACE_IRQFLAGS
+ bl .trace_hardirqs_off
+ addi r1,r1,128
+#endif
+ ld r0,16(r1)
+ mtlr r0
+ blr
+
+1: /* Let's set the _TLF_NAPPING flag so interrupts make us return
+ * to the right spot
+ */
+ clrrdi r11,r1,THREAD_SHIFT
+ ld r10,TI_LOCAL_FLAGS(r11)
+ ori r10,r10,_TLF_NAPPING
+ std r10,TI_LOCAL_FLAGS(r11)
+
+ /* We can now re-enable hard interrupts and go to sleep */
+ wrteei 1
+1: PPC_WAIT(0)
+ b 1b
+
+#endif /* CONFIG_PPC64 */
^ permalink raw reply related
* Re: [PATCH 09/13] powerpc/book3e: Add generic 64-bit idle powersave support
From: Benjamin Herrenschmidt @ 2010-07-14 4:09 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1278656215-24705-9-git-send-email-benh@kernel.crashing.org>
On Fri, 2010-07-09 at 16:16 +1000, Benjamin Herrenschmidt wrote:
> We use a similar technique to ppc32: We set a thread local flag
> to indicate that we are about to enter or have entered the stop
> state, and have fixup code in the async interrupt entry code that
> reacts to this flag to make us return to a different location
> (sets NIP to LINK in our case).
.../...
Commenting on my own patch ... :-) This has issues:
> +_GLOBAL(book3e_idle)
> + /* Save LR for later */
> + mflr r0
> + std r0,16(r1)
> +
> + /* Hard disable interrupts */
> + wrteei 0
> +
> + /* Now check if an interrupt came in while we were soft disabled
> + * since we may otherwise lose it (doorbells etc...). We know
> + * that since PACAHARDIRQEN will have been cleared in that case.
> + */
> + lbz r3,PACAHARDIRQEN(r13)
> + cmpwi cr0,r3,0
> + beqlr
> +
> + /* Now we are going to mark ourselves as soft and hard enables in
> + * order to be able to take interrupts while asleep. We inform lockdep
> + * of that. We don't actually turn interrupts on just yet tho.
> + */
> +#ifdef CONFIG_TRACE_IRQFLAGS
> + bl .trace_hardirqs_on
Oops... we just clobbered our saved LR on the stack. Need a stackframe
> +#endif
> + li r0,1
> + stb r0,PACASOFTIRQEN(r13)
> + stb r0,PACAHARDIRQEN(r13)
> +
> + /* Interrupts will make use return to LR, so get something we want
> + * in there
> + */
> + bl 1f
We return here with IRQs enabled, we really need to turn them back off
or bad things will happen if an interrupt pops before we clear
TFL_NAPPING.
I'll send a respin.
Cheers,
Ben.
> + /* We are back from the interrupt, the caller will local_irq_enable()
> + * so to avoid stupid warning, let's turn them off here if irqtrace
> + * is enabled.
> + */
> +#ifdef CONFIG_TRACE_IRQFLAGS
> + li r0,0
> + stb r0,PACASOFTIRQEN(r13)
> + bl .trace_hardirqs_off
> +#endif
> + ld r0,16(r1)
> + mtlr r0
> + blr
> +
> +1: /* Let's set the _TLF_NAPPING flag so interrupts make us return
> + * to the right spot
> + */
> + clrrdi r11,r1,THREAD_SHIFT
> + ld r10,TI_LOCAL_FLAGS(r11)
> + ori r10,r10,_TLF_NAPPING
> + std r10,TI_LOCAL_FLAGS(r11)
> +
> + /* We can now re-enable hard interrupts and go to sleep */
> + wrteei 1
> +1: PPC_WAIT(0)
> + b 1b
> +
> +#endif /* CONFIG_PPC64 */
> \ No newline at end of file
^ permalink raw reply
* Re: [PATCH] kbuild: Enable building defconfigs from Kconfig files
From: Linus Torvalds @ 2010-07-14 4:04 UTC (permalink / raw)
To: Grant Likely
Cc: Michal Marek, Stephen Rothwell, Catalin Marinas, LKML,
Russell King, Andrew Morton, ppc-dev, linux-arm-kernel
In-Reply-To: <AANLkTimC_vXCAOrfTSndZyk8lgkjTlILVSYVYeIg6cUt@mail.gmail.com>
On Tue, Jul 13, 2010 at 7:26 PM, Grant Likely <grant.likely@secretlab.ca> w=
rote:
>
> I chose to use -D /dev/null (defconfig from an empty file) instead of
> -n (allnoconfig) so that default values in Kconfig would get
> respected. =A0For the benefit of everyone else, here's an excerpt from
> our IRC conversation this afternoon:
>
> 19:49 < gcl> sfr: [...] Your patch and my patch are
> =A0 =A0 =A0 =A0 =A0 =A0 essentially doing exactly the same thing, except =
that I used '-d'
> =A0 =A0 =A0 =A0 =A0 =A0 and you used '-n'.
> 19:50 < gcl> s/-d/-D/
> 19:55 < sfr> right
> 19:55 < sfr> Linus wanted us to use -n
Just a note: Linus doesn't really care.
IOW, I used -n not because of any fundamental belief that it is
correct, but just because ti happened to be how I happened to decide
to solve it. It's entirely possible that starting from the Kconfig
defaults (rather than "no") is the right way to go.
I think either approach is likely fine. The -D /dev/null approach
would presumably give smaller Kconfig.xyz files, assuming our defaults
are sane (an maybe that could be at least a partial validation of the
defaults we do have). While the -n approach is in some ways more
stable, in that the resulting Kconfig.xyz entires would presumably be
more stand-alone, and there wouldn't be any subtle interactions when
somebody changes a default value int he Kconfig file.
So I can see advantages to either model. And either model clearly
would want the improvements to "select" that are independent (ie warn
about unsatisfied 'depends on' constraints, and select recursively.
Maybe we already fixed the recursive select thing, I forget).
I also think we need to allow setting of actual values. I don't know
what the syntax would be. A "set" statement that overrides a default
in the Kconfig file, so that you can do
set NODES_SHIFT 10
which would basically be equivalent to a "select" of a tristate
variable, but instead set the actual value? I dunno.
And quite frankly, maybe somebody comes up with a better model
entirely. I like the Kconfig.xyz model, in that it should be
human-readable/writable and shouldn't introduce any fundamentally new
concepts (except the fairly simple extensions to the Kconfig
language), but maybe there are better models.
Regardless, I don't have anything against either set of patches
(Grant's or Stephen's).
Linus
^ permalink raw reply
* Re: [PATCH v2 2/2] Crypto: Talitos: Support for Async_tx XOR offload
From: hank peng @ 2010-07-14 3:58 UTC (permalink / raw)
To: Vishnu Suresh
Cc: herbert, B04825, linux-kernel, linux-raid, linuxppc-dev,
linux-crypto, dan.j.williams, Maneesh Gupta, R58472
In-Reply-To: <1260977698-4076-1-git-send-email-Vishnu@freescale.com>
Hi:
I used your patch and test it on MPC8548 board. Today, I found a
problem when doing raid5 recovering.
talitos e0030000.crypto: master data transfer error
talitos e0030000.crypto: xor operation: talitos error -22
------------[ cut here ]------------
Kernel BUG at c02dcb6c [verbose debug info unavailable]
Oops: Exception in kernel mode, sig: 5 [#1]
MPC85xx CDS
Modules linked in: iscsi_trgt
NIP: c02dcb6c LR: c02dcb6c CTR: c023e7a8
REGS: e8b8d820 TRAP: 0700 Not tainted (2.6.31.6)
MSR: 00029000 <EE,ME,CE> CR: 22008022 XER: 20000000
TASK =3D ef8cb2e0[1897] 'md2_raid5' THREAD: e8b8c000
GPR00: c02dcb6c e8b8d8d0 ef8cb2e0 00000040 00007c99 ffffffff c023bccc 00007=
c5f
GPR08: c04a5c60 c049b5fc 00007c99 00004000 80008022 00000000 3fff5700 c3374=
754
GPR16: c337474c 00000000 00000000 ffffffea 00000001 00000000 000186a0 00000=
000
GPR24: ffffffea ffffffea ef81f850 0000000c 00029000 ffffffea ef81f850 efb1d=
580
NIP [c02dcb6c] talitos_release_xor+0xfc/0x104
LR [c02dcb6c] talitos_release_xor+0xfc/0x104
Call Trace:
[e8b8d8d0] [c02dcb6c] talitos_release_xor+0xfc/0x104 (unreliable)
[e8b8d8f0] [c02db928] flush_channel+0x11c/0x178
[e8b8d920] [c02dd344] talitos_interrupt+0x320/0x9e8
[e8b8d970] [c0060b3c] handle_IRQ_event+0x5c/0x140
[e8b8d990] [c006280c] handle_fasteoi_irq+0x68/0x118
[e8b8d9a0] [c0004f08] do_IRQ+0x94/0xb0
[e8b8d9c0] [c000fe00] ret_from_except+0x0/0x18
[e8b8da80] [c02b47a0] release_stripe+0x24/0x3c
[e8b8da90] [c02ba4ec] raid5_end_read_request+0x160/0x3f8
[e8b8dae0] [c00ba36c] bio_endio+0x48/0x6c
[e8b8daf0] [c01f80e0] req_bio_endio+0xa4/0x128
[e8b8db10] [c01f81f0] blk_update_request+0x8c/0x43c
[e8b8db40] [c01f85c0] blk_update_bidi_request+0x20/0x88
[e8b8db60] [c01f92c4] blk_end_bidi_request+0x1c/0x58
[e8b8db80] [c01f9314] blk_end_request+0x14/0x24
[e8b8db90] [c025ece0] scsi_io_completion+0x8c/0x4ac
[e8b8dbd0] [c0257fd0] scsi_finish_command+0xd0/0xf4
[e8b8dbf0] [c025f1c8] scsi_softirq_done+0xc8/0x150
[e8b8dc10] [c01fe114] blk_done_softirq+0x80/0xa0
[e8b8dc30] [c003a0d8] __do_softirq+0xa8/0x128
[e8b8dc70] [c0004e70] do_softirq+0x54/0x58
[e8b8dc80] [c0039f4c] irq_exit+0x94/0x98
[e8b8dc90] [c0004f0c] do_IRQ+0x98/0xb0
[e8b8dcb0] [c000fe00] ret_from_except+0x0/0x18
[e8b8dd70] [c00679c8] mempool_alloc_slab+0x1c/0x2c
[e8b8ddb0] [c02b6814] ops_run_io+0x1ac/0x2b8
[e8b8ddf0] [c02b93e4] handle_stripe5+0xa80/0x15c0
[e8b8de70] [c02bb408] handle_stripe+0x34/0x12d4
[e8b8df10] [c02bc8ec] raid5d+0x244/0x458
[e8b8df70] [c02c9624] md_thread+0x5c/0x124
[e8b8dfc0] [c004ab24] kthread+0x78/0x7c
[e8b8dff0] [c000f52c] kernel_thread+0x4c/0x68
Instruction dump:
bb61000c 38210020 7c0803a6 4bffefac 4bf63bc9 80be0008 7c641b78 3c60c042
7fa6eb78 38631ccc 4cc63182 4bd58b9d <0fe00000> 48000000 9421ffd0 7c0802a6
Kernel panic - not syncing: Fatal exception in interrupt
Rebooting in 1 seconds..
------------[ cut here ]------------
Badness at c0223124 [verbose debug info unavailable]
NIP: c0223124 LR: c0223308 CTR: 00000000
REGS: e8b8d580 TRAP: 0700 Tainted: G D (2.6.31.6)
MSR: 00021000 <ME,CE> CR: 82008088 XER: 20000000
TASK =3D ef8cb2e0[1897] 'md2_raid5' THREAD: e8b8c000
GPR00: 00000001 e8b8d630 ef8cb2e0 e84f1d60 00000000 e84f1d60 e84f1d7c c04a1=
364
GPR08: c04a5c60 e8b8c000 0000873b e8b8d650 82008088 00000000 3fff5700 c3374=
754
GPR16: c337474c 00000000 00000000 ffffffea 00000001 00000000 000186a0 00000=
000
GPR24: ffffffea ffffffea 00000000 ffffffff ffffffff 00000000 00001106 e84f1=
d60
NIP [c0223124] pci_get_dev_by_id+0x34/0x98
LR [c0223308] pci_get_subsys+0x64/0xa4
Call Trace:
[e8b8d630] [c021e378] no_pci_devices+0x34/0x50 (unreliable)
[e8b8d650] [c0223308] pci_get_subsys+0x64/0xa4
[e8b8d670] [c0017be0] mpc85xx_cds_restart+0x24/0x90
[e8b8d690] [c000e7d0] machine_restart+0x34/0x4c
[e8b8d6a0] [c00447e0] emergency_restart+0x14/0x24
[e8b8d6b0] [c003473c] panic+0x118/0x158
[e8b8d700] [c000cf24] die+0x160/0x16c
[e8b8d720] [c000d1b0] _exception+0x12c/0x154
[e8b8d810] [c000fdb4] ret_from_except_full+0x0/0x4c
[e8b8d8d0] [c02dcb6c] talitos_release_xor+0xfc/0x104
[e8b8d8f0] [c02db928] flush_channel+0x11c/0x178
[e8b8d920] [c02dd344] talitos_interrupt+0x320/0x9e8
[e8b8d970] [c0060b3c] handle_IRQ_event+0x5c/0x140
[e8b8d990] [c006280c] handle_fasteoi_irq+0x68/0x118
[e8b8d9a0] [c0004f08] do_IRQ+0x94/0xb0
[e8b8d9c0] [c000fe00] ret_from_except+0x0/0x18
[e8b8da80] [c02b47a0] release_stripe+0x24/0x3c
[e8b8da90] [c02ba4ec] raid5_end_read_request+0x160/0x3f8
[e8b8dae0] [c00ba36c] bio_endio+0x48/0x6c
[e8b8daf0] [c01f80e0] req_bio_endio+0xa4/0x128
[e8b8db10] [c01f81f0] blk_update_request+0x8c/0x43c
[e8b8db40] [c01f85c0] blk_update_bidi_request+0x20/0x88
[e8b8db60] [c01f92c4] blk_end_bidi_request+0x1c/0x58
[e8b8db80] [c01f9314] blk_end_request+0x14/0x24
[e8b8db90] [c025ece0] scsi_io_completion+0x8c/0x4ac
[e8b8dbd0] [c0257fd0] scsi_finish_command+0xd0/0xf4
[e8b8dbf0] [c025f1c8] scsi_softirq_done+0xc8/0x150
[e8b8dc10] [c01fe114] blk_done_softirq+0x80/0xa0
[e8b8dc30] [c003a0d8] __do_softirq+0xa8/0x128
[e8b8dc70] [c0004e70] do_softirq+0x54/0x58
[e8b8dc80] [c0039f4c] irq_exit+0x94/0x98
[e8b8dc90] [c0004f0c] do_IRQ+0x98/0xb0
[e8b8dcb0] [c000fe00] ret_from_except+0x0/0x18
[e8b8dd70] [c00679c8] mempool_alloc_slab+0x1c/0x2c
[e8b8ddb0] [c02b6814] ops_run_io+0x1ac/0x2b8
[e8b8ddf0] [c02b93e4] handle_stripe5+0xa80/0x15c0
[e8b8de70] [c02bb408] handle_stripe+0x34/0x12d4
[e8b8df10] [c02bc8ec] raid5d+0x244/0x458
[e8b8df70] [c02c9624] md_thread+0x5c/0x124
[e8b8dfc0] [c004ab24] kthread+0x78/0x7c
[e8b8dff0] [c000f52c] kernel_thread+0x4c/0x68
Instruction dump:
7c0802a6 7d800026 7c651b78 bf810010 54290024 90010024 7c9d2378 9181000c
8009000c 5400016e 7c0000d0 54000ffe <0f000000> 3b800000 2e040000 3cc0c022
This oops is invoked by the following code:
static void talitos_release_xor(struct device *dev, struct talitos_desc *hw=
desc,
void *context, int error)
{
struct talitos_xor_desc *desc =3D context;
struct talitos_xor_chan *xor_chan;
dma_async_tx_callback callback;
void *callback_param;
if (unlikely(error)) {
dev_err(dev, "xor operation: talitos error %d\n", error);
BUG();
<-----------------------------------------------------------------
here
}
I wonder here why a tailitos error occured, BUG is invoked? I think we
can do something to error recovery other than invoking BUG.
2009/12/16 Vishnu Suresh <Vishnu@freescale.com>:
> Expose Talitos's XOR functionality to be used for
> RAID Parity calculation via the Async_tx layer.
>
> Known Issue:
> When used with fsldma, random crashes are observed
> on some platforms. Hence, inter-operability with fsldma
> is currently disabled
>
> Thanks to Surender Kumar and Lee Nipper for their help in
> realising this driver
>
> Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
> Signed-off-by: Dipen Dudhat <Dipen.Dudhat@freescale.com>
> Signed-off-by: Maneesh Gupta <Maneesh.Gupta@freescale.com>
> Signed-off-by: Vishnu Suresh <Vishnu@freescale.com>
> ---
> Changes with respect to v1 as per comments received
> o. Rebased to linux-next as of 20091216
> o. The selection is based exclusive of fsldma
> o. Intoduced a new Kernel Configuration variable
> =C2=A0 *. This enables selecting the Cryptographic functionality
> =C2=A0 =C2=A0 =C2=A0of Talitos along with fsldma.
> =C2=A0 *. Disables the XOR parity calculation offload, if fsldma enabled
> =C2=A0 =C2=A0 =C2=A0either as kernel in-built or as a module
> =C2=A0 *. Once the inter-operability with fsldma is resolved, this option
> =C2=A0 =C2=A0 =C2=A0can be removed
>
> =C2=A0drivers/crypto/Kconfig =C2=A0 | =C2=A0 =C2=A09 +
> =C2=A0drivers/crypto/talitos.c | =C2=A0402 ++++++++++++++++++++++++++++++=
+++++++++++++++-
> =C2=A0drivers/crypto/talitos.h | =C2=A0 =C2=A02 +
> =C2=A03 files changed, 412 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
> index b08403d..f8a6376 100644
> --- a/drivers/crypto/Kconfig
> +++ b/drivers/crypto/Kconfig
> @@ -203,6 +203,15 @@ config CRYPTO_DEV_TALITOS
> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0To compile this driver as a module, cho=
ose M here: the module
> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0will be called talitos.
>
> +config CRYPTO_DEV_TALITOS_RAIDXOR
> + =C2=A0 =C2=A0 =C2=A0 bool "Talitos RAID5 XOR Calculation Offload"
> + =C2=A0 =C2=A0 =C2=A0 select DMA_ENGINE
> + =C2=A0 =C2=A0 =C2=A0 depends on CRYPTO_DEV_TALITOS
> + =C2=A0 =C2=A0 =C2=A0 depends on FSL_DMA=3Dn
> + =C2=A0 =C2=A0 =C2=A0 help
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 Say 'Y' here to use the Freescale Security =
Engine (SEC) to
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 offload RAID XOR parity Calculation
> +
> =C2=A0config CRYPTO_DEV_IXP4XX
> =C2=A0 =C2=A0 =C2=A0 =C2=A0tristate "Driver for IXP4xx crypto hardware ac=
celeration"
> =C2=A0 =C2=A0 =C2=A0 =C2=A0depends on ARCH_IXP4XX
> diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
> index c47ffe8..e63b25a 100644
> --- a/drivers/crypto/talitos.c
> +++ b/drivers/crypto/talitos.c
> @@ -1,7 +1,7 @@
> =C2=A0/*
> =C2=A0* talitos - Freescale Integrated Security Engine (SEC) device drive=
r
> =C2=A0*
> - * Copyright (c) 2008 Freescale Semiconductor, Inc.
> + * Copyright (c) 2008-2009 Freescale Semiconductor, Inc.
> =C2=A0*
> =C2=A0* Scatterlist Crypto API glue code copied from files with the follo=
wing:
> =C2=A0* Copyright (c) 2006-2007 Herbert Xu <herbert@gondor.apana.org.au>
> @@ -37,6 +37,8 @@
> =C2=A0#include <linux/io.h>
> =C2=A0#include <linux/spinlock.h>
> =C2=A0#include <linux/rtnetlink.h>
> +#include <linux/dmaengine.h>
> +#include <linux/raid/xor.h>
>
> =C2=A0#include <crypto/algapi.h>
> =C2=A0#include <crypto/aes.h>
> @@ -140,6 +142,10 @@ struct talitos_private {
>
> =C2=A0 =C2=A0 =C2=A0 =C2=A0/* hwrng device */
> =C2=A0 =C2=A0 =C2=A0 =C2=A0struct hwrng rng;
> +#ifdef CONFIG_CRYPTO_DEV_TALITOS_RAIDXOR
> + =C2=A0 =C2=A0 =C2=A0 /* XOR Device */
> + =C2=A0 =C2=A0 =C2=A0 struct dma_device dma_dev_common;
> +#endif /* CONFIG_CRYPTO_DEV_TALITOS_RAIDXOR */
> =C2=A0};
>
> =C2=A0/* .features flag */
> @@ -684,6 +690,375 @@ static void talitos_unregister_rng(struct device *d=
ev)
> =C2=A0 =C2=A0 =C2=A0 =C2=A0hwrng_unregister(&priv->rng);
> =C2=A0}
>
> +#ifdef CONFIG_CRYPTO_DEV_TALITOS_RAIDXOR
> +/*
> + * async_tx interface for XOR-capable SECs
> + *
> + * Dipen Dudhat <Dipen.Dudhat@freescale.com>
> + * Maneesh Gupta <Maneesh.Gupta@freescale.com>
> + * Vishnu Suresh <Vishnu@freescale.com>
> + */
> +
> +/**
> + * talitos_xor_chan - context management for the async_tx channel
> + * @completed_cookie: the last completed cookie
> + * @desc_lock: lock for tx queue
> + * @total_desc: number of descriptors allocated
> + * @submit_q: queue of submitted descriptors
> + * @pending_q: queue of pending descriptors
> + * @in_progress_q: queue of descriptors in progress
> + * @free_desc: queue of unused descriptors
> + * @dev: talitos device implementing this channel
> + * @common: the corresponding xor channel in async_tx
> + */
> +struct talitos_xor_chan {
> + =C2=A0 =C2=A0 =C2=A0 dma_cookie_t completed_cookie;
> + =C2=A0 =C2=A0 =C2=A0 spinlock_t desc_lock;
> + =C2=A0 =C2=A0 =C2=A0 unsigned int total_desc;
> + =C2=A0 =C2=A0 =C2=A0 struct list_head submit_q;
> + =C2=A0 =C2=A0 =C2=A0 struct list_head pending_q;
> + =C2=A0 =C2=A0 =C2=A0 struct list_head in_progress_q;
> + =C2=A0 =C2=A0 =C2=A0 struct list_head free_desc;
> + =C2=A0 =C2=A0 =C2=A0 struct device *dev;
> + =C2=A0 =C2=A0 =C2=A0 struct dma_chan common;
> +};
> +
> +/**
> + * talitos_xor_desc - software xor descriptor
> + * @async_tx: the referring async_tx descriptor
> + * @node:
> + * @hwdesc: h/w descriptor
> + */
> +struct talitos_xor_desc {
> + =C2=A0 =C2=A0 =C2=A0 struct dma_async_tx_descriptor async_tx;
> + =C2=A0 =C2=A0 =C2=A0 struct list_head tx_list;
> + =C2=A0 =C2=A0 =C2=A0 struct list_head node;
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_desc hwdesc;
> +};
> +
> +static enum dma_status talitos_is_tx_complete(struct dma_chan *chan,
> + =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 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 dma_cookie_t cookie,
> + =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 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 dma_cookie_t *done,
> + =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 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 dma_cookie_t *used)
> +{
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_chan *xor_chan;
> + =C2=A0 =C2=A0 =C2=A0 dma_cookie_t last_used;
> + =C2=A0 =C2=A0 =C2=A0 dma_cookie_t last_complete;
> +
> + =C2=A0 =C2=A0 =C2=A0 xor_chan =3D container_of(chan, struct talitos_xor=
_chan, common);
> +
> + =C2=A0 =C2=A0 =C2=A0 last_used =3D chan->cookie;
> + =C2=A0 =C2=A0 =C2=A0 last_complete =3D xor_chan->completed_cookie;
> +
> + =C2=A0 =C2=A0 =C2=A0 if (done)
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 *done =3D last_complet=
e;
> +
> + =C2=A0 =C2=A0 =C2=A0 if (used)
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 *used =3D last_used;
> +
> + =C2=A0 =C2=A0 =C2=A0 return dma_async_is_complete(cookie, last_complete=
, last_used);
> +}
> +
> +static void talitos_release_xor(struct device *dev, struct talitos_desc =
*hwdesc,
> + =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 void *context, int error)
> +{
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_desc *desc =3D context;
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_chan *xor_chan;
> + =C2=A0 =C2=A0 =C2=A0 dma_async_tx_callback callback;
> + =C2=A0 =C2=A0 =C2=A0 void *callback_param;
> +
> + =C2=A0 =C2=A0 =C2=A0 if (unlikely(error)) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 dev_err(dev, "xor oper=
ation: talitos error %d\n", error);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 BUG();
> + =C2=A0 =C2=A0 =C2=A0 }
> +
> + =C2=A0 =C2=A0 =C2=A0 xor_chan =3D container_of(desc->async_tx.chan, str=
uct talitos_xor_chan,
> + =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 common);
> + =C2=A0 =C2=A0 =C2=A0 spin_lock_bh(&xor_chan->desc_lock);
> + =C2=A0 =C2=A0 =C2=A0 if (xor_chan->completed_cookie < desc->async_tx.co=
okie)
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 xor_chan->completed_co=
okie =3D desc->async_tx.cookie;
> +
> + =C2=A0 =C2=A0 =C2=A0 callback =3D desc->async_tx.callback;
> + =C2=A0 =C2=A0 =C2=A0 callback_param =3D desc->async_tx.callback_param;
> + =C2=A0 =C2=A0 =C2=A0 list_del(&desc->node);
> + =C2=A0 =C2=A0 =C2=A0 list_add_tail(&desc->node, &xor_chan->free_desc);
> + =C2=A0 =C2=A0 =C2=A0 spin_unlock_bh(&xor_chan->desc_lock);
> +
> + =C2=A0 =C2=A0 =C2=A0 if (callback)
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 callback(callback_para=
m);
> +
> + =C2=A0 =C2=A0 =C2=A0 /* run dependent operations */
> + =C2=A0 =C2=A0 =C2=A0 dma_run_dependencies(&desc->async_tx);
> +}
> +
> +static void talitos_process_pending(struct talitos_xor_chan *xor_chan)
> +{
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_desc *desc, *_desc;
> +
> + =C2=A0 =C2=A0 =C2=A0 spin_lock_bh(&xor_chan->desc_lock);
> + =C2=A0 =C2=A0 =C2=A0 list_for_each_entry_safe(desc, _desc, &xor_chan->p=
ending_q, node) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (talitos_submit(xor=
_chan->dev, &desc->hwdesc,
> + =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=A0talitos_release_xor, desc) =
!=3D -EINPROGRESS)
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 break;
> +
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 list_del(&desc->node);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 list_add_tail(&desc->n=
ode, &xor_chan->in_progress_q);
> + =C2=A0 =C2=A0 =C2=A0 }
> + =C2=A0 =C2=A0 =C2=A0 spin_unlock_bh(&xor_chan->desc_lock);
> +}
> +
> +/**
> + * talitos_issue_pending - move the descriptors in submit
> + * queue to pending queue and submit them for processing
> + * @chan: DMA channel
> + */
> +static void talitos_issue_pending(struct dma_chan *chan)
> +{
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_chan *xor_chan;
> +
> + =C2=A0 =C2=A0 =C2=A0 xor_chan =3D container_of(chan, struct talitos_xor=
_chan, common);
> + =C2=A0 =C2=A0 =C2=A0 spin_lock_bh(&xor_chan->desc_lock);
> + =C2=A0 =C2=A0 =C2=A0 list_splice_tail_init(&xor_chan->submit_q,
> + =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&xor_chan->pending_q);
> + =C2=A0 =C2=A0 =C2=A0 spin_unlock_bh(&xor_chan->desc_lock);
> + =C2=A0 =C2=A0 =C2=A0 talitos_process_pending(xor_chan);
> +}
> +
> +static dma_cookie_t talitos_async_tx_submit(struct dma_async_tx_descript=
or *tx)
> +{
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_desc *desc;
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_chan *xor_chan;
> + =C2=A0 =C2=A0 =C2=A0 dma_cookie_t cookie;
> +
> + =C2=A0 =C2=A0 =C2=A0 desc =3D container_of(tx, struct talitos_xor_desc,=
async_tx);
> + =C2=A0 =C2=A0 =C2=A0 xor_chan =3D container_of(tx->chan, struct talitos=
_xor_chan, common);
> +
> + =C2=A0 =C2=A0 =C2=A0 cookie =3D xor_chan->common.cookie + 1;
> + =C2=A0 =C2=A0 =C2=A0 if (cookie < 0)
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 cookie =3D 1;
> +
> + =C2=A0 =C2=A0 =C2=A0 desc->async_tx.cookie =3D cookie;
> + =C2=A0 =C2=A0 =C2=A0 xor_chan->common.cookie =3D desc->async_tx.cookie;
> +
> + =C2=A0 =C2=A0 =C2=A0 list_splice_tail_init(&desc->tx_list,
> + =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&xor_chan->submit_q);
> +
> + =C2=A0 =C2=A0 =C2=A0 return cookie;
> +}
> +
> +static struct talitos_xor_desc *talitos_xor_alloc_descriptor(
> + =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 struct talitos_xor_chan *xor_chan, gfp_t=
flags)
> +{
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_desc *desc;
> +
> + =C2=A0 =C2=A0 =C2=A0 desc =3D kmalloc(sizeof(*desc), flags);
> + =C2=A0 =C2=A0 =C2=A0 if (desc) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 xor_chan->total_desc++=
;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 memset(desc, 0, sizeof=
(*desc));
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 dma_async_tx_descripto=
r_init(&desc->async_tx, &xor_chan->common);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 desc->async_tx.tx_subm=
it =3D talitos_async_tx_submit;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 INIT_LIST_HEAD(&desc->=
node);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 INIT_LIST_HEAD(&desc->=
tx_list);
> + =C2=A0 =C2=A0 =C2=A0 }
> +
> + =C2=A0 =C2=A0 =C2=A0 return desc;
> +}
> +
> +static void talitos_free_chan_resources(struct dma_chan *chan)
> +{
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_chan *xor_chan;
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_desc *desc, *_desc;
> +
> + =C2=A0 =C2=A0 =C2=A0 xor_chan =3D container_of(chan, struct talitos_xor=
_chan, common);
> +
> + =C2=A0 =C2=A0 =C2=A0 list_for_each_entry_safe(desc, _desc, &xor_chan->s=
ubmit_q, node) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 list_del(&desc->node);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 xor_chan->total_desc--=
;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 kfree(desc);
> + =C2=A0 =C2=A0 =C2=A0 }
> + =C2=A0 =C2=A0 =C2=A0 list_for_each_entry_safe(desc, _desc, &xor_chan->p=
ending_q, node) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 list_del(&desc->node);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 xor_chan->total_desc--=
;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 kfree(desc);
> + =C2=A0 =C2=A0 =C2=A0 }
> + =C2=A0 =C2=A0 =C2=A0 list_for_each_entry_safe(desc, _desc, &xor_chan->i=
n_progress_q, node) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 list_del(&desc->node);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 xor_chan->total_desc--=
;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 kfree(desc);
> + =C2=A0 =C2=A0 =C2=A0 }
> + =C2=A0 =C2=A0 =C2=A0 list_for_each_entry_safe(desc, _desc, &xor_chan->f=
ree_desc, node) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 list_del(&desc->node);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 xor_chan->total_desc--=
;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 kfree(desc);
> + =C2=A0 =C2=A0 =C2=A0 }
> + =C2=A0 =C2=A0 =C2=A0 BUG_ON(unlikely(xor_chan->total_desc)); /* Some de=
scriptor not freed? */
> +}
> +
> +static int talitos_alloc_chan_resources(struct dma_chan *chan)
> +{
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_chan *xor_chan;
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_desc *desc;
> + =C2=A0 =C2=A0 =C2=A0 LIST_HEAD(tmp_list);
> + =C2=A0 =C2=A0 =C2=A0 int i;
> +
> + =C2=A0 =C2=A0 =C2=A0 xor_chan =3D container_of(chan, struct talitos_xor=
_chan, common);
> +
> + =C2=A0 =C2=A0 =C2=A0 if (!list_empty(&xor_chan->free_desc))
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return xor_chan->total=
_desc;
> +
> + =C2=A0 =C2=A0 =C2=A0 /* 256 initial descriptors */
> + =C2=A0 =C2=A0 =C2=A0 for (i =3D 0; i < 256; i++) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 desc =3D talitos_xor_a=
lloc_descriptor(xor_chan, GFP_KERNEL);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (!desc) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 dev_err(xor_chan->common.device->dev,
> + =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 "Only %d initial descriptors\n", i);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 break;
> + =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 list_add_tail(&desc->n=
ode, &tmp_list);
> + =C2=A0 =C2=A0 =C2=A0 }
> +
> + =C2=A0 =C2=A0 =C2=A0 if (!i)
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return -ENOMEM;
> +
> + =C2=A0 =C2=A0 =C2=A0 /* At least one desc is allocated */
> + =C2=A0 =C2=A0 =C2=A0 list_splice_init(&tmp_list, &xor_chan->free_desc);
> +
> + =C2=A0 =C2=A0 =C2=A0 return xor_chan->total_desc;
> +}
> +
> +static struct dma_async_tx_descriptor * talitos_prep_dma_xor(
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 unsigned int src_cnt, size_t len, unsigned long flags)
> +{
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_chan *xor_chan;
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_desc *new;
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_desc *desc;
> + =C2=A0 =C2=A0 =C2=A0 int i, j;
> +
> + =C2=A0 =C2=A0 =C2=A0 BUG_ON(unlikely(len > TALITOS_MAX_DATA_LEN));
> +
> + =C2=A0 =C2=A0 =C2=A0 xor_chan =3D container_of(chan, struct talitos_xor=
_chan, common);
> +
> + =C2=A0 =C2=A0 =C2=A0 if (!list_empty(&xor_chan->free_desc)) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 new =3D container_of(x=
or_chan->free_desc.next,
> + =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=A0struct talitos_xor_desc, no=
de);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 list_del(&new->node);
> + =C2=A0 =C2=A0 =C2=A0 } else {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 new =3D talitos_xor_al=
loc_descriptor(xor_chan, GFP_KERNEL);
> + =C2=A0 =C2=A0 =C2=A0 }
> +
> + =C2=A0 =C2=A0 =C2=A0 if (!new) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 dev_err(xor_chan->comm=
on.device->dev,
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 "No free memory for XOR DMA descriptor\n");
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return NULL;
> + =C2=A0 =C2=A0 =C2=A0 }
> +
> + =C2=A0 =C2=A0 =C2=A0 desc =3D &new->hwdesc;
> + =C2=A0 =C2=A0 =C2=A0 /* Set destination: Last pointer pair */
> + =C2=A0 =C2=A0 =C2=A0 to_talitos_ptr(&desc->ptr[6], dest);
> + =C2=A0 =C2=A0 =C2=A0 desc->ptr[6].len =3D cpu_to_be16(len);
> + =C2=A0 =C2=A0 =C2=A0 desc->ptr[6].j_extent =3D 0;
> +
> + =C2=A0 =C2=A0 =C2=A0 /* Set Sources: End loading from second-last point=
er pair */
> + =C2=A0 =C2=A0 =C2=A0 for (i =3D 5, j =3D 0; (j < src_cnt) && (i > 0); i=
--, j++) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 to_talitos_ptr(&desc->=
ptr[i], src[j]);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 desc->ptr[i].len =3D c=
pu_to_be16(len);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 desc->ptr[i].j_extent =
=3D 0;
> + =C2=A0 =C2=A0 =C2=A0 }
> +
> + =C2=A0 =C2=A0 =C2=A0 /*
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0* documentation states first 0 ptr/len combo=
marks end of sources
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0* yet device produces scatter boundary error=
unless all subsequent
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0* sources are zeroed out
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0*/
> + =C2=A0 =C2=A0 =C2=A0 for (; i >=3D 0; i--) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 to_talitos_ptr(&desc->=
ptr[i], 0);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 desc->ptr[i].len =3D 0=
;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 desc->ptr[i].j_extent =
=3D 0;
> + =C2=A0 =C2=A0 =C2=A0 }
> +
> + =C2=A0 =C2=A0 =C2=A0 desc->hdr =3D DESC_HDR_SEL0_AESU | DESC_HDR_MODE0_=
AESU_XOR
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | DESC_H=
DR_TYPE_RAID_XOR;
> +
> + =C2=A0 =C2=A0 =C2=A0 list_add_tail(&new->node, &new->tx_list);
> +
> + =C2=A0 =C2=A0 =C2=A0 new->async_tx.flags =3D flags;
> + =C2=A0 =C2=A0 =C2=A0 new->async_tx.cookie =3D -EBUSY;
> +
> + =C2=A0 =C2=A0 =C2=A0 return &new->async_tx;
> +}
> +
> +static void talitos_unregister_async_xor(struct device *dev)
> +{
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_private *priv =3D dev_get_drvdata(d=
ev);
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_chan *xor_chan;
> + =C2=A0 =C2=A0 =C2=A0 struct dma_chan *chan;
> +
> + =C2=A0 =C2=A0 =C2=A0 if (priv->dma_dev_common.chancnt)
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 dma_async_device_unreg=
ister(&priv->dma_dev_common);
> +
> + =C2=A0 =C2=A0 =C2=A0 list_for_each_entry(chan, &priv->dma_dev_common.ch=
annels, device_node) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 xor_chan =3D container=
_of(chan, struct talitos_xor_chan, common);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 list_del(&chan->device=
_node);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 priv->dma_dev_common.c=
hancnt--;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 kfree(xor_chan);
> + =C2=A0 =C2=A0 =C2=A0 }
> +}
> +
> +/**
> + * talitos_register_dma_async - Initialize the Freescale XOR ADMA device
> + * It is registered as a DMA device with the capability to perform
> + * XOR operation with the Async_tx layer.
> + * The various queues and channel resources are also allocated.
> + */
> +static int talitos_register_async_tx(struct device *dev, int max_xor_src=
s)
> +{
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_private *priv =3D dev_get_drvdata(d=
ev);
> + =C2=A0 =C2=A0 =C2=A0 struct dma_device *dma_dev =3D &priv->dma_dev_comm=
on;
> + =C2=A0 =C2=A0 =C2=A0 struct talitos_xor_chan *xor_chan;
> + =C2=A0 =C2=A0 =C2=A0 int err;
> +
> + =C2=A0 =C2=A0 =C2=A0 xor_chan =3D kzalloc(sizeof(struct talitos_xor_cha=
n), GFP_KERNEL);
> + =C2=A0 =C2=A0 =C2=A0 if (!xor_chan) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 dev_err(dev, "unable t=
o allocate xor channel\n");
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return -ENOMEM;
> + =C2=A0 =C2=A0 =C2=A0 }
> +
> + =C2=A0 =C2=A0 =C2=A0 dma_dev->dev =3D dev;
> + =C2=A0 =C2=A0 =C2=A0 dma_dev->device_alloc_chan_resources =3D talitos_a=
lloc_chan_resources;
> + =C2=A0 =C2=A0 =C2=A0 dma_dev->device_free_chan_resources =3D talitos_fr=
ee_chan_resources;
> + =C2=A0 =C2=A0 =C2=A0 dma_dev->device_prep_dma_xor =3D talitos_prep_dma_=
xor;
> + =C2=A0 =C2=A0 =C2=A0 dma_dev->max_xor =3D max_xor_srcs;
> + =C2=A0 =C2=A0 =C2=A0 dma_dev->device_is_tx_complete =3D talitos_is_tx_c=
omplete;
> + =C2=A0 =C2=A0 =C2=A0 dma_dev->device_issue_pending =3D talitos_issue_pe=
nding;
> + =C2=A0 =C2=A0 =C2=A0 INIT_LIST_HEAD(&dma_dev->channels);
> + =C2=A0 =C2=A0 =C2=A0 dma_cap_set(DMA_XOR, dma_dev->cap_mask);
> +
> + =C2=A0 =C2=A0 =C2=A0 xor_chan->dev =3D dev;
> + =C2=A0 =C2=A0 =C2=A0 xor_chan->common.device =3D dma_dev;
> + =C2=A0 =C2=A0 =C2=A0 xor_chan->total_desc =3D 0;
> + =C2=A0 =C2=A0 =C2=A0 INIT_LIST_HEAD(&xor_chan->submit_q);
> + =C2=A0 =C2=A0 =C2=A0 INIT_LIST_HEAD(&xor_chan->pending_q);
> + =C2=A0 =C2=A0 =C2=A0 INIT_LIST_HEAD(&xor_chan->in_progress_q);
> + =C2=A0 =C2=A0 =C2=A0 INIT_LIST_HEAD(&xor_chan->free_desc);
> + =C2=A0 =C2=A0 =C2=A0 spin_lock_init(&xor_chan->desc_lock);
> +
> + =C2=A0 =C2=A0 =C2=A0 list_add_tail(&xor_chan->common.device_node, &dma_=
dev->channels);
> + =C2=A0 =C2=A0 =C2=A0 dma_dev->chancnt++;
> +
> + =C2=A0 =C2=A0 =C2=A0 err =3D dma_async_device_register(dma_dev);
> + =C2=A0 =C2=A0 =C2=A0 if (err) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 dev_err(dev, "Unable t=
o register XOR with Async_tx\n");
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto err_out;
> + =C2=A0 =C2=A0 =C2=A0 }
> +
> + =C2=A0 =C2=A0 =C2=A0 return err;
> +
> +err_out:
> + =C2=A0 =C2=A0 =C2=A0 talitos_unregister_async_xor(dev);
> + =C2=A0 =C2=A0 =C2=A0 return err;
> +}
> +#endif /* CONFIG_CRYPTO_DEV_TALITOS_RAIDXOR */
> =C2=A0/*
> =C2=A0* crypto alg
> =C2=A0*/
> @@ -1768,6 +2143,10 @@ static int talitos_remove(struct of_device *ofdev)
> =C2=A0 =C2=A0 =C2=A0 =C2=A0tasklet_kill(&priv->done_task);
>
> =C2=A0 =C2=A0 =C2=A0 =C2=A0iounmap(priv->reg);
> +#ifdef CONFIG_CRYPTO_DEV_TALITOS_RAIDXOR
> + =C2=A0 =C2=A0 =C2=A0 if (priv->dma_dev_common.chancnt)
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 talitos_unregister_asy=
nc_xor(dev);
> +#endif /* CONFIG_CRYPTO_DEV_TALITOS_RAIDXOR */
>
> =C2=A0 =C2=A0 =C2=A0 =C2=A0dev_set_drvdata(dev, NULL);
>
> @@ -1926,6 +2305,27 @@ static int talitos_probe(struct of_device *ofdev,
> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0dev_info(dev, "hwrng\n");
> =C2=A0 =C2=A0 =C2=A0 =C2=A0}
>
> +#ifdef CONFIG_CRYPTO_DEV_TALITOS_RAIDXOR
> + =C2=A0 =C2=A0 =C2=A0 /*
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0* register with async_tx xor, if capable
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0* SEC 2.x support up to 3 RAID sources,
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0* SEC 3.x support up to 6
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0*/
> + =C2=A0 =C2=A0 =C2=A0 if (hw_supports(dev, DESC_HDR_SEL0_AESU | DESC_HDR=
_TYPE_RAID_XOR)) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int max_xor_srcs =3D 3=
;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (of_device_is_compa=
tible(np, "fsl,sec3.0"))
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 max_xor_srcs =3D 6;
> +
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D talitos_regist=
er_async_tx(dev, max_xor_srcs);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (err) {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 dev_err(dev, "failed to register async_tx xor: %d\n",
> + =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 err);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 goto err_out;
> + =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 dev_info(dev, "max_xor=
_srcs %d\n", max_xor_srcs);
> + =C2=A0 =C2=A0 =C2=A0 }
> +#endif /* CONFIG_CRYPTO_DEV_TALITOS_RAIDXOR */
> +
> =C2=A0 =C2=A0 =C2=A0 =C2=A0/* register crypto algorithms the device suppo=
rts */
> =C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 0; i < ARRAY_SIZE(driver_algs); i++=
) {
> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (hw_supports(de=
v, driver_algs[i].desc_hdr_template)) {
> diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h
> index ff5a145..b6197bc 100644
> --- a/drivers/crypto/talitos.h
> +++ b/drivers/crypto/talitos.h
> @@ -155,6 +155,7 @@
> =C2=A0/* primary execution unit mode (MODE0) and derivatives */
> =C2=A0#define =C2=A0 =C2=A0 =C2=A0 =C2=A0DESC_HDR_MODE0_ENCRYPT =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0cpu_to_be32(0x00100000)
> =C2=A0#define =C2=A0 =C2=A0 =C2=A0 =C2=A0DESC_HDR_MODE0_AESU_CBC =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 cpu_to_be32(0x00200000)
> +#define =C2=A0 =C2=A0 =C2=A0 =C2=A0DESC_HDR_MODE0_AESU_XOR =C2=A0 =C2=A0=
=C2=A0 =C2=A0 cpu_to_be32(0x0c600000)
> =C2=A0#define =C2=A0 =C2=A0 =C2=A0 =C2=A0DESC_HDR_MODE0_DEU_CBC =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0cpu_to_be32(0x00400000)
> =C2=A0#define =C2=A0 =C2=A0 =C2=A0 =C2=A0DESC_HDR_MODE0_DEU_3DES =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 cpu_to_be32(0x00200000)
> =C2=A0#define =C2=A0 =C2=A0 =C2=A0 =C2=A0DESC_HDR_MODE0_MDEU_INIT =C2=A0 =
=C2=A0 =C2=A0 =C2=A0cpu_to_be32(0x01000000)
> @@ -202,6 +203,7 @@
> =C2=A0#define DESC_HDR_TYPE_IPSEC_ESP =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cpu_to_be32(1 << 3)
> =C2=A0#define DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU =C2=A0cpu_to_be32(2 <=
< 3)
> =C2=A0#define DESC_HDR_TYPE_HMAC_SNOOP_NO_AFEU =C2=A0 =C2=A0 =C2=A0 cpu_t=
o_be32(4 << 3)
> +#define DESC_HDR_TYPE_RAID_XOR =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0 =C2=A0 cpu_to_be32(21 << 3)
>
> =C2=A0/* link table extent field bits */
> =C2=A0#define DESC_PTR_LNKTBL_JUMP =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 0x80
> --
> 1.6.4.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-raid" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at =C2=A0http://vger.kernel.org/majordomo-info.html
>
--=20
The simplest is not all best but the best is surely the simplest!
^ permalink raw reply
* Re: [PATCH 4/7] Allow sysfs memory directories to be split
From: KAMEZAWA Hiroyuki @ 2010-07-14 3:25 UTC (permalink / raw)
To: Nathan Fontenot; +Cc: linuxppc-dev, linux-kernel, Dave Hansen
In-Reply-To: <4C3D2C6B.3050203@austin.ibm.com>
On Tue, 13 Jul 2010 22:18:03 -0500
Nathan Fontenot <nfont@austin.ibm.com> wrote:
> On 07/13/2010 07:35 PM, KAMEZAWA Hiroyuki wrote:
> > On Tue, 13 Jul 2010 10:51:58 -0500
> > Nathan Fontenot <nfont@austin.ibm.com> wrote:
> >
> >>>
> >>> And for what purpose this interface is ? Does this split memory block into 2 pieces
> >>> of the same size ?? sounds __very__ strange interface to me.
> >>
> >> Yes, this splits the memory_block into two blocks of the same size. This was
> >> suggested as something we may want to do. From ppc perspective I am not sure we
> >> would use this.
> >>
> >> The split functionality is not required. The main goal of the patch set is to
> >> reduce the number of memory sysfs directories created. From a ppc perspective
> >> the split functionality is not really needed.
> >>
> >
> > Okay, this is an offer from me.
> >
> > 1. I think you can add an boot option as "don't create memory sysfs".
> > please do.
>
> I posted a patch to do that a week or so ago, it didn't go over very well.
>
> >
> > 2. I'd like to write a configfs module for handling memory hotplug even when
> > sysfs directroy is not created.
> > Because configfs support rmdir/mkdir, the user (ppc's daemon?) has to do
> >
> > When offlining section X.
> > # insmod configfs_memory.ko
> > # mount -t configfs none /configfs
> > # mkdir /configfs/memoryX
> > # echo offline > /configfs/memoryX/state
> > # rmdir /configfs/memoryX
> >
> > And making this operation as the default bahavior for all arch's memory hotplug may
> > be better...
> >
> > Dave, how do you think ? Because ppc guys uses "probe" interface already,
> > this can be handled... no ?
>
> ppc would still require the existance of the 'probe' interface.
>
> Are you objecting to the 'split' functionality?
yes.
> If so I do not see any reason from ppc
> perspective that it is needed. This was something Dave suggested, unless I am missing
> something.
>
> Since ppc needs the 'probe' interface in sysfs, and for ppc having mutliple
> memory_block_sections reside under a single memory_block makes memory hotplug
> simpler. On ppc we do emory hotplug operations on an LMB size basis. With my
> patches this now lets us set each memory_block to span an LMB's worth of
> memory. Now we could do emory hotplug in a single operation instead of multiple
> operations to offline/online all of the memory sections in an LMB.
>
Why per-section memory offlining is provided is for allowing good success-rate of
memory offlining. Because memory-hotplug has to "migrate or free" all used page
under a section, possibility of memory unplug depends on usage of memory.
If a section contains unmovable page(kernel page), we can't offline sectin.
For example, comparing
1. offlining 128MB of memory at once
2. offlining 8 chunks of 16MB memory
"2" can get very good possibility and system-busy time can be much reduced.
IIUC, ppc's 1st requirement is "resizing" not "hot-removing some memory device",
"2" is much welcomed. So, some fine-grained interface to section_size is
appreciated. So, "multiple operations" is much better than single operation.
As I posted show/hide patch, I'm writing it in configfs. I think it meets IBM's
requirements.
_But_, it's IBM's issue not Fujitsu's. So, final decistion will depend on you guys.
Anyway, I don't like a too fancy interface as "split".
Thanks,
-Kame
^ permalink raw reply
* Re: [PATCH 4/7] Allow sysfs memory directories to be split
From: Dave Hansen @ 2010-07-14 3:26 UTC (permalink / raw)
To: KAMEZAWA Hiroyuki; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20100714093550.40036034.kamezawa.hiroyu@jp.fujitsu.com>
On Wed, 2010-07-14 at 09:35 +0900, KAMEZAWA Hiroyuki wrote:
> 2. I'd like to write a configfs module for handling memory hotplug even when
> sysfs directroy is not created.
> Because configfs support rmdir/mkdir, the user (ppc's daemon?) has to do
>
> When offlining section X.
> # insmod configfs_memory.ko
> # mount -t configfs none /configfs
> # mkdir /configfs/memoryX
> # echo offline > /configfs/memoryX/state
> # rmdir /configfs/memoryX
>
> And making this operation as the default bahavior for all arch's memory hotplug may
> be better...
>
> Dave, how do you think ? Because ppc guys uses "probe" interface already,
> this can be handled... no ?
I think creating a interface to duplicate the existing sysfs one is a
bad idea. I also think removing the existing sysfs one isn't feasible
since there are users, and it's truly part of the ABI. So, I'm not
really a fan on the configfs interface. :(
I really do think the sysfs interface is fixable. We should at least
give it a good shot before largely duplicating its functionality.
-- Dave
^ permalink raw reply
* Re: [PATCH 4/7] Allow sysfs memory directories to be split
From: Nathan Fontenot @ 2010-07-14 3:18 UTC (permalink / raw)
To: KAMEZAWA Hiroyuki; +Cc: linuxppc-dev, linux-kernel, Dave Hansen
In-Reply-To: <20100714093550.40036034.kamezawa.hiroyu@jp.fujitsu.com>
On 07/13/2010 07:35 PM, KAMEZAWA Hiroyuki wrote:
> On Tue, 13 Jul 2010 10:51:58 -0500
> Nathan Fontenot <nfont@austin.ibm.com> wrote:
>
>>>
>>> And for what purpose this interface is ? Does this split memory block into 2 pieces
>>> of the same size ?? sounds __very__ strange interface to me.
>>
>> Yes, this splits the memory_block into two blocks of the same size. This was
>> suggested as something we may want to do. From ppc perspective I am not sure we
>> would use this.
>>
>> The split functionality is not required. The main goal of the patch set is to
>> reduce the number of memory sysfs directories created. From a ppc perspective
>> the split functionality is not really needed.
>>
>
> Okay, this is an offer from me.
>
> 1. I think you can add an boot option as "don't create memory sysfs".
> please do.
I posted a patch to do that a week or so ago, it didn't go over very well.
>
> 2. I'd like to write a configfs module for handling memory hotplug even when
> sysfs directroy is not created.
> Because configfs support rmdir/mkdir, the user (ppc's daemon?) has to do
>
> When offlining section X.
> # insmod configfs_memory.ko
> # mount -t configfs none /configfs
> # mkdir /configfs/memoryX
> # echo offline > /configfs/memoryX/state
> # rmdir /configfs/memoryX
>
> And making this operation as the default bahavior for all arch's memory hotplug may
> be better...
>
> Dave, how do you think ? Because ppc guys uses "probe" interface already,
> this can be handled... no ?
ppc would still require the existance of the 'probe' interface.
Are you objecting to the 'split' functionality? If so I do not see any reason from ppc
perspective that it is needed. This was something Dave suggested, unless I am missing
something.
Since ppc needs the 'probe' interface in sysfs, and for ppc having mutliple
memory_block_sections reside under a single memory_block makes memory hotplug
simpler. On ppc we do emory hotplug operations on an LMB size basis. With my
patches this now lets us set each memory_block to span an LMB's worth of
memory. Now we could do emory hotplug in a single operation instead of multiple
operations to offline/online all of the memory sections in an LMB.
Of course the easy solution would be to increase SECTION_SIZE_BITS, but we need
support hardware that can have LMB's from 16 MB to 256 MB in size so the
SECTION_SIZE_BITS value has to remain small.
>
> One problem is that I don't have enough knowledge about configfs..it seems complex.
Me neither, thoug I will take a look at it.
-Nathan
^ permalink raw reply
* Re: [PATCH] kbuild: Enable building defconfigs from Kconfig files
From: Grant Likely @ 2010-07-14 2:26 UTC (permalink / raw)
To: Stephen Rothwell
Cc: Michal Marek, Linus, LKML, Russell King, Catalin Marinas,
Andrew Morton, ppc-dev, linux-arm-kernel
In-Reply-To: <20100713114322.57c8b166.sfr@canb.auug.org.au>
[cc'ing rmk and linux-arm-kernel]
On Mon, Jul 12, 2010 at 7:43 PM, Stephen Rothwell <sfr@canb.auug.org.au> wr=
ote:
> After this change, doing a "make xxx_defconfig" will check first for
> a file called arch/<arch>/configs/Kconfig.xxx and use that to generate
> the .config (effectively starting from an allnoconfig). =A0If that file
> doesn't exist, it will use arch/<ARCH>/configs/xxx_defconfig as now.
Oops, I hadn't seen this patch when I wrote mine this afternoon[1].
:-) A few minor differences, but essentially the same solution.
[1] http://patchwork.ozlabs.org/patch/58823/
I chose to use -D /dev/null (defconfig from an empty file) instead of
-n (allnoconfig) so that default values in Kconfig would get
respected. For the benefit of everyone else, here's an excerpt from
our IRC conversation this afternoon:
19:49 < gcl> sfr: [...] Your patch and my patch are
essentially doing exactly the same thing, except that I used '=
-d'
and you used '-n'.
19:50 < gcl> s/-d/-D/
19:55 < sfr> right
19:55 < sfr> Linus wanted us to use -n
19:55 < sfr> because that way you get what you asked for, not what the defa=
ults
say ...
19:58 < gcl> I suppose we don't currently have a way to say "select FOO=3Dn=
", so
I suppose that makes sense
19:58 < gcl> although I think using the defaults unless told not to is a be=
tter
approach in the long run
19:59 < gcl> most of the time I *don't want* to ask for something in the
defconfig. :-)
20:00 < gcl> I just want TheBestOrCorrectAnswer to be chosen for me
20:04 < sfr> gcl: go read Linus' vision :-)
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
> ---
> =A0scripts/kconfig/Makefile | =A0 14 +++++++++++++-
> =A01 files changed, 13 insertions(+), 1 deletions(-)
>
> Hi Linus,
>
> Is this more the direction you want to take?
>
> There are still 2 main problems with is approach:
>
> =A0 =A0 =A0 =A0- there are some config options that are globally and
> unconditionally enabled that some platforms may not want. =A0The only way
> currently to turn them off is to reproduce the config entry with the
> different default. =A0I am not sure if we need a wa to turn them off or t=
o
> just change them to being neede to be selected by those that do want them=
.
> =A0 =A0 =A0 =A0- we have no way to select options that are neither bool o=
r
> tristate to suitable values. =A0Again the only way to do that currently i=
s
> to reproduce the config entry with a different default value.
For both of the above problems, what if we added syntax like the
following to Kconfig?
config FOO
bool
select BAR =3D n
select FOO_VALUE =3D 54
> I am currently working towards using this to recreate the PowerPC
> defconfigs, but it is a slow process as they have some much stuff enabled
> in them and some of it is probably actually not relevant.
If the trimmed configs are merged, then there is no rush on this. We
can keep them around and switch them over as people want to make
changes.
> This process is made easier by the recent commit "kbuild: Warn on
> selecting symbols with unmet direct dependencies" that is in the kbuild
> tree (and linux-next).
Ah, I didn't know that change was being merged. That indeed makes
things easier, and eliminates the post-test that I do to make sure
that the resulting config is actually valid.
> diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
> index 7ea649d..1ab8f45 100644
> --- a/scripts/kconfig/Makefile
> +++ b/scripts/kconfig/Makefile
> @@ -117,9 +117,21 @@ else
> =A0 =A0 =A0 =A0$(Q)$< -D arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kc=
onfig)
> =A0endif
>
> -%_defconfig: $(obj)/conf
> +configs_dir :=3D $(srctree)/arch/$(SRCARCH)/configs
> +# We check a level of sub directories because arch/powerpc
> +# has its defconfig files arranged that way
> +old_defconfigs :=3D $(patsubst $(configs_dir)/%,%,\
> + =A0 =A0 =A0 $(wildcard $(configs_dir)/*_defconfig) \
> + =A0 =A0 =A0 $(wildcard $(configs_dir)/*/*_defconfig))
> +defconfigs :=3D $(patsubst $(configs_dir)/Kconfig.%,%_defconfig,\
> + =A0 =A0 =A0 $(wildcard $(configs_dir)/Kconfig.*))
> +
Ugh. My first impression is that all this shouldn't be necessary, and
it should be okay to just make the two following rules include a
pattern dependency for the source file. However, as I play with it, I
cannot seem to get the rules right to handle the sub directories. The
$(defconfigs) patsubst at least could be done solely with dependencies
on the target rule if the files were named *.Kconfig instead of
Kconfig.* (because subdirectories are not handled in that case). For
example:
%_defconfig: $(obj)/conf arch/$(SRCARCH)/configs/%.Kconfig
$(Q)$< -n arch/$(SRCARCH)/configs/$*.Kconfig
> +$(old_defconfigs): %_defconfig: $(obj)/conf
> =A0 =A0 =A0 =A0$(Q)$< -D arch/$(SRCARCH)/configs/$@ $(Kconfig)
>
> +$(defconfigs): %_defconfig: $(obj)/conf
> + =A0 =A0 =A0 $(Q)$< -n arch/$(SRCARCH)/configs/Kconfig.$*
> +
> =A0# Help text used by make help
> =A0help:
> =A0 =A0 =A0 =A0@echo =A0' =A0config =A0 =A0 =A0 =A0 =A0- Update current c=
onfig utilising a line-oriented program'
Cheers,
g.
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 4/7] Allow sysfs memory directories to be split
From: KAMEZAWA Hiroyuki @ 2010-07-14 0:35 UTC (permalink / raw)
To: Nathan Fontenot; +Cc: linuxppc-dev, linux-kernel, Dave Hansen
In-Reply-To: <4C3C8B9E.7000208@austin.ibm.com>
On Tue, 13 Jul 2010 10:51:58 -0500
Nathan Fontenot <nfont@austin.ibm.com> wrote:
> >
> > And for what purpose this interface is ? Does this split memory block into 2 pieces
> > of the same size ?? sounds __very__ strange interface to me.
>
> Yes, this splits the memory_block into two blocks of the same size. This was
> suggested as something we may want to do. From ppc perspective I am not sure we
> would use this.
>
> The split functionality is not required. The main goal of the patch set is to
> reduce the number of memory sysfs directories created. From a ppc perspective
> the split functionality is not really needed.
>
Okay, this is an offer from me.
1. I think you can add an boot option as "don't create memory sysfs".
please do.
2. I'd like to write a configfs module for handling memory hotplug even when
sysfs directroy is not created.
Because configfs support rmdir/mkdir, the user (ppc's daemon?) has to do
When offlining section X.
# insmod configfs_memory.ko
# mount -t configfs none /configfs
# mkdir /configfs/memoryX
# echo offline > /configfs/memoryX/state
# rmdir /configfs/memoryX
And making this operation as the default bahavior for all arch's memory hotplug may
be better...
Dave, how do you think ? Because ppc guys uses "probe" interface already,
this can be handled... no ?
One problem is that I don't have enough knowledge about configfs..it seems complex.
Thanks,
-Kame
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox