* [PATCHv3] watchdog: add support for the Synopsys DesignWare WDT
From: Wim Van Sebroeck @ 2011-01-09 10:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294401797-24158-1-git-send-email-jamie@jamieiles.com>
Hi Jamie,
On top of other comments from Viresh:
> +static int dw_wdt_open(struct inode *inode, struct file *filp)
> +{
> + /* Make sure we don't get unloaded. */
> + __module_get(THIS_MODULE);
> +
> + spin_lock(&dw_wdt.lock);
> + if (!dw_wdt_is_enabled()) {
> + /*
> + * The watchdog is not currently enabled. Set the timeout to
> + * the maximum and then start it.
> + */
> + dw_wdt_set_top(DW_WDT_MAX_TOP);
> + writel(WDOG_CONTROL_REG_WDT_EN_MASK,
> + dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
> + }
> + spin_unlock(&dw_wdt.lock);
> +
> + return nonseekable_open(inode, filp);
> +}
Would be nice to have the open /dev/watchdog once protection here also.
> +static int __devexit dw_wdt_drv_remove(struct platform_device *pdev)
> +{
> + clk_disable(dw_wdt.clk);
> + clk_put(dw_wdt.clk);
> +
> + misc_deregister(&dw_wdt_miscdev);
> +
> + return 0;
> +}
misc_deregister (=link to user-space) should be called before the clk_disabel calls.
Kind regards,
Wim.
^ permalink raw reply
* [PATCH v5 3/3] ahci_platforms: add support for CNS3xxx SoC devices
From: mkl0301 at gmail.com @ 2011-01-09 7:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294557970-654-1-git-send-email-mkl0301@gmail.com>
From: Mac Lin <mkl0301@gmail.com>
CNS3xxx override the softreset function of ahci_platform ahci_softreset by
cns3xxx_ahci_softreset, which would retry ahci_do_softreset again with pmp=0 if
pmp=15 failed, for the controller has problem receiving D2H Reg FIS of the
different PMP setting of the previous sent H2D Reg FIS.
Following describe the isssue with original ahci_platform driver on
linux-2.6.37-rc3, arm/cns3xxx.
If CONFIG_SATA_PMP is enabled, while not using multiplier and connect the disks
directly to the board, the disk cannot be found due to software reset always
failed.
ahci ahci.0: forcing PORTS_IMPL to 0x3
ahci ahci.0: AHCI 0001.0100 32 slots 2 ports 3 Gbps 0x3 impl platform mode
ahci ahci.0: flags: ncq sntf pm led clo only pmp pio slum part ccc
scsi0 : ahci_platform
scsi1 : ahci_platform
ata1: SATA max UDMA/133 irq_stat 0x00400040, connection status changed irq 65
ata2: SATA max UDMA/133 mmio [mem 0x83000000-0x83ffffff] port 0x180 irq 65
ata2: SATA link down (SStatus 0 SControl 300)
ata1: link is slow to respond, please be patient (ready=0)
ata1: softreset failed (device not ready)
ata1: link is slow to respond, please be patient (ready=0)
ata1: softreset failed (device not ready)
ata1: link is slow to respond, please be patient (ready=0)
ata1: softreset failed (device not ready)
ata1: limiting SATA link speed to 1.5 Gbps
ata1: SATA link down (SStatus 1 SControl 310)
While using multiplier with CONFIG_SATA_PMP enabled, or using disks directly
without CONFIG_SATA_PMP have no issue. It seems the device is sending D2H Reg
FIS, but controller is not reflecting it on any known means.
Signed-off-by: Mac Lin <mkl0301@gmail.com>
Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>
---
arch/arm/mach-cns3xxx/devices.c | 2 +-
drivers/ata/Kconfig | 11 ++++++++
drivers/ata/Makefile | 1 +
drivers/ata/ahci_cns3xxx.c | 51 +++++++++++++++++++++++++++++++++++++++
drivers/ata/ahci_platform.c | 3 ++
drivers/ata/ahci_platform.h | 2 +
6 files changed, 69 insertions(+), 1 deletions(-)
create mode 100644 drivers/ata/ahci_cns3xxx.c
diff --git a/arch/arm/mach-cns3xxx/devices.c b/arch/arm/mach-cns3xxx/devices.c
index 50b4d31..b496f02 100644
--- a/arch/arm/mach-cns3xxx/devices.c
+++ b/arch/arm/mach-cns3xxx/devices.c
@@ -40,7 +40,7 @@ static struct resource cns3xxx_ahci_resource[] = {
static u64 cns3xxx_ahci_dmamask = DMA_BIT_MASK(32);
static struct platform_device cns3xxx_ahci_pdev = {
- .name = "ahci",
+ .name = "ahci-cns3xxx",
.id = 0,
.resource = cns3xxx_ahci_resource,
.num_resources = ARRAY_SIZE(cns3xxx_ahci_resource),
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 36e2319..5d8b1a3 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -75,6 +75,17 @@ config SATA_AHCI_PLATFORM
If unsure, say N.
+config SATA_AHCI_CNS3XXX
+ bool "AHCI Support on the Cavium Networks CNS3xxx SOC"
+ depends on ARCH_CNS3XXX
+ depends on SATA_AHCI_PLATFORM
+ help
+ This option enables AHCI platform driver to support CNS3xxx
+ System-on-Chip devices. This is only needed when using CNS3xxx AHCI
+ controller.
+
+ If unsure, say N.
+
config SATA_FSL
tristate "Freescale 3.0Gbps SATA support"
depends on FSL_SOC
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index d17bfe7..7f2d32e 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_ATA) += libata.o
obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o
obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platforms.o libahci.o
ahci_platforms-y += ahci_platform.o
+ahci_platforms-$(CONFIG_SATA_AHCI_CNS3XXX) += ahci_cns3xxx.o
obj-$(CONFIG_SATA_FSL) += sata_fsl.o
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
diff --git a/drivers/ata/ahci_cns3xxx.c b/drivers/ata/ahci_cns3xxx.c
new file mode 100644
index 0000000..7cc841e
--- /dev/null
+++ b/drivers/ata/ahci_cns3xxx.c
@@ -0,0 +1,51 @@
+/*
+ * AHCI support for CNS3xxx SoC
+ *
+ * Copyright 2010 MontaVista Software, LLC.
+ * Copyright 2010 Cavium Networks
+ *
+ * Authors: Anton Vorontsov <avorontsov@mvista.com>
+ * Mac Lin <mkl0301@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/libata.h>
+#include <linux/ahci_platform.h>
+#include "ahci.h"
+
+/*
+ * TODO: move cns3xxx_ahci_init to here after cns3xxx_pwr*() calls are
+ * thread-safe
+ */
+
+static int cns3xxx_ahci_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ int pmp = sata_srst_pmp(link);
+ int ret;
+
+ ret = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
+ if (pmp && ret)
+ return ahci_do_softreset(link, class, 0, deadline,
+ ahci_check_ready);
+ return ret;
+}
+
+static struct ata_port_operations cns3xxx_ahci_ops = {
+ .inherits = &ahci_ops,
+ .softreset = cns3xxx_ahci_softreset,
+};
+
+static const struct ata_port_info cns3xxx_ata_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &cns3xxx_ahci_ops,
+};
+
+struct ahci_platform_data cns3xxx_ahci_platform_data = {
+ .ata_port_info = &cns3xxx_ata_port_info,
+};
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index f0e2569..35ddae1 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -179,6 +179,9 @@ static int __devexit ahci_remove(struct platform_device *pdev)
static const struct platform_device_id ahci_platform_ids[] = {
{ "ahci", },
+#ifdef CONFIG_SATA_AHCI_CNS3XXX
+ { "ahci-cns3xxx", (kernel_ulong_t)&cns3xxx_ahci_platform_data},
+#endif
{ },
};
MODULE_DEVICE_TABLE(platform, ahci_platform_ids);
diff --git a/drivers/ata/ahci_platform.h b/drivers/ata/ahci_platform.h
index cf16e6f..d9ea5ab 100644
--- a/drivers/ata/ahci_platform.h
+++ b/drivers/ata/ahci_platform.h
@@ -13,4 +13,6 @@
#ifndef _DRIVERS_SATA_AHCI_PLATFORMS_H
#define _DRIVERS_SATA_AHCI_PLATFORMS_H
+extern struct ahci_platform_data cns3xxx_ahci_platform_data;
+
#endif /*_DRIVERS_SATA_AHCI_PLATFORMS_H*/
--
1.7.3
^ permalink raw reply related
* [PATCH v5 2/3] ahci_platform: switch to module device table matching
From: mkl0301 at gmail.com @ 2011-01-09 7:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294557970-654-1-git-send-email-mkl0301@gmail.com>
From: Mac Lin <mkl0301@gmail.com>
Switch the driver to use module device table matching mechanism to add SoC-specific parts to the generic driver.
Signed-off-by: Mac Lin <mkl0301@gmail.com>
Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>
---
drivers/ata/ahci_platform.c | 14 +++++++++++++-
drivers/ata/ahci_platform.h | 16 ++++++++++++++++
2 files changed, 29 insertions(+), 1 deletions(-)
create mode 100644 drivers/ata/ahci_platform.h
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 6fef1fa..f0e2569 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -19,9 +19,11 @@
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
#include <linux/libata.h>
#include <linux/ahci_platform.h>
#include "ahci.h"
+#include "ahci_platform.h"
static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT("ahci_platform"),
@@ -29,6 +31,7 @@ static struct scsi_host_template ahci_platform_sht = {
static int __init ahci_probe(struct platform_device *pdev)
{
+ const struct platform_device_id *platid = platform_get_device_id(pdev);
struct device *dev = &pdev->dev;
struct ahci_platform_data *pdata = dev->platform_data;
struct ata_port_info pi = {
@@ -46,6 +49,9 @@ static int __init ahci_probe(struct platform_device *pdev)
int i;
int rc;
+ if (!pdata && platid && platid->driver_data)
+ pdata = (void *)platid->driver_data;
+
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(dev, "no mmio space\n");
@@ -171,12 +177,19 @@ static int __devexit ahci_remove(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id ahci_platform_ids[] = {
+ { "ahci", },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, ahci_platform_ids);
+
static struct platform_driver ahci_driver = {
.remove = __devexit_p(ahci_remove),
.driver = {
.name = "ahci",
.owner = THIS_MODULE,
},
+ .id_table = ahci_platform_ids,
};
static int __init ahci_init(void)
@@ -194,4 +207,3 @@ module_exit(ahci_exit);
MODULE_DESCRIPTION("AHCI SATA platform driver");
MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:ahci");
diff --git a/drivers/ata/ahci_platform.h b/drivers/ata/ahci_platform.h
new file mode 100644
index 0000000..cf16e6f
--- /dev/null
+++ b/drivers/ata/ahci_platform.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2010 MontaVista Software, LLC.
+ * Copyright 2010 Cavium Networks
+ *
+ * Authors: Anton Vorontsov <avorontsov@mvista.com>
+ * Mac Lin <mkl0301@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _DRIVERS_SATA_AHCI_PLATFORMS_H
+#define _DRIVERS_SATA_AHCI_PLATFORMS_H
+
+#endif /*_DRIVERS_SATA_AHCI_PLATFORMS_H*/
--
1.7.3
^ permalink raw reply related
* [PATCH v5 1/3] ahci_platform: rename module ahci_platform to ahci_platforms
From: mkl0301 at gmail.com @ 2011-01-09 7:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294557970-654-1-git-send-email-mkl0301@gmail.com>
From: Mac Lin <mkl0301@gmail.com>
Due to build system limitations, intermediate and final objects can't have the
same names. And as we're going to start building SoC-specific objects, rename
ahci_platform to ahci_platforms, into which link ahci_platform and SoC-specific
objects.
Signed-off-by: Mac Lin <mkl0301@gmail.com>
Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>
---
drivers/ata/Makefile | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 2b67c90..d17bfe7 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -3,7 +3,9 @@ obj-$(CONFIG_ATA) += libata.o
# non-SFF interface
obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o
-obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
+obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platforms.o libahci.o
+ahci_platforms-y += ahci_platform.o
+
obj-$(CONFIG_SATA_FSL) += sata_fsl.o
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
--
1.7.3
^ permalink raw reply related
* [PATCH v5 0/3] add CNS3xxx AHCI support
From: mkl0301 at gmail.com @ 2011-01-09 7:26 UTC (permalink / raw)
To: linux-arm-kernel
From: Mac Lin <mkl0301@gmail.com>
v5:
- Rename ahci_platforms.h to ahci_platform.h
- s/pltfm/platform/ in ahci_platform.c
v4: http://www.spinics.net/lists/linux-ide/msg39852.html
- v2 basically, which make SoC-specific changes into separate files
- Rename module ahci_platform to ahci_platforms, into which link the ahci_platform and the SoC-specific changes
- No rename of ahci_platform.c
- Some cosmetic code changes since v2
v3: http://www.spinics.net/lists/arm-kernel/msg109924.html
- Make the SoC-specific changes into ahci_platform.c directly.
- Some cosmetic code changes
=> ahci_platform.c is less readable due to SoC-specific changes and macro
v2: http://www.spinics.net/lists/linux-ide/msg39766.html
- Renaming ahci_platform.c to ahci_pltfm.c for linking SoC specific changes into ahci_platform, while not changing the module name.
- Switch ahci_platform to module device table matching to add SoC specific support
- Add CNS3xxx SoC specific AHCI support to ahci_cns3xxx.c
v1: http://www.spinics.net/lists/arm-kernel/msg106236.html
- Add CNS3xxx SoC specific AHCI support to arch/arm/mach-cns3xxx
=> The changes depends on libahci and libata, i.e. both of them need to be built into kernel
This patchset is based on linux-2.6.37
^ permalink raw reply
* suspicious code in linux/arch/arm/common/sa1111.c
From: Pavel Machek @ 2011-01-09 7:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <AANLkTin6QAr7=7-59aKzunh6nQGhCKPJ11OspBtC4NHB@mail.gmail.com>
On Tue 2010-11-16 17:09:59, Eric Miao wrote:
> On Tue, Nov 16, 2010 at 5:07 PM, Pavel Machek <pma@sysgo.com> wrote:
> > Hi!
> >
> > Is this good idea?
> >
> > Signed-off-by: Pavel Machek <pma@sysgo.com>
>
> Yep, obviously was a typo.
Can you apply the patch? Or should I re--generate one with better changelog?
> > diff -ur linux.ofic//arch/arm/common/sa1111.c linux/arch/arm/common/sa1111.c
> > --- linux.ofic//arch/arm/common/sa1111.c ? ? ? ?2010-10-17 20:31:13.000000000 +0200
> > +++ linux/arch/arm/common/sa1111.c ? ? ?2010-11-05 10:44:17.000000000 +0100
> > @@ -282,7 +312,7 @@
> > ? ? ? ?for (i = 0; i < 8; i++) {
> > ? ? ? ? ? ? ? ?sa1111_writel(ip0 ^ mask, mapbase + SA1111_INTPOL0);
> > ? ? ? ? ? ? ? ?sa1111_writel(ip0, mapbase + SA1111_INTPOL0);
> > - ? ? ? ? ? ? ? if (sa1111_readl(mapbase + SA1111_INTSTATCLR1) & mask)
> > + ? ? ? ? ? ? ? if (sa1111_readl(mapbase + SA1111_INTSTATCLR0) & mask)
> > ? ? ? ? ? ? ? ? ? ? ? ?break;
> > ? ? ? ?}
> >
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* [PATCH] ARM: sched_clock: improve mult/shift accuracy with high frequency clocks
From: Nicolas Pitre @ 2011-01-09 3:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.00.1012202014500.10437@xanadu.home>
Ping.
I think this patch is needed independently of what happens to
__clocksource_updatefreq_scale(). We must cover at least the full hw
clock range because of update_sched_clock(). But no more than the full
hw clock range otherwise we lose precision in the mult factor. Without
this patch we lose two bits of precision on Kirkwood.
On Mon, 20 Dec 2010, Nicolas Pitre wrote:
>
> The minsec argument to clocks_calc_mult_shift() [ which appears to be
> misnamed by the way ] is used to clamp the magnitude of the mult factor
> so that the given range won't overflow a 64 bit result. The mult factor
> is itself already limited to a maximum of 32 bits. Given that the largest
> clock tick range we may have is also 32 bits, there is no way our usage of
> any computed mult factor would ever overflow 64 bits.
>
> The choice of 60 seconds here for minsec is rather arbitrary. If the
> mult factor wasn't already limited to 32 bits, this value of 60 would
> create overflows for clocks which take more than 60 seconds to wrap.
>
> And for clocks which take less than 60 seconds to wrap then we do lose
> precision as the mult factor is made smaller (fewer bits) to be adjusted
> to a range which is larger than what we actually use. This currently
> affects clocks faster than 71MHz.
>
> We could use minsec = 0 instead of 60 and a good 32-bit mult factor would
> be computed in all cases. But let's be formal and provide the actual
> range to clocks_calc_mult_shift(). None of the cyc_to_fixed_sched_clock()
> users are affected as they all are using clocks < 71MHz.
>
> Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
>
> diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c
> index 2cdcc92..f7a0f93 100644
> --- a/arch/arm/kernel/sched_clock.c
> +++ b/arch/arm/kernel/sched_clock.c
> @@ -30,11 +30,13 @@ void __init init_sched_clock(struct clock_data *cd, void (*update)(void),
> unsigned long r, w;
> u64 res, wrap;
> char r_unit;
> + u32 mask = (1ULL << clock_bits) - 1;
>
> sched_clock_update_fn = update;
>
> /* calculate the mult/shift to convert counter ticks to ns. */
> - clocks_calc_mult_shift(&cd->mult, &cd->shift, rate, NSEC_PER_SEC, 60);
> + clocks_calc_mult_shift(&cd->mult, &cd->shift, rate, NSEC_PER_SEC,
> + mask/rate);
>
> r = rate;
> if (r >= 4000000) {
> @@ -46,7 +48,7 @@ void __init init_sched_clock(struct clock_data *cd, void (*update)(void),
> }
>
> /* calculate how many ns until we wrap */
> - wrap = cyc_to_ns((1ULL << clock_bits) - 1, cd->mult, cd->shift);
> + wrap = cyc_to_ns(mask, cd->mult, cd->shift);
> do_div(wrap, NSEC_PER_MSEC);
> w = wrap;
>
> @@ -54,6 +56,7 @@ void __init init_sched_clock(struct clock_data *cd, void (*update)(void),
> res = cyc_to_ns(1ULL, cd->mult, cd->shift);
> pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lums\n",
> clock_bits, r, r_unit, res, w);
> + pr_debug("sched_clock: mult=0x%08x shift=%u)\n", cd->mult, cd->shift);
>
> /*
> * Start the timer to keep sched_clock() properly updated and
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
^ permalink raw reply
* [PATCH v4 1/3] ahci_platform: rename module ahci_platform to ahci_platforms
From: Anton Vorontsov @ 2011-01-09 3:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294537775-21714-2-git-send-email-mkl0301@gmail.com>
On Sun, Jan 09, 2011 at 09:49:33AM +0800, mkl0301 at gmail.com wrote:
> From: Mac Lin <mkl0301@gmail.com>
>
> Due to build system limitations, intermediate and final objects can't have the
> same names. And as we're going to start building SoC-specific objects, rename
> ahci_platform to ahci_platforms, into which link ahci_platform and SoC-specific
> objects.
>
> Signed-off-by: Mac Lin <mkl0301@gmail.com>
Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>
Thanks Mac!
> ---
> drivers/ata/Makefile | 4 +++-
> 1 files changed, 3 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
> index 2b67c90..d17bfe7 100644
> --- a/drivers/ata/Makefile
> +++ b/drivers/ata/Makefile
> @@ -3,7 +3,9 @@ obj-$(CONFIG_ATA) += libata.o
>
> # non-SFF interface
> obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o
> -obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
> +obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platforms.o libahci.o
> +ahci_platforms-y += ahci_platform.o
> +
> obj-$(CONFIG_SATA_FSL) += sata_fsl.o
> obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
> obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
> --
> 1.7.3
--
Anton Vorontsov
Email: cbouatmailru at gmail.com
^ permalink raw reply
* [PATCH v4 3/3] ahci_platforms: add support for CNS3xxx SoC devices
From: Anton Vorontsov @ 2011-01-09 3:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294537775-21714-4-git-send-email-mkl0301@gmail.com>
On Sun, Jan 09, 2011 at 09:49:35AM +0800, mkl0301 at gmail.com wrote:
> From: Mac Lin <mkl0301@gmail.com>
>
> CNS3xxx override the softreset function of ahci_platform ahci_softreset by
> cns3xxx_ahci_softreset, which would retry ahci_do_softreset again with pmp=0 if
> pmp=15 failed, for the controller has problem receiving D2H Reg FIS of the
> different PMP setting of the previous sent H2D Reg FIS.
[...]
> Signed-off-by: Mac Lin <mkl0301@gmail.com>
Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>
Thanks!
--
Anton Vorontsov
Email: cbouatmailru at gmail.com
^ permalink raw reply
* [PATCH v4 2/3] ahci_platform: switch to module device table matching
From: Anton Vorontsov @ 2011-01-09 2:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294537775-21714-3-git-send-email-mkl0301@gmail.com>
On Sun, Jan 09, 2011 at 09:49:34AM +0800, mkl0301 at gmail.com wrote:
> From: Mac Lin <mkl0301@gmail.com>
>
> Switch the driver to use module device table matching mechanism to add SoC-specific parts to the generic driver.
>
> Signed-off-by: Mac Lin <mkl0301@gmail.com>
> ---
> drivers/ata/ahci_platform.c | 14 +++++++++++++-
> drivers/ata/ahci_platforms.h | 16 ++++++++++++++++
I think header and .c file names should match. I.e. just
ahci_platform.h.
> 2 files changed, 29 insertions(+), 1 deletions(-)
> create mode 100644 drivers/ata/ahci_platforms.h
>
> diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
> index 6fef1fa..190db2c 100644
> --- a/drivers/ata/ahci_platform.c
> +++ b/drivers/ata/ahci_platform.c
> @@ -19,9 +19,11 @@
> #include <linux/interrupt.h>
> #include <linux/device.h>
> #include <linux/platform_device.h>
> +#include <linux/mod_devicetable.h>
> #include <linux/libata.h>
> #include <linux/ahci_platform.h>
> #include "ahci.h"
> +#include "ahci_platforms.h"
>
> static struct scsi_host_template ahci_platform_sht = {
> AHCI_SHT("ahci_platform"),
> @@ -29,6 +31,7 @@ static struct scsi_host_template ahci_platform_sht = {
>
> static int __init ahci_probe(struct platform_device *pdev)
> {
> + const struct platform_device_id *platid = platform_get_device_id(pdev);
> struct device *dev = &pdev->dev;
> struct ahci_platform_data *pdata = dev->platform_data;
> struct ata_port_info pi = {
> @@ -46,6 +49,9 @@ static int __init ahci_probe(struct platform_device *pdev)
> int i;
> int rc;
>
> + if (!pdata && platid && platid->driver_data)
> + pdata = (void *)platid->driver_data;
> +
> mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> if (!mem) {
> dev_err(dev, "no mmio space\n");
> @@ -171,12 +177,19 @@ static int __devexit ahci_remove(struct platform_device *pdev)
> return 0;
> }
>
> +static const struct platform_device_id ahci_pltfm_ids[] = {
s/pltfm/platform/ to match the rest of the driver.
On the next resend, feel free to add my
Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>
Thanks!
--
Anton Vorontsov
Email: cbouatmailru at gmail.com
^ permalink raw reply
* [PATCH v4 3/3] ahci_platforms: add support for CNS3xxx SoC devices
From: mkl0301 at gmail.com @ 2011-01-09 1:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294537775-21714-1-git-send-email-mkl0301@gmail.com>
From: Mac Lin <mkl0301@gmail.com>
CNS3xxx override the softreset function of ahci_platform ahci_softreset by
cns3xxx_ahci_softreset, which would retry ahci_do_softreset again with pmp=0 if
pmp=15 failed, for the controller has problem receiving D2H Reg FIS of the
different PMP setting of the previous sent H2D Reg FIS.
Following describe the isssue with original ahci_platform driver on
linux-2.6.37-rc3, arm/cns3xxx.
If CONFIG_SATA_PMP is enabled, while not using multiplier and connect the disks
directly to the board, the disk cannot be found due to software reset always
failed.
ahci ahci.0: forcing PORTS_IMPL to 0x3
ahci ahci.0: AHCI 0001.0100 32 slots 2 ports 3 Gbps 0x3 impl platform mode
ahci ahci.0: flags: ncq sntf pm led clo only pmp pio slum part ccc
scsi0 : ahci_platform
scsi1 : ahci_platform
ata1: SATA max UDMA/133 irq_stat 0x00400040, connection status changed irq 65
ata2: SATA max UDMA/133 mmio [mem 0x83000000-0x83ffffff] port 0x180 irq 65
ata2: SATA link down (SStatus 0 SControl 300)
ata1: link is slow to respond, please be patient (ready=0)
ata1: softreset failed (device not ready)
ata1: link is slow to respond, please be patient (ready=0)
ata1: softreset failed (device not ready)
ata1: link is slow to respond, please be patient (ready=0)
ata1: softreset failed (device not ready)
ata1: limiting SATA link speed to 1.5 Gbps
ata1: SATA link down (SStatus 1 SControl 310)
While using multiplier with CONFIG_SATA_PMP enabled, or using disks directly
without CONFIG_SATA_PMP have no issue. It seems the device is sending D2H Reg
FIS, but controller is not reflecting it on any known means.
Signed-off-by: Mac Lin <mkl0301@gmail.com>
---
arch/arm/mach-cns3xxx/devices.c | 2 +-
drivers/ata/Kconfig | 11 ++++++++
drivers/ata/Makefile | 1 +
drivers/ata/ahci_cns3xxx.c | 51 +++++++++++++++++++++++++++++++++++++++
drivers/ata/ahci_platform.c | 3 ++
drivers/ata/ahci_platforms.h | 2 +
6 files changed, 69 insertions(+), 1 deletions(-)
create mode 100644 drivers/ata/ahci_cns3xxx.c
diff --git a/arch/arm/mach-cns3xxx/devices.c b/arch/arm/mach-cns3xxx/devices.c
index 50b4d31..b496f02 100644
--- a/arch/arm/mach-cns3xxx/devices.c
+++ b/arch/arm/mach-cns3xxx/devices.c
@@ -40,7 +40,7 @@ static struct resource cns3xxx_ahci_resource[] = {
static u64 cns3xxx_ahci_dmamask = DMA_BIT_MASK(32);
static struct platform_device cns3xxx_ahci_pdev = {
- .name = "ahci",
+ .name = "ahci-cns3xxx",
.id = 0,
.resource = cns3xxx_ahci_resource,
.num_resources = ARRAY_SIZE(cns3xxx_ahci_resource),
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 36e2319..5d8b1a3 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -75,6 +75,17 @@ config SATA_AHCI_PLATFORM
If unsure, say N.
+config SATA_AHCI_CNS3XXX
+ bool "AHCI Support on the Cavium Networks CNS3xxx SOC"
+ depends on ARCH_CNS3XXX
+ depends on SATA_AHCI_PLATFORM
+ help
+ This option enables AHCI platform driver to support CNS3xxx
+ System-on-Chip devices. This is only needed when using CNS3xxx AHCI
+ controller.
+
+ If unsure, say N.
+
config SATA_FSL
tristate "Freescale 3.0Gbps SATA support"
depends on FSL_SOC
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index d17bfe7..7f2d32e 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_ATA) += libata.o
obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o
obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platforms.o libahci.o
ahci_platforms-y += ahci_platform.o
+ahci_platforms-$(CONFIG_SATA_AHCI_CNS3XXX) += ahci_cns3xxx.o
obj-$(CONFIG_SATA_FSL) += sata_fsl.o
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
diff --git a/drivers/ata/ahci_cns3xxx.c b/drivers/ata/ahci_cns3xxx.c
new file mode 100644
index 0000000..7cc841e
--- /dev/null
+++ b/drivers/ata/ahci_cns3xxx.c
@@ -0,0 +1,51 @@
+/*
+ * AHCI support for CNS3xxx SoC
+ *
+ * Copyright 2010 MontaVista Software, LLC.
+ * Copyright 2010 Cavium Networks
+ *
+ * Authors: Anton Vorontsov <avorontsov@mvista.com>
+ * Mac Lin <mkl0301@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/libata.h>
+#include <linux/ahci_platform.h>
+#include "ahci.h"
+
+/*
+ * TODO: move cns3xxx_ahci_init to here after cns3xxx_pwr*() calls are
+ * thread-safe
+ */
+
+static int cns3xxx_ahci_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ int pmp = sata_srst_pmp(link);
+ int ret;
+
+ ret = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
+ if (pmp && ret)
+ return ahci_do_softreset(link, class, 0, deadline,
+ ahci_check_ready);
+ return ret;
+}
+
+static struct ata_port_operations cns3xxx_ahci_ops = {
+ .inherits = &ahci_ops,
+ .softreset = cns3xxx_ahci_softreset,
+};
+
+static const struct ata_port_info cns3xxx_ata_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &cns3xxx_ahci_ops,
+};
+
+struct ahci_platform_data cns3xxx_ahci_platform_data = {
+ .ata_port_info = &cns3xxx_ata_port_info,
+};
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 190db2c..ad0f921 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -179,6 +179,9 @@ static int __devexit ahci_remove(struct platform_device *pdev)
static const struct platform_device_id ahci_pltfm_ids[] = {
{ "ahci", },
+#ifdef CONFIG_SATA_AHCI_CNS3XXX
+ { "ahci-cns3xxx", (kernel_ulong_t)&cns3xxx_ahci_platform_data},
+#endif
{ },
};
MODULE_DEVICE_TABLE(platform, ahci_pltfm_ids);
diff --git a/drivers/ata/ahci_platforms.h b/drivers/ata/ahci_platforms.h
index cf16e6f..d9ea5ab 100644
--- a/drivers/ata/ahci_platforms.h
+++ b/drivers/ata/ahci_platforms.h
@@ -13,4 +13,6 @@
#ifndef _DRIVERS_SATA_AHCI_PLATFORMS_H
#define _DRIVERS_SATA_AHCI_PLATFORMS_H
+extern struct ahci_platform_data cns3xxx_ahci_platform_data;
+
#endif /*_DRIVERS_SATA_AHCI_PLATFORMS_H*/
--
1.7.3
^ permalink raw reply related
* [PATCH v4 2/3] ahci_platform: switch to module device table matching
From: mkl0301 at gmail.com @ 2011-01-09 1:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294537775-21714-1-git-send-email-mkl0301@gmail.com>
From: Mac Lin <mkl0301@gmail.com>
Switch the driver to use module device table matching mechanism to add SoC-specific parts to the generic driver.
Signed-off-by: Mac Lin <mkl0301@gmail.com>
---
drivers/ata/ahci_platform.c | 14 +++++++++++++-
drivers/ata/ahci_platforms.h | 16 ++++++++++++++++
2 files changed, 29 insertions(+), 1 deletions(-)
create mode 100644 drivers/ata/ahci_platforms.h
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 6fef1fa..190db2c 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -19,9 +19,11 @@
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
#include <linux/libata.h>
#include <linux/ahci_platform.h>
#include "ahci.h"
+#include "ahci_platforms.h"
static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT("ahci_platform"),
@@ -29,6 +31,7 @@ static struct scsi_host_template ahci_platform_sht = {
static int __init ahci_probe(struct platform_device *pdev)
{
+ const struct platform_device_id *platid = platform_get_device_id(pdev);
struct device *dev = &pdev->dev;
struct ahci_platform_data *pdata = dev->platform_data;
struct ata_port_info pi = {
@@ -46,6 +49,9 @@ static int __init ahci_probe(struct platform_device *pdev)
int i;
int rc;
+ if (!pdata && platid && platid->driver_data)
+ pdata = (void *)platid->driver_data;
+
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(dev, "no mmio space\n");
@@ -171,12 +177,19 @@ static int __devexit ahci_remove(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id ahci_pltfm_ids[] = {
+ { "ahci", },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, ahci_pltfm_ids);
+
static struct platform_driver ahci_driver = {
.remove = __devexit_p(ahci_remove),
.driver = {
.name = "ahci",
.owner = THIS_MODULE,
},
+ .id_table = ahci_pltfm_ids,
};
static int __init ahci_init(void)
@@ -194,4 +207,3 @@ module_exit(ahci_exit);
MODULE_DESCRIPTION("AHCI SATA platform driver");
MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:ahci");
diff --git a/drivers/ata/ahci_platforms.h b/drivers/ata/ahci_platforms.h
new file mode 100644
index 0000000..cf16e6f
--- /dev/null
+++ b/drivers/ata/ahci_platforms.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2010 MontaVista Software, LLC.
+ * Copyright 2010 Cavium Networks
+ *
+ * Authors: Anton Vorontsov <avorontsov@mvista.com>
+ * Mac Lin <mkl0301@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _DRIVERS_SATA_AHCI_PLATFORMS_H
+#define _DRIVERS_SATA_AHCI_PLATFORMS_H
+
+#endif /*_DRIVERS_SATA_AHCI_PLATFORMS_H*/
--
1.7.3
^ permalink raw reply related
* [PATCH v4 1/3] ahci_platform: rename module ahci_platform to ahci_platforms
From: mkl0301 at gmail.com @ 2011-01-09 1:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294537775-21714-1-git-send-email-mkl0301@gmail.com>
From: Mac Lin <mkl0301@gmail.com>
Due to build system limitations, intermediate and final objects can't have the
same names. And as we're going to start building SoC-specific objects, rename
ahci_platform to ahci_platforms, into which link ahci_platform and SoC-specific
objects.
Signed-off-by: Mac Lin <mkl0301@gmail.com>
---
drivers/ata/Makefile | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 2b67c90..d17bfe7 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -3,7 +3,9 @@ obj-$(CONFIG_ATA) += libata.o
# non-SFF interface
obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o
-obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
+obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platforms.o libahci.o
+ahci_platforms-y += ahci_platform.o
+
obj-$(CONFIG_SATA_FSL) += sata_fsl.o
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
--
1.7.3
^ permalink raw reply related
* [PATCH v4 0/3] add CNS3xxx AHCI support
From: mkl0301 at gmail.com @ 2011-01-09 1:49 UTC (permalink / raw)
To: linux-arm-kernel
From: Mac Lin <mkl0301@gmail.com>
v4:
- v2 basically, which make SoC-specific changes into separate files
- Rename module ahci_platform to ahci_platforms, into which link the ahci_platform and the SoC-specific changes
- No rename of ahci_platform.c
- Some cosmetic code changes since v2
v3: http://www.spinics.net/lists/arm-kernel/msg109924.html
- Make the SoC-specific changes into ahci_platform.c directly.
- Some cosmetic code changes
=> ahci_platform.c is less readable due to SoC-specific changes and macro
v2: http://www.spinics.net/lists/linux-ide/msg39766.html
- Renaming ahci_platform.c to ahci_pltfm.c for linking SoC specific changes into ahci_platform, while not changing the module name.
- Switch ahci_platform to module device table matching to add SoC specific support
- Add CNS3xxx SoC specific AHCI support to ahci_cns3xxx.c
v1: http://www.spinics.net/lists/arm-kernel/msg106236.html
- Add CNS3xxx SoC specific AHCI support to arch/arm/mach-cns3xxx
=> The changes depends on libahci and libata, i.e. both of them need to be built into kernel
This patchset is based on linux-2.6.37
Mac Lin (3):
ahci_platform: rename module ahci_platform to ahci_platforms
ahci_platform: switch to module device table matching
ahci_platforms: add support for CNS3xxx SoC devices
arch/arm/mach-cns3xxx/devices.c | 2 +-
drivers/ata/Kconfig | 11 ++++++++
drivers/ata/Makefile | 5 +++-
drivers/ata/ahci_cns3xxx.c | 51 +++++++++++++++++++++++++++++++++++++++
drivers/ata/ahci_platform.c | 17 ++++++++++++-
drivers/ata/ahci_platforms.h | 18 +++++++++++++
6 files changed, 101 insertions(+), 3 deletions(-)
create mode 100644 drivers/ata/ahci_cns3xxx.c
create mode 100644 drivers/ata/ahci_platforms.h
^ permalink raw reply
* [RFC PATCH] Avoid aliasing mappings in DMA coherent allocator
From: Janusz Krzysztofik @ 2011-01-09 1:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <201101031928.37091.jkrzyszt@tis.icnet.pl>
(Cc linux-omap, please refere to a copy of Russell's initial message:
http://lists.infradead.org/pipermail/linux-arm-kernel/2010-December/036463.html)
Monday 03 January 2011 19:28:36 Janusz Krzysztofik wrote:
> I'll try to prepare for review a followup patch that updates those
> <{mach,plat}/memory.h> and similiar include files which provided
> their own non-default CONSISTENT_DMA_SIZE values.
Below is an example of how a build time configuration for OMAP could
be updated.
However, more looking at this, I think that a finer control of reserved
memory area sizes, yet better selected at run time for a specific
machine or board type, could be benefitial in case of kernels intended
to run on multiple board types, like those built with omap1_defconfig,
or even on multiple machine types, like in omap2plus_defconfig case.
Signed-off-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
---
--- linux-2.6.37-rc7/arch/arm/plat-omap/include/plat/memory.h.orig 2011-01-07 02:37:44.000000000 +0100
+++ linux-2.6.37-rc7/arch/arm/plat-omap/include/plat/memory.h 2011-01-07 03:01:25.000000000 +0100
@@ -86,17 +86,21 @@
#endif /* CONFIG_ARCH_OMAP15XX */
/* Override the ARM default */
-#ifdef CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE
+#ifndef CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE
+#define CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE 0
+#endif
-#if (CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE == 0)
+#if (CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE == 0) && \
+ (defined(CONFIG_SND_OMAP_SOC) || defined(CONFIG_SND_OMAP_SOC_MODULE))
#undef CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE
-#define CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE 2
+#define CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE 1
#endif
-#define CONSISTENT_DMA_SIZE \
- (((CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE + 1) & ~1) * 1024 * 1024)
+#define CONSISTENT_WC_SIZE \
+ (CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE * 1024 * 1024)
-#endif
+#define CONSISTENT_DMA_SIZE \
+ ((CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE % 2 ? 1 : 2) * 1024 * 1024)
#endif
--- linux-2.6.37-rc7/drivers/video/omap/Kconfig.orig 2010-12-24 13:42:46.000000000 +0100
+++ linux-2.6.37-rc7/drivers/video/omap/Kconfig 2011-01-07 01:56:45.000000000 +0100
@@ -85,9 +85,10 @@ config FB_OMAP_CONSISTENT_DMA_SIZE
range 1 14
default 2
help
- Increase the DMA consistent memory size according to your video
+ Increase the DMA writecombine memory size according to your video
memory needs, for example if you want to use multiple planes.
- The size must be 2MB aligned.
+ Note that 256kB can be consumed by OMAP sound driver if active.
+ Specifying an odd number reduces DMA coherent memory from 2 to 1MB.
If unsure say 1.
config FB_OMAP_DMA_TUNE
^ permalink raw reply
* udelay() broken for SMP cores?
From: Russell King - ARM Linux @ 2011-01-08 23:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20100422001417.GF27575@shareable.org>
On Thu, Apr 22, 2010 at 01:14:17AM +0100, Jamie Lokier wrote:
> Russell King - ARM Linux wrote:
> > Ok, since you seem to have a clear idea how to convert this into a double
> > nested loop, try converting it:
> >
> > @ 0 <= r0 <= 0x7fffff06
> > ldr r2, .LC0 (loops_per_jiffy)
> > ldr r2, [r2] @ max = 0x01ffffff
> > mov r0, r0, lsr #14 @ max = 0x0001ffff
> > mov r2, r2, lsr #10 @ max = 0x00007fff
> > mul r0, r2, r0 @ max = 2^32-1
> > movs r0, r0, lsr #6
> > moveq pc, lr
> > 1: subs r0, r0, #1
> > bhi 1b
> > mov pc, lr
> >
> > into two loops without losing the precision - note that the multiply
> > is part of a 'dividing by multiply+shift' technique.
>
> ldr r2, loops_per_jiffy
> ldr r3, microseconds_per_jiffy
> mov r4, r2
> 1: subs r4, r4, r3
> bhi 1b
> subs r0, r0, #1
> add r4, r4, r2
> bhi 1b
> mov pc, lr
>
> Goodnight :)
I thought I'd dig this out and give it a go - but it has problems. Let's
say usec_per_jiffy is 10000. Initially, loops_per_jiffy is 1<<12 or 4096
at boot.
If udelay() is used prior to calibration (it is - see things like OMAP/8250
console drivers which use udelay(1)), the initial loops_per_jiffy value
will be used.
So, r0 = 10000. r3 = 10000. r2 = 4096.
mov r4, r2 @ r4 := 4096
1: subs r4, r4, r3 @ r4 -= 10000 := -5904
bhi 1b @ not taken
subs r0, r0, #1 @ r0 -= 1 := 9999
add r4, r4, r2 @ r4 += 4096 := -1808 (or 4294965488)
bhi 1b @ taken
That's the first iteration. The next iteration:
1: subs r4, r4, r3 @ r4 -= 10000 := 4294955488
bhi 1b @ taken
1: subs r4, r4, r3 @ r4 -= 10000 := 4294945488
bhi 1b @ taken
... which means we have about 429493 loops to go ...
So this becomes an extremely slow loop - it works when loops_per_jiffy >
usec_per_jiffy.
Even with a value of 8192 (the first tried lpj in the calibration loop),
things eventually go wrong - r4 on each iteration goes -1808, -3616, ..
-9040 and then we're into the problem above - and this will be the case
for anyone with HZ=100.
So, this solution has undesirable behaviours... and this is what I've
come up with - we manually increase the lpj and decrease the required
delay by a power of two until we meet the necessary preconditions
(lpj >= usec/jiffy).
.LC0: .long loops_per_jiffy
.long (1000000 + (HZ / 2))/HZ
ENTRY(__delay)
ldr r3, .LC0 + 4 @ usec/jiffy
mov r2, r0
mov r0, r3
b 2f
ENTRY(__udelay)
ldr r2, .LC0
ldr r3, .LC0 + 4 @ usec/jiffy
ldr r2, [r2] @ lpj
2: cmp r2, r3
movcc r2, r2, lsl #1
movcc r0, r0, lsr #1
bcc 2b
mov ip, r2
1: subs ip, ip, r3
addls ip, ip, r2
sublss r0, r0, #2
bhi 1b
mov pc, lr
Note that I've also tweaked the loop a little to make the cycle count
(in theory) around the loop the same no matter what it does.
This way, I get the same lpj calibration value as the old way - which is
good as with the old way, we were calibrating just this loop:
1: subs r0, r0, #1
bhi 1b
mov pc, lr
where r0 = lpj and the target delay time was 1 jiffy.
Now, what sparked this off was:
> > We could go to ns delays, but then we have a big problem - the cost of
> > calculating the number of loops starts to become significant compared to
> > the delays - and that's a quality of implementation factor. In fact,
> > the existing cost has always been significant for short delays for
> > slower (sub-100MHz) ARMs.
>
> I'm surprised it makes much difference to, say, 20MHz ARMs because you
> could structure it as a nested loop, the inner one executed once per
> microsecond and calibrated to 1us. The delays don't have to be super
> accurate.
With this nested loop approach we can't go to ns resolution.
nsec_per_jiffy would be 10000000, and with an initial loops_per_jiffy
of 4096 or 8192, this would be extremely bad.
That said, I do think your approach has merit - especially as we're
now seeing CPUs in the 2000 BogoMips range, and our existing solution
goes bad at 3355 BogoMips. As the board I have is something like 8
months old we've probably got what, 10 months left according to Moore's
law?
^ permalink raw reply
* still nfs problems [Was: Linux 2.6.37-rc8]
From: Trond Myklebust @ 2011-01-08 23:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294505384.4181.14.camel@heimdal.trondhjem.org>
On Sat, 2011-01-08 at 11:49 -0500, Trond Myklebust wrote:
> On Fri, 2011-01-07 at 13:11 -0600, James Bottomley wrote:
> > On the other hand, the xdr routines, since they take the pages anyway,
> > could use a scatterlist approach to writing through the kernel mapping
> > instead of using vmap ... we have all the machinery for this in
> > lib/scatterlist.c ... it's not designed for this case, since it's
> > designed to allow arbitrary linear reads and writes on a block
> > scatterlist, but the principle is the same ... it looks like it would be
> > rather a big patch, though ...
>
> The following alternative seems to work for me, but has only been
> lightly tested so far. It's a bit large for a stable patch, but not too
> ungainly.
>
> It modifies xdr_stream, adding the ability to iterate through page data.
> To avoid kmap()/kunmap(), it does require that pages be allocated in
> lowmem, but since the only use case here is when using page arrays as
> temporary buffers, that seems like an acceptable compromise.
...and here is an update which makes the whole process transparent to
the decoder. It basically teaches xdr_inline_decode() how to switch
buffers when it hits the end of the current iovec and/or page.
Cheers
Trond
-----------------------------------------------------------------------------------
>From 8b2e60cef5c65eef41ab61286f62dec6bfb1ac27 Mon Sep 17 00:00:00 2001
From: Trond Myklebust <Trond.Myklebust@netapp.com>
Date: Sat, 8 Jan 2011 17:45:38 -0500
Subject: [PATCH] NFS: Don't use vm_map_ram() in readdir
vm_map_ram() is not available on NOMMU platforms, and causes trouble
on incoherrent architectures such as ARM when we access the page data
through both the direct and the virtual mapping.
The alternative is to use the direct mapping to access page data
for the case when we are not crossing a page boundary, but to copy
the data into a linear scratch buffer when we are accessing data
that spans page boundaries.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
---
fs/nfs/dir.c | 44 ++++++-------
fs/nfs/nfs2xdr.c | 6 --
fs/nfs/nfs3xdr.c | 6 --
fs/nfs/nfs4xdr.c | 6 --
include/linux/sunrpc/xdr.h | 4 +-
net/sunrpc/xdr.c | 155 +++++++++++++++++++++++++++++++++++---------
6 files changed, 148 insertions(+), 73 deletions(-)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 996dd89..0108cf4 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -33,7 +33,6 @@
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/sched.h>
-#include <linux/vmalloc.h>
#include <linux/kmemleak.h>
#include "delegation.h"
@@ -459,25 +458,26 @@ out:
/* Perform conversion from xdr to cache array */
static
int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry,
- void *xdr_page, struct page *page, unsigned int buflen)
+ struct page **xdr_pages, struct page *page, unsigned int buflen)
{
struct xdr_stream stream;
- struct xdr_buf buf;
- __be32 *ptr = xdr_page;
+ struct xdr_buf buf = {
+ .pages = xdr_pages,
+ .page_len = buflen,
+ .buflen = buflen,
+ .len = buflen,
+ };
+ struct page *scratch;
struct nfs_cache_array *array;
unsigned int count = 0;
int status;
- buf.head->iov_base = xdr_page;
- buf.head->iov_len = buflen;
- buf.tail->iov_len = 0;
- buf.page_base = 0;
- buf.page_len = 0;
- buf.buflen = buf.head->iov_len;
- buf.len = buf.head->iov_len;
-
- xdr_init_decode(&stream, &buf, ptr);
+ scratch = alloc_page(GFP_KERNEL);
+ if (scratch == NULL)
+ return -ENOMEM;
+ xdr_init_decode(&stream, &buf, NULL);
+ xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
do {
status = xdr_decode(desc, entry, &stream);
@@ -506,6 +506,8 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
} else
status = PTR_ERR(array);
}
+
+ put_page(scratch);
return status;
}
@@ -521,7 +523,6 @@ static
void nfs_readdir_free_large_page(void *ptr, struct page **pages,
unsigned int npages)
{
- vm_unmap_ram(ptr, npages);
nfs_readdir_free_pagearray(pages, npages);
}
@@ -530,9 +531,8 @@ void nfs_readdir_free_large_page(void *ptr, struct page **pages,
* to nfs_readdir_free_large_page
*/
static
-void *nfs_readdir_large_page(struct page **pages, unsigned int npages)
+int nfs_readdir_large_page(struct page **pages, unsigned int npages)
{
- void *ptr;
unsigned int i;
for (i = 0; i < npages; i++) {
@@ -541,13 +541,11 @@ void *nfs_readdir_large_page(struct page **pages, unsigned int npages)
goto out_freepages;
pages[i] = page;
}
+ return 0;
- ptr = vm_map_ram(pages, npages, 0, PAGE_KERNEL);
- if (!IS_ERR_OR_NULL(ptr))
- return ptr;
out_freepages:
nfs_readdir_free_pagearray(pages, i);
- return NULL;
+ return -ENOMEM;
}
static
@@ -577,8 +575,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
memset(array, 0, sizeof(struct nfs_cache_array));
array->eof_index = -1;
- pages_ptr = nfs_readdir_large_page(pages, array_size);
- if (!pages_ptr)
+ status = nfs_readdir_large_page(pages, array_size);
+ if (status < 0)
goto out_release_array;
do {
unsigned int pglen;
@@ -587,7 +585,7 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
if (status < 0)
break;
pglen = status;
- status = nfs_readdir_page_filler(desc, &entry, pages_ptr, page, pglen);
+ status = nfs_readdir_page_filler(desc, &entry, pages, page, pglen);
if (status < 0) {
if (status == -ENOSPC)
status = 0;
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 5914a19..b382a1b 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -487,12 +487,6 @@ nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_se
entry->d_type = DT_UNKNOWN;
- p = xdr_inline_peek(xdr, 8);
- if (p != NULL)
- entry->eof = !p[0] && p[1];
- else
- entry->eof = 0;
-
return p;
out_overflow:
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index f6cc60f..ba91236 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -647,12 +647,6 @@ nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_s
memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
}
- p = xdr_inline_peek(xdr, 8);
- if (p != NULL)
- entry->eof = !p[0] && p[1];
- else
- entry->eof = 0;
-
return p;
out_overflow:
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 9f1826b..0662a98 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -6215,12 +6215,6 @@ __be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
if (verify_attr_len(xdr, p, len) < 0)
goto out_overflow;
- p = xdr_inline_peek(xdr, 8);
- if (p != NULL)
- entry->eof = !p[0] && p[1];
- else
- entry->eof = 0;
-
return p;
out_overflow:
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index 498ab93..7783c68 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -201,6 +201,8 @@ struct xdr_stream {
__be32 *end; /* end of available buffer space */
struct kvec *iov; /* pointer to the current kvec */
+ struct kvec scratch; /* Scratch buffer */
+ struct page **page_ptr; /* pointer to the current page */
};
extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
@@ -208,7 +210,7 @@ extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
unsigned int base, unsigned int len);
extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
-extern __be32 *xdr_inline_peek(struct xdr_stream *xdr, size_t nbytes);
+extern void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen);
extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index cd9e841..679cd67 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -552,6 +552,74 @@ void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int b
}
EXPORT_SYMBOL_GPL(xdr_write_pages);
+static void xdr_set_iov(struct xdr_stream *xdr, struct kvec *iov,
+ __be32 *p, unsigned int len)
+{
+ if (len > iov->iov_len)
+ len = iov->iov_len;
+ if (p == NULL)
+ p = (__be32*)iov->iov_base;
+ xdr->p = p;
+ xdr->end = (__be32*)(iov->iov_base + len);
+ xdr->iov = iov;
+ xdr->page_ptr = NULL;
+}
+
+static int xdr_set_page_base(struct xdr_stream *xdr,
+ unsigned int base, unsigned int len)
+{
+ unsigned int pgnr;
+ unsigned int maxlen;
+ unsigned int pgoff;
+ unsigned int pgend;
+ void *kaddr;
+
+ maxlen = xdr->buf->page_len;
+ if (base >= maxlen)
+ return -EINVAL;
+ maxlen -= base;
+ if (len > maxlen)
+ len = maxlen;
+
+ base += xdr->buf->page_base;
+
+ pgnr = base >> PAGE_SHIFT;
+ xdr->page_ptr = &xdr->buf->pages[pgnr];
+ kaddr = page_address(*xdr->page_ptr);
+
+ pgoff = base & ~PAGE_MASK;
+ xdr->p = (__be32*)(kaddr + pgoff);
+
+ pgend = pgoff + len;
+ if (pgend > PAGE_SIZE)
+ pgend = PAGE_SIZE;
+ xdr->end = (__be32*)(kaddr + pgend);
+ xdr->iov = NULL;
+ return 0;
+}
+
+static void xdr_set_next_page(struct xdr_stream *xdr)
+{
+ unsigned int newbase;
+
+ newbase = (1 + xdr->page_ptr - xdr->buf->pages) << PAGE_SHIFT;
+ newbase -= xdr->buf->page_base;
+
+ if (xdr_set_page_base(xdr, newbase, PAGE_SIZE) < 0)
+ xdr_set_iov(xdr, xdr->buf->tail, NULL, xdr->buf->len);
+}
+
+static bool xdr_set_next_buffer(struct xdr_stream *xdr)
+{
+ if (xdr->page_ptr != NULL)
+ xdr_set_next_page(xdr);
+ else if (xdr->iov == xdr->buf->head) {
+ if (xdr_set_page_base(xdr, 0, PAGE_SIZE) < 0)
+ xdr_set_iov(xdr, xdr->buf->tail, NULL, xdr->buf->len);
+ }
+ return xdr->p != xdr->end;
+}
+
/**
* xdr_init_decode - Initialize an xdr_stream for decoding data.
* @xdr: pointer to xdr_stream struct
@@ -560,41 +628,67 @@ EXPORT_SYMBOL_GPL(xdr_write_pages);
*/
void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
{
- struct kvec *iov = buf->head;
- unsigned int len = iov->iov_len;
-
- if (len > buf->len)
- len = buf->len;
xdr->buf = buf;
- xdr->iov = iov;
- xdr->p = p;
- xdr->end = (__be32 *)((char *)iov->iov_base + len);
+ xdr->scratch.iov_base = NULL;
+ xdr->scratch.iov_len = 0;
+ if (buf->head[0].iov_len != 0)
+ xdr_set_iov(xdr, buf->head, p, buf->len);
+ else if (buf->page_len != 0)
+ xdr_set_page_base(xdr, 0, buf->len);
}
EXPORT_SYMBOL_GPL(xdr_init_decode);
-/**
- * xdr_inline_peek - Allow read-ahead in the XDR data stream
- * @xdr: pointer to xdr_stream struct
- * @nbytes: number of bytes of data to decode
- *
- * Check if the input buffer is long enough to enable us to decode
- * 'nbytes' more bytes of data starting at the current position.
- * If so return the current pointer without updating the current
- * pointer position.
- */
-__be32 * xdr_inline_peek(struct xdr_stream *xdr, size_t nbytes)
+static __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
{
__be32 *p = xdr->p;
__be32 *q = p + XDR_QUADLEN(nbytes);
if (unlikely(q > xdr->end || q < p))
return NULL;
+ xdr->p = q;
return p;
}
-EXPORT_SYMBOL_GPL(xdr_inline_peek);
/**
- * xdr_inline_decode - Retrieve non-page XDR data to decode
+ * xdr_set_scratch_buffer - Attach a scratch buffer for decoding data.
+ * @xdr: pointer to xdr_stream struct
+ * @buf: pointer to an empty buffer
+ * @buflen: size of 'buf'
+ *
+ * The scratch buffer is used when decoding from an array of pages.
+ * If an xdr_inline_decode() call spans across page boundaries, then
+ * we copy the data into the scratch buffer in order to allow linear
+ * access.
+ */
+void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen)
+{
+ xdr->scratch.iov_base = buf;
+ xdr->scratch.iov_len = buflen;
+}
+EXPORT_SYMBOL_GPL(xdr_set_scratch_buffer);
+
+static __be32 *xdr_copy_to_scratch(struct xdr_stream *xdr, size_t nbytes)
+{
+ __be32 *p;
+ void *cpdest = xdr->scratch.iov_base;
+ size_t cplen = (char *)xdr->end - (char *)xdr->p;
+
+ if (nbytes > xdr->scratch.iov_len)
+ return NULL;
+ memcpy(cpdest, xdr->p, cplen);
+ cpdest += cplen;
+ nbytes -= cplen;
+ if (!xdr_set_next_buffer(xdr))
+ return NULL;
+ p = __xdr_inline_decode(xdr, nbytes);
+ if (p == NULL)
+ return NULL;
+ memcpy(cpdest, p, nbytes);
+ return xdr->scratch.iov_base;
+}
+
+/**
+ * xdr_inline_decode - Retrieve XDR data to decode
* @xdr: pointer to xdr_stream struct
* @nbytes: number of bytes of data to decode
*
@@ -605,13 +699,16 @@ EXPORT_SYMBOL_GPL(xdr_inline_peek);
*/
__be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
{
- __be32 *p = xdr->p;
- __be32 *q = p + XDR_QUADLEN(nbytes);
+ __be32 *p;
- if (unlikely(q > xdr->end || q < p))
+ if (nbytes == 0)
+ return xdr->p;
+ if (xdr->p == xdr->end && !xdr_set_next_buffer(xdr))
return NULL;
- xdr->p = q;
- return p;
+ p = __xdr_inline_decode(xdr, nbytes);
+ if (p != NULL)
+ return p;
+ return xdr_copy_to_scratch(xdr, nbytes);
}
EXPORT_SYMBOL_GPL(xdr_inline_decode);
@@ -671,16 +768,12 @@ EXPORT_SYMBOL_GPL(xdr_read_pages);
*/
void xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
{
- char * kaddr = page_address(xdr->buf->pages[0]);
xdr_read_pages(xdr, len);
/*
* Position current pointer at beginning of tail, and
* set remaining message length.
*/
- if (len > PAGE_CACHE_SIZE - xdr->buf->page_base)
- len = PAGE_CACHE_SIZE - xdr->buf->page_base;
- xdr->p = (__be32 *)(kaddr + xdr->buf->page_base);
- xdr->end = (__be32 *)((char *)xdr->p + len);
+ xdr_set_page_base(xdr, 0, len);
}
EXPORT_SYMBOL_GPL(xdr_enter_page);
--
1.7.3.4
--
Trond Myklebust
Linux NFS client maintainer
NetApp
Trond.Myklebust at netapp.com
www.netapp.com
^ permalink raw reply related
* [PATCH] ep93xx: add framebuffer support to edb93xx boards
From: Martin Guy @ 2011-01-08 19:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <0D753D10438DA54287A00B027084269764C41240B9@AUSP01VMBX24.collaborationhost.net>
On Fri, Jan 7, 2011 at 11:38 PM, H Hartley Sweeten
<hartleys@visionengravers.com> wrote:
> The ep9307, ep9312, and ep9315 variants of the ep93xx processor include the
> raster engine needed for framebuffer support.
>
> This allows the EDB93xx boards with those processors to use the framebuffer
> driver.
>
> Tested on an EDB9307A with the following kernel parameters:
> ? ? ? ?video=640x480-16 at 60
> ? ? ? ?video=1024x768-16 at 60
>
> Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
The code looks good, but there are hardware bugs in the EP93XX that
make the screen image jump a few pixels to the right once every few
seconds. We found that 800x600-16 and 1024x768-8 were the highest
modes that are stable.
Did you find 1024x768-16 to be stable, say when running X and moving a
window? The effect was most visible on a phosphor CRT, less noticeable
on an LCD.
M
^ permalink raw reply
* [PATCH 1/6] i2c-pxa: move i2c_pxa_remove to __devexit instead of just __exit
From: Ben Dooks @ 2011-01-08 17:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294193110-23958-1-git-send-email-dbaryshkov@gmail.com>
On 05/01/11 02:05, Dmitry Eremin-Solenikov wrote:
> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
> Cc: linux-i2c at vger.kernel.org
> Cc: Ben Dooks <ben-linux@fluff.org>
> ---
this should be queued, and probably sent to Linus
at the end of the weekend.
^ permalink raw reply
* still nfs problems [Was: Linux 2.6.37-rc8]
From: Trond Myklebust @ 2011-01-08 16:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294427467.4895.66.camel@mulgrave.site>
On Fri, 2011-01-07 at 13:11 -0600, James Bottomley wrote:
> On the other hand, the xdr routines, since they take the pages anyway,
> could use a scatterlist approach to writing through the kernel mapping
> instead of using vmap ... we have all the machinery for this in
> lib/scatterlist.c ... it's not designed for this case, since it's
> designed to allow arbitrary linear reads and writes on a block
> scatterlist, but the principle is the same ... it looks like it would be
> rather a big patch, though ...
The following alternative seems to work for me, but has only been
lightly tested so far. It's a bit large for a stable patch, but not too
ungainly.
It modifies xdr_stream, adding the ability to iterate through page data.
To avoid kmap()/kunmap(), it does require that pages be allocated in
lowmem, but since the only use case here is when using page arrays as
temporary buffers, that seems like an acceptable compromise.
Cheers
Trond
---------------------------------------------------------------------------------
>From f87f13e3198ec536c1b9cfe19ad47df4fb922382 Mon Sep 17 00:00:00 2001
From: Trond Myklebust <Trond.Myklebust@netapp.com>
Date: Fri, 7 Jan 2011 18:51:33 -0500
Subject: [PATCH] NFS: Don't use vm_map_ram() in readdir
vm_map_ram() is not available on NOMMU platforms, and causes trouble
on incoherrent architectures such as ARM when we access the page data
through both the direct and the virtual mapping.
The alternative is to use the direct mapping to access page data
for the case when we are not crossing a page boundary, but to copy
the data into a linear scratch buffer when we are accessing data
that spans page boundaries.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
---
fs/nfs/dir.c | 45 ++++++++---------
fs/nfs/nfs2xdr.c | 6 --
fs/nfs/nfs3xdr.c | 6 --
fs/nfs/nfs4xdr.c | 6 --
include/linux/sunrpc/xdr.h | 4 +-
net/sunrpc/xdr.c | 115 ++++++++++++++++++++++++++++++++++++--------
6 files changed, 120 insertions(+), 62 deletions(-)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 996dd89..ad9e5e0 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -33,7 +33,6 @@
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/sched.h>
-#include <linux/vmalloc.h>
#include <linux/kmemleak.h>
#include "delegation.h"
@@ -459,25 +458,27 @@ out:
/* Perform conversion from xdr to cache array */
static
int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry,
- void *xdr_page, struct page *page, unsigned int buflen)
+ struct page **xdr_pages, struct page *page, unsigned int buflen)
{
struct xdr_stream stream;
- struct xdr_buf buf;
- __be32 *ptr = xdr_page;
+ struct xdr_buf buf = {
+ .pages = xdr_pages,
+ .page_len = buflen,
+ .buflen = buflen,
+ .len = buflen,
+ };
struct nfs_cache_array *array;
unsigned int count = 0;
+ struct page *scratch;
int status;
- buf.head->iov_base = xdr_page;
- buf.head->iov_len = buflen;
- buf.tail->iov_len = 0;
- buf.page_base = 0;
- buf.page_len = 0;
- buf.buflen = buf.head->iov_len;
- buf.len = buf.head->iov_len;
-
- xdr_init_decode(&stream, &buf, ptr);
+ scratch = alloc_page(GFP_KERNEL);
+ if (scratch == NULL)
+ return -ENOMEM;
+ xdr_init_decode(&stream, &buf, NULL);
+ xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
+ xdr_enter_page(&stream, buflen);
do {
status = xdr_decode(desc, entry, &stream);
@@ -506,6 +507,8 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
} else
status = PTR_ERR(array);
}
+
+ put_page(scratch);
return status;
}
@@ -521,7 +524,6 @@ static
void nfs_readdir_free_large_page(void *ptr, struct page **pages,
unsigned int npages)
{
- vm_unmap_ram(ptr, npages);
nfs_readdir_free_pagearray(pages, npages);
}
@@ -530,9 +532,8 @@ void nfs_readdir_free_large_page(void *ptr, struct page **pages,
* to nfs_readdir_free_large_page
*/
static
-void *nfs_readdir_large_page(struct page **pages, unsigned int npages)
+int nfs_readdir_large_page(struct page **pages, unsigned int npages)
{
- void *ptr;
unsigned int i;
for (i = 0; i < npages; i++) {
@@ -541,13 +542,11 @@ void *nfs_readdir_large_page(struct page **pages, unsigned int npages)
goto out_freepages;
pages[i] = page;
}
+ return 0;
- ptr = vm_map_ram(pages, npages, 0, PAGE_KERNEL);
- if (!IS_ERR_OR_NULL(ptr))
- return ptr;
out_freepages:
nfs_readdir_free_pagearray(pages, i);
- return NULL;
+ return -ENOMEM;
}
static
@@ -577,8 +576,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
memset(array, 0, sizeof(struct nfs_cache_array));
array->eof_index = -1;
- pages_ptr = nfs_readdir_large_page(pages, array_size);
- if (!pages_ptr)
+ status = nfs_readdir_large_page(pages, array_size);
+ if (status < 0)
goto out_release_array;
do {
unsigned int pglen;
@@ -587,7 +586,7 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
if (status < 0)
break;
pglen = status;
- status = nfs_readdir_page_filler(desc, &entry, pages_ptr, page, pglen);
+ status = nfs_readdir_page_filler(desc, &entry, pages, page, pglen);
if (status < 0) {
if (status == -ENOSPC)
status = 0;
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 5914a19..b382a1b 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -487,12 +487,6 @@ nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_se
entry->d_type = DT_UNKNOWN;
- p = xdr_inline_peek(xdr, 8);
- if (p != NULL)
- entry->eof = !p[0] && p[1];
- else
- entry->eof = 0;
-
return p;
out_overflow:
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index f6cc60f..ba91236 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -647,12 +647,6 @@ nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_s
memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
}
- p = xdr_inline_peek(xdr, 8);
- if (p != NULL)
- entry->eof = !p[0] && p[1];
- else
- entry->eof = 0;
-
return p;
out_overflow:
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 9f1826b..0662a98 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -6215,12 +6215,6 @@ __be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
if (verify_attr_len(xdr, p, len) < 0)
goto out_overflow;
- p = xdr_inline_peek(xdr, 8);
- if (p != NULL)
- entry->eof = !p[0] && p[1];
- else
- entry->eof = 0;
-
return p;
out_overflow:
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index 498ab93..7783c68 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -201,6 +201,8 @@ struct xdr_stream {
__be32 *end; /* end of available buffer space */
struct kvec *iov; /* pointer to the current kvec */
+ struct kvec scratch; /* Scratch buffer */
+ struct page **page_ptr; /* pointer to the current page */
};
extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
@@ -208,7 +210,7 @@ extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
unsigned int base, unsigned int len);
extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
-extern __be32 *xdr_inline_peek(struct xdr_stream *xdr, size_t nbytes);
+extern void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen);
extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index cd9e841..cff0974 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -569,29 +569,112 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
xdr->iov = iov;
xdr->p = p;
xdr->end = (__be32 *)((char *)iov->iov_base + len);
+ xdr->page_ptr = NULL;
+ xdr->scratch.iov_base = NULL;
+ xdr->scratch.iov_len = 0;
}
EXPORT_SYMBOL_GPL(xdr_init_decode);
/**
- * xdr_inline_peek - Allow read-ahead in the XDR data stream
+ * xdr_set_scratch_buffer - Attach a scratch buffer for decoding data.
* @xdr: pointer to xdr_stream struct
- * @nbytes: number of bytes of data to decode
+ * @buf: pointer to an empty buffer
+ * @buflen: size of 'buf'
*
- * Check if the input buffer is long enough to enable us to decode
- * 'nbytes' more bytes of data starting at the current position.
- * If so return the current pointer without updating the current
- * pointer position.
+ * The scratch buffer is used when decoding from an array of pages.
+ * If an xdr_inline_decode() call spans across page boundaries, then
+ * we copy the data into the scratch buffer in order to allow linear
+ * access.
*/
-__be32 * xdr_inline_peek(struct xdr_stream *xdr, size_t nbytes)
+void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen)
+{
+ xdr->scratch.iov_base = buf;
+ xdr->scratch.iov_len = buflen;
+}
+EXPORT_SYMBOL_GPL(xdr_set_scratch_buffer);
+
+static int xdr_set_page_base(struct xdr_stream *xdr,
+ unsigned int base, unsigned int len)
+{
+ unsigned int pgnr;
+ unsigned int maxlen;
+ unsigned int pgoff;
+ unsigned int pgend;
+ void *kaddr;
+
+ maxlen = xdr->buf->page_len;
+ if (base >= maxlen)
+ return -EINVAL;
+ maxlen -= base;
+
+ if (len > maxlen)
+ len = maxlen;
+
+ base += xdr->buf->page_base;
+
+ pgnr = base >> PAGE_SHIFT;
+ xdr->page_ptr = &xdr->buf->pages[pgnr];
+ kaddr = page_address(*xdr->page_ptr);
+
+ pgoff = base & ~PAGE_MASK;
+ xdr->p = (__be32*)(kaddr + pgoff);
+
+ pgend = pgoff + len;
+ if (pgend > PAGE_SIZE)
+ pgend = PAGE_SIZE;
+ xdr->end = (__be32*)(kaddr + pgend);
+ return 0;
+}
+
+static int xdr_set_next_page(struct xdr_stream *xdr)
+{
+ unsigned int newbase;
+
+ newbase = (1 + xdr->page_ptr - xdr->buf->pages) << PAGE_SHIFT;
+ newbase -= xdr->buf->page_base;
+
+ return xdr_set_page_base(xdr, newbase, PAGE_SIZE);
+}
+
+static __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
{
__be32 *p = xdr->p;
__be32 *q = p + XDR_QUADLEN(nbytes);
if (unlikely(q > xdr->end || q < p))
return NULL;
+ xdr->p = q;
return p;
}
-EXPORT_SYMBOL_GPL(xdr_inline_peek);
+
+static __be32 *xdr_page_inline_decode(struct xdr_stream *xdr, size_t nbytes)
+{
+ size_t cplen;
+ void *cpdest;
+ __be32 *p;
+
+ if (xdr->p == xdr->end && xdr_set_next_page(xdr) < 0)
+ return NULL;
+
+ p = __xdr_inline_decode(xdr, nbytes);
+ if (p != NULL)
+ return p;
+
+ if (nbytes > xdr->scratch.iov_len)
+ return NULL;
+ cplen = (char *)xdr->end - (char *)xdr->p;
+ cpdest = xdr->scratch.iov_base;
+ memcpy(cpdest, xdr->p, cplen);
+ cpdest += cplen;
+ nbytes -= cplen;
+ if (xdr_set_next_page(xdr) < 0)
+ return NULL;
+ p = __xdr_inline_decode(xdr, nbytes);
+ if (p == NULL)
+ return NULL;
+ memcpy(cpdest, p, nbytes);
+ return xdr->scratch.iov_base;
+}
/**
* xdr_inline_decode - Retrieve non-page XDR data to decode
@@ -605,13 +688,9 @@ EXPORT_SYMBOL_GPL(xdr_inline_peek);
*/
__be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
{
- __be32 *p = xdr->p;
- __be32 *q = p + XDR_QUADLEN(nbytes);
-
- if (unlikely(q > xdr->end || q < p))
- return NULL;
- xdr->p = q;
- return p;
+ if (xdr->page_ptr == NULL)
+ return __xdr_inline_decode(xdr, nbytes);
+ return xdr_page_inline_decode(xdr, nbytes);
}
EXPORT_SYMBOL_GPL(xdr_inline_decode);
@@ -671,16 +750,12 @@ EXPORT_SYMBOL_GPL(xdr_read_pages);
*/
void xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
{
- char * kaddr = page_address(xdr->buf->pages[0]);
xdr_read_pages(xdr, len);
/*
* Position current pointer at beginning of tail, and
* set remaining message length.
*/
- if (len > PAGE_CACHE_SIZE - xdr->buf->page_base)
- len = PAGE_CACHE_SIZE - xdr->buf->page_base;
- xdr->p = (__be32 *)(kaddr + xdr->buf->page_base);
- xdr->end = (__be32 *)((char *)xdr->p + len);
+ xdr_set_page_base(xdr, 0, len);
}
EXPORT_SYMBOL_GPL(xdr_enter_page);
--
1.7.3.4
--
Trond Myklebust
Linux NFS client maintainer
NetApp
Trond.Myklebust at netapp.com
www.netapp.com
^ permalink raw reply related
* [PATCH] i2c-pxa: fix unbinding/rebinding of the device
From: Uwe Kleine-König @ 2011-01-08 16:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294502804-6580-1-git-send-email-dbaryshkov@gmail.com>
On Sat, Jan 08, 2011 at 07:06:44PM +0300, Dmitry Eremin-Solenikov wrote:
> When a "pxa2xx-i2c" device was unbound (e.g. via sysfs) the remove
> callback was not called because it was discarded when linking the
> kernel. Because of that the resources allocated in probe were not
> freed and so a clean unbind/rebind was impossible.
>
> Fix that by moving the remove callback to .devexit.text.
>
> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Acked-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
Thanks
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* [PATCH] i2c-pxa: fix unbinding/rebinding of the device
From: Dmitry Eremin-Solenikov @ 2011-01-08 16:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110106124028.GX25121@pengutronix.de>
When a "pxa2xx-i2c" device was unbound (e.g. via sysfs) the remove
callback was not called because it was discarded when linking the
kernel. Because of that the resources allocated in probe were not
freed and so a clean unbind/rebind was impossible.
Fix that by moving the remove callback to .devexit.text.
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Cc: linux-i2c at vger.kernel.org
Cc: Ben Dooks <ben-linux@fluff.org>
---
drivers/i2c/busses/i2c-pxa.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index f4c19a9..0f10955 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -1115,7 +1115,7 @@ emalloc:
return ret;
}
-static int __exit i2c_pxa_remove(struct platform_device *dev)
+static int __devexit i2c_pxa_remove(struct platform_device *dev)
{
struct pxa_i2c *i2c = platform_get_drvdata(dev);
@@ -1169,7 +1169,7 @@ static const struct dev_pm_ops i2c_pxa_dev_pm_ops = {
static struct platform_driver i2c_pxa_driver = {
.probe = i2c_pxa_probe,
- .remove = __exit_p(i2c_pxa_remove),
+ .remove = __devexit_p(i2c_pxa_remove),
.driver = {
.name = "pxa2xx-i2c",
.owner = THIS_MODULE,
--
1.7.2.3
^ permalink raw reply related
* [PATCH 1/2] Add a common struct clk
From: Sascha Hauer @ 2011-01-08 13:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1294199462.348449.192344022926.1.gpush@pororo>
Hi Jeremy,
On Wed, Jan 05, 2011 at 11:51:02AM +0800, Jeremy Kerr wrote:
> We currently have ~21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
>
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, containing a set of clock operations. Different
> clock implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
>
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
>
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
>
> struct clk {
> const struct clk_ops *ops;
> unsigned int enable_count;
> int flags;
> union {
> struct mutex mutex;
> spinlock_t spinlock;
> } lock;
> };
I'm currently thinking about how to get the locking right with this
approach. In the current i.MX implementation we have a global lock which
protects the clock enable counter and also the register accesses in the
clock code. With the common struct clock we have a lock per clock which
only protects the enable counter, so we have to introduce a second lock
to protect the register accesses.
The problem comes with nested calls to for example clk_enable which
happens when the parent clock gets enabled. currently we do this with
clk->enable(clk->parent) which results in an unlocked clk_enable of the
parent. With common struct clk we would have to call
clk_enable(clk_get_parent(clk) which results in taking the lock a second
time.
Any ideas how to solve this?
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* [PATCH] [ARM] orion5x: accelerate NAND on the TS-78xx
From: Alexander Clouter @ 2011-01-08 12:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <o7qev7-2en.ln1@chipmunk.wormnet.eu>
Alexander Clouter <alex@digriz.org.uk> wrote:
>>
>> On Tue, Jan 04, 2011 at 11:51:59PM +0000, Alexander Clouter wrote:
>>> The NAND supports 32bit reads and writes so lets stop shunting 8bit
>>> chunks across the bus.
>>>
>>> Doing a dumb 'dd' benchmark, this increases performance roughly like so:
>>> * read: 1.3MB/s to 3.4MB/s
>>> * write: 614kB/s to 882kB/s
>>
>> Try something like the below. It's slightly more typing, but the
>> underlying string IO functions should improve your transfer speed.
>> Note that they won't do endian conversions.
>>
> I get roughly the same speeds with your approach...I am happy to swing
> either your way or my original implementation; well actually it was
> stolen from Nico's orion_nand implementation :)
>
> What should I submit? These functions will at somestage get DMA support
> added.
>
I decided I prefer your version and it 'hides' the while loops and is
easier to read.
Cheers
--
Alexander Clouter
.sigmonster says: What!? Me worry?
-- Alfred E. Newman
^ permalink raw reply
* [PATCHv2] [ARM] orion5x: accelerate NAND on the TS-78xx
From: Alexander Clouter @ 2011-01-08 11:55 UTC (permalink / raw)
To: linux-arm-kernel
The NAND supports 32bit reads and writes so lets stop shunting 8bit
chunks across the bus.
Doing a dumb 'dd' benchmark, this increases performance roughly like so:
* read: 1.3MB/s to 3.4MB/s
* write: 614kB/s to 882kB/s
Changelog:
v2: used approach suggested by Russell King instead
<20110105003316.GJ24935@n2100.arm.linux.org.uk>
v1: initial release <20110104235158.GQ12386@chipmunk>
Signed-off-by: Alexander Clouter <alex@digriz.org.uk>
---
arch/arm/mach-orion5x/ts78xx-setup.c | 56 ++++++++++++++++++++++++++++++++++
1 files changed, 56 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index c1c1cd0..89682e1 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -191,6 +191,60 @@ static int ts78xx_ts_nand_dev_ready(struct mtd_info *mtd)
return readb(TS_NAND_CTRL) & 0x20;
}
+static void ts78xx_ts_nand_write_buf(struct mtd_info *mtd,
+ const uint8_t *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ void __iomem *io_base = chip->IO_ADDR_W;
+ unsigned long off = ((unsigned long)buf & 3);
+ int sz;
+
+ if (off) {
+ sz = min(4 - off, len);
+ writesb(io_base, buf, sz);
+ buf += sz;
+ len -= sz;
+ }
+
+ sz = len >> 2;
+ if (sz) {
+ u32 *buf32 = (u32 *)buf;
+ writesl(io_base, buf32, sz);
+ buf += sz << 2;
+ len -= sz << 2;
+ }
+
+ if (len)
+ writesb(io_base, buf, len);
+}
+
+static void ts78xx_ts_nand_read_buf(struct mtd_info *mtd,
+ uint8_t *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ void __iomem *io_base = chip->IO_ADDR_R;
+ unsigned long off = ((unsigned long)buf & 3);
+ int sz;
+
+ if (off) {
+ sz = min(4 - off, len);
+ readsb(io_base, buf, sz);
+ buf += sz;
+ len -= sz;
+ }
+
+ sz = len >> 2;
+ if (sz) {
+ u32 *buf32 = (u32 *)buf;
+ readsl(io_base, buf32, sz);
+ buf += sz << 2;
+ len -= sz << 2;
+ }
+
+ if (len)
+ readsb(io_base, buf, len);
+}
+
const char *ts_nand_part_probes[] = { "cmdlinepart", NULL };
static struct mtd_partition ts78xx_ts_nand_parts[] = {
@@ -233,6 +287,8 @@ static struct platform_nand_data ts78xx_ts_nand_data = {
*/
.cmd_ctrl = ts78xx_ts_nand_cmd_ctrl,
.dev_ready = ts78xx_ts_nand_dev_ready,
+ .write_buf = ts78xx_ts_nand_write_buf,
+ .read_buf = ts78xx_ts_nand_read_buf,
},
};
--
1.7.2.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox