* Re: [PATCH 2/2][RT] powerpc - Make the irq reverse mapping radix tree lockless
From: Nick Piggin @ 2008-07-24 11:11 UTC (permalink / raw)
To: Sebastien Dugue
Cc: Tim Chavez, Linux-rt, linux-kernel, Jean Pierre Dion, linux-ppc,
Paul Mackerras, Gilles Carry
In-Reply-To: <20080724125044.53b604cb@bull.net>
On Thursday 24 July 2008 20:50, Sebastien Dugue wrote:
> From: Sebastien Dugue <sebastien.dugue@bull.net>
> Date: Tue, 22 Jul 2008 11:56:41 +0200
> Subject: [PATCH][RT] powerpc - Make the irq reverse mapping radix tree
> lockless
>
> The radix tree used by interrupt controllers for their irq reverse
> mapping (currently only the XICS found on pSeries) have a complex locking
> scheme dating back to before the advent of the concurrent radix tree on
> preempt-rt.
>
> Take advantage of this and of the fact that the items of the tree are
> pointers to a static array (irq_map) elements which can never go under us
> to simplify the locking.
>
> Concurrency between readers and writers are handled by the intrinsic
> properties of the concurrent radix tree. Concurrency between the tree
> initialization which is done asynchronously with readers and writers access
> is handled via an atomic variable (revmap_trees_allocated) set when the
> tree has been initialized and checked before any reader or writer access
> just like we used to check for tree.gfp_mask != 0 before.
Hmm, RCU radix tree is in mainline too for quite a while. I thought
Ben had already converted this code over ages ago...
Nothing against the -rt patch, but mainline should probably be updated
to use RCU as well?
^ permalink raw reply
* Re: [PATCH 0/2][RT] powerpc - fix bug in irq reverse mapping radix tree
From: Sebastien Dugue @ 2008-07-24 11:08 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Tim Chavez, Linux RT Users, Jean Pierre Dion, linux-kernel,
linux-ppc, Paul Mackerras, Gilles Carry
In-Reply-To: <1216851458.11027.346.camel@pasglop>
On Thu, 24 Jul 2008 08:17:38 +1000 Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
>
> > The root cause of this bug lies in the fact that the XICS interrupt controller
> > uses a radix tree for its reverse irq mapping and that we cannot allocate the tree
> > nodes (even GFP_ATOMIC) with preemption disabled.
>
> Is that yet another caes of -rt changing some basic kernel semantics ?
Ahem, not really new: http://lkml.org/lkml/2007/11/12/211
>
> > In fact, we have 2 nested preemption disabling when we want to allocate
> > a new node:
> >
> > - setup_irq() does a spin_lock_irqsave() before calling xics_startup() which
> > then calls irq_radix_revmap() to insert a new node in the tree
> >
> > - irq_radix_revmap() also does a spin_lock_irqsave() (in irq_radix_wrlock())
> > before the radix_tree_insert()
> >
> > The first patch moves the call to irq_radix_revmap() from xics_startup() out to
> > xics_host_map_direct() and xics_host_map_lpar() which are called with preemption
> > enabled.
>
> I suppose that would work.
It should indeed. Instead of inserting the new mapping at request_irq() time,
we do it a bit before at create_irq_mapping time.
>
> > The second patch is a little more involved in that it takes advantage of
> > the concurrent radix tree to simplify the locking requirements and allows
> > to allocate a new node outside a preemption disabled section.
> >
> > I just hope I've correctly understood the concurrent radix trees semantic
> > and got the (absence of) locking right.
>
> Hrm, that will need some scrutinity.
Yep, that will need a few more pair of eyes along with brains behind those ;-)
Thanks,
Sebastien.
>
> Thanks for looking at this.
>
> Cheers,
> Ben.
>
>
>
^ permalink raw reply
* [PATCH 2/2][RT] powerpc - Make the irq reverse mapping radix tree lockless
From: Sebastien Dugue @ 2008-07-24 10:50 UTC (permalink / raw)
To: Linux-rt
Cc: Tim Chavez, linux-kernel, Jean Pierre Dion, linux-ppc,
Paul Mackerras, Gilles Carry
In-Reply-To: <20080724122352.3bc76bda@bull.net>
From: Sebastien Dugue <sebastien.dugue@bull.net>
Date: Tue, 22 Jul 2008 11:56:41 +0200
Subject: [PATCH][RT] powerpc - Make the irq reverse mapping radix tree lockless
The radix tree used by interrupt controllers for their irq reverse mapping
(currently only the XICS found on pSeries) have a complex locking scheme
dating back to before the advent of the concurrent radix tree on preempt-rt.
Take advantage of this and of the fact that the items of the tree are
pointers to a static array (irq_map) elements which can never go under us
to simplify the locking.
Concurrency between readers and writers are handled by the intrinsic
properties of the concurrent radix tree. Concurrency between the tree
initialization which is done asynchronously with readers and writers access is
handled via an atomic variable (revmap_trees_allocated) set when the tree
has been initialized and checked before any reader or writer access just
like we used to check for tree.gfp_mask != 0 before.
Signed-off-by: Sebastien Dugue <sebastien.dugue@bull.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
---
arch/powerpc/kernel/irq.c | 102 ++++++++++++----------------------------------
1 file changed, 27 insertions(+), 75 deletions(-)
Index: linux-2.6.25.8-rt7/arch/powerpc/kernel/irq.c
===================================================================
--- linux-2.6.25.8-rt7.orig/arch/powerpc/kernel/irq.c
+++ linux-2.6.25.8-rt7/arch/powerpc/kernel/irq.c
@@ -403,8 +403,7 @@ void do_softirq(void)
static LIST_HEAD(irq_hosts);
static DEFINE_RAW_SPINLOCK(irq_big_lock);
-static DEFINE_PER_CPU(unsigned int, irq_radix_reader);
-static unsigned int irq_radix_writer;
+static atomic_t revmap_trees_allocated = ATOMIC_INIT(0);
struct irq_map_entry irq_map[NR_IRQS];
static unsigned int irq_virq_count = NR_IRQS;
static struct irq_host *irq_default_host;
@@ -547,57 +546,6 @@ void irq_set_virq_count(unsigned int cou
irq_virq_count = count;
}
-/* radix tree not lockless safe ! we use a brlock-type mecanism
- * for now, until we can use a lockless radix tree
- */
-static void irq_radix_wrlock(unsigned long *flags)
-{
- unsigned int cpu, ok;
-
- spin_lock_irqsave(&irq_big_lock, *flags);
- irq_radix_writer = 1;
- smp_mb();
- do {
- barrier();
- ok = 1;
- for_each_possible_cpu(cpu) {
- if (per_cpu(irq_radix_reader, cpu)) {
- ok = 0;
- break;
- }
- }
- if (!ok)
- cpu_relax();
- } while(!ok);
-}
-
-static void irq_radix_wrunlock(unsigned long flags)
-{
- smp_wmb();
- irq_radix_writer = 0;
- spin_unlock_irqrestore(&irq_big_lock, flags);
-}
-
-static void irq_radix_rdlock(unsigned long *flags)
-{
- local_irq_save(*flags);
- __get_cpu_var(irq_radix_reader) = 1;
- smp_mb();
- if (likely(irq_radix_writer == 0))
- return;
- __get_cpu_var(irq_radix_reader) = 0;
- smp_wmb();
- spin_lock(&irq_big_lock);
- __get_cpu_var(irq_radix_reader) = 1;
- spin_unlock(&irq_big_lock);
-}
-
-static void irq_radix_rdunlock(unsigned long flags)
-{
- __get_cpu_var(irq_radix_reader) = 0;
- local_irq_restore(flags);
-}
-
static int irq_setup_virq(struct irq_host *host, unsigned int virq,
irq_hw_number_t hwirq)
{
@@ -752,7 +700,6 @@ void irq_dispose_mapping(unsigned int vi
{
struct irq_host *host;
irq_hw_number_t hwirq;
- unsigned long flags;
if (virq == NO_IRQ)
return;
@@ -784,15 +731,20 @@ void irq_dispose_mapping(unsigned int vi
if (hwirq < host->revmap_data.linear.size)
host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
break;
- case IRQ_HOST_MAP_TREE:
+ case IRQ_HOST_MAP_TREE: {
+ DEFINE_RADIX_TREE_CONTEXT(ctx, &host->revmap_data.tree);
+
/* Check if radix tree allocated yet */
- if (host->revmap_data.tree.gfp_mask == 0)
+ if (atomic_read(&revmap_trees_allocated) == 0)
break;
- irq_radix_wrlock(&flags);
- radix_tree_delete(&host->revmap_data.tree, hwirq);
- irq_radix_wrunlock(flags);
+
+ radix_tree_lock(&ctx);
+ radix_tree_delete(ctx.tree, hwirq);
+ radix_tree_unlock(&ctx);
+
break;
}
+ }
/* Destroy map */
smp_mb();
@@ -845,22 +797,20 @@ unsigned int irq_radix_revmap(struct irq
struct radix_tree_root *tree;
struct irq_map_entry *ptr;
unsigned int virq;
- unsigned long flags;
WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
- /* Check if the radix tree exist yet. We test the value of
- * the gfp_mask for that. Sneaky but saves another int in the
- * structure. If not, we fallback to slow mode
- */
- tree = &host->revmap_data.tree;
- if (tree->gfp_mask == 0)
+ /* Check if the radix tree exist yet. */
+ if (atomic_read(&revmap_trees_allocated) == 0)
return irq_find_mapping(host, hwirq);
- /* Now try to resolve */
- irq_radix_rdlock(&flags);
+ /*
+ * Now try to resolve
+ * No rcu_read_lock(ing) needed, the ptr returned can't go under us
+ * as it's referencing an entry in the static irq_map table.
+ */
+ tree = &host->revmap_data.tree;
ptr = radix_tree_lookup(tree, hwirq);
- irq_radix_rdunlock(flags);
/* Found it, return */
if (ptr) {
@@ -871,9 +821,10 @@ unsigned int irq_radix_revmap(struct irq
/* If not there, try to insert it */
virq = irq_find_mapping(host, hwirq);
if (virq != NO_IRQ) {
- irq_radix_wrlock(&flags);
- radix_tree_insert(tree, hwirq, &irq_map[virq]);
- irq_radix_wrunlock(flags);
+ DEFINE_RADIX_TREE_CONTEXT(ctx, tree);
+ radix_tree_lock(&ctx);
+ radix_tree_insert(ctx.tree, hwirq, &irq_map[virq]);
+ radix_tree_unlock(&ctx);
}
return virq;
}
@@ -984,14 +935,15 @@ void irq_early_init(void)
static int irq_late_init(void)
{
struct irq_host *h;
- unsigned long flags;
- irq_radix_wrlock(&flags);
list_for_each_entry(h, &irq_hosts, link) {
if (h->revmap_type == IRQ_HOST_MAP_TREE)
INIT_RADIX_TREE(&h->revmap_data.tree, GFP_ATOMIC);
}
- irq_radix_wrunlock(flags);
+
+ /* Make sure the radix trees inits are visible before setting the flag */
+ smp_mb();
+ atomic_set(&revmap_trees_allocated, 1);
return 0;
}
^ permalink raw reply
* [PATCH 0/2][RT] powerpc - fix bug in irq reverse mapping radix tree (Resend)
From: Sebastien Dugue @ 2008-07-24 10:23 UTC (permalink / raw)
To: Linux-rt
Cc: Tim Chavez, linux-kernel, Jean Pierre Dion, linux-ppc,
Paul Mackerras, Gilles Carry
(This is resend as vger dropped my previous attempt, sorry for the duplication)
Hi,
here are 2 patches for fixing the following bug occuring on IBM pSeries under
an RT kernel:
BUG: sleeping function called from invalid context swapper(1) at kernel/rtmutex.c:739
in_atomic():1 [00000002], irqs_disabled():1
Call Trace:
[c0000001e20f3340] [c000000000010370] .show_stack+0x70/0x1bc (unreliable)
[c0000001e20f33f0] [c000000000049380] .__might_sleep+0x11c/0x138
[c0000001e20f3470] [c0000000002a2f64] .__rt_spin_lock+0x3c/0x98
[c0000001e20f34f0] [c0000000000c3f20] .kmem_cache_alloc+0x68/0x184
[c0000001e20f3590] [c000000000193f3c] .radix_tree_node_alloc+0xf0/0x144
[c0000001e20f3630] [c000000000195190] .radix_tree_insert+0x18c/0x2fc
[c0000001e20f36f0] [c00000000000c710] .irq_radix_revmap+0x1a4/0x1e4
[c0000001e20f37b0] [c00000000003b3f0] .xics_startup+0x30/0x54
[c0000001e20f3840] [c00000000008b864] .setup_irq+0x26c/0x370
[c0000001e20f38f0] [c00000000008ba68] .request_irq+0x100/0x158
[c0000001e20f39a0] [c0000000001ee9c0] .hvc_open+0xb4/0x148
[c0000001e20f3a40] [c0000000001d72ec] .tty_open+0x200/0x368
[c0000001e20f3af0] [c0000000000ce928] .chrdev_open+0x1f4/0x25c
[c0000001e20f3ba0] [c0000000000c8bf0] .__dentry_open+0x188/0x2c8
[c0000001e20f3c50] [c0000000000c8dec] .do_filp_open+0x50/0x70
[c0000001e20f3d70] [c0000000000c8e8c] .do_sys_open+0x80/0x148
[c0000001e20f3e20] [c00000000000928c] .init_post+0x4c/0x100
[c0000001e20f3ea0] [c0000000003c0e0c] .kernel_init+0x428/0x478
[c0000001e20f3f90] [c000000000027448] .kernel_thread+0x4c/0x68
The root cause of this bug lies in the fact that the XICS interrupt controller
uses a radix tree for its reverse irq mapping and that we cannot allocate the tree
nodes (even GFP_ATOMIC) with preemption disabled.
In fact, we have 2 nested preemption disabling when we want to allocate
a new node:
- setup_irq() does a spin_lock_irqsave() before calling xics_startup() which
then calls irq_radix_revmap() to insert a new node in the tree
- irq_radix_revmap() also does a spin_lock_irqsave() (in irq_radix_wrlock())
before the radix_tree_insert()
The first patch moves the call to irq_radix_revmap() from xics_startup() out to
xics_host_map_direct() and xics_host_map_lpar() which are called with preemption
enabled.
The second patch is a little more involved in that it takes advantage of
the concurrent radix tree to simplify the locking requirements and allows
to allocate a new node outside a preemption disabled section.
I just hope I've correctly understood the concurrent radix trees semantic
and got the (absence of) locking right.
Sebastien.
^ permalink raw reply
* [PATCH 1/2][RT] powerpc - XICS: move the call to irq_radix_revmap from xics_startup to xics_host_map
From: Sebastien Dugue @ 2008-07-24 10:48 UTC (permalink / raw)
To: Linux-rt
Cc: Tim Chavez, linux-kernel, Jean Pierre Dion, linux-ppc,
Paul Mackerras, Gilles Carry
In-Reply-To: <20080724122352.3bc76bda@bull.net>
From: Sebastien Dugue <sebastien.dugue@bull.net>
Date: Tue, 22 Jul 2008 13:05:24 +0200
Subject: [PATCH][RT] powerpc - XICS: move the call to irq_radix_revmap from xics_startup to xics_host_map
This patch moves the insertion of an irq into the reverse mapping radix tree
from xics_startup() into xics_host_map().
The reason for this change is that xics_startup() is called with preemption
disabled (which is not the case for xics_host_map()) which is a problem under a
preempt-rt kernel as we cannot even allocate GFP_ATOMIC memory for the radix tree
nodes.
Signed-off-by: Sebastien Dugue <sebastien.dugue@bull.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/platforms/pseries/xics.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
Index: linux-2.6.25.8-rt7/arch/powerpc/platforms/pseries/xics.c
===================================================================
--- linux-2.6.25.8-rt7.orig/arch/powerpc/platforms/pseries/xics.c
+++ linux-2.6.25.8-rt7/arch/powerpc/platforms/pseries/xics.c
@@ -311,12 +311,6 @@ static void xics_mask_irq(unsigned int v
static unsigned int xics_startup(unsigned int virq)
{
- unsigned int irq;
-
- /* force a reverse mapping of the interrupt so it gets in the cache */
- irq = (unsigned int)irq_map[virq].hwirq;
- irq_radix_revmap(xics_host, irq);
-
/* unmask it */
xics_unmask_irq(virq);
return 0;
@@ -529,8 +523,14 @@ static int xics_host_match(struct irq_ho
static int xics_host_map_direct(struct irq_host *h, unsigned int virq,
irq_hw_number_t hw)
{
+ unsigned int irq;
+
pr_debug("xics: map_direct virq %d, hwirq 0x%lx\n", virq, hw);
+ /* force a reverse mapping of the interrupt so it gets in the cache */
+ irq = (unsigned int)irq_map[virq].hwirq;
+ irq_radix_revmap(xics_host, irq);
+
get_irq_desc(virq)->status |= IRQ_LEVEL;
set_irq_chip_and_handler(virq, &xics_pic_direct, handle_fasteoi_irq);
return 0;
@@ -539,8 +539,14 @@ static int xics_host_map_direct(struct i
static int xics_host_map_lpar(struct irq_host *h, unsigned int virq,
irq_hw_number_t hw)
{
+ unsigned int irq;
+
pr_debug("xics: map_direct virq %d, hwirq 0x%lx\n", virq, hw);
+ /* force a reverse mapping of the interrupt so it gets in the cache */
+ irq = (unsigned int)irq_map[virq].hwirq;
+ irq_radix_revmap(xics_host, irq);
+
get_irq_desc(virq)->status |= IRQ_LEVEL;
set_irq_chip_and_handler(virq, &xics_pic_lpar, handle_fasteoi_irq);
return 0;
^ permalink raw reply
* [PATCH] watchdog: delete unused driver mpc8xx_wdt.c
From: Jochen Friedrich @ 2008-07-24 10:22 UTC (permalink / raw)
To: wim; +Cc: linuxppc-dev list, Kernel, Linux
The watchdog driver mpc8xx_wdt.c was a device interface to
arch/ppc/syslib/m8xx_wdt.c for MPC8xx hardware. Now that ARCH=ppc is
gone, this driver is of no more use. For ARCH=powerpc, MPC8xx hardware
is supported by mpc8xxx_wdt.c.
Signed-off-by: Jochen Friedrich <jochen@scram.de>
---
drivers/watchdog/Kconfig | 4 -
drivers/watchdog/Makefile | 1 -
drivers/watchdog/mpc8xx_wdt.c | 169 -----------------------------------------
3 files changed, 0 insertions(+), 174 deletions(-)
delete mode 100644 drivers/watchdog/mpc8xx_wdt.c
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index a7a8285..ac54ad5 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -691,10 +691,6 @@ config MPC5200_WDT
tristate "MPC5200 Watchdog Timer"
depends on PPC_MPC52xx
-config 8xx_WDT
- tristate "MPC8xx Watchdog Timer"
- depends on 8xx
-
config 8xxx_WDT
tristate "MPC8xxx Platform Watchdog Timer"
depends on PPC_8xx || PPC_83xx || PPC_86xx
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 73fd301..11defe0 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -101,7 +101,6 @@ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
# PARISC Architecture
# POWERPC Architecture
-obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o
obj-$(CONFIG_8xxx_WDT) += mpc8xxx_wdt.o
obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
diff --git a/drivers/watchdog/mpc8xx_wdt.c b/drivers/watchdog/mpc8xx_wdt.c
deleted file mode 100644
index 85b5734..0000000
--- a/drivers/watchdog/mpc8xx_wdt.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * mpc8xx_wdt.c - MPC8xx watchdog userspace interface
- *
- * Author: Florian Schirmer <jolt@tuxbox.org>
- *
- * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/miscdevice.h>
-#include <linux/module.h>
-#include <linux/watchdog.h>
-#include <asm/8xx_immap.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <syslib/m8xx_wdt.h>
-
-static unsigned long wdt_opened;
-static int wdt_status;
-
-static void mpc8xx_wdt_handler_disable(void)
-{
- volatile uint __iomem *piscr;
- piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr;
-
- if (!m8xx_has_internal_rtc)
- m8xx_wdt_stop_timer();
- else
- out_be32(piscr, in_be32(piscr) & ~(PISCR_PIE | PISCR_PTE));
-
- printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
-}
-
-static void mpc8xx_wdt_handler_enable(void)
-{
- volatile uint __iomem *piscr;
- piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr;
-
- if (!m8xx_has_internal_rtc)
- m8xx_wdt_install_timer();
- else
- out_be32(piscr, in_be32(piscr) | PISCR_PIE | PISCR_PTE);
-
- printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n");
-}
-
-static int mpc8xx_wdt_open(struct inode *inode, struct file *file)
-{
- if (test_and_set_bit(0, &wdt_opened))
- return -EBUSY;
-
- m8xx_wdt_reset();
- mpc8xx_wdt_handler_disable();
-
- return nonseekable_open(inode, file);
-}
-
-static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
-{
- m8xx_wdt_reset();
-
-#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
- mpc8xx_wdt_handler_enable();
-#endif
-
- clear_bit(0, &wdt_opened);
-
- return 0;
-}
-
-static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len,
- loff_t * ppos)
-{
- if (len)
- m8xx_wdt_reset();
-
- return len;
-}
-
-static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int timeout;
- static struct watchdog_info info = {
- .options = WDIOF_KEEPALIVEPING,
- .firmware_version = 0,
- .identity = "MPC8xx watchdog",
- };
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- if (copy_to_user((void *)arg, &info, sizeof(info)))
- return -EFAULT;
- break;
-
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- if (put_user(wdt_status, (int *)arg))
- return -EFAULT;
- wdt_status &= ~WDIOF_KEEPALIVEPING;
- break;
-
- case WDIOC_GETTEMP:
- return -EOPNOTSUPP;
-
- case WDIOC_SETOPTIONS:
- return -EOPNOTSUPP;
-
- case WDIOC_KEEPALIVE:
- m8xx_wdt_reset();
- wdt_status |= WDIOF_KEEPALIVEPING;
- break;
-
- case WDIOC_SETTIMEOUT:
- return -EOPNOTSUPP;
-
- case WDIOC_GETTIMEOUT:
- timeout = m8xx_wdt_get_timeout();
- if (put_user(timeout, (int *)arg))
- return -EFAULT;
- break;
-
- default:
- return -ENOTTY;
- }
-
- return 0;
-}
-
-static const struct file_operations mpc8xx_wdt_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = mpc8xx_wdt_write,
- .ioctl = mpc8xx_wdt_ioctl,
- .open = mpc8xx_wdt_open,
- .release = mpc8xx_wdt_release,
-};
-
-static struct miscdevice mpc8xx_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &mpc8xx_wdt_fops,
-};
-
-static int __init mpc8xx_wdt_init(void)
-{
- return misc_register(&mpc8xx_wdt_miscdev);
-}
-
-static void __exit mpc8xx_wdt_exit(void)
-{
- misc_deregister(&mpc8xx_wdt_miscdev);
-
- m8xx_wdt_reset();
- mpc8xx_wdt_handler_enable();
-}
-
-module_init(mpc8xx_wdt_init);
-module_exit(mpc8xx_wdt_exit);
-
-MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
-MODULE_DESCRIPTION("MPC8xx watchdog driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
--
1.5.6.3
^ permalink raw reply related
* Re: how to allocate 9MB of memory in kernel ?
From: Arnd Bergmann @ 2008-07-24 9:31 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: Misbah khan
In-Reply-To: <18627544.post@talk.nabble.com>
On Thursday 24 July 2008, Misbah khan wrote:
>
> Hi all ...
>
> I am uploading the source code which is doing the following :-
>
> 1. mapping cpld register using ioremap coping the data to circular buffer
> and remapping it to user space .
>
> 2. It can also map kernel virtual dma memory to user space if compiled
> conditionally .
>
> following is the problem which i am facing ...
>
> 1. It is somitimes giving following kernel panic ....
>
> nable to handle kernel NULL pointer dereference at virtual address 00000000
> pgd = c0004000
> [00000000] *pgd=00000000
> Internal error: Oops: 17 [#1]
> Modules linked in: fluke_driver tstamp sig_router mvci_spi mvci_sf_pcd
> mvci_sci_unidir_s1 mvci_sci_diff mvci_sci_bidir_s
> 1 mvci_rtmd_s1 mvci_kwiso_s1 mvci_kw1281_s1 mvci_kh_s1 mvci_j1850
> mvci_gm_sbc mvci_diagh_s1 g_ether mvci_dcl mvci_can1 f
> pga_conf arcotg_udc adc_dac keypad(F) splc501_lcd(F) cpld
> CPU: 0
> PC is at cascade+0x64/0x8c
> LR is at __init_begin+0x3fff8000/0x30
> pc : [<c00484ac>] lr : [<00000000>] Tainted: GF
> sp : c0293ea8 ip : 0040b000 fp : c0293ecc
> r10: 8001d9f0 r9 : c0292000 r8 : 00000001
> r7 : c0292000 r6 : 0000000c r5 : c02fa048 r4 : 00000000
> r3 : c02fa2f8 r2 : 0000261a r1 : bf01ab70 r0 : c02fa2f8
> Flags: Nzcv IRQs off FIQs on Mode SVC_32 Segment kernel
> Control: C5387F
> Table: 8698C000 DAC: 00000017
> Process swapper (pid: 0, stack limit = 0xc0292250)
> Stack: (0xc0293ea8 to 0xc0294000)
> 3ea0: bf01ab70 c02fb440 0000000a 00000000 c02fa048
> 0000000a
> 3ec0: c0293efc c0293ed0 c0048810 c0048454 c0293eec c0293ee0 c002a30c
> 00000001
> 3ee0: c02f9e44 0000000a 00000002 00000001 c0293f1c c0293f00 c00442a0
> c0048794
> 3f00: c0293f2c 0000001d c0294740 00000000 c0293f2c c0293f20 c00446d4
> c0044254
> 3f20: c0293f4c c0293f30 c00217b0 c0044698 c0293f5c ffffffff 0000ffff
> 00000001
> 3f40: c0293fa4 c0293f50 c00209e4 c0021770 00000001 00000001 c0292000
> 00000000
> 3f60: c0022068 c0292000 c0298c44 c03121c0 8001da24 4107b364 8001d9f0
> c0293fa4
> 3f80: c0293fa8 c0293f98 c0021d48 c002209c 60000013 ffffffff c0293fbc
> c0293fa8
> 3fa0: c0021d48 c0022074 c02faae0 c02f292c c0293fcc c0293fc0 c00202e0
> c0021d24
> 3fc0: c0293ff4 c0293fd0 c0008848 c00202b4 c00083c4 00000000 00000000
> c02f29a8
> 3fe0: 00000000 00c5387d 00000000 c0293ff8 80008030 c00086e0 00000000
> 00000000
> Backtrace:
> [<c0048448>] (cascade+0x0/0x8c) from [<c0048810>]
> (run_timer_softirq+0x88/0x1e8)
> r6 = 0000000A r5 = C02FA048 r4 = 00000000
> [<c0048788>] (run_timer_softirq+0x0/0x1e8) from [<c00442a0>]
> (__do_softirq+0x58/0xc8)
> r8 = 00000001 r7 = 00000002 r6 = 0000000A r5 = C02F9E44
> r4 = 00000001
> [<c0044248>] (__do_softirq+0x0/0xc8) from [<c00446d4>] (irq_exit+0x48/0x5c)
> r6 = 00000000 r5 = C0294740 r4 = 0000001D
> [<c004468c>] (irq_exit+0x0/0x5c) from [<c00217b0>] (asm_do_IRQ+0x4c/0x64)
> [<c0021764>] (asm_do_IRQ+0x0/0x64) from [<c00209e4>] (__irq_svc+0x44/0x80)
> r6 = 00000001 r5 = 0000FFFF r4 = FFFFFFFF
> [<c0022068>] (default_idle+0x0/0x3c) from [<c0021d48>] (cpu_idle+0x30/0x5c)
> [<c0021d18>] (cpu_idle+0x0/0x5c) from [<c00202e0>] (rest_init+0x38/0x40)
> r5 = C02F292C r4 = C02FAAE0
> [<c00202a8>] (rest_init+0x0/0x40) from [<c0008848>]
> (start_kernel+0x174/0x1c0)
> [<c00086d4>] (start_kernel+0x0/0x1c0) from [<80008030>] (0x80008030)
> Code: e1530005 15822000 ebffffb6 e1a0e004 (e5944000)
> <0>Kernel panic - not syncing: Aiee, killing interrupt handler!
>
>
> also when i run it on X86 PC i am able to get the data and no panic where in
> on the board it is giving the above error ....
>
> 2. I can raed the data using the user application when i run it on X86 PC
> where in i cant able to read the data when i run it on the board the data i
> was getting was always '/0' filled buffer .
>
>
> Here is the compilete code .............
>
>
> static int McBSP_DriverOpen(struct inode *inode,struct file *file)
> {
> /* Reintialize file operation structure */
> file->f_op=&fluke_fops;
>
this is already set.
> printk(KERN_DEBUG" fluke driver open success \n");
>
> if (device_open_count == 0)
> {
> device_open_count = 1;
>
> /* Reset the read and write index*/
> buf_index_area.write_index=0;
> buf_index_area.read_index=-1;
> buf_index_area.count_index=0;
>
> #ifdef SIMULATION
> /* Initialize the Timer */
> init_timer(&fluke_timer);
> fluke_timer.expires = jiffies + (HZ*10);//Timer will Expire after 60 sec
> fluke_timer.data = 0;
> fluke_timer.function = (void *)timer_func;
> add_timer(&fluke_timer);
> #endif
> }
>
> return 0;
> }
Using the count in this way is racy, best write the code so
that it can allow multiple opens.
> irqreturn_t DataAcqIntHandler(int irq,void *dev_id, struct pt_regs *regs)
> {
> printk(KERN_ALERT" In Interrupt Handler\n");
> /* Data present status is set to wake up the read call */
> data_present_status=1;
>
> /* Wake up the blocked Select call */
> wake_up_interruptible(&wait_queue);
>
> #ifndef SIMULATION
> /* Clear the interrupt in the interrupt pending registor */
> cpi->ic_scprrh |=DATA_ACQ_INT_CLEAR;
> #endif
>
> return IRQ_HANDLED;
>
> }/* End of PpsIntrHandler() */
The interrupt handler should be able to deal with shared interrupts,
and needs to check if the interrupt came from this device, returning
IRQ_NONE otherwise.
> static int __init McBSP_DriverInit(void)
> {
> unsigned int virt_addr = 0;
> int mem = 0;
>
> //buf_area = vmalloc(sizeof(circularbuffer_S));
> //if(!buf_area)
> //{
> // printk(KERN_ALERT"vmalloc failed \n");
> // return -1;
> //}
>
> #if 0
> /*
> * Allocate memory for the circular buffer in the DMA coherent area
> * and algin it in the Cache
> */
> mem = L1_CACHE_ALIGN(sizeof(circularbuffer_S));
>
> buf_ptr = (char *)dma_alloc_coherent(NULL, mem, &dma_addr,GFP_KERNEL);
no need for the cast.
> printk(KERN_INFO" buf_ptr = 0x%x \n",(int )buf_ptr);
> if(NULL == buf_ptr )
> {
> printk(KERN_ALERT" Allocation of Memory failure ");
> return -1;
> }
>
> buf_area = (circularbuffer_S *)(((unsigned int )buf_ptr + PAGE_SIZE - 1) \
> & PAGE_MASK);
>
> printk(KERN_INFO" buf_area = 0x%x \n",(int )buf_area);
>
> if(NULL == buf_area)
> {
> printk(KERN_ALERT" Circular buffer memory not allocated \n");
> return -1;
> }
>
> /* Marking the Pages as reserved */
> for (virt_addr = (unsigned int)buf_area; \
> virt_addr < (unsigned int )buf_area + sizeof(circularbuffer_S);\
> virt_addr += PAGE_SIZE)
> {
> /* Set the pages as reserved */
> SetPageReserved(virt_to_page(virt_addr));
> //mem_map_reserve(virt_to_page(virt_addr));
> }
no need for SetPageReserved, it already is marked as in use through
the allocation.
> phy_addr = virt_to_phys(buf_ptr);
You can't use virt_to_phys to get the dma address. You also don't need that
because you already have it in dma_addr.
> printk(KERN_INFO"Allocated Memory for Circular Buffer at physical
> 0x0%x\n",phy_addr);
>
> #else
>
> buf_area = ioremap(0xB2000000,0x4000); //(0xB2000000,0x4000);
> //(7700000,900000);
> if(!buf_area)
> {
> printk(KERN_ALERT"ioremap failed \n");
> return -1;
> }
Don't hardcode the numbers here, you should get the values from the
device tree, and use of_iomap().
> printk(" Ioremap mapped to virtual 0x0%x \n",buf_area);
> *((unsigned int *)buf_area) = 0xa5a5a5a5;
> printk(" Ioremap data 0x0%x \n",*((unsigned int *)buf_area + 0));
>
> #endif
>
> /* Device major number is registered to set the driver entry point */
> if(register_chrdev(MAJOR_NO,MODULE_NAME, &fluke_fops)==0)
> {
> printk(KERN_DEBUG" Fluke driver registeration success \n");
>
> }
> else
> {
> printk(KERN_ALERT" Fluke driver registeration failed \n");
> return -1;
> }
Since it's just one device, it's easier to use a misc_device.
> /*
> * Register Data Acq interrupt request with specified irq and install the
> * handler
> */
> if(request_irq(DATA_ACQ_INT,(void *)DataAcqIntHandler, SA_INTERRUPT,
> MODULE_NAME, NULL)==0)
> {
> printk(KERN_DEBUG" Data Acq interrupt request returns success \n");
> }
> else
> {
> printk(KERN_DEBUG" Data Acq interrupt request failed \n");
> unregister_chrdev(MAJOR_NO,MODULE_NAME);
> return -1;
>
> }
hardcoding interrupt numbers is broken, interrupt numbers are relative to
one interrupt controller. Use irq_of_parse_and_map.
> static int McBSP_DriverIoctl(struct inode *inode, struct file *file,\
> unsigned int cmd, unsigned long param)
> {
> int i;
> daq_t daq_param;
>
> printk(KERN_DEBUG"In ioctl command \n");
>
> switch(cmd)
> {
> case START_ACQ_DATA:
>
> if(copy_from_user(&daq_param,(void *)param,sizeof(daq_param)))
> {
>
> return -1;
> }
>
> /* For Simulation we are writing the data */
> if(WriteBuf() < 0)
> {
> printk(" Writing to the memory failure \n");
> return -1;
> }
>
> /* Wait for the Interrupt to occur */
> wait_event_interruptible( wait_queue, data_present_status !=0);
>
> printk("Read Index before read %d\n",buf_index_area.read_index);
> data_present_status=0;
Racy, you could have multiple threads doing this ioctl.
Moreover, you should not block in an ioctl but rather
implement a poll() function for waiting.
> buf_index_area.read_index++;
> buf_index_area.read_index%=NO_FRAMES;
>
> if(buf_index_area.read_index ==((buf_index_area.write_index +1) %
> NO_FRAMES))
> //if(buf_index_area.read_index == buf_index_area.write_index )
> {
> printk("Read failure because read and write index are same\n");
> return -1;
> }
>
> /* Decrement the count index to indicate the data availibility */
> down(&mutex);
> buf_index_area.count_index--;
> up(&mutex);
New drivers should not use semaphores (up/down) in places where they can use real
mutexes (mutex_lock/mutex_unlock).
> static int McBSP_DriverMmap(struct file *file,struct vm_area_struct *vma)
> {
>
> unsigned long start = vma->vm_start;
> unsigned long size = vma->vm_end - vma->vm_start; //0x900000;
> unsigned long phy_add = virt_to_phys(buf_ptr); //0x7700000;
virt_to_phys doesn't work on vmalloc memory.
> int ret = 0;
>
> /* Make the mmaped area noncacheable */
> vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
>
> /* Set the Flags to give permissions to Mmaped area */
> vma->vm_flags |=VM_RESERVED;
> vma->vm_flags |=VM_READ;
> vma->vm_flags |=VM_WRITE;
> vma->vm_flags |=VM_IO;
> //vma->vm_flags |=VM_SHARED;
> //vma->vm_flags |=VM_LOCKED;
For memory, you typically want to set vm_page_prot to use non-guarded mapping,
so that user space accesses are faster.
Not sure if VM_IO is right for vmalloc.
Arnd <><
^ permalink raw reply
* Xilinx Linux 2.6 for XPS LL_TEMAC and LL_FIFO problem
From: Mirek23 @ 2008-07-24 9:19 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <20080316214832.3F77A538046@mail141-sin.bigfish.com>
Dear All,
I have done a design using EDK 8.2 using Hard_Temac IP component. In the EDK
9.2 there is a new idea to use ll_temac in conjunction with ll_fifo or
ll_dma. So far I was using happily the linux kernel by Grant Likey.
Unfortunately it does not deal with ll_temac. I have download the kernel
from git.xilinx.com.
I have tried to build the kernel 2.6.26 (by xilinx) but it seems to be that
it is not well prepared for ll_fifo.
I have noticed that in drivers/xilinx_common there are files related to
ll_fifo but in the drivers/Makefile there is no rule to build ll_fifo. The
same refers to the file arch/ppc/syslib/virtex_devices.c -> there are no
entries for LL_FIFO. I have the impression that one can use only LL_DMA but
not LL_FIFO.
Does anybody has modified the kernel to deal with LL_TEMAC together with
LL_FIFO?
I will be grateful for any hint.
Best Regards
Mirek
--
View this message in context: http://www.nabble.com/Compile-time-error%2C-compiling-Xilinx-Linux-2.6-for-XPS-LLTEMAC-tp16065692p18628194.html
Sent from the linuxppc-embedded mailing list archive at Nabble.com.
^ permalink raw reply
* Re: how to allocate 9MB of memory in kernel ?
From: Misbah khan @ 2008-07-24 8:33 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <18605418.post@talk.nabble.com>
Hi all ...
I am uploading the source code which is doing the following :-
1. mapping cpld register using ioremap coping the data to circular buffer
and remapping it to user space .
2. It can also map kernel virtual dma memory to user space if compiled
conditionally .
following is the problem which i am facing ...
1. It is somitimes giving following kernel panic ....
nable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c0004000
[00000000] *pgd=00000000
Internal error: Oops: 17 [#1]
Modules linked in: fluke_driver tstamp sig_router mvci_spi mvci_sf_pcd
mvci_sci_unidir_s1 mvci_sci_diff mvci_sci_bidir_s
1 mvci_rtmd_s1 mvci_kwiso_s1 mvci_kw1281_s1 mvci_kh_s1 mvci_j1850
mvci_gm_sbc mvci_diagh_s1 g_ether mvci_dcl mvci_can1 f
pga_conf arcotg_udc adc_dac keypad(F) splc501_lcd(F) cpld
CPU: 0
PC is at cascade+0x64/0x8c
LR is at __init_begin+0x3fff8000/0x30
pc : [<c00484ac>] lr : [<00000000>] Tainted: GF
sp : c0293ea8 ip : 0040b000 fp : c0293ecc
r10: 8001d9f0 r9 : c0292000 r8 : 00000001
r7 : c0292000 r6 : 0000000c r5 : c02fa048 r4 : 00000000
r3 : c02fa2f8 r2 : 0000261a r1 : bf01ab70 r0 : c02fa2f8
Flags: Nzcv IRQs off FIQs on Mode SVC_32 Segment kernel
Control: C5387F
Table: 8698C000 DAC: 00000017
Process swapper (pid: 0, stack limit = 0xc0292250)
Stack: (0xc0293ea8 to 0xc0294000)
3ea0: bf01ab70 c02fb440 0000000a 00000000 c02fa048
0000000a
3ec0: c0293efc c0293ed0 c0048810 c0048454 c0293eec c0293ee0 c002a30c
00000001
3ee0: c02f9e44 0000000a 00000002 00000001 c0293f1c c0293f00 c00442a0
c0048794
3f00: c0293f2c 0000001d c0294740 00000000 c0293f2c c0293f20 c00446d4
c0044254
3f20: c0293f4c c0293f30 c00217b0 c0044698 c0293f5c ffffffff 0000ffff
00000001
3f40: c0293fa4 c0293f50 c00209e4 c0021770 00000001 00000001 c0292000
00000000
3f60: c0022068 c0292000 c0298c44 c03121c0 8001da24 4107b364 8001d9f0
c0293fa4
3f80: c0293fa8 c0293f98 c0021d48 c002209c 60000013 ffffffff c0293fbc
c0293fa8
3fa0: c0021d48 c0022074 c02faae0 c02f292c c0293fcc c0293fc0 c00202e0
c0021d24
3fc0: c0293ff4 c0293fd0 c0008848 c00202b4 c00083c4 00000000 00000000
c02f29a8
3fe0: 00000000 00c5387d 00000000 c0293ff8 80008030 c00086e0 00000000
00000000
Backtrace:
[<c0048448>] (cascade+0x0/0x8c) from [<c0048810>]
(run_timer_softirq+0x88/0x1e8)
r6 = 0000000A r5 = C02FA048 r4 = 00000000
[<c0048788>] (run_timer_softirq+0x0/0x1e8) from [<c00442a0>]
(__do_softirq+0x58/0xc8)
r8 = 00000001 r7 = 00000002 r6 = 0000000A r5 = C02F9E44
r4 = 00000001
[<c0044248>] (__do_softirq+0x0/0xc8) from [<c00446d4>] (irq_exit+0x48/0x5c)
r6 = 00000000 r5 = C0294740 r4 = 0000001D
[<c004468c>] (irq_exit+0x0/0x5c) from [<c00217b0>] (asm_do_IRQ+0x4c/0x64)
[<c0021764>] (asm_do_IRQ+0x0/0x64) from [<c00209e4>] (__irq_svc+0x44/0x80)
r6 = 00000001 r5 = 0000FFFF r4 = FFFFFFFF
[<c0022068>] (default_idle+0x0/0x3c) from [<c0021d48>] (cpu_idle+0x30/0x5c)
[<c0021d18>] (cpu_idle+0x0/0x5c) from [<c00202e0>] (rest_init+0x38/0x40)
r5 = C02F292C r4 = C02FAAE0
[<c00202a8>] (rest_init+0x0/0x40) from [<c0008848>]
(start_kernel+0x174/0x1c0)
[<c00086d4>] (start_kernel+0x0/0x1c0) from [<80008030>] (0x80008030)
Code: e1530005 15822000 ebffffb6 e1a0e004 (e5944000)
<0>Kernel panic - not syncing: Aiee, killing interrupt handler!
also when i run it on X86 PC i am able to get the data and no panic where in
on the board it is giving the above error ....
2. I can raed the data using the user application when i run it on X86 PC
where in i cant able to read the data when i run it on the board the data i
was getting was always '/0' filled buffer .
Here is the compilete code .............
/******************************************************************************
* McBSP_Driver.c
*
* Fluke Driver
*
* Description:
*
* Libraries Used:
*
*
* Unit Test Drivers (Binary):
*
* <fix me >
*
*
* Special Compile Flags
* Nil
*
* Revision History:
* (17/July/2008) Misbah
* Created the file
*
* Copyright (C)
*
******************************************************************************/
/******************************************************************************
* Include Files
*****************************************************************************/
/* Standard linux files includes */
#include<linux/kernel.h>
//#include<linux/config.h>
#include<linux/ioctl.h>
#include<linux/types.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/delay.h>
#include<linux/init.h>
#include<linux/interrupt.h>
#include<linux/version.h>
#include<linux/wait.h>
#include<linux/poll.h>
#include<linux/timer.h>
#include<linux/irq.h>
#include<asm/uaccess.h>
#include<linux/time.h>
#include<asm/io.h>
#include<asm/bitops.h>
#include<linux/mm.h>
//#include<asm/mmzone.h>
#include<linux/bootmem.h>
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
#include <asm/pgtable.h>
#include<asm/io.h>
#include<asm/bitops.h>
#include"fluke_driver.h"
static int McBSP_DriverOpen(struct inode *inode,struct file *file);
static int McBSP_DriverInit(void);
static int McBSP_DriverIoctl(struct inode *inode, struct file *file,\
unsigned int cmd, unsigned long param);
static ssize_t McBSP_DriverWrite(struct file *file,
const char __user *buf, size_t len,loff_t *offset);
static ssize_t McBSP_DriverRead(struct file *file,char __user *buf,size_t
len,
loff_t *offset);
static int McBSP_DriverMmap(struct file *file,struct vm_area_struct *vma);
static void MmapOpen(struct vm_area_struct *vma);
static void MmapClose(struct vm_area_struct *vma);
static void McBSP_DriverExit(void);
static int McBSP_DriverClose(struct inode *inode,struct file *file);
static int WriteBuf(void);
void timer_func(void);
static struct timer_list fluke_timer;
static dma_addr_t dma_addr;
static char *buf_ptr;
static struct file_operations fluke_fops =
{
.owner = THIS_MODULE,
.open = McBSP_DriverOpen,
// .read = McBSP_DriverRead,
.ioctl = McBSP_DriverIoctl,
.mmap = McBSP_DriverMmap,
// .write = McBSP_DriverWrite,
.release = McBSP_DriverClose,
};
/* File operation structure for mmap system call */
static struct vm_operations_struct mmap_op=
{
.open = MmapOpen,
.close = MmapClose,
};
static circularbuffer_S *buf_area = NULL;
static circularbuffer_index_S buf_index_area;
static int device_open_count = 0;
static int data_present_status = 0;
void *ioremap_ptr;
static int phy_addr ;
/* static declaration of wait queue */
static DECLARE_WAIT_QUEUE_HEAD(wait_queue);
static DECLARE_MUTEX(mutex);
module_init(McBSP_DriverInit);
module_exit(McBSP_DriverExit);
MODULE_AUTHOR("Misbah U K");
MODULE_LICENSE ("GPL");
#define SIMULATION
/****************************************************************************
*
* Description: This function will open fluke device
*
* Input: File structure pointer and Inode structure pointer.
* ( passed by the kernel )
*
* output: Returns 0 on Success.
*
***************************************************************************/
static int McBSP_DriverOpen(struct inode *inode,struct file *file)
{
/* Reintialize file operation structure */
file->f_op=&fluke_fops;
printk(KERN_DEBUG" fluke driver open success \n");
if (device_open_count == 0)
{
device_open_count = 1;
/* Reset the read and write index*/
buf_index_area.write_index=0;
buf_index_area.read_index=-1;
buf_index_area.count_index=0;
#ifdef SIMULATION
/* Initialize the Timer */
init_timer(&fluke_timer);
fluke_timer.expires = jiffies + (HZ*10);//Timer will Expire after 60 sec
fluke_timer.data = 0;
fluke_timer.function = (void *)timer_func;
add_timer(&fluke_timer);
#endif
}
return 0;
}
/******************************************************************************
*
* Description : Interrupt handler function.
*
* Input: NONE
*
* Output: NONE
*
*****************************************************************************/
irqreturn_t DataAcqIntHandler(int irq,void *dev_id, struct pt_regs *regs)
{
printk(KERN_ALERT" In Interrupt Handler\n");
/* Data present status is set to wake up the read call */
data_present_status=1;
/* Wake up the blocked Select call */
wake_up_interruptible(&wait_queue);
#ifndef SIMULATION
/* Clear the interrupt in the interrupt pending registor */
cpi->ic_scprrh |=DATA_ACQ_INT_CLEAR;
#endif
return IRQ_HANDLED;
}/* End of PpsIntrHandler() */
#ifdef SIMULATION
void timer_func(void)
{
printk(KERN_ALERT" In the timer function \n");
/* Data present status is set to wake up the read call */
data_present_status=1;
/* Wake up the blocked Read call */
wake_up_interruptible(&wait_queue);
}
#endif
/***************************************************************************
*
* Description: Register the device and perform Initialization.
*
* Input: NIL
*
* Output: Returns 0 on Success and -1 on failure
*
**************************************************************************/
static int __init McBSP_DriverInit(void)
{
unsigned int virt_addr = 0;
int mem = 0;
//buf_area = vmalloc(sizeof(circularbuffer_S));
//if(!buf_area)
//{
// printk(KERN_ALERT"vmalloc failed \n");
// return -1;
//}
#if 0
/*
* Allocate memory for the circular buffer in the DMA coherent area
* and algin it in the Cache
*/
mem = L1_CACHE_ALIGN(sizeof(circularbuffer_S));
buf_ptr = (char *)dma_alloc_coherent(NULL, mem, &dma_addr,GFP_KERNEL);
printk(KERN_INFO" buf_ptr = 0x%x \n",(int )buf_ptr);
if(NULL == buf_ptr )
{
printk(KERN_ALERT" Allocation of Memory failure ");
return -1;
}
buf_area = (circularbuffer_S *)(((unsigned int )buf_ptr + PAGE_SIZE - 1) \
& PAGE_MASK);
printk(KERN_INFO" buf_area = 0x%x \n",(int )buf_area);
if(NULL == buf_area)
{
printk(KERN_ALERT" Circular buffer memory not allocated \n");
return -1;
}
/* Marking the Pages as reserved */
for (virt_addr = (unsigned int)buf_area; \
virt_addr < (unsigned int )buf_area + sizeof(circularbuffer_S);\
virt_addr += PAGE_SIZE)
{
/* Set the pages as reserved */
SetPageReserved(virt_to_page(virt_addr));
//mem_map_reserve(virt_to_page(virt_addr));
}
phy_addr = virt_to_phys(buf_ptr);
printk(KERN_INFO"Allocated Memory for Circular Buffer at physical
0x0%x\n",phy_addr);
#else
buf_area = ioremap(0xB2000000,0x4000); //(0xB2000000,0x4000);
//(7700000,900000);
if(!buf_area)
{
printk(KERN_ALERT"ioremap failed \n");
return -1;
}
printk(" Ioremap mapped to virtual 0x0%x \n",buf_area);
*((unsigned int *)buf_area) = 0xa5a5a5a5;
printk(" Ioremap data 0x0%x \n",*((unsigned int *)buf_area + 0));
#endif
/* Device major number is registered to set the driver entry point */
if(register_chrdev(MAJOR_NO,MODULE_NAME, &fluke_fops)==0)
{
printk(KERN_DEBUG" Fluke driver registeration success \n");
}
else
{
printk(KERN_ALERT" Fluke driver registeration failed \n");
return -1;
}
/*
* Register Data Acq interrupt request with specified irq and install the
* handler
*/
if(request_irq(DATA_ACQ_INT,(void *)DataAcqIntHandler, SA_INTERRUPT,
MODULE_NAME, NULL)==0)
{
printk(KERN_DEBUG" Data Acq interrupt request returns success \n");
}
else
{
printk(KERN_DEBUG" Data Acq interrupt request failed \n");
unregister_chrdev(MAJOR_NO,MODULE_NAME);
return -1;
}
/* Reset the read and write index*/
buf_index_area.write_index=0;
buf_index_area.read_index=0;
buf_index_area.count_index=0;
return 0;
}
/***************************************************************************
*
* Description: Input/Output entry point for driver.
*
* Input: Inode pointer, File pointer, command and parameter.
*
* Output: Returns 0 on success and -1 on failure.
*
**************************************************************************/
static int McBSP_DriverIoctl(struct inode *inode, struct file *file,\
unsigned int cmd, unsigned long param)
{
int i;
daq_t daq_param;
printk(KERN_DEBUG"In ioctl command \n");
switch(cmd)
{
case START_ACQ_DATA:
if(copy_from_user(&daq_param,(void *)param,sizeof(daq_param)))
{
return -1;
}
/* For Simulation we are writing the data */
if(WriteBuf() < 0)
{
printk(" Writing to the memory failure \n");
return -1;
}
/* Wait for the Interrupt to occur */
wait_event_interruptible( wait_queue, data_present_status !=0);
printk("Read Index before read %d\n",buf_index_area.read_index);
data_present_status=0;
buf_index_area.read_index++;
buf_index_area.read_index%=NO_FRAMES;
if(buf_index_area.read_index ==((buf_index_area.write_index +1) %
NO_FRAMES))
//if(buf_index_area.read_index == buf_index_area.write_index )
{
printk("Read failure because read and write index are same\n");
return -1;
}
/* Decrement the count index to indicate the data availibility */
down(&mutex);
buf_index_area.count_index--;
up(&mutex);
/* copy the circular buffer read index */
daq_param.circular_index = buf_index_area.read_index;
/*for(i = 0;i < SIZE_FRAME; i++)
{
printk("%c",buf_area->fluke[buf_index_area.read_index].buffer[i]);
}
*/
/* Configure ADC unit for No of samples and period */
/* < To Dod > */
#ifdef SIMULATION
/* Reinitialize the timer and run it again */
init_timer(&fluke_timer);
fluke_timer.function=(void *)timer_func;
fluke_timer.data=0;
fluke_timer.expires=jiffies + (HZ*10);
del_timer(&fluke_timer);
printk(KERN_DEBUG"Timer reinitialize in ioctl \n");
add_timer(&fluke_timer);
#endif
printk("Read Index after read %d\n",buf_index_area.read_index);
if(copy_to_user((void *)param,&daq_param,sizeof(daq_param)))
{
return -1;
}
break;
default:
return(0);
}
return (0);
}
/******************************************************************************
* Description: This function writes data to the device.
*
* Inputs: NONE
*
* Outputs: Returns No of bytes copied or -1 on failure.
******************************************************************************/
static ssize_t McBSP_DriverWrite(struct file *file,
const char __user *buf, size_t len,loff_t *offset)
{
int i,write_index;
write_index = buf_index_area.write_index;
if(buf_index_area.read_index ==((buf_index_area.write_index +1) %
NO_FRAMES))
//if(buf_index_area.read_index == buf_index_area.write_index )
{
printk(KERN_ALERT"Not able to write\n");
return -1;
}
printk(KERN_INFO" Before Write index = %d\n",buf_index_area.write_index);
for(i=0;i<len;i++)
{
buf_area->fluke[write_index].buffer[i]=buf[i];
//memset(buf_area->fluke[write_index].buffer,'A',SIZE_FRAME);
//for(i = 0;i < SIZE_FRAME; i++)
//{
// printk("%c",buf_area->fluke[write_index].buffer[i]);
//}
//printk(" %c",buf_area->fluke[write_index].buffer[i]);
}
for(i = 0;i < SIZE_FRAME; i++)
{
printk("%c",buf_area->fluke[write_index].buffer[i]);
}
//len = copy_from_user(buf_area->fluke[write_index].buffer,buf,len);
//memcpy_fromio(ioremap_ptr,buf_area->fluke[write_index].buffer,4);
buf_index_area.count_index++;
buf_index_area.write_index++;
buf_index_area.write_index%=3;
printk(KERN_INFO" After Write index = %d\n",buf_index_area.write_index);
return len;
}
/******************************************************************************
* Description: This function writes data to the circular buffer.
*
* Inputs: NONE
*
* Outputs: Returns No of bytes copied or -1 on failure.
******************************************************************************/
static int WriteBuf(void)
{
int i;
printk(" write Index is %d \n",buf_index_area.write_index);
if(buf_index_area.read_index ==((buf_index_area.write_index +1) %
NO_FRAMES))
//if(buf_index_area.read_index == buf_index_area.write_index )
{
printk(KERN_ALERT"Not able to write\n");
return -1;
}
memset(buf_area->fluke[buf_index_area.write_index].buffer,'A',SIZE_FRAME);
/*for(i = 0;i < SIZE_FRAME; i++)
{
printk("%c",buf_index_area.fluke[buf_index_area.write_index].buffer[i]);
}
*/
buf_index_area.count_index++;
buf_index_area.write_index++;
buf_index_area.write_index%=3;
printk(" write Index incremented to %d \n",buf_index_area.write_index);
return 0;
}
/******************************************************************************
* Description: This function reads data from the shared mmap area.
*
* Inputs: file structuer,data buffer pointer and length of data.
*
* Outputs: Return no of bytes read or -1 on failure.
*
******************************************************************************/
static ssize_t McBSP_DriverRead(struct file *file,char __user *buf,size_t
len,
loff_t *offset)
{
int temp_read_index,i;
printk(KERN_INFO"Entering %s\n",__FUNCTION__);
/* Wait till timer Expires */
wait_event_interruptible( wait_queue, data_present_status !=0);
data_present_status=0;
buf_index_area.read_index++;
buf_index_area.read_index%=NO_FRAMES;
/* Decrement the count index to indicate the data availibility */
down(&mutex);
buf_index_area.count_index--;
up(&mutex);
temp_read_index = buf_index_area.read_index;
printk(KERN_INFO"Exting %s\n",__FUNCTION__);
printk(KERN_INFO"count_index=%d\n",buf_index_area.count_index);
printk(KERN_INFO"read_index=%d\n",buf_index_area.read_index);
/*for(i = 0 ;i < SIZE_FRAME ; i++)
{
printk("%c",buf_area->fluke[temp_read_index].buffer[i]);
}
*/
return((temp_read_index));
}
/*****************************************************************************
* Description:This function is used to map the memory area to user
application.
* There is a circular buffer which is created in the driver.
* This region is mmaped to the user application by this function.
* This fuction sets the permissions for that area accordingly.
*
* Inputs:file pointer, virtual memory area structure.
*
* Outputs: Returns 0 on success or -1 on failure.
*******************************************************************************/
static int McBSP_DriverMmap(struct file *file,struct vm_area_struct *vma)
{
unsigned long start = vma->vm_start;
unsigned long size = vma->vm_end - vma->vm_start; //0x900000;
unsigned long phy_add = virt_to_phys(buf_ptr); //0x7700000;
int ret = 0;
/* Make the mmaped area noncacheable */
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
/* Set the Flags to give permissions to Mmaped area */
vma->vm_flags |=VM_RESERVED;
vma->vm_flags |=VM_READ;
vma->vm_flags |=VM_WRITE;
vma->vm_flags |=VM_IO;
//vma->vm_flags |=VM_SHARED;
//vma->vm_flags |=VM_LOCKED;
printk(KERN_DEBUG"In mmap function\n");
/* Mmap the kernel buffer to user space */
if(remap_pfn_range(vma,start,(phy_add >>
PAGE_SHIFT),size,vma->vm_page_prot))
//if(remap_pfn_range(vma,start,vma->vm_pgoff,size,vma->vm_page_prot))
{
printk(KERN_ALERT"remap_pfn_range failed\n");
goto mmap_exit;
}
printk(KERN_ALERT"phy addr 0x%08X mmapped to virt addr 0x%08X, size =
0x%08X\n",
(unsigned int)phy_add, (unsigned int)start, (unsigned int)size);
/* Initialize the file operation structure of Mmaped area */
vma->vm_ops=&mmap_op;
/* Open the Mmaped area */
MmapOpen(vma);
mmap_exit:
return ret;
}
/******************************************************************************
* Description: This function opens mmaped area for the device.
*
* Inputs: Virtual memory area structure.
*
* Outputs: none
******************************************************************************/
static void MmapOpen(struct vm_area_struct *vma)
{
printk("Mmaped are is opened \n");
printk("Virtual= %lx, Physical=%lx \n",vma->vm_start,
(vma->vm_pgoff << PAGE_SHIFT));
return;
}
/******************************************************************************
* Description: This function closes mmaped area for the device
*
* Inputs: Virtual Memory structure.
*
* Outputs: Return CASHEL_SUCCESS after closing the device.
******************************************************************************/
static void MmapClose(struct vm_area_struct *vma)
{
printk(KERN_DEBUG"Mmaped are is closed\n ");
return;
}
/******************************************************************************
*
* Description : Unregisters the driver and makes the resources free.
*
* Input : NIL
*
* Output : NIL
*
*****************************************************************************/
static void __exit McBSP_DriverExit(void)
{
unsigned int virt_addr;
#if 0
/* Clear or Free the pages which are reserverd */
for (virt_addr=(unsigned int)buf_area; virt_addr < (unsigned int)buf_area
+ sizeof(circularbuffer_S);
virt_addr += PAGE_SIZE)
{
// clear all pages
ClearPageReserved(virt_to_page(virt_addr));
}
/* Free the mmaped buffer area */
dma_free_coherent(NULL,L1_CACHE_ALIGN(sizeof(circularbuffer_S)),
buf_ptr,dma_addr);
#else
iounmap(buf_area);
#endif
/* Unregister the device */
if(unregister_chrdev(MAJOR_NO , MODULE_NAME)==0)
printk(KERN_DEBUG" device cleanup success\n");
else
printk(KERN_ALERT" device cleanup failed \n");
/* Free IRQ */
free_irq(DATA_ACQ_INT,NULL);
//if(buf_area)
// vfree(buf_area);
}
/******************************************************************************
* Description: This function closes the device
*
* Inputs: Inode structure pointer, File structure pointer
*
* Outputs: Return 0 on success and -1 on failure.
******************************************************************************/
static int McBSP_DriverClose(struct inode *inode,struct file *file)
{
device_open_count--;
if(device_open_count == 0)
{
/* Delete the timer */
del_timer(&fluke_timer);
}
printk(KERN_INFO" device closed %d\n",device_open_count);
return 0;
}
/******************************************************************************
* File Ends
*****************************************************************************/
#define MODULE_NAME "fluke_driver"
#define MAJOR_NO 333
#define NO_FRAMES 3
#define SIZE_FRAME 1024*5//(1024*1024*1)/* 3MB */
#define DATA_ACQ_INT 23 /* To Do <for testing only > */
#define DATA_ACQ_INT_CLEAR 1 /* To Do <for testing only > */
#define MAGIC_NUM 'D'
#define START_ACQ_DATA _IOWR(MAGIC_NUM, 0,unsigned long)
/* Frame */
typedef struct
{
char buffer[SIZE_FRAME];
}frame_S;
/* Circular Buffer Structured */
/* Mmaped area Structure */
typedef struct
{
frame_S fluke[NO_FRAMES];
}circularbuffer_S;
typedef struct
{
unsigned int count_index;
unsigned int read_index;
unsigned int write_index;
}circularbuffer_index_S;
typedef struct
{
int test_period_ms; /*????? send to driver*/
int req_no_sample; /*send to driver*/
int acq_no_of_sample; /* return by driver*/
int circular_index; /* return by driver*/
int sampling_rate_hz; /*send to driver*/
}daq_t;
/******************************************************************************
* File Ends
*****************************************************************************/
/******************************************************************************
* McBSP_appl.c
*
* Fluke Driver
*
* Description:
*
* Libraries Used:
*
*
* Unit Test Drivers (Binary):
*
* <fix me >
*
*
* Special Compile Flags
* Nil
*
* Revision History:
* (17/July/2008) Misbah
* Created the file
*
* Copyright (C)
*
******************************************************************************/
/******************************************************************************
* Include Files
*****************************************************************************/
/* Standard linux files includes */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include "fluke_driver.h"
#define FLUKE_DRIVER "/dev/fluke"
int main (int argc ,char *argv[])
{
circularbuffer_S *mmap_ptr;
int fd = -1,i;
int size_mmap = sizeof(circularbuffer_S);
int read_index = -1,ret = -1 ;
FILE *fp1,*fp2,*fp3;
char buf[1024];
char *mmap_data;
daq_t daq_param;
/* Initialize the config param */
daq_param.test_period_ms = 60*1000 ;
daq_param.acq_no_of_sample = 0;
daq_param.req_no_sample =0;
daq_param.sampling_rate_hz = 0;
mmap_data = (char *)malloc(sizeof(circularbuffer_S));
/* creat files for frames */
fp1 = fopen("frame1.txt","w");
fp2 = fopen("frame2.txt","w");
fp3 = fopen("frame3.txt","w");
/* Open the device file */
fd = open(FLUKE_DRIVER , O_RDWR);
if (fd == -1)
{
printf(" Error in opening fluke device \n");
return -1;
}
/* map the kernel memory to user space */
mmap_ptr = mmap(NULL,size_mmap,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
printf(" Virtual addr of the pointer is 0x%x \n",(unsigned int)mmap_ptr);
if(mmap_ptr == NULL )
{
printf(" mapped ptr returns NULL from driver n");
return -1;
}
while(1)
{
/* Write to driver for testing only */
memset(buf,'Z',sizeof(buf));
printf(" Writing to driver \n");
//write(fd,buf,sizeof(buf));
/* Block on read to get the circular buffer read index */
//read_index = read(fd, buf , 1024);
//printf(" Here is the read for you %s\n",buf);
if (ioctl(fd , START_ACQ_DATA ,&daq_param) < 0)
{
printf(" ioctl failed \n");
return -1 ;
}
read_index = daq_param.circular_index;
printf(" read index from application %d \n",read_index);
/* Print the data read */
//for(i = 0;i <= 1024 ; i++)
printf(" %s \n",mmap_ptr->fluke[read_index].buffer);
/* Write the data read fron the driver to the file */
if(read_index >= 0)
{
ret = (SIZE_FRAME) ;
memcpy(mmap_data, \
mmap_ptr->fluke[read_index].buffer,SIZE_FRAME);
if(read_index == 0)
fwrite(mmap_ptr->fluke[read_index].buffer ,SIZE_FRAME , 1 ,fp1);
else if(read_index == 1)
fwrite(mmap_ptr->fluke[read_index].buffer ,SIZE_FRAME , 1 ,fp2);
else if(read_index == 2)
fwrite(mmap_ptr->fluke[read_index].buffer ,SIZE_FRAME , 1 ,fp3);
else
{
printf("Not able to write to file as read_index returns %d
\n",read_index );
return -1;
}
}
}
if(mmap_data)
free(mmap_data);
fclose(fp1);
fclose(fp2);
fclose(fp3);
return 0;
}
/******************************************************************************
* File Ends
*****************************************************************************/
please help me to resolve this issue .......
Thanks in advance ...
---- Misbah <><
Misbah khan wrote:
>
>
> If you SDRAM is you main memory, you need vmalloc and remap_vmalloc_range.
> If the SDRAM is not your main memory but some I/O attached buffer, you
> need
> ioremap/of_iomap and remap_pfn_range.
>
> My SDRAM is the main memory of which 9MB i have to allocate in the driver.
>
> If i allocate 9BM using vmalloc and remap to user space how should it
> address to the 9MB
> SDRAM contigues address which i need to map for user access ?
>
>
> Arnd Bergmann wrote:
>>
>> On Tuesday 22 July 2008, Misbah khan wrote:
>>> First of all let me thank you for your valuable suggessions ...
>>>
>>> 1. I wanted to allocate 9MB in kernel and wanted that memory to be
>>> mapped to
>>> the physically continews SDRAM memory. but till now i could not found a
>>> way
>>> to do so ???
>>>
>>> 2. So i thought to use ioremap to map SDRAM and make it accessible to
>>> user
>>> using mmap technique but there is only one doubt and that is will it be
>>> secure and stable and whether it is a right way of doing ???
>>
>> As I have told you a few times now, you *either* allocate the memory *or*
>> ioremap it, NOT BOTH!!!
>>
>> If you SDRAM is you main memory, you need vmalloc and
>> remap_vmalloc_range.
>> If the SDRAM is not your main memory but some I/O attached buffer, you
>> need
>> ioremap/of_iomap and remap_pfn_range.
>>
>> Arnd <><
>> _______________________________________________
>> Linuxppc-embedded mailing list
>> Linuxppc-embedded@ozlabs.org
>> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>>
>>
>
>
--
View this message in context: http://www.nabble.com/how-to-allocate-9MB-of-memory-in-kernel---tp18503022p18627544.html
Sent from the linuxppc-embedded mailing list archive at Nabble.com.
^ permalink raw reply
* [RFC,PATCH] scripts/package: add powerpc images to tarball
From: Jeremy Kerr @ 2008-07-24 8:17 UTC (permalink / raw)
To: linux-kernel, linuxppc-dev
Currently, tarball builds for powerpc kernels don't have any boot
images (other than vmlinux) present.
Add support for powerpc builds in the buildtar script, to include
a few default images.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
---
RFC: any requests for more/less boot images?
---
scripts/package/buildtar | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/scripts/package/buildtar b/scripts/package/buildtar
index 28574ae..85e5563 100644
--- a/scripts/package/buildtar
+++ b/scripts/package/buildtar
@@ -72,6 +72,16 @@ case "${ARCH}" in
x86|i386|x86_64)
[ -f "${objtree}/arch/x86/boot/bzImage" ] && cp -v -- "${objtree}/arch/x86/boot/bzImage" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}"
;;
+ powerpc)
+ for img in zImage zImage.pseries zImage.iseries \
+ dtbImage dtbImage.ps3
+ do
+ imgpath=arch/powerpc/boot/${img}
+ [ -f "${objtree}/${imgpath}" ] || continue
+ cp -v -- "${objtree}/${imgpath}" \
+ "${tmpdir}/boot/${img}-${KERNELRELEASE}"
+ done
+ ;;
alpha)
[ -f "${objtree}/arch/alpha/boot/vmlinux.gz" ] && cp -v -- "${objtree}/arch/alpha/boot/vmlinux.gz" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}"
;;
^ permalink raw reply related
* Re: [PATCH 0/6][RFC] kvmppc: paravirtualization interface
From: Christian Ehrhardt @ 2008-07-24 8:17 UTC (permalink / raw)
To: Tony Breeds; +Cc: linuxppc-dev, embedded-hypervisor, hollisb, kvm-ppc
In-Reply-To: <20080724020112.GM20457@bakeyournoodle.com>
Tony Breeds wrote:
> On Wed, Jul 23, 2008 at 10:36:41AM +0200, ehrhardt@linux.vnet.ibm.com wrote:
>
>> From: Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
>>
>> This patch series implements a paravirtualization interface using:
>> - the device tree mechanism to pass hypervisor informations to the guest
>> - hypercalls for guest->host calls
>> - an example exploiter of that interface (magic page)
>> This is work in progress, but working so far. I just start to really exploit
>> the fuctionality behind the magic page mechanism therefor I can't provide any
>> performance improvements so far, but it is evolved enough for RFC and to start
>> the standardization discussion.
>>
>
> Are you aiming this for the current merge window, ie for 2.6.27?
>
The aim is not really fixed. It would be nice to get into 2.6.27, but
since I can't yet expect how long it takes ...
Actually the guest patches would already go through reviews and
upstream, due to the fact that the guest code changes are not that (the
major part of the implementation will go over kvmppc -> kvm upstream).
But since I want to discuss about the standardization on the embedded
hypervisor list first, the naming of the device tree entries are not
fixed yet.
Therefor I can't yet define which kernel version merge window I'll
target/reach.
btw - embedded hypervisor - I got advised that this is a closed list
which I forgot.
Sorry for all who got bounces on a replay-all action. The next version
of the patch series will go to the involved open source lists only and a
separate more standardization than patch style mail series to embedded
hypervisor.
> Yours Tony
>
> linux.conf.au http://www.marchsouth.org/
> Jan 19 - 24 2009 The Australian Linux Technical Conference!
>
--
Grüsse / regards,
Christian Ehrhardt
IBM Linux Technology Center, Open Virtualization
^ permalink raw reply
* Re: [PATCH 3/6] kvmppc: add hypercall infrastructure - guest part
From: Christian Ehrhardt @ 2008-07-24 7:56 UTC (permalink / raw)
To: Tony Breeds; +Cc: linuxppc-dev, embedded-hypervisor, hollisb, kvm-ppc
In-Reply-To: <20080724014538.GJ20457@bakeyournoodle.com>
Tony Breeds wrote:
> On Wed, Jul 23, 2008 at 10:36:44AM +0200, ehrhardt@linux.vnet.ibm.com wrote:
>
>> From: Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
>>
>
> Hi Christian,
>
>> This adds the guest portion of the hypercall infrastructure, basically an
>> illegal instruction with a defined layout.
>> See http://kvm.qumranet.com/kvmwiki/PowerPC_Hypercall_ABI for more detail
>> on the hypercall ABI for powerpc.
>>
>> Signed-off-by: Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
>> ---
>>
>> [diffstat]
>> kvm_para.h | 16 ++++++++++++++++
>> 1 file changed, 16 insertions(+)
>>
>> [diff]
>> diff --git a/include/asm-powerpc/kvm_para.h b/include/asm-powerpc/kvm_para.h
>> --- a/include/asm-powerpc/kvm_para.h
>> +++ b/include/asm-powerpc/kvm_para.h
>> @@ -25,6 +25,8 @@
>> #ifdef __KERNEL__
>>
>> #include <linux/of.h>
>> +
>> +#define KVM_HYPERCALL_BIN 0x03ffffff
>>
>
> Ummm didn't you add this in patch 2 of 6?
>
This is just because I initially wanted to split Host & Guest patch series.
I need to separate my patches a bit more anyway for the next submission
thanks for pointing out this duplication.
> Yours Tony
>
> linux.conf.au http://www.marchsouth.org/
> Jan 19 - 24 2009 The Australian Linux Technical Conference!
>
>
--
Grüsse / regards,
Christian Ehrhardt
IBM Linux Technology Center, Open Virtualization
^ permalink raw reply
* Re: [PATCH 1/6] kvmppc: read device tree hypervisor node infrastructure
From: Christian Ehrhardt @ 2008-07-24 7:44 UTC (permalink / raw)
To: Tony Breeds; +Cc: linuxppc-dev, hollisb, kvm-ppc
In-Reply-To: <20080724014133.GH20457@bakeyournoodle.com>
Tony Breeds wrote:
> On Wed, Jul 23, 2008 at 10:36:42AM +0200, ehrhardt@linux.vnet.ibm.com wrote:
>
> Hi Christian,
> A few comments inlined ...
>
>
[...]
>> +
>> static inline int kvm_para_available(void)
>> {
>> - return 0;
>> + struct device_node *dn;
>> +
>> + dn = of_find_node_by_path("/hypervisor");
>>
>
> You need an of_node_put(dn);
>
>
I just looked at the linux/of.h and did not see that I have to free it
again.
Thanks for the hint, I inserted both calls.
>> +
>> + return !!dn;
>> }
>>
>> static inline unsigned int kvm_arch_para_features(void)
>> {
>> - return 0;
>> + struct device_node *dn;
>> + const int *dtval;
>> + unsigned int features = 0;
>> + int i;
>> +
>> + dn = of_find_node_by_path("/hypervisor");
>> + if (!dn)
>> + return 0;
>> +
>> + for (i = 0; i < ARRAY_SIZE(para_features)-1; i++) {
>>
>
> Why -1? Isn't ARRAY_SIZE(para_features) adequate?
>
yeah I already had this, bit the change was folded into the wrong patch,
fixed now
[...]
> Yours Tony
>
> linux.conf.au http://www.marchsouth.org/
> Jan 19 - 24 2009 The Australian Linux Technical Conference!
>
>
--
Grüsse / regards,
Christian Ehrhardt
IBM Linux Technology Center, Open Virtualization
^ permalink raw reply
* Re: bug: mutex_lock() in interrupt conntext via phy_stop() in gianfar
From: Sebastian Siewior @ 2008-07-24 7:27 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: netdev, Li Yang, Nate Case, Vitaly Bordug, linuxppc-dev
In-Reply-To: <1216851168.11027.343.camel@pasglop>
* Benjamin Herrenschmidt | 2008-07-24 08:12:48 [+1000]:
>On Mon, 2008-07-21 at 17:57 -0500, Nate Case wrote:
>> On Fri, 2008-07-18 at 14:10 +0200, Sebastian Siewior wrote:
>> > Commit 35b5f6b1a aka [PHYLIB: Locking fixes for PHY I/O potentially sleeping]
>> > changed the phydev->lock from spinlock into a mutex. Now, the following
>> > code path got triggered while NFS was unavailable:
>> >
>> [snip]
>> > |[ 194.864733] BUG: sleeping function called from invalid context at /home/bigeasy/git/linux-2.6-powerpc/kernel/mutex.c:87
>> > |[ 194.875529] in_atomic():1, irqs_disabled():0
>> > |[ 194.879805] Call Trace:
>> > |[ 194.882250] [c0383d90] [c0006dd8] show_stack+0x48/0x184 (unreliable)
>> > |[ 194.888649] [c0383db0] [c001e938] __might_sleep+0xe0/0xf4
>> > |[ 194.894069] [c0383dc0] [c025a43c] mutex_lock+0x24/0x3c
>> > |[ 194.899234] [c0383de0] [c019005c] phy_stop+0x20/0x70
>> > |[ 194.904234] [c0383df0] [c018d4ec] stop_gfar+0x28/0xf4
>> > |[ 194.909305] [c0383e10] [c018e8c4] gfar_timeout+0x30/0x60
>> > |[ 194.914638] [c0383e20] [c01fe7c0] dev_watchdog+0xa8/0x144
>>
>> Hmm.. I'm not sure what the best solution is to this. Make the
>> stop_gfar() call happen in a workqueue, and make a similar change to
>> ucc_geth, fec_mpc52xx, and fs_enet? Modify phy_stop() to do the work in
>> a workqueue conditionally if in interrupt context? Between these two
>> I'd lean toward the latter.
>>
>> Does anyone have any better ideas?
>
>Move the reset task to a workqueue.
Done in [1] Ben.
[1] http://marc.info/?l=linux-netdev&m=121684347609062&w=2
>Cheers,
>Ben.
Sebastian
^ permalink raw reply
* filling dummy struct snd_dma_buffer
From: dinesh @ 2008-07-24 6:20 UTC (permalink / raw)
To: linuxppc-dev, alsa-devel, Grant Likely
In-Reply-To: <9e4733910807230709l4249eaf6m750bad811342ba13@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 154 bytes --]
Hi
i want to fill dummy "struct snd_dma_buffer" in which i want to pass base address of allocated BUFFER DESCRIPTOR(BD).
help me.
Regards,
Dinesh dua
[-- Attachment #2: Type: text/html, Size: 500 bytes --]
^ permalink raw reply
* Re: [PATCH 14/16 v4] ibmvscsi: driver enablement for CMO
From: Benjamin Herrenschmidt @ 2008-07-24 5:59 UTC (permalink / raw)
To: James Bottomley
Cc: linux-scsi, linuxppc-dev, paulus, Brian King, David Darrington
In-Reply-To: <20080723183527.GQ12905@linux.vnet.ibm.com>
On Wed, 2008-07-23 at 13:35 -0500, Robert Jennings wrote:
> From: Robert Jennings <rcj@linux.vnet.ibm.com>
>
> Enable the driver to function in a Cooperative Memory Overcommitment (CMO)
> environment.
>
> The following changes are made to enable the driver for CMO:
> * DMA mapping errors will not result in error messages if entitlement has
> been exceeded and resources were not available.
> * The driver has a get_desired_dma function defined to function
> in a CMO environment. It will indicate how much IO memory it would like
> to function.
>
> Signed-off-by: Robert Jennings <rcj@linux.vnet.ibm.com>
> Acked by: Brian King <brking@linux.vnet.ibm.com>
>
> ---
> We would like to take this patch through linuxppc-dev with the full
> change set for this feature. We are copying linux-scsi for review and ack.
James, if you are ok with this patch, can you Ack it ? I'll merge it via
the powerpc tree along with all its dependencies.
Thanks in advance !
Cheers,
Ben.
> ---
> drivers/scsi/ibmvscsi/ibmvscsi.c | 45 +++++++++++++++++++++++++++++++++------
> drivers/scsi/ibmvscsi/ibmvscsi.h | 2 ++
> 2 files changed, 40 insertions(+), 7 deletions(-)
>
> Index: b/drivers/scsi/ibmvscsi/ibmvscsi.c
> ===================================================================
> --- a/drivers/scsi/ibmvscsi/ibmvscsi.c
> +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
> @@ -72,6 +72,7 @@
> #include <linux/delay.h>
> #include <asm/firmware.h>
> #include <asm/vio.h>
> +#include <asm/firmware.h>
> #include <scsi/scsi.h>
> #include <scsi/scsi_cmnd.h>
> #include <scsi/scsi_host.h>
> @@ -426,8 +427,10 @@ static int map_sg_data(struct scsi_cmnd
> SG_ALL * sizeof(struct srp_direct_buf),
> &evt_struct->ext_list_token, 0);
> if (!evt_struct->ext_list) {
> - sdev_printk(KERN_ERR, cmd->device,
> - "Can't allocate memory for indirect table\n");
> + if (!firmware_has_feature(FW_FEATURE_CMO))
> + sdev_printk(KERN_ERR, cmd->device,
> + "Can't allocate memory "
> + "for indirect table\n");
> return 0;
> }
> }
> @@ -743,7 +746,9 @@ static int ibmvscsi_queuecommand(struct
> srp_cmd->lun = ((u64) lun) << 48;
>
> if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
> - sdev_printk(KERN_ERR, cmnd->device, "couldn't convert cmd to srp_cmd\n");
> + if (!firmware_has_feature(FW_FEATURE_CMO))
> + sdev_printk(KERN_ERR, cmnd->device,
> + "couldn't convert cmd to srp_cmd\n");
> free_event_struct(&hostdata->pool, evt_struct);
> return SCSI_MLQUEUE_HOST_BUSY;
> }
> @@ -855,7 +860,10 @@ static void send_mad_adapter_info(struct
> DMA_BIDIRECTIONAL);
>
> if (dma_mapping_error(req->buffer)) {
> - dev_err(hostdata->dev, "Unable to map request_buffer for adapter_info!\n");
> + if (!firmware_has_feature(FW_FEATURE_CMO))
> + dev_err(hostdata->dev,
> + "Unable to map request_buffer for "
> + "adapter_info!\n");
> free_event_struct(&hostdata->pool, evt_struct);
> return;
> }
> @@ -1400,7 +1408,9 @@ static int ibmvscsi_do_host_config(struc
> DMA_BIDIRECTIONAL);
>
> if (dma_mapping_error(host_config->buffer)) {
> - dev_err(hostdata->dev, "dma_mapping error getting host config\n");
> + if (!firmware_has_feature(FW_FEATURE_CMO))
> + dev_err(hostdata->dev,
> + "dma_mapping error getting host config\n");
> free_event_struct(&hostdata->pool, evt_struct);
> return -1;
> }
> @@ -1604,7 +1614,7 @@ static struct scsi_host_template driver_
> .eh_host_reset_handler = ibmvscsi_eh_host_reset_handler,
> .slave_configure = ibmvscsi_slave_configure,
> .change_queue_depth = ibmvscsi_change_queue_depth,
> - .cmd_per_lun = 16,
> + .cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT,
> .can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
> .this_id = -1,
> .sg_tablesize = SG_ALL,
> @@ -1613,6 +1623,26 @@ static struct scsi_host_template driver_
> };
>
> /**
> + * ibmvscsi_get_desired_dma - Calculate IO memory desired by the driver
> + *
> + * @vdev: struct vio_dev for the device whose desired IO mem is to be returned
> + *
> + * Return value:
> + * Number of bytes of IO data the driver will need to perform well.
> + */
> +static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev)
> +{
> + /* iu_storage data allocated in initialize_event_pool */
> + unsigned long desired_io = max_requests * sizeof(union viosrp_iu);
> +
> + /* add io space for sg data */
> + desired_io += (IBMVSCSI_MAX_SECTORS_DEFAULT *
> + IBMVSCSI_CMDS_PER_LUN_DEFAULT);
> +
> + return desired_io;
> +}
> +
> +/**
> * Called by bus code for each adapter
> */
> static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
> @@ -1641,7 +1671,7 @@ static int ibmvscsi_probe(struct vio_dev
> hostdata->host = host;
> hostdata->dev = dev;
> atomic_set(&hostdata->request_limit, -1);
> - hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */
> + hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT;
>
> rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_requests);
> if (rc != 0 && rc != H_RESOURCE) {
> @@ -1735,6 +1765,7 @@ static struct vio_driver ibmvscsi_driver
> .id_table = ibmvscsi_device_table,
> .probe = ibmvscsi_probe,
> .remove = ibmvscsi_remove,
> + .get_desired_dma = ibmvscsi_get_desired_dma,
> .driver = {
> .name = "ibmvscsi",
> .owner = THIS_MODULE,
> Index: b/drivers/scsi/ibmvscsi/ibmvscsi.h
> ===================================================================
> --- a/drivers/scsi/ibmvscsi/ibmvscsi.h
> +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
> @@ -45,6 +45,8 @@ struct Scsi_Host;
> #define MAX_INDIRECT_BUFS 10
>
> #define IBMVSCSI_MAX_REQUESTS_DEFAULT 100
> +#define IBMVSCSI_CMDS_PER_LUN_DEFAULT 16
> +#define IBMVSCSI_MAX_SECTORS_DEFAULT 256 /* 32 * 8 = default max I/O 32 pages */
> #define IBMVSCSI_MAX_CMDS_PER_LUN 64
>
> /* ------------------------------------------------------------
^ permalink raw reply
* Re: Getting GPIO to build again
From: Grant Likely @ 2008-07-24 5:08 UTC (permalink / raw)
To: Jon Smirl; +Cc: ppc-dev
In-Reply-To: <9e4733910807232009o634027cajde78395f95ae95ce@mail.gmail.com>
On Wed, Jul 23, 2008 at 11:09:59PM -0400, Jon Smirl wrote:
> I just synced up to linus/master....
There is a fix for this in my tree for the 5200, but ben/paulus haven't
pulled it yet.
g.
>
> CC arch/powerpc/platforms/52xx/mpc52xx_gpio.o
> In file included from arch/powerpc/platforms/52xx/mpc52xx_gpio.c:22:
> include/linux/of_gpio.h:26: error: field 'gc' has incomplete type
> include/linux/of_gpio.h: In function 'to_of_gpio_chip':
> include/linux/of_gpio.h:34: warning: type defaults to 'int' in
> declaration of '__mptr'
> include/linux/of_gpio.h:34: warning: initialization from incompatible
> pointer type
> In file included from include/asm/gpio.h:18,
> from arch/powerpc/platforms/52xx/mpc52xx_gpio.c:26:
> include/asm-generic/gpio.h: At top level:
> include/asm-generic/gpio.h:24: error: redefinition of 'gpio_is_valid'
> include/linux/gpio.h:24: error: previous definition of 'gpio_is_valid' was here
> In file included from arch/powerpc/platforms/52xx/mpc52xx_gpio.c:26:
> include/asm/gpio.h:27: error: redefinition of 'gpio_get_value'
> include/linux/gpio.h:50: error: previous definition of 'gpio_get_value' was here
> include/asm/gpio.h:32: error: redefinition of 'gpio_set_value'
> include/linux/gpio.h:57: error: previous definition of 'gpio_set_value' was here
> include/asm/gpio.h:37: error: redefinition of 'gpio_cansleep'
> include/linux/gpio.h:63: error: previous definition of 'gpio_cansleep' was here
> include/asm/gpio.h:45: error: redefinition of 'gpio_to_irq'
> include/linux/gpio.h:83: error: previous definition of 'gpio_to_irq' was here
> include/asm/gpio.h:50: error: redefinition of 'irq_to_gpio'
> include/linux/gpio.h:90: error: previous definition of 'irq_to_gpio' was here
> make[2]: *** [arch/powerpc/platforms/52xx/mpc52xx_gpio.o] Error 1
> make[1]: *** [arch/powerpc/platforms/52xx] Error 2
> make: *** [arch/powerpc/platforms] Error 2
>
>
> --
> Jon Smirl
> jonsmirl@gmail.com
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
^ permalink raw reply
* [PATCH v2] powerpc/cell: set fixed mapping to weak if we find a pcie-endpoint
From: Mark Nelson @ 2008-07-24 4:28 UTC (permalink / raw)
To: linuxppc-dev; +Cc: paulus
In-Reply-To: <200807241022.44903.markn@au1.ibm.com>
From: Mark Nelson <markn@au1.ibm.com>
At the moment the fixed mapping is by default strongly ordered (the
iommu_fixed=weak boot option must be used to make the fixed mapping weakly
ordered). If we're on a setup where the southbridge is being used in
endpoint mode (triblade and CAB boards) the default should be a weakly
ordered fixed mapping.
This adds a check so that if a node of type pcie-endpoint can be found in
the device tree the fixed mapping is set to be weak by default (but can be
overridden using iommu_fixed=strong).
Signed-off-by: Mark Nelson <markn@au1.ibm.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
Updated thanks to Stephen Rothwell's tip that pciep didn't need to be initialized
Sorry for any confusion
arch/powerpc/platforms/cell/iommu.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
Index: upstream/arch/powerpc/platforms/cell/iommu.c
===================================================================
--- upstream.orig/arch/powerpc/platforms/cell/iommu.c
+++ upstream/arch/powerpc/platforms/cell/iommu.c
@@ -1150,12 +1150,23 @@ static int iommu_fixed_disabled;
static int __init setup_iommu_fixed(char *str)
{
+ struct device_node *pciep;
+
if (strcmp(str, "off") == 0)
iommu_fixed_disabled = 1;
- else if (strcmp(str, "weak") == 0)
+ /* If we can find a pcie-endpoint in the device tree assume that
+ * we're on a triblade or a CAB so by default the fixed mapping
+ * should be set to be weakly ordered; but only if the boot
+ * option WASN'T set for strong ordering
+ */
+ pciep = of_find_node_by_type(NULL, "pcie-endpoint");
+
+ if (strcmp(str, "weak") == 0 || (pciep && strcmp(str, "strong") != 0))
iommu_fixed_is_weak = 1;
+ of_node_put(pciep);
+
return 1;
}
__setup("iommu_fixed=", setup_iommu_fixed);
^ permalink raw reply
* section .dummy lma 0xc0294310 overlaps previous sections
From: Sean MacLennan @ 2008-07-24 4:18 UTC (permalink / raw)
To: linuxppc-dev
Anybody else seeing these? With Linus' latest I get three of these
warnings: .tmp_vmlinux1, .tmp_vmlinux2, and vmlinux.
The kernel boots.
Cheers,
Sean
^ permalink raw reply
* Re: [PATCH] [V2] powerpc: Xilinx: PS2: driver updates based on review
From: Dmitry Torokhov @ 2008-07-24 3:37 UTC (permalink / raw)
To: John Linn; +Cc: Sadanand, linuxppc-dev, linux-input
In-Reply-To: <20080710193451.ED2B51D18066@mail97-dub.bigfish.com>
Hi John,
On Thu, Jul 10, 2008 at 12:34:43PM -0700, John Linn wrote:
> Review comments were incorporated to improve the driver.
>
> 1. Some data was eliminated that was not needed.
> 2. Renaming of variables for clarity.
> 3. Removed unneeded type casting.
> 4. Changed to use dev_err rather than other I/O.
> 5. Merged together some functions.
> 6. Added kerneldoc format to functions.
>
There were some changes made to the original version of the patch that I
applied so this one did not patch cleanly. I think I fixed it up right
but if you could give it a look over before I commit it that would be
great.
Thanks!
--
Dmitry
Input: xilinx_ps2 - various cleanups
From: John Linn <john.linn@xilinx.com>
Review comments were incorporated to improve the driver.
1. Some data was eliminated that was not needed.
2. Renaming of variables for clarity.
3. Removed unneeded type casting.
4. Changed to use dev_err rather than other I/O.
5. Merged together some functions.
6. Added kerneldoc format to functions.
Signed-off-by: Sadanand <sadanan@xilinx.com>
Signed-off-by: John Linn <john.linn@xilinx.com>
Acked-by: Peter Korsgaard <jacmet@sunsite.dk>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---
drivers/input/serio/xilinx_ps2.c | 211 +++++++++++++++++++-------------------
1 files changed, 108 insertions(+), 103 deletions(-)
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c
index 0ed044d..85515cf 100644
--- a/drivers/input/serio/xilinx_ps2.c
+++ b/drivers/input/serio/xilinx_ps2.c
@@ -58,23 +58,20 @@
/* Mask for all the Receive Interrupts */
#define XPS2_IPIXR_RX_ALL (XPS2_IPIXR_RX_OVF | XPS2_IPIXR_RX_ERR | \
- XPS2_IPIXR_RX_FULL)
+ XPS2_IPIXR_RX_FULL)
/* Mask for all the Interrupts */
#define XPS2_IPIXR_ALL (XPS2_IPIXR_TX_ALL | XPS2_IPIXR_RX_ALL | \
- XPS2_IPIXR_WDT_TOUT)
+ XPS2_IPIXR_WDT_TOUT)
/* Global Interrupt Enable mask */
#define XPS2_GIER_GIE_MASK 0x80000000
struct xps2data {
int irq;
- u32 phys_addr;
- u32 remap_size;
spinlock_t lock;
- u8 rxb; /* Rx buffer */
void __iomem *base_address; /* virt. address of control registers */
- unsigned int dfl;
+ unsigned int flags;
struct serio serio; /* serio */
};
@@ -82,8 +79,13 @@ struct xps2data {
/* XPS PS/2 data transmission calls */
/************************************/
-/*
- * xps2_recv() will attempt to receive a byte of data from the PS/2 port.
+/**
+ * xps2_recv() - attempts to receive a byte from the PS/2 port.
+ * @drvdata: pointer to ps2 device private data structure
+ * @byte: address where the read data will be copied
+ *
+ * If there is any data available in the PS/2 receiver, this functions reads
+ * the data, otherwise it returns error.
*/
static int xps2_recv(struct xps2data *drvdata, u8 *byte)
{
@@ -116,33 +118,27 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)
/* Check which interrupt is active */
if (intr_sr & XPS2_IPIXR_RX_OVF)
- printk(KERN_WARNING "%s: receive overrun error\n",
- drvdata->serio.name);
+ dev_warn(drvdata->serio.dev.parent, "receive overrun error\n");
if (intr_sr & XPS2_IPIXR_RX_ERR)
- drvdata->dfl |= SERIO_PARITY;
+ drvdata->flags |= SERIO_PARITY;
if (intr_sr & (XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_WDT_TOUT))
- drvdata->dfl |= SERIO_TIMEOUT;
+ drvdata->flags |= SERIO_TIMEOUT;
if (intr_sr & XPS2_IPIXR_RX_FULL) {
- status = xps2_recv(drvdata, &drvdata->rxb);
+ status = xps2_recv(drvdata, &c);
/* Error, if a byte is not received */
if (status) {
- printk(KERN_ERR
- "%s: wrong rcvd byte count (%d)\n",
- drvdata->serio.name, status);
+ dev_err(drvdata->serio.dev.parent,
+ "wrong rcvd byte count (%d)\n", status);
} else {
- c = drvdata->rxb;
- serio_interrupt(&drvdata->serio, c, drvdata->dfl);
- drvdata->dfl = 0;
+ serio_interrupt(&drvdata->serio, c, drvdata->flags);
+ drvdata->flags = 0;
}
}
- if (intr_sr & XPS2_IPIXR_TX_ACK)
- drvdata->dfl = 0;
-
return IRQ_HANDLED;
}
@@ -150,8 +146,15 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)
/* serio callbacks */
/*******************/
-/*
- * sxps2_write() sends a byte out through the PS/2 interface.
+/**
+ * sxps2_write() - sends a byte out through the PS/2 port.
+ * @pserio: pointer to the serio structure of the PS/2 port
+ * @c: data that needs to be written to the PS/2 port
+ *
+ * This function checks if the PS/2 transmitter is empty and sends a byte.
+ * Otherwise it returns error. Transmission fails only when nothing is connected
+ * to the PS/2 port. Thats why, we do not try to resend the data in case of a
+ * failure.
*/
static int sxps2_write(struct serio *pserio, unsigned char c)
{
@@ -174,33 +177,39 @@ static int sxps2_write(struct serio *pserio, unsigned char c)
return status;
}
-/*
- * sxps2_open() is called when a port is open by the higher layer.
+/**
+ * sxps2_open() - called when a port is opened by the higher layer.
+ * @pserio: pointer to the serio structure of the PS/2 device
+ *
+ * This function requests irq and enables interrupts for the PS/2 device.
*/
static int sxps2_open(struct serio *pserio)
{
struct xps2data *drvdata = pserio->port_data;
- int retval;
+ int error;
+ u8 c;
- retval = request_irq(drvdata->irq, &xps2_interrupt, 0,
+ error = request_irq(drvdata->irq, &xps2_interrupt, 0,
DRIVER_NAME, drvdata);
- if (retval) {
- printk(KERN_ERR
- "%s: Couldn't allocate interrupt %d\n",
- drvdata->serio.name, drvdata->irq);
- return retval;
+ if (error) {
+ dev_err(drvdata->serio.dev.parent,
+ "Couldn't allocate interrupt %d\n", drvdata->irq);
+ return error;
}
/* start reception by enabling the interrupts */
out_be32(drvdata->base_address + XPS2_GIER_OFFSET, XPS2_GIER_GIE_MASK);
out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, XPS2_IPIXR_RX_ALL);
- (void)xps2_recv(drvdata, &drvdata->rxb);
+ (void)xps2_recv(drvdata, &c);
return 0; /* success */
}
-/*
- * sxps2_close() frees the interrupt.
+/**
+ * sxps2_close() - frees the interrupt.
+ * @pserio: pointer to the serio structure of the PS/2 device
+ *
+ * This function frees the irq and disables interrupts for the PS/2 device.
*/
static void sxps2_close(struct serio *pserio)
{
@@ -212,24 +221,41 @@ static void sxps2_close(struct serio *pserio)
free_irq(drvdata->irq, drvdata);
}
-/*********************/
-/* Device setup code */
-/*********************/
-
-static int xps2_setup(struct device *dev, struct resource *regs_res,
- struct resource *irq_res)
+/**
+ * xps2_of_probe - probe method for the PS/2 device.
+ * @of_dev: pointer to OF device structure
+ * @match: pointer to the stucture used for matching a device
+ *
+ * This function probes the PS/2 device in the device tree.
+ * It initializes the driver data structure and the hardware.
+ * It returns 0, if the driver is bound to the PS/2 device, or a negative
+ * value if there is an error.
+ */
+static int __devinit xps2_of_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
{
+ struct resource r_irq; /* Interrupt resources */
+ struct resource r_mem; /* IO mem resources */
struct xps2data *drvdata;
struct serio *serio;
- unsigned long remap_size;
- int retval;
+ struct device *dev = &ofdev->dev;
+ resource_size_t remap_size, phys_addr;
+ int error;
- if (!dev)
- return -EINVAL;
+ dev_info(dev, "Device Tree Probing \'%s\'\n",
+ ofdev->node->name);
- if (!regs_res || !irq_res) {
- dev_err(dev, "IO resource(s) not found\n");
- return -EINVAL;
+ /* Get iospace for the device */
+ error = of_address_to_resource(ofdev->node, 0, &r_mem);
+ if (error) {
+ dev_err(dev, "invalid address\n");
+ return error;
+ }
+
+ /* Get IRQ for the device */
+ if (of_irq_to_resource(ofdev->node, 0, &r_irq) == NO_IRQ) {
+ dev_err(dev, "no IRQ found\n");
+ return -ENODEV;
}
drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL);
@@ -241,24 +267,23 @@ static int xps2_setup(struct device *dev, struct resource *regs_res,
dev_set_drvdata(dev, drvdata);
spin_lock_init(&drvdata->lock);
- drvdata->irq = irq_res->start;
+ drvdata->irq = r_irq.start;
- remap_size = regs_res->end - regs_res->start + 1;
- if (!request_mem_region(regs_res->start, remap_size, DRIVER_NAME)) {
+ phys_addr = r_mem.start;
+ remap_size = r_mem.end - r_mem.start + 1;
+ if (!request_mem_region(phys_addr, remap_size, DRIVER_NAME)) {
dev_err(dev, "Couldn't lock memory region at 0x%08X\n",
- (unsigned int)regs_res->start);
- retval = -EBUSY;
+ (unsigned int)phys_addr);
+ error = -EBUSY;
goto failed1;
}
/* Fill in configuration data and add them to the list */
- drvdata->phys_addr = regs_res->start;
- drvdata->remap_size = remap_size;
- drvdata->base_address = ioremap(regs_res->start, remap_size);
+ drvdata->base_address = ioremap(phys_addr, remap_size);
if (drvdata->base_address == NULL) {
dev_err(dev, "Couldn't ioremap memory at 0x%08X\n",
- (unsigned int)regs_res->start);
- retval = -EFAULT;
+ (unsigned int)phys_addr);
+ error = -EFAULT;
goto failed2;
}
@@ -270,7 +295,8 @@ static int xps2_setup(struct device *dev, struct resource *regs_res,
out_be32(drvdata->base_address + XPS2_SRST_OFFSET, XPS2_SRST_RESET);
dev_info(dev, "Xilinx PS2 at 0x%08X mapped to 0x%08X, irq=%d\n",
- drvdata->phys_addr, (u32)drvdata->base_address, drvdata->irq);
+ (unsigned int)phys_addr, (u32)drvdata->base_address,
+ drvdata->irq);
serio = &drvdata->serio;
serio->id.type = SERIO_8042;
@@ -280,71 +306,50 @@ static int xps2_setup(struct device *dev, struct resource *regs_res,
serio->port_data = drvdata;
serio->dev.parent = dev;
snprintf(serio->name, sizeof(serio->name),
- "Xilinx XPS PS/2 at %08X", drvdata->phys_addr);
+ "Xilinx XPS PS/2 at %08X", (unsigned int)phys_addr);
snprintf(serio->phys, sizeof(serio->phys),
- "xilinxps2/serio at %08X", drvdata->phys_addr);
+ "xilinxps2/serio at %08X", (unsigned int)phys_addr);
serio_register_port(serio);
return 0; /* success */
failed2:
- release_mem_region(regs_res->start, remap_size);
+ release_mem_region(phys_addr, remap_size);
failed1:
kfree(drvdata);
dev_set_drvdata(dev, NULL);
- return retval;
-}
-
-/***************************/
-/* OF Platform Bus Support */
-/***************************/
-
-static int __devinit xps2_of_probe(struct of_device *ofdev, const struct
- of_device_id * match)
-{
- struct resource r_irq; /* Interrupt resources */
- struct resource r_mem; /* IO mem resources */
- int rc = 0;
-
- printk(KERN_INFO "Device Tree Probing \'%s\'\n",
- ofdev->node->name);
-
- /* Get iospace for the device */
- rc = of_address_to_resource(ofdev->node, 0, &r_mem);
- if (rc) {
- dev_err(&ofdev->dev, "invalid address\n");
- return rc;
- }
-
- /* Get IRQ for the device */
- rc = of_irq_to_resource(ofdev->node, 0, &r_irq);
- if (rc == NO_IRQ) {
- dev_err(&ofdev->dev, "no IRQ found\n");
- return rc;
- }
-
- return xps2_setup(&ofdev->dev, &r_mem, &r_irq);
+ return error;
}
+/**
+ * xps2_of_remove - unbinds the driver from the PS/2 device.
+ * @of_dev: pointer to OF device structure
+ *
+ * This function is called if a device is physically removed from the system or
+ * if the driver module is being unloaded. It frees any resources allocated to
+ * the device.
+ */
static int __devexit xps2_of_remove(struct of_device *of_dev)
{
struct device *dev = &of_dev->dev;
- struct xps2data *drvdata;
-
- if (!dev)
- return -EINVAL;
-
- drvdata = dev_get_drvdata(dev);
+ struct xps2data *drvdata = dev_get_drvdata(dev);
+ struct resource r_mem; /* IO mem resources */
serio_unregister_port(&drvdata->serio);
iounmap(drvdata->base_address);
- release_mem_region(drvdata->phys_addr, drvdata->remap_size);
+
+ /* Get iospace of the device */
+ if (of_address_to_resource(of_dev->node, 0, &r_mem))
+ dev_err(dev, "invalid address\n");
+ else
+ release_mem_region(r_mem.start, r_mem.end - r_mem.start + 1);
+
kfree(drvdata);
dev_set_drvdata(dev, NULL);
- return 0; /* success */
+ return 0;
}
/* Match table for of_platform binding */
^ permalink raw reply related
* Re: Getting GPIO to build again
From: Jon Smirl @ 2008-07-24 3:34 UTC (permalink / raw)
To: ppc-dev
In-Reply-To: <9e4733910807232009o634027cajde78395f95ae95ce@mail.gmail.com>
This lets me build again, no clue if it is the correct fix.
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 3a7a11a..e14dbe3 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -3,6 +3,7 @@ config OF_DEVICE
depends on OF && (SPARC || PPC_OF)
config OF_GPIO
+ select GENERIC_GPIO
def_bool y
depends on OF && PPC_OF && HAVE_GPIO_LIB
help
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply related
* Getting GPIO to build again
From: Jon Smirl @ 2008-07-24 3:09 UTC (permalink / raw)
To: ppc-dev
I just synced up to linus/master....
CC arch/powerpc/platforms/52xx/mpc52xx_gpio.o
In file included from arch/powerpc/platforms/52xx/mpc52xx_gpio.c:22:
include/linux/of_gpio.h:26: error: field 'gc' has incomplete type
include/linux/of_gpio.h: In function 'to_of_gpio_chip':
include/linux/of_gpio.h:34: warning: type defaults to 'int' in
declaration of '__mptr'
include/linux/of_gpio.h:34: warning: initialization from incompatible
pointer type
In file included from include/asm/gpio.h:18,
from arch/powerpc/platforms/52xx/mpc52xx_gpio.c:26:
include/asm-generic/gpio.h: At top level:
include/asm-generic/gpio.h:24: error: redefinition of 'gpio_is_valid'
include/linux/gpio.h:24: error: previous definition of 'gpio_is_valid' was here
In file included from arch/powerpc/platforms/52xx/mpc52xx_gpio.c:26:
include/asm/gpio.h:27: error: redefinition of 'gpio_get_value'
include/linux/gpio.h:50: error: previous definition of 'gpio_get_value' was here
include/asm/gpio.h:32: error: redefinition of 'gpio_set_value'
include/linux/gpio.h:57: error: previous definition of 'gpio_set_value' was here
include/asm/gpio.h:37: error: redefinition of 'gpio_cansleep'
include/linux/gpio.h:63: error: previous definition of 'gpio_cansleep' was here
include/asm/gpio.h:45: error: redefinition of 'gpio_to_irq'
include/linux/gpio.h:83: error: previous definition of 'gpio_to_irq' was here
include/asm/gpio.h:50: error: redefinition of 'irq_to_gpio'
include/linux/gpio.h:90: error: previous definition of 'irq_to_gpio' was here
make[2]: *** [arch/powerpc/platforms/52xx/mpc52xx_gpio.o] Error 1
make[1]: *** [arch/powerpc/platforms/52xx] Error 2
make: *** [arch/powerpc/platforms] Error 2
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* Re: [PATCH 0/6][RFC] kvmppc: paravirtualization interface
From: Tony Breeds @ 2008-07-24 2:01 UTC (permalink / raw)
To: ehrhardt; +Cc: linuxppc-dev, embedded-hypervisor, hollisb, kvm-ppc
In-Reply-To: <1216802207-32675-1-git-send-email-ehrhardt@linux.vnet.ibm.com>
On Wed, Jul 23, 2008 at 10:36:41AM +0200, ehrhardt@linux.vnet.ibm.com wrote:
> From: Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
>
> This patch series implements a paravirtualization interface using:
> - the device tree mechanism to pass hypervisor informations to the guest
> - hypercalls for guest->host calls
> - an example exploiter of that interface (magic page)
> This is work in progress, but working so far. I just start to really exploit
> the fuctionality behind the magic page mechanism therefor I can't provide any
> performance improvements so far, but it is evolved enough for RFC and to start
> the standardization discussion.
Are you aiming this for the current merge window, ie for 2.6.27?
Yours Tony
linux.conf.au http://www.marchsouth.org/
Jan 19 - 24 2009 The Australian Linux Technical Conference!
^ permalink raw reply
* Re: [PATCH 5/6] kvmppc: magic page paravirtualization - guest part
From: Tony Breeds @ 2008-07-24 1:59 UTC (permalink / raw)
To: ehrhardt; +Cc: linuxppc-dev, embedded-hypervisor, hollisb, kvm-ppc
In-Reply-To: <1216802207-32675-6-git-send-email-ehrhardt@linux.vnet.ibm.com>
On Wed, Jul 23, 2008 at 10:36:46AM +0200, ehrhardt@linux.vnet.ibm.com wrote:
Hi Christian,
<snip>
> +/*
> + * this is guest memory granted to the hypervisor;
> + * the hypervisor can place data in this area and rewrite
> + * privileged instructions to read from this area without
> + * trapping.
> + * Only the Hypervisor needs to be aware of the structure layout
> + * which makes the guest more felxible - the guest only guarantees
> + * the size which is requested by the hypervisor and read from a
> + * device tree entry.
> + */
> +void *kvm_magicpage;
static?
<snip>
> +/* reads the specified data field out of the hypervisor node */
> +static inline int kvmppc_pv_read_data(char *dtcell)
> +{
> + struct device_node *dn;
> + const int *dtval;
> +
> + dn = of_find_node_by_path("/hypervisor");
> + if (!dn)
> + return -EINVAL;
> +
> + dtval = of_get_property(dn, dtcell, NULL);
> + if (dtval)
> + return *dtval;
> + else
> + return -EINVAL;
You need an of_node_put(dn) in this function somewhere.
Yours Tony
linux.conf.au http://www.marchsouth.org/
Jan 19 - 24 2009 The Australian Linux Technical Conference!
^ permalink raw reply
* Re: [PATCH 4/6] kvmppc: magic page hypercall - host part
From: Tony Breeds @ 2008-07-24 1:49 UTC (permalink / raw)
To: ehrhardt; +Cc: linuxppc-dev, embedded-hypervisor, hollisb, kvm-ppc
In-Reply-To: <1216802207-32675-5-git-send-email-ehrhardt@linux.vnet.ibm.com>
On Wed, Jul 23, 2008 at 10:36:45AM +0200, ehrhardt@linux.vnet.ibm.com wrote:
Hi Christian,
> long kvm_arch_dev_ioctl(struct file *filp,
> unsigned int ioctl, unsigned long arg)
> {
> - return -EINVAL;
> + long r = -EINVAL;
> +
> + switch (ioctl) {
> + case KVM_GET_PPCPV_MAGICPAGE_SIZE:
> + r = -EINVAL;
Not needed you set it on the declaration.
> + if (arg)
> + goto out;
> + r = 1024;
Ummm what does 1024 represent? can it me #defined? or at least add a
comment.
> + break;
> + default:
> + r = -EINVAL;
Not needed you set it on the declaration.
> + }
> +out:
> + return r;
> }
Yours Tony
linux.conf.au http://www.marchsouth.org/
Jan 19 - 24 2009 The Australian Linux Technical Conference!
^ 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