* [RFC/PATCH 5/7] Enable MSI on Powerpc
From: Michael Ellerman @ 2006-09-28 21:53 UTC (permalink / raw)
To: linux-kernel; +Cc: Eric W. Biederman, linuxppc-dev
In-Reply-To: <1159480412.269240.988552559176.qpush@concordia>
Allow PCI_MSI to build on Powerpc.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/kernel/Makefile | 4 ++++
drivers/pci/Kconfig | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
Index: to-merge/arch/powerpc/kernel/Makefile
===================================================================
--- to-merge.orig/arch/powerpc/kernel/Makefile
+++ to-merge/arch/powerpc/kernel/Makefile
@@ -67,6 +67,10 @@ pci64-$(CONFIG_PPC64) += pci_64.o pci_d
pci_direct_iommu.o iomap.o
pci32-$(CONFIG_PPC32) := pci_32.o
obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y)
+
+msiobj-y := msi.o
+obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
+
kexec-$(CONFIG_PPC64) := machine_kexec_64.o
kexec-$(CONFIG_PPC32) := machine_kexec_32.o
obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o $(kexec-y)
Index: to-merge/drivers/pci/Kconfig
===================================================================
--- to-merge.orig/drivers/pci/Kconfig
+++ to-merge/drivers/pci/Kconfig
@@ -4,7 +4,7 @@
config PCI_MSI
bool "Message Signaled Interrupts (MSI and MSI-X)"
depends on PCI
- depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
+ depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || PPC
help
This allows device drivers to enable MSI (Message Signaled
Interrupts). Message Signaled Interrupts enable a device to
^ permalink raw reply
* [RFC/PATCH 6/7] RTAS MSI implementation
From: Michael Ellerman @ 2006-09-28 21:53 UTC (permalink / raw)
To: linux-kernel; +Cc: Eric W. Biederman, linuxppc-dev
In-Reply-To: <1159480412.269240.988552559176.qpush@concordia>
Powerpc MSI support via RTAS. Based on Jake's code.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/kernel/Makefile | 1
arch/powerpc/kernel/msi-rtas.c | 246 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 247 insertions(+)
Index: to-merge/arch/powerpc/kernel/Makefile
===================================================================
--- to-merge.orig/arch/powerpc/kernel/Makefile
+++ to-merge/arch/powerpc/kernel/Makefile
@@ -69,6 +69,7 @@ pci32-$(CONFIG_PPC32) := pci_32.o
obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y)
msiobj-y := msi.o
+msiobj-$(CONFIG_PPC_PSERIES) += msi-rtas.o
obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
kexec-$(CONFIG_PPC64) := machine_kexec_64.o
Index: to-merge/arch/powerpc/kernel/msi-rtas.c
===================================================================
--- /dev/null
+++ to-merge/arch/powerpc/kernel/msi-rtas.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2006 Jake Moilanen <moilanen@austin.ibm.com>, IBM Corp.
+ * Copyright (C) 2006 Michael Ellerman, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#define DEBUG 1
+
+#include <linux/irq.h>
+#include <asm/msi.h>
+#include <asm/rtas.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+static int query_token, change_token;
+
+#define RTAS_QUERY_MSI_FN 0
+#define RTAS_CHANGE_MSI_FN 1
+#define RTAS_RESET_MSI_FN 2
+
+
+/* RTAS Helpers */
+
+static int rtas_change_msi(struct pci_dn *pdn, u32 function, u32 num_irqs)
+{
+ u32 addr, seq_num, rtas_ret[2];
+ unsigned long buid;
+ int rc;
+
+ addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+ buid = pdn->phb->buid;
+
+ seq_num = 1;
+ do {
+ rc = rtas_call(change_token, 6, 3, rtas_ret, addr,
+ BUID_HI(buid), BUID_LO(buid),
+ function, num_irqs, seq_num);
+
+ seq_num = rtas_ret[1];
+ } while (rtas_busy_delay(rc));
+
+ if (rc) {
+ printk(KERN_WARNING "Error[%d]: getting the number of"
+ " MSI interrupts for %s\n", rc, pci_name(pdn->pcidev));
+ return rc;
+ }
+
+ return rtas_ret[0];
+}
+
+static int rtas_query_irq_number(struct pci_dn *pdn, int offset)
+{
+ u32 addr, rtas_ret[2];
+ unsigned long buid;
+ int rc;
+
+ addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+ buid = pdn->phb->buid;
+
+ do {
+ rc = rtas_call(query_token, 4, 3, rtas_ret, addr,
+ BUID_HI(buid), BUID_LO(buid), offset);
+ } while (rtas_busy_delay(rc));
+
+ if (rc) {
+ printk(KERN_WARNING "Error[%d]: Querying irq source number "
+ "for %s\n", rc, pci_name(pdn->pcidev));
+ return rc;
+ }
+
+ return rtas_ret[0];
+}
+
+/*
+ * The spec gives firmware the option to enable either MSI or MSI-X,
+ * this doesn't wash with the Linux API. For the time beinging, we
+ * kludge around that by checking ourselves the right type is enabled.
+ */
+static int check_msi_type(struct pci_dev *pdev, int type)
+{
+ int pos, msi_enabled, msix_enabled;
+ u16 reg;
+
+ pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
+ if (!pos)
+ return -1;
+
+ pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, ®);
+
+ msi_enabled = msix_enabled = 0;
+
+ if (reg & PCI_MSI_FLAGS_ENABLE)
+ msi_enabled = 1;
+
+ if (reg & PCI_MSIX_FLAGS_ENABLE)
+ msix_enabled = 1;
+
+ if (type == PCI_CAP_ID_MSI && (msix_enabled || !msi_enabled)) {
+ pr_debug("check_msi_type: Expected MSI but got %s.\n",
+ msix_enabled ? "MSI-X" : "none");
+ return -1;
+ }
+
+ if (type == PCI_CAP_ID_MSIX && (msi_enabled || !msix_enabled)) {
+ pr_debug("check_msi_type: Expected MSI-X but got %s.\n",
+ msi_enabled ? "MSI" : "none");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void msi_rtas_free(struct pci_dev *pdev, int num,
+ struct msix_entry *entries, int type)
+{
+ struct device_node *dn;
+ struct pci_dn *pdn;
+ int i;
+
+ dn = pci_device_to_OF_node(pdev);
+ if (!dn) {
+ pr_debug("msi_rtas_free: No OF device node for %s\n",
+ pci_name(pdev));
+ return;
+ }
+
+ pdn = PCI_DN(dn);
+ if (!pdn) {
+ pr_debug("msi_rtas_free: No PCI DN for %s\n",
+ pci_name(pdev));
+ return;
+ }
+
+ for (i = 0; i < num; i++) {
+ irq_dispose_mapping(entries[i].vector);
+ }
+
+ /* XXX can we do anything sane if this fails? */
+ rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, 0);
+}
+
+static int msi_rtas_check(struct pci_dev *pdev, int num,
+ struct msix_entry *entries, int type)
+{
+ struct device_node *dn;
+ int i;
+
+ dn = pci_device_to_OF_node(pdev);
+
+ if (!of_find_property(dn, "ibm,req#msi", NULL)) {
+ pr_debug("msi_rtas_check: No ibm,req#msi for %s\n",
+ pci_name(pdev));
+ return -1;
+ }
+
+ /*
+ * Firmware gives us no control over which entries are allocated
+ * for MSI-X, it seems to assume we want 0 - n. For now just insist
+ * that the entries array entry members are 0 - n.
+ */
+ for (i = 0; i < num; i++) {
+ if (entries[i].entry != i) {
+ pr_debug("msi_rtas_check: entries[i].entry != i\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int msi_rtas_alloc(struct pci_dev *pdev, int num,
+ struct msix_entry *entries, int type)
+{
+ struct pci_dn *pdn;
+ int hwirq, virq, i;
+
+ pdn = PCI_DN(pci_device_to_OF_node(pdev));
+
+ /*
+ * In the case of an error it's not clear whether the device is left
+ * with MSI enabled or not, I think we should explicitly disable.
+ */
+ if (rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, num) != num)
+ goto out_free;
+
+ if (check_msi_type(pdev, type))
+ goto out_free;
+
+ for (i = 0; i < num; i++) {
+ hwirq = rtas_query_irq_number(pdn, i);
+ if (hwirq < 0)
+ goto out_free;
+
+ virq = irq_create_mapping(NULL, hwirq);
+
+ if (virq == NO_IRQ) {
+ pr_debug("msi_rtas_alloc: Failed mapping hwirq %d\n",
+ hwirq);
+ goto out_free;
+ }
+
+ entries[i].vector = virq;
+ }
+
+ return 0;
+
+ out_free:
+ msi_rtas_free(pdev, num, entries, type);
+ return -1;
+}
+
+static struct ppc_msi_ops rtas_msi_ops = {
+ .check = msi_rtas_check,
+ .alloc = msi_rtas_alloc,
+ .free = msi_rtas_free
+};
+
+static struct ppc_msi_ops *rtas_get_msi_ops(struct pci_dev *pdev)
+{
+ return &rtas_msi_ops;
+}
+
+static int msi_rtas_init(void)
+{
+ query_token = rtas_token("ibm,query-interrupt-source-number");
+ change_token = rtas_token("ibm,change-msi");
+
+ if ((query_token == RTAS_UNKNOWN_SERVICE) ||
+ (change_token == RTAS_UNKNOWN_SERVICE)) {
+ pr_debug("rtas_msi_init: Couldn't find RTAS tokens, no "
+ "MSI support available.\n");
+ return 0;
+ }
+
+ pr_debug("rtas_msi_init: Registering RTAS MSI ops.\n");
+
+ ppc_md.get_msi_ops = rtas_get_msi_ops;
+
+ return 0;
+}
+__initcall(msi_rtas_init);
^ permalink raw reply
* [RFC/PATCH 7/7] Preliminary MPIC MSI backend
From: Michael Ellerman @ 2006-09-28 21:53 UTC (permalink / raw)
To: linux-kernel; +Cc: Eric W. Biederman, linuxppc-dev
In-Reply-To: <1159480412.269240.988552559176.qpush@concordia>
A pretty hackish MPIC backend, just enough to flesh out the design.
Based on code from Segher.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/kernel/Makefile | 1
arch/powerpc/kernel/msi-mpic.c | 90 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 91 insertions(+)
Index: to-merge/arch/powerpc/kernel/Makefile
===================================================================
--- to-merge.orig/arch/powerpc/kernel/Makefile
+++ to-merge/arch/powerpc/kernel/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_PCI) += $(pci64-y) $(pci32
msiobj-y := msi.o
msiobj-$(CONFIG_PPC_PSERIES) += msi-rtas.o
+msiobj-$(CONFIG_PPC_PMAC) += msi-mpic.o
obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
kexec-$(CONFIG_PPC64) := machine_kexec_64.o
Index: to-merge/arch/powerpc/kernel/msi-mpic.c
===================================================================
--- /dev/null
+++ to-merge/arch/powerpc/kernel/msi-mpic.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2006 Segher Boessenkool, IBM Corp.
+ * Copyright (C) 2006 Michael Ellerman, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#define DEBUG 1
+
+#include <linux/irq.h>
+#include <asm/msi.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+static int msi_mpic_check(struct pci_dev *pdev, int num,
+ struct msix_entry *entries, int type)
+{
+ /* The irq allocator needs more work to support MSI-X/multi-MSI */
+ if (type == PCI_CAP_ID_MSIX || num != 1)
+ return 1;
+
+ return 0;
+}
+
+static void msi_mpic_free(struct pci_dev *pdev, int num,
+ struct msix_entry *entries, int type)
+{
+ for (i = 0; i < num; i++)
+ irq_dispose_mapping(entries[i].vector);
+}
+
+static int msi_mpic_alloc(struct pci_dev *pdev, int num,
+ struct msix_entry *entries, int type)
+{
+ irq_hw_number_t hwirq;
+ unsigned int virq;
+
+ /* We need a smarter allocator for MSI-X/multi-MSI */
+ hwirq = irq_map[pdev->irq].hwirq;
+ hwirq += 100;
+
+ virq = irq_create_mapping(NULL, hwirq);
+ if (virq == NO_IRQ) {
+ pr_debug("msi_mpic_alloc: Failed mapping hwirq %d\n", hwirq);
+ return -1;
+ }
+
+ set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
+ entries[i].vector = virq;
+
+ return 0;
+}
+
+static int msi_mpic_setup_msi_msg(struct pci_dev *pdev,
+ struct msix_entry *entry, struct msi_msg *msg, int type)
+{
+ msg->address_lo = 0xfee00000; /* XXX What is this value? */
+ msg->address_hi = 0;
+ msg->data = pdev->irq | 0x8000;
+
+ return 0;
+}
+
+static struct ppc_msi_ops mpic_msi_ops = {
+ .check = msi_mpic_check,
+ .alloc = msi_mpic_alloc,
+ .free = msi_mpic_free
+ .enable = msi_raw_enable,
+ .disable = msi_raw_disable,
+ .setup_msi_msg = msi_mpic_setup_msi_msg,
+};
+
+static struct ppc_msi_ops *mpic_get_msi_ops(struct pci_dev *pdev)
+{
+ return &mpic_msi_ops;
+}
+
+static int msi_mpic_init(void)
+{
+ /* XXX Do this in mpic_init ? */
+ pr_debug("mpic_msi_init: Registering MPIC MSI ops.\n");
+ ppc_md.get_msi_ops = mpic_get_msi_ops;
+
+ return 0;
+}
+__initcall(msi_mpic_init);
^ permalink raw reply
* mount- crashes with sig-11 error - linux-2.6.16.2
From: agnel juni @ 2006-09-28 22:51 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <45179FF7.3000400@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 6722 bytes --]
Hi
We are using linux-2.6.16.2. We are trying to mount the compact flash (64MB) with FAT16 filesystem, using system ACE driver.
We are able to run filesystem check, partition the CF etc, but the issue is with mount.
'Mount' shows inconsistent results, meaning mount crashes with sig-11 error. Sametime when it succeeds we are able to copy/read/ and remove files from the CF.
Please find the screen-dump of the kernel oops below:
Any help is greatly appreciated.
/******************* screen-dump*******************/
Oops: kernel access of bad area, sig: 11 [#1]
NIP: C004AD4C LR: C004CF98 CTR: 0FF050A0
REGS: dfd8ddf8 TRAP: 0300 Not tainted (2.6.16.2)
MSR: 00029000 <EE,ME> CR: 84004024 XER: 20000000
DAR: 00000008, DSISR: 00000000
TASK = dfc93450[620] 'exe' THREAD: dfd8c000
GPR00: C004CF98 DFD8DEA8 DFC93450 DFD610CC DFF7D000 00000000 00029000 DFD8C000
GPR08: C024D1F4 00000004 00000007 DFF7D090 24004022 10062C0C 00000000 00000000
GPR16: 00000000 7FE73BA0 10060000 10060000 1006F650 10060000 1006F520 00000000
GPR24: 1005AC48 10036970 00000005 1003EE68 DFC93450 00000000 00000000 DFD610CC
NIP [C004AD4C] remove_vma+0x24/0x9c
LR [C004CF98] exit_mmap+0xb4/0xec
Call Trace:
[DFD8DEA8] [C004ADA0] remove_vma+0x78/0x9c (unreliable)
[DFD8DEB8] [C004CF98] exit_mmap+0xb4/0xec
[DFD8DED8] [C0016CEC] mmput+0x50/0xd4
[DFD8DEE8] [C001B2D8] exit_mm+0x120/0x1a0
[DFD8DF00] [C001B914] do_exit+0x11c/0x77c
[DFD8DF38] [C001BFB0] do_group_exit+0x0/0x80
[DFD8DF40] [C0001BC4] ret_from_syscall+0x0/0x3c
Instruction dump:
4d9e0020 80a40080 4bffff58 7c0802a6 9421fff0 bfc10008 7c7f1b78 90010014
81230044 83c3000c 2f890000 419e0010 <80090004> 2f800000 409e0064 807f004c
Fixing recursive fault but reboot is needed!
Oops: kernel access of bad area, sig: 11 [#2]
NIP: C00556B8 LR: C00557E4 CTR: 00000000
REGS: dfdbfe08 TRAP: 0300 Not tainted (2.6.16.2)
MSR: 00021000 <ME> CR: 22008028 XER: 00000000
DAR: 00000000, DSISR: 00800000
TASK = dff6c030[4] 'events/0' THREAD: dfdbe000
GPR00: 00100100 DFDBFEB8 DFF6C030 C0258D20 DFF7D010 00000018 DFD61000 C0256E20
GPR08: 00000000 00200200 DFD61EE4 C0256E28 C0220000 10062C0C 1FFB9700 00000000
GPR16: 00000001 FFFFFFFF 00000000 007FFF00 1FFB3604 1FF63CE0 1FFCEF78 C01F0000
GPR24: C0240000 00100100 C0240000 00000000 DFF7D010 00000018 00000002 C0258D20
NIP [C00556B8] free_block+0xa8/0x148
LR [C00557E4] drain_array_locked+0x8c/0xd8
Call Trace:
[DFDBFEB8] [C0055338] kmem_freepages+0x98/0xdc (unreliable)
[DFDBFED8] [C00557E4] drain_array_locked+0x8c/0xd8
[DFDBFEF0] [C0056F80] cache_reap+0x74/0x18c
[DFDBFF28] [C002B578] run_workqueue+0x9c/0x110
[DFDBFF48] [C002B6E4] worker_thread+0xf8/0x13c
[DFDBFFC0] [C002F6F0] kthread+0xf4/0x130
[DFDBFFF0] [C000413C] kernel_thread+0x44/0x60
Instruction dump:
7cfbfa14 3c000010 80e70014 3d2a4000 60000100 5529c9f4 7d295a14 80c9001c
3d200020 61290200 81060004 81660000 <91680000> 910b0004 3966001c 90060000
BUG: events/0/4, lock held at task exit time!
[c01f5d60] {cache_chain_mutex}
.. held by: events/0: 4 [dff6c030, 110]
... acquired at: cache_reap+0x1c/0x18c
Thanks
Junita
Ameet Patil <ammubhai@gmail.com> wrote: agnel juni wrote:
> Hi Ameet
>
> I have posted a few messages regarding Ssytem ACE driver for Linux-2.6.
>
> We are working on a AMCC 440SPe based custom board.
>
> We applied the patch from
> //http://www.cs.york.ac.uk/rtslab/demos/amos/xupv2pro/patches/linuxppc-2.6.17.1-sysace-1.2.patch
> //and applied against 2.6.16-2 kernel.
>
> We are trying to make the driver work in interrupt mode.
>
> First, I would like to know if the driver tested in interrupt mode.
>
> We are able to mount the CF, but it is very inconsistent.
>
> Same is the case with fdisk command. When it fails,we get errors which you could see in the screen-dump below.//
> //
> Are we missing to apply the right patch? Please let us know your
> inputs to go forward.
> Looking forwards for your reply.
>
> Thanks
> Junita
>
> /*************** Screen dump ********************/
> # fdisk /dev/xsysace
> 1. sector = 0 xsa_cur_req->sector=0
> System ACE: Error 0 when reading sector 2.
> 2. sector = 2 xsa_cur_req->sector=16
> end_request: I/O error, System ACE: Error 0 when reading sectoru dev
> xsa, sector 16
> Buffer I/O error on device xsa, logical block 2
> 1. sector = 184 xsa_cur_req->sector=184
>
> Command (m for help): p
>
> Disk /dev/xsysace: 524 MB, 524869632 bytes
> 17 heads, 59 sectors/track, 1022 cylinders
> Units = cylinders of 1003 * 512 = 513536 bytes
>
> Device Boot Start End Blocks Id System
> /dev/xsysace1 1 1022 512503+ 6 FAT16
>
> Command (m for help): q
> And for 'mount'
> #
> #
> # mount -t msdos /dev/xsysace /root/cf
> 1. sector = 0 xsa_cur_req->sector=0
> 1. sector = 503 xsa_cur_req->sector=503
> 1. sector = 504 xsa_cur_req->sector=504
> 1. sector = 506 xsa_cur_req->sector=506
> 1. sector = 508 xsa_cur_req->sector=508
> 1. sector = 510 xsa_cur_req->sector=510
> # cd /root/cf
> < Here Prints Some Symbols like + - etc, which i am
> not able to capture/copy -------------ERROR
> b: No such file or directory--------------------------------ERROR
> pci.h
> #
> Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.n0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.d#
> # cp pci.h /root/
> # cd ../
> # ls
> app cf hello1 pci.h
> #
> #/root
> /dev/xsysace /root/cf
> FAT: bogus number of reserved sectors
> VFS: Can't find a valid FAT filesystem on dev xsa.
> mount: Mounting /dev/xsysace on /root/cf failed: Invalid argument
> #
>
>
>
> //
>
>
>
> //
>
> ------------------------------------------------------------------------
> Find out what India is talking about on - Yahoo! Answers India
>
> Send FREE SMS to your friend's mobile from Yahoo! Messenger Version 8.
> Get it NOW
>
Hi Agnel,
The driver was last tested with 2.6.17 kernel and till date works
fine in the interrupt mode. I have been using it since the last 4 months
now. It should also work on 2.6.16-2 kernel I think, but I have not
tested this. Have you made any changes to the driver? If so... please
give the details so I can give you better feedback as to where things
might have gone wrong. When time permits I shall try my patch on the
2.6.16-2 kernel and let you know if it works for me.
Thanks,
-Ameet
---------------------------------
Find out what India is talking about on - Yahoo! Answers India
Send FREE SMS to your friend's mobile from Yahoo! Messenger Version 8. Get it NOW
[-- Attachment #2: Type: text/html, Size: 8109 bytes --]
^ permalink raw reply
* Support for Linux Trace Tool (ltt)
From: Bizhan Gholikhamseh (bgholikh) @ 2006-09-28 23:01 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 123 bytes --]
Hi All,
Is there any support for Linux ltt on Linux 2.6 (perfably 2.6.11) for
ppc architecture (MPC8541E)?
Thanks,
BG
[-- Attachment #2: Type: text/html, Size: 684 bytes --]
^ permalink raw reply
* Re: [RFC/PATCH 7/7] Preliminary MPIC MSI backend
From: Michael Ellerman @ 2006-09-28 23:37 UTC (permalink / raw)
To: linux-kernel; +Cc: linuxppc-dev, Eric W. Biederman
In-Reply-To: <20060928215349.45C0667C47@ozlabs.org>
[-- Attachment #1: Type: text/plain, Size: 530 bytes --]
On Fri, 2006-09-29 at 07:53 +1000, Michael Ellerman wrote:
> A pretty hackish MPIC backend, just enough to flesh out the design.
> Based on code from Segher.
>
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Missing a quilt ref, new one coming RSN.
cheers
--
Michael Ellerman
OzLabs, IBM Australia Development Lab
wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)
We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 191 bytes --]
^ permalink raw reply
* [PATCH] Preliminary MPIC MSI backend
From: Michael Ellerman @ 2006-09-29 0:16 UTC (permalink / raw)
To: linux-kernel; +Cc: linuxppc-dev, Eric W. Biederman
In-Reply-To: <1159486661.25820.1.camel@localhost.localdomain>
A pretty hackish MPIC backend, just enough to flesh out the design.
Based on code from Segher.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/kernel/Makefile | 1
arch/powerpc/kernel/msi-mpic.c | 92 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 93 insertions(+)
Index: to-merge/arch/powerpc/kernel/Makefile
===================================================================
--- to-merge.orig/arch/powerpc/kernel/Makefile
+++ to-merge/arch/powerpc/kernel/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_PCI) += $(pci64-y) $(pci32
msiobj-y := msi.o
msiobj-$(CONFIG_PPC_PSERIES) += msi-rtas.o
+msiobj-$(CONFIG_PPC_PMAC) += msi-mpic.o
obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
kexec-$(CONFIG_PPC64) := machine_kexec_64.o
Index: to-merge/arch/powerpc/kernel/msi-mpic.c
===================================================================
--- /dev/null
+++ to-merge/arch/powerpc/kernel/msi-mpic.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2006 Segher Boessenkool, IBM Corp.
+ * Copyright (C) 2006 Michael Ellerman, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#define DEBUG 1
+
+#include <linux/irq.h>
+#include <asm/msi.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+static int msi_mpic_check(struct pci_dev *pdev, int num,
+ struct msix_entry *entries, int type)
+{
+ /* The irq allocator needs more work to support MSI-X/multi-MSI */
+ if (type == PCI_CAP_ID_MSIX || num != 1)
+ return 1;
+
+ return 0;
+}
+
+static void msi_mpic_free(struct pci_dev *pdev, int num,
+ struct msix_entry *entries, int type)
+{
+ int i;
+
+ for (i = 0; i < num; i++)
+ irq_dispose_mapping(entries[i].vector);
+}
+
+static int msi_mpic_alloc(struct pci_dev *pdev, int num,
+ struct msix_entry *entries, int type)
+{
+ irq_hw_number_t hwirq;
+ unsigned int virq;
+
+ /* We need a smarter allocator for MSI-X/multi-MSI */
+ hwirq = irq_map[pdev->irq].hwirq;
+ hwirq += 100;
+
+ virq = irq_create_mapping(NULL, hwirq);
+ if (virq == NO_IRQ) {
+ pr_debug("msi_mpic_alloc: Failed mapping hwirq %lu\n", hwirq);
+ return -1;
+ }
+
+ set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
+ entries[0].vector = virq;
+
+ return 0;
+}
+
+static int msi_mpic_setup_msi_msg(struct pci_dev *pdev,
+ struct msix_entry *entry, struct msi_msg *msg, int type)
+{
+ msg->address_lo = 0xfee00000; /* XXX What is this value? */
+ msg->address_hi = 0;
+ msg->data = pdev->irq | 0x8000;
+
+ return 0;
+}
+
+static struct ppc_msi_ops mpic_msi_ops = {
+ .check = msi_mpic_check,
+ .alloc = msi_mpic_alloc,
+ .free = msi_mpic_free,
+ .enable = msi_raw_enable,
+ .disable = msi_raw_disable,
+ .setup_msi_msg = msi_mpic_setup_msi_msg,
+};
+
+static struct ppc_msi_ops *mpic_get_msi_ops(struct pci_dev *pdev)
+{
+ return &mpic_msi_ops;
+}
+
+static int msi_mpic_init(void)
+{
+ /* XXX Do this in mpic_init ? */
+ pr_debug("mpic_msi_init: Registering MPIC MSI ops.\n");
+ ppc_md.get_msi_ops = mpic_get_msi_ops;
+
+ return 0;
+}
+__initcall(msi_mpic_init);
^ permalink raw reply
* About cache
From: enorm @ 2006-09-29 1:25 UTC (permalink / raw)
To: linuxppc-embedded
Hi,
I found in mpc85xx start.s, before doing any initialization it disabled
i-cache & d-cache. Must we do so? If we don't disable them what will it
cause?
Best Regards
Enorm
^ permalink raw reply
* Trouble with 2.6 Kernel
From: Glenn.G.Hart @ 2006-09-29 2:35 UTC (permalink / raw)
To: linuxppc-embedded
I am trying to get Linux PPC 2.6.17.1 up and running on a Xilinx Virtex-4
FX 12 FPGA. Everything appears to proceed normally, but at the end of the
kernel initialization it gives me a scheduling while atomic error. I have
found on the web others having this problem, but without a good solution.
Do I have something configured wrong or do I need a patch. The output of
the kernel is shown below.
Thanks,
Glenn
loaded at: 00400000 004E113C
board data at: 004DF124 004DF13C
relocated to: 004050EC 00405104
zimage at: 00405801 004DEC72
avail ram: 004E2000 10000000
Linux/PPC load: console=ttyS0,9600 console=tty0 root=/dev/sda2
Uncompressing Linux...done.
Now booting the kernel
Linux version 2.6.17.1 (root@AFedora3) (gcc version 3.4.5) #18 PREEMPT Thu
Sep 28 02:29:45 EDT 2006
Xilinx Virtex-II Pro port
Port by MontaVista Software, Inc. (source@mvista.com)
Built 1 zonelists
Kernel command line: console=ttyS0,9600 console=tty0 root=/dev/sda2
Xilinx INTC #0 at 0x41200000 mapped to 0xFDFFE000
PID hash table entries: 2048 (order: 11, 8192 bytes)
Console: colour dummy device 80x25
Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
Memory: 257792k available (1528k kernel code, 400k data, 84k init, 0k
highmem)
Mount-cache hash table entries: 512
NET: Registered protocol family 16
NET: Registered protocol family 2
IP route cache hash table entries: 2048 (order: 1, 8192 bytes)
TCP established hash table entries: 8192 (order: 3, 32768 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 8192 bind 4096)
TCP reno registered
io scheduler noop registered (default)
Serial: 8250/16550 driver $Revision: 1.90 $ 1 ports, IRQ sharing disabled
serial8250.0: ttyS0 at MMIO 0x40401003 (irq = 1) is a 16450
RAMDISK driver initialized: 1 RAM disks of 4096K size 1024 blocksize
loop: loaded (max 8 devices)
nbd: registered device at major 43
eth0: using fifo mode.
eth0: Xilinx EMAC #0 at 0x80400000 mapped to 0xD1000000, irq=0
eth0: id 2.0a; block id 0, type 8
mice: PS/2 mouse device common for all mice
ip_conntrack version 2.4 (2048 buckets, 16384 max) - 188 bytes per
conntrack
BUG: scheduling while atomic: swapper/0xffffffff/1
Call Trace:
[C0451E50] [C0008F20] show_stack+0x58/0x180 (unreliable)
[C0451E80] [C017AAC0] schedule+0x48/0x6e4
[C0451EB0] [C017B340] wait_for_completion+0xbc/0x158
[C0451EF0] [C003400C] synchronize_rcu+0x38/0x48
[C0451F30] [C01140D4] synchronize_net+0x10/0x20
[C0451F40] [C0124760] nf_register_hook+0xac/0xc0
[C0451F50] [C0124860] nf_register_hooks+0x34/0x7c
[C0451F70] [C01DD3C0] ip_conntrack_standalone_init+0xb8/0x154
[C0451F90] [C0002470] init+0xa4/0x280
[C0451FF0] [C00051FC] kernel_thread+0x44/0x60
^ permalink raw reply
* RE: [PATCH 0/12] Add support for QE and 8360EMDS board -v2
From: Li Yang-r58472 @ 2006-09-29 3:21 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, paulus
In-Reply-To: <98C2C73A-F57B-49A6-9727-D76A1AE9746C@kernel.crashing.org>
> -----Original Message-----
> From: Kumar Gala [mailto:galak@kernel.crashing.org]
> Sent: Friday, September 29, 2006 12:37 AM
> To: Li Yang-r58472
> Cc: linuxppc-dev@ozlabs.org; paulus@samba.org
> Subject: Re: [PATCH 0/12] Add support for QE and 8360EMDS board -v2
>=20
>=20
> On Sep 28, 2006, at 11:09 AM, Li Yang wrote:
>=20
> > On 9/28/06, Kumar Gala <galak@kernel.crashing.org> wrote:
> >>
> >> On Sep 28, 2006, at 3:18 AM, Li Yang wrote:
> >>
> >> > Paul,
> >> >
> >> > The series of patches add generic QE infrastructure called
> >> > qe_lib, and MPC8360EMDS board support. Qe_lib is used by
> >> > QE device drivers such as ucc_geth driver.
> >> >
> >> > This version updates QE interrupt controller to use new irq
> >> > mapping mechanism, addresses all the comments received with
> >> > last submission and includes some style fixes.
> >> >
> >> > v2 change: Change to use device tree for BCSR and MURAM;
> >> > Remove I/O port interrupt handling code as it is not generic
> >> > enough.
> >>
> >> Before accepting any of this code, I'd like to see what the drivers
> >> look like that are using it. Its hard to make significant
> >> comments w/
> >> o seeing what the consumers of all the 'lib' code look like.
> >
> > Current in-tree user of the lib is driver/net/ucc_geth.c. There is
> > also QE ATM driver which is included in Alex's 8360sar project. QE
> > USB host/client drivers are in Freescale LTIB BSP.
>=20
> is there a serial driver?
No. It is not very necessary to have serial support for QE, as there is
separate DUART SoC. We can use 8250 serial driver for that.
- Leo
^ permalink raw reply
* scc ethernet driver error - bus contention?
From: Lichang Che @ 2006-09-29 3:07 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 620 bytes --]
Hello,
I'm using Linux 2.6.16 + uboot on MPC8250 - SMC2 for UART and SCC4 for 10M
Ethernet. The problem I got is as follows:
1. If the GBL bit is set (with address snooping), an underrun happens for
each frame transmission.
2. If the GBL bit is disabled, the underrun problem disappears but nearly
all frames are corrupted - the frame can be received (without CRC etc) by
another machine but the data is not correct.
3. If the frame to be sent is copied into the dual port ram first and the
transmission is triggered, the frame can be successfully received.
Can anyone give me some hint?
Cheers
[-- Attachment #2: Type: text/html, Size: 3521 bytes --]
^ permalink raw reply
* RE: About cache
From: Xu, Li (GE, Research) @ 2006-09-29 4:45 UTC (permalink / raw)
To: enorm, linuxppc-embedded
In-Reply-To: <00a901c6e366$1d3e4f70$a309a8c0@enorm>
WW91IGhhdmUgdG8gZG8gc28uDQpUaGF0IHdpbGwgcHJldmVudCBDUFUgZnJvbSBmZXRjaGluZyBk
YXRhIG9yIGluc3RydWN0aW9ucyBmcm9tIGktY2FjaGUgYW5kIGQtY2FjaGUNCmF0IHRoZSBpbml0
aWFsaXphdGlvbiB0aW1lIHNpbmNlIHRoZSBjYWNoZSBpcyBub3QgaW5pdGlhbGl6ZWQgeWV0Lg0K
DQoJLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0gDQoJRnJvbTogbGludXhwcGMtZW1iZWRkZWQt
Ym91bmNlcytsaS54dT1nZS5jb21Ab3psYWJzLm9yZyBvbiBiZWhhbGYgb2YgZW5vcm0gDQoJU2Vu
dDogRnJpIDkvMjkvMjAwNiA5OjI1IEFNIA0KCVRvOiBsaW51eHBwYy1lbWJlZGRlZEBvemxhYnMu
b3JnIA0KCUNjOiANCglTdWJqZWN0OiBBYm91dCBjYWNoZQ0KCQ0KCQ0KDQoJSGksDQoJDQoJSSBm
b3VuZCBpbiBtcGM4NXh4IHN0YXJ0LnMsIGJlZm9yZSBkb2luZyBhbnkgaW5pdGlhbGl6YXRpb24g
aXQgZGlzYWJsZWQNCgkgaS1jYWNoZSAmIGQtY2FjaGUuIE11c3Qgd2UgZG8gc28/IElmIHdlIGRv
bid0IGRpc2FibGUgdGhlbSB3aGF0IHdpbGwgaXQNCgkgY2F1c2U/DQoJDQoJQmVzdCBSZWdhcmRz
DQoJRW5vcm0NCgkNCgkNCgkNCgkNCg0K
^ permalink raw reply
* LSP for MPC8247
From: Akhilesh Soni @ 2006-09-29 4:56 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: linuxppc-embedded-request
[-- Attachment #1: Type: text/plain, Size: 297 bytes --]
Hi,
Is there any open soure LSP for freescale MPC8247 available.
I've an LSP for MPC8245 and I need for MPC8247. How much effort would be required to change from 8245 to 8247. Is somebody already done this ?
Any pointer or suggestions would be highly appreciated.
Regards,
Akhilesh
[-- Attachment #2: Type: text/html, Size: 1015 bytes --]
^ permalink raw reply
* [PATCH] Cell interrupt rework (final)
From: Benjamin Herrenschmidt @ 2006-09-29 5:00 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev list, Paul Mackerras, cbe-oss-dev@ozlabs.org
This patch reworks the cell iic interrupt handling so that:
- Node ID is back in the interrupt number (only one IRQ host is created
for all nodes). This allows interrupts from sources on another node to
be routed non-locally. This will allow possibly one day to fix maxcpus=1
or 2 and still get interrupts from devices on BE 1. (A bit more fixing
is needed for that) and it will allow us to implement actual affinity
control of external interrupts.
- Added handling of the IO exceptions interrupts (badly named, but I
re-used the name initially used by STI). Those are the interrupts
exposed by IIC_ISR and IIC_IRR, such as the IOC translation exception,
performance monitor, etc... Those get their special numbers in the IRQ
number space and are internally implemented as a cascade on unit 0xe,
class 1 of each node.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
Hi Arnd !
It occurred to me that the version of the Cell interrupt rework I sent
you was still not the latest one ! In fact, I wasn't using the latest
one myself, only Jeremy was :) I messed up with my patch handling
locally. The result is that the version you have is causing occasional
loss of interrupts, typically the case where IDE disappears after
loading the SPUs a bit.
This is the real latest version that works and that survives parallel
SPU torture and hard disk activity. The problem was that unexepcted
interrupts wouldn't be ack'ed (the priority register wouldn't be put
back to 0xff). The bug was in the original code but it would somewhat
recover after some fairly high latency by getting some even higher
priority interrupt since it's eoi would unconditionally set back the
priority to 0xff. The new code implements a nice prio stack however, and
thus ends up with the priority never going back down.
Paulus: please merge upstream too.
Index: linux-cell/arch/powerpc/platforms/cell/interrupt.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/interrupt.c 2006-09-08 17:17:10.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/interrupt.c 2006-09-29 14:36:23.000000000 +1000
@@ -21,6 +21,12 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * TODO:
+ * - Fix various assumptions related to HW CPU numbers vs. linux CPU numbers
+ * vs node numbers in the setup code
+ * - Implement proper handling of maxcpus=1/2 (that is, routing of irqs from
+ * a non-active node to the active node)
*/
#include <linux/interrupt.h>
@@ -44,24 +50,25 @@ struct iic {
u8 target_id;
u8 eoi_stack[16];
int eoi_ptr;
- struct irq_host *host;
+ struct device_node *node;
};
static DEFINE_PER_CPU(struct iic, iic);
#define IIC_NODE_COUNT 2
-static struct irq_host *iic_hosts[IIC_NODE_COUNT];
+static struct irq_host *iic_host;
/* Convert between "pending" bits and hw irq number */
static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits)
{
unsigned char unit = bits.source & 0xf;
+ unsigned char node = bits.source >> 4;
+ unsigned char class = bits.class & 3;
+ /* Decode IPIs */
if (bits.flags & CBE_IIC_IRQ_IPI)
- return IIC_IRQ_IPI0 | (bits.prio >> 4);
- else if (bits.class <= 3)
- return (bits.class << 4) | unit;
+ return IIC_IRQ_TYPE_IPI | (bits.prio >> 4);
else
- return IIC_IRQ_INVALID;
+ return (node << IIC_IRQ_NODE_SHIFT) | (class << 4) | unit;
}
static void iic_mask(unsigned int irq)
@@ -86,21 +93,70 @@ static struct irq_chip iic_chip = {
.eoi = iic_eoi,
};
+
+static void iic_ioexc_eoi(unsigned int irq)
+{
+}
+
+static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc,
+ struct pt_regs *regs)
+{
+ struct cbe_iic_regs *node_iic = desc->handler_data;
+ unsigned int base = (irq & 0xffffff00) | IIC_IRQ_TYPE_IOEXC;
+ unsigned long bits, ack;
+ int cascade;
+
+ for (;;) {
+ bits = in_be64(&node_iic->iic_is);
+ if (bits == 0)
+ break;
+ /* pre-ack edge interrupts */
+ ack = bits & IIC_ISR_EDGE_MASK;
+ if (ack)
+ out_be64(&node_iic->iic_is, ack);
+ /* handle them */
+ for (cascade = 63; cascade >= 0; cascade--)
+ if (bits & (0x8000000000000000UL >> cascade)) {
+ unsigned int cirq =
+ irq_linear_revmap(iic_host,
+ base | cascade);
+ if (cirq != NO_IRQ)
+ generic_handle_irq(cirq, regs);
+ }
+ /* post-ack level interrupts */
+ ack = bits & ~IIC_ISR_EDGE_MASK;
+ if (ack)
+ out_be64(&node_iic->iic_is, ack);
+ }
+ desc->chip->eoi(irq);
+}
+
+
+static struct irq_chip iic_ioexc_chip = {
+ .typename = " CELL-IOEX",
+ .mask = iic_mask,
+ .unmask = iic_unmask,
+ .eoi = iic_ioexc_eoi,
+};
+
/* Get an IRQ number from the pending state register of the IIC */
static unsigned int iic_get_irq(struct pt_regs *regs)
{
struct cbe_iic_pending_bits pending;
struct iic *iic;
+ unsigned int virq;
iic = &__get_cpu_var(iic);
*(unsigned long *) &pending =
in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
+ if (!(pending.flags & CBE_IIC_IRQ_VALID))
+ return NO_IRQ;
+ virq = irq_linear_revmap(iic_host, iic_pending_to_hwnum(pending));
+ if (virq == NO_IRQ)
+ return NO_IRQ;
iic->eoi_stack[++iic->eoi_ptr] = pending.prio;
BUG_ON(iic->eoi_ptr > 15);
- if (pending.flags & CBE_IIC_IRQ_VALID)
- return irq_linear_revmap(iic->host,
- iic_pending_to_hwnum(pending));
- return NO_IRQ;
+ return virq;
}
#ifdef CONFIG_SMP
@@ -108,12 +164,7 @@ static unsigned int iic_get_irq(struct p
/* Use the highest interrupt priorities for IPI */
static inline int iic_ipi_to_irq(int ipi)
{
- return IIC_IRQ_IPI0 + IIC_NUM_IPIS - 1 - ipi;
-}
-
-static inline int iic_irq_to_ipi(int irq)
-{
- return IIC_NUM_IPIS - 1 - (irq - IIC_IRQ_IPI0);
+ return IIC_IRQ_TYPE_IPI + 0xf - ipi;
}
void iic_setup_cpu(void)
@@ -123,7 +174,7 @@ void iic_setup_cpu(void)
void iic_cause_IPI(int cpu, int mesg)
{
- out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4);
+ out_be64(&per_cpu(iic, cpu).regs->generate, (0xf - mesg) << 4);
}
u8 iic_get_target_id(int cpu)
@@ -134,9 +185,7 @@ EXPORT_SYMBOL_GPL(iic_get_target_id);
struct irq_host *iic_get_irq_host(int node)
{
- if (node < 0 || node >= IIC_NODE_COUNT)
- return NULL;
- return iic_hosts[node];
+ return iic_host;
}
EXPORT_SYMBOL_GPL(iic_get_irq_host);
@@ -149,34 +198,20 @@ static irqreturn_t iic_ipi_action(int ir
return IRQ_HANDLED;
}
-
static void iic_request_ipi(int ipi, const char *name)
{
- int node, virq;
+ int virq;
- for (node = 0; node < IIC_NODE_COUNT; node++) {
- char *rname;
- if (iic_hosts[node] == NULL)
- continue;
- virq = irq_create_mapping(iic_hosts[node],
- iic_ipi_to_irq(ipi));
- if (virq == NO_IRQ) {
- printk(KERN_ERR
- "iic: failed to map IPI %s on node %d\n",
- name, node);
- continue;
- }
- rname = kzalloc(strlen(name) + 16, GFP_KERNEL);
- if (rname)
- sprintf(rname, "%s node %d", name, node);
- else
- rname = (char *)name;
- if (request_irq(virq, iic_ipi_action, IRQF_DISABLED,
- rname, (void *)(long)ipi))
- printk(KERN_ERR
- "iic: failed to request IPI %s on node %d\n",
- name, node);
+ virq = irq_create_mapping(iic_host, iic_ipi_to_irq(ipi));
+ if (virq == NO_IRQ) {
+ printk(KERN_ERR
+ "iic: failed to map IPI %s\n", name);
+ return;
}
+ if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, name,
+ (void *)(long)ipi))
+ printk(KERN_ERR
+ "iic: failed to request IPI %s\n", name);
}
void iic_request_IPIs(void)
@@ -193,16 +228,24 @@ void iic_request_IPIs(void)
static int iic_host_match(struct irq_host *h, struct device_node *node)
{
- return h->host_data != NULL && node == h->host_data;
+ return device_is_compatible(node,
+ "IBM,CBEA-Internal-Interrupt-Controller");
}
static int iic_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hw)
{
- if (hw < IIC_IRQ_IPI0)
- set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq);
- else
+ switch (hw & IIC_IRQ_TYPE_MASK) {
+ case IIC_IRQ_TYPE_IPI:
set_irq_chip_and_handler(virq, &iic_chip, handle_percpu_irq);
+ break;
+ case IIC_IRQ_TYPE_IOEXC:
+ set_irq_chip_and_handler(virq, &iic_ioexc_chip,
+ handle_fasteoi_irq);
+ break;
+ default:
+ set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq);
+ }
return 0;
}
@@ -211,11 +254,39 @@ static int iic_host_xlate(struct irq_hos
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
{
- /* Currently, we don't translate anything. That needs to be fixed as
- * we get better defined device-trees. iic interrupts have to be
- * explicitely mapped by whoever needs them
- */
- return -ENODEV;
+ unsigned int node, ext, unit, class;
+ const u32 *val;
+
+ if (!device_is_compatible(ct,
+ "IBM,CBEA-Internal-Interrupt-Controller"))
+ return -ENODEV;
+ if (intsize != 1)
+ return -ENODEV;
+ val = get_property(ct, "#interrupt-cells", NULL);
+ if (val == NULL || *val != 1)
+ return -ENODEV;
+
+ node = intspec[0] >> 24;
+ ext = (intspec[0] >> 16) & 0xff;
+ class = (intspec[0] >> 8) & 0xff;
+ unit = intspec[0] & 0xff;
+
+ /* Check if node is in supported range */
+ if (node > 1)
+ return -EINVAL;
+
+ /* Build up interrupt number, special case for IO exceptions */
+ *out_hwirq = (node << IIC_IRQ_NODE_SHIFT);
+ if (unit == IIC_UNIT_IIC && class == 1)
+ *out_hwirq |= IIC_IRQ_TYPE_IOEXC | ext;
+ else
+ *out_hwirq |= IIC_IRQ_TYPE_NORMAL |
+ (class << IIC_IRQ_CLASS_SHIFT) | unit;
+
+ /* Dummy flags, ignored by iic code */
+ *out_flags = IRQ_TYPE_EDGE_RISING;
+
+ return 0;
}
static struct irq_host_ops iic_host_ops = {
@@ -225,7 +296,7 @@ static struct irq_host_ops iic_host_ops
};
static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr,
- struct irq_host *host)
+ struct device_node *node)
{
/* XXX FIXME: should locate the linux CPU number from the HW cpu
* number properly. We are lucky for now
@@ -237,28 +308,27 @@ static void __init init_one_iic(unsigned
iic->target_id = ((hw_cpu & 2) << 3) | ((hw_cpu & 1) ? 0xf : 0xe);
iic->eoi_stack[0] = 0xff;
- iic->host = host;
+ iic->node = of_node_get(node);
out_be64(&iic->regs->prio, 0);
- printk(KERN_INFO "IIC for CPU %d at %lx mapped to %p, target id 0x%x\n",
- hw_cpu, addr, iic->regs, iic->target_id);
+ printk(KERN_INFO "IIC for CPU %d target id 0x%x : %s\n",
+ hw_cpu, iic->target_id, node->full_name);
}
static int __init setup_iic(void)
{
struct device_node *dn;
struct resource r0, r1;
- struct irq_host *host;
- int found = 0;
- u32 *np;
+ unsigned int node, cascade, found = 0;
+ struct cbe_iic_regs *node_iic;
+ const u32 *np;
for (dn = NULL;
(dn = of_find_node_by_name(dn,"interrupt-controller")) != NULL;) {
if (!device_is_compatible(dn,
"IBM,CBEA-Internal-Interrupt-Controller"))
continue;
- np = (u32 *)get_property(dn, "ibm,interrupt-server-ranges",
- NULL);
+ np = get_property(dn, "ibm,interrupt-server-ranges", NULL);
if (np == NULL) {
printk(KERN_WARNING "IIC: CPU association not found\n");
of_node_put(dn);
@@ -270,19 +340,33 @@ static int __init setup_iic(void)
of_node_put(dn);
return -ENODEV;
}
- host = NULL;
- if (found < IIC_NODE_COUNT) {
- host = irq_alloc_host(IRQ_HOST_MAP_LINEAR,
- IIC_SOURCE_COUNT,
- &iic_host_ops,
- IIC_IRQ_INVALID);
- iic_hosts[found] = host;
- BUG_ON(iic_hosts[found] == NULL);
- iic_hosts[found]->host_data = of_node_get(dn);
- found++;
- }
- init_one_iic(np[0], r0.start, host);
- init_one_iic(np[1], r1.start, host);
+ found++;
+ init_one_iic(np[0], r0.start, dn);
+ init_one_iic(np[1], r1.start, dn);
+
+ /* Setup cascade for IO exceptions. XXX cleanup tricks to get
+ * node vs CPU etc...
+ * Note that we configure the IIC_IRR here with a hard coded
+ * priority of 1. We might want to improve that later.
+ */
+ node = np[0] >> 1;
+ node_iic = cbe_get_cpu_iic_regs(np[0]);
+ cascade = node << IIC_IRQ_NODE_SHIFT;
+ cascade |= 1 << IIC_IRQ_CLASS_SHIFT;
+ cascade |= IIC_UNIT_IIC;
+ cascade = irq_create_mapping(iic_host, cascade);
+ if (cascade == NO_IRQ)
+ continue;
+ set_irq_data(cascade, node_iic);
+ set_irq_chained_handler(cascade , iic_ioexc_cascade);
+ out_be64(&node_iic->iic_ir,
+ (1 << 12) /* priority */ |
+ (node << 4) /* dest node */ |
+ IIC_UNIT_THREAD_0 /* route them to thread 0 */);
+ /* Flush pending (make sure it triggers if there is
+ * anything pending
+ */
+ out_be64(&node_iic->iic_is, 0xfffffffffffffffful);
}
if (found)
@@ -293,6 +377,12 @@ static int __init setup_iic(void)
void __init iic_init_IRQ(void)
{
+ /* Setup an irq host data structure */
+ iic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT,
+ &iic_host_ops, IIC_IRQ_INVALID);
+ BUG_ON(iic_host == NULL);
+ irq_set_default_host(iic_host);
+
/* Discover and initialize iics */
if (setup_iic() < 0)
panic("IIC: Failed to initialize !\n");
Index: linux-cell/arch/powerpc/platforms/cell/interrupt.h
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/interrupt.h 2006-09-08 17:17:10.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/interrupt.h 2006-09-22 12:56:14.000000000 +1000
@@ -2,48 +2,76 @@
#define ASM_CELL_PIC_H
#ifdef __KERNEL__
/*
- * Mapping of IIC pending bits into per-node
- * interrupt numbers.
+ * Mapping of IIC pending bits into per-node interrupt numbers.
*
- * IRQ FF CC SS PP FF CC SS PP Description
+ * Interrupt numbers are in the range 0...0x1ff where the top bit
+ * (0x100) represent the source node. Only 2 nodes are supported with
+ * the current code though it's trivial to extend that if necessary using
+ * higher level bits
*
- * 00-3f 80 02 +0 00 - 80 02 +0 3f South Bridge
- * 00-3f 80 02 +b 00 - 80 02 +b 3f South Bridge
- * 41-4a 80 00 +1 ** - 80 00 +a ** SPU Class 0
- * 51-5a 80 01 +1 ** - 80 01 +a ** SPU Class 1
- * 61-6a 80 02 +1 ** - 80 02 +a ** SPU Class 2
- * 70-7f C0 ** ** 00 - C0 ** ** 0f IPI
+ * The bottom 8 bits are split into 2 type bits and 6 data bits that
+ * depend on the type:
*
- * F flags
- * C class
- * S source
- * P Priority
- * + node number
- * * don't care
+ * 00 (0x00 | data) : normal interrupt. data is (class << 4) | source
+ * 01 (0x40 | data) : IO exception. data is the exception number as
+ * defined by bit numbers in IIC_SR
+ * 10 (0x80 | data) : IPI. data is the IPI number (obtained from the priority)
+ * and node is always 0 (IPIs are per-cpu, their source is
+ * not relevant)
+ * 11 (0xc0 | data) : reserved
*
- * A node consists of a Cell Broadband Engine and an optional
- * south bridge device providing a maximum of 64 IRQs.
- * The south bridge may be connected to either IOIF0
- * or IOIF1.
- * Each SPE is represented as three IRQ lines, one per
- * interrupt class.
- * 16 IRQ numbers are reserved for inter processor
- * interruptions, although these are only used in the
- * range of the first node.
+ * In addition, interrupt number 0x80000000 is defined as always invalid
+ * (that is the node field is expected to never extend to move than 23 bits)
*
- * This scheme needs 128 IRQ numbers per BIF node ID,
- * which means that with the total of 512 lines
- * available, we can have a maximum of four nodes.
*/
enum {
- IIC_IRQ_INVALID = 0xff,
- IIC_IRQ_MAX = 0x3f,
- IIC_IRQ_EXT_IOIF0 = 0x20,
- IIC_IRQ_EXT_IOIF1 = 0x2b,
- IIC_IRQ_IPI0 = 0x40,
- IIC_NUM_IPIS = 0x10, /* IRQs reserved for IPI */
- IIC_SOURCE_COUNT = 0x50,
+ IIC_IRQ_INVALID = 0x80000000u,
+ IIC_IRQ_NODE_MASK = 0x100,
+ IIC_IRQ_NODE_SHIFT = 8,
+ IIC_IRQ_MAX = 0x1ff,
+ IIC_IRQ_TYPE_MASK = 0xc0,
+ IIC_IRQ_TYPE_NORMAL = 0x00,
+ IIC_IRQ_TYPE_IOEXC = 0x40,
+ IIC_IRQ_TYPE_IPI = 0x80,
+ IIC_IRQ_CLASS_SHIFT = 4,
+ IIC_IRQ_CLASS_0 = 0x00,
+ IIC_IRQ_CLASS_1 = 0x10,
+ IIC_IRQ_CLASS_2 = 0x20,
+ IIC_SOURCE_COUNT = 0x200,
+
+ /* Here are defined the various source/dest units. Avoid using those
+ * definitions if you can, they are mostly here for reference
+ */
+ IIC_UNIT_SPU_0 = 0x4,
+ IIC_UNIT_SPU_1 = 0x7,
+ IIC_UNIT_SPU_2 = 0x3,
+ IIC_UNIT_SPU_3 = 0x8,
+ IIC_UNIT_SPU_4 = 0x2,
+ IIC_UNIT_SPU_5 = 0x9,
+ IIC_UNIT_SPU_6 = 0x1,
+ IIC_UNIT_SPU_7 = 0xa,
+ IIC_UNIT_IOC_0 = 0x0,
+ IIC_UNIT_IOC_1 = 0xb,
+ IIC_UNIT_THREAD_0 = 0xe, /* target only */
+ IIC_UNIT_THREAD_1 = 0xf, /* target only */
+ IIC_UNIT_IIC = 0xe, /* source only (IO exceptions) */
+
+ /* Base numbers for the external interrupts */
+ IIC_IRQ_EXT_IOIF0 =
+ IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_0,
+ IIC_IRQ_EXT_IOIF1 =
+ IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_1,
+
+ /* Base numbers for the IIC_ISR interrupts */
+ IIC_IRQ_IOEX_TMI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 63,
+ IIC_IRQ_IOEX_PMI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 62,
+ IIC_IRQ_IOEX_ATI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 61,
+ IIC_IRQ_IOEX_MATBFI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 60,
+ IIC_IRQ_IOEX_ELDI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 59,
+
+ /* Which bits in IIC_ISR are edge sensitive */
+ IIC_ISR_EDGE_MASK = 0x4ul,
};
extern void iic_init_IRQ(void);
@@ -52,7 +80,6 @@ extern void iic_request_IPIs(void);
extern void iic_setup_cpu(void);
extern u8 iic_get_target_id(int cpu);
-extern struct irq_host *iic_get_irq_host(int node);
extern void spider_init_IRQ(void);
Index: linux-cell/arch/powerpc/platforms/cell/spider-pic.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spider-pic.c 2006-09-08 17:17:10.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/spider-pic.c 2006-09-29 14:37:00.000000000 +1000
@@ -240,10 +240,9 @@ static void spider_irq_cascade(unsigned
static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
{
unsigned int virq;
- u32 *imap, *tmp;
+ const u32 *imap, *tmp;
int imaplen, intsize, unit;
struct device_node *iic;
- struct irq_host *iic_host;
#if 0 /* Enable that when we have a way to retreive the node as well */
/* First, we check wether we have a real "interrupts" in the device
@@ -258,25 +257,25 @@ static unsigned int __init spider_find_c
#endif
/* Now do the horrible hacks */
- tmp = (u32 *)get_property(pic->of_node, "#interrupt-cells", NULL);
+ tmp = get_property(pic->of_node, "#interrupt-cells", NULL);
if (tmp == NULL)
return NO_IRQ;
intsize = *tmp;
- imap = (u32 *)get_property(pic->of_node, "interrupt-map", &imaplen);
+ imap = get_property(pic->of_node, "interrupt-map", &imaplen);
if (imap == NULL || imaplen < (intsize + 1))
return NO_IRQ;
iic = of_find_node_by_phandle(imap[intsize]);
if (iic == NULL)
return NO_IRQ;
imap += intsize + 1;
- tmp = (u32 *)get_property(iic, "#interrupt-cells", NULL);
+ tmp = get_property(iic, "#interrupt-cells", NULL);
if (tmp == NULL)
return NO_IRQ;
intsize = *tmp;
/* Assume unit is last entry of interrupt specifier */
unit = imap[intsize - 1];
/* Ok, we have a unit, now let's try to get the node */
- tmp = (u32 *)get_property(iic, "ibm,interrupt-server-ranges", NULL);
+ tmp = get_property(iic, "ibm,interrupt-server-ranges", NULL);
if (tmp == NULL) {
of_node_put(iic);
return NO_IRQ;
@@ -289,11 +288,11 @@ static unsigned int __init spider_find_c
* the iic host from the iic OF node, but that way I'm still compatible
* with really really old old firmwares for which we don't have a node
*/
- iic_host = iic_get_irq_host(pic->node_id);
- if (iic_host == NULL)
- return NO_IRQ;
/* Manufacture an IIC interrupt number of class 2 */
- virq = irq_create_mapping(iic_host, 0x20 | unit);
+ virq = irq_create_mapping(NULL,
+ (pic->node_id << IIC_IRQ_NODE_SHIFT) |
+ (2 << IIC_IRQ_CLASS_SHIFT) |
+ unit);
if (virq == NO_IRQ)
printk(KERN_ERR "spider_pic: failed to map cascade !");
return virq;
Index: linux-cell/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spu_base.c 2006-09-08 17:17:10.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/spu_base.c 2006-09-22 12:56:14.000000000 +1000
@@ -568,24 +568,23 @@ static void spu_unmap(struct spu *spu)
/* This function shall be abstracted for HV platforms */
static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
{
- struct irq_host *host;
unsigned int isrc;
u32 *tmp;
- host = iic_get_irq_host(spu->node);
- if (host == NULL)
- return -ENODEV;
-
- /* Get the interrupt source from the device-tree */
+ /* Get the interrupt source unit from the device-tree */
tmp = (u32 *)get_property(np, "isrc", NULL);
if (!tmp)
return -ENODEV;
- spu->isrc = isrc = tmp[0];
+ isrc = tmp[0];
+
+ /* Add the node number */
+ isrc |= spu->node << IIC_IRQ_NODE_SHIFT;
+ spu->isrc = isrc;
/* Now map interrupts of all 3 classes */
- spu->irqs[0] = irq_create_mapping(host, 0x00 | isrc);
- spu->irqs[1] = irq_create_mapping(host, 0x10 | isrc);
- spu->irqs[2] = irq_create_mapping(host, 0x20 | isrc);
+ spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
+ spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
+ spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
/* Right now, we only fail if class 2 failed */
return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
^ permalink raw reply
* [PATCH] powerpc: cell spu problem state mapping updates
From: Benjamin Herrenschmidt @ 2006-09-29 5:10 UTC (permalink / raw)
To: cbe-oss-dev@ozlabs.org; +Cc: linuxppc-dev list, Paul Mackerras, Arnd Bergmann
This patch adds a new "psmap" file to spufs that allows mmap of all of
the problem state mapping of SPEs. It is compatible with 64k pages. In
addition, it removes mmap ability of individual files when using 64k
pages, with the exception of signal1 and signal2 which will both map the
entire 64k page holding both registers. It also removes
CONFIG_SPUFS_MMAP as there is no point in not building mmap support in
spufs.
It goes along a separate patch to libspe implementing usage of that new
file to access problem state registers.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
Arnd: Unless I screwed up, this should be the same as the previous one I
sent you, with the addition of the changelog you requested and the
removal of the typo on WARRANTY.
Paul: If Arnd agrees, add that to your merge queue.
Index: linux-cell/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spufs/file.c 2006-09-29 15:04:30.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/spufs/file.c 2006-09-29 15:04:46.000000000 +1000
@@ -36,6 +36,8 @@
#include "spufs.h"
+#define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000)
+
static int
spufs_mem_open(struct inode *inode, struct file *file)
@@ -88,7 +90,6 @@ spufs_mem_write(struct file *file, const
return ret;
}
-#ifdef CONFIG_SPUFS_MMAP
static struct page *
spufs_mem_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
@@ -133,22 +134,19 @@ spufs_mem_mmap(struct file *file, struct
vma->vm_ops = &spufs_mem_mmap_vmops;
return 0;
}
-#endif
static struct file_operations spufs_mem_fops = {
.open = spufs_mem_open,
.read = spufs_mem_read,
.write = spufs_mem_write,
.llseek = generic_file_llseek,
-#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_mem_mmap,
-#endif
};
-#ifdef CONFIG_SPUFS_MMAP
static struct page *spufs_ps_nopage(struct vm_area_struct *vma,
unsigned long address,
- int *type, unsigned long ps_offs)
+ int *type, unsigned long ps_offs,
+ unsigned long ps_size)
{
struct page *page = NOPAGE_SIGBUS;
int fault_type = VM_FAULT_SIGBUS;
@@ -158,7 +156,7 @@ static struct page *spufs_ps_nopage(stru
int ret;
offset += vma->vm_pgoff << PAGE_SHIFT;
- if (offset >= 0x4000)
+ if (offset >= ps_size)
goto out;
ret = spu_acquire_runnable(ctx);
@@ -179,10 +177,11 @@ static struct page *spufs_ps_nopage(stru
return page;
}
+#if SPUFS_MMAP_4K
static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
- return spufs_ps_nopage(vma, address, type, 0x4000);
+ return spufs_ps_nopage(vma, address, type, 0x4000, 0x1000);
}
static struct vm_operations_struct spufs_cntl_mmap_vmops = {
@@ -191,17 +190,12 @@ static struct vm_operations_struct spufs
/*
* mmap support for problem state control area [0x4000 - 0x4fff].
- * Mapping this area requires that the application have CAP_SYS_RAWIO,
- * as these registers require special care when read/writing.
*/
static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma)
{
if (!(vma->vm_flags & VM_SHARED))
return -EINVAL;
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
-
vma->vm_flags |= VM_RESERVED;
vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
| _PAGE_NO_CACHE | _PAGE_GUARDED);
@@ -209,7 +203,9 @@ static int spufs_cntl_mmap(struct file *
vma->vm_ops = &spufs_cntl_mmap_vmops;
return 0;
}
-#endif
+#else /* SPUFS_MMAP_4K */
+#define spufs_cntl_mmap NULL
+#endif /* !SPUFS_MMAP_4K */
static int spufs_cntl_open(struct inode *inode, struct file *file)
{
@@ -242,9 +238,7 @@ static struct file_operations spufs_cntl
.open = spufs_cntl_open,
.read = spufs_cntl_read,
.write = spufs_cntl_write,
-#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_cntl_mmap,
-#endif
};
static int
@@ -657,11 +651,19 @@ static ssize_t spufs_signal1_write(struc
return 4;
}
-#ifdef CONFIG_SPUFS_MMAP
static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
- return spufs_ps_nopage(vma, address, type, 0x14000);
+#if PAGE_SIZE == 0x1000
+ return spufs_ps_nopage(vma, address, type, 0x14000, 0x1000);
+#elif PAGE_SIZE == 0x10000
+ /* For 64k pages, both signal1 and signal2 can be used to mmap the whole
+ * signal 1 and 2 area
+ */
+ return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000);
+#else
+#error unsupported page size
+#endif
}
static struct vm_operations_struct spufs_signal1_mmap_vmops = {
@@ -680,15 +682,12 @@ static int spufs_signal1_mmap(struct fil
vma->vm_ops = &spufs_signal1_mmap_vmops;
return 0;
}
-#endif
static struct file_operations spufs_signal1_fops = {
.open = spufs_signal1_open,
.read = spufs_signal1_read,
.write = spufs_signal1_write,
-#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_signal1_mmap,
-#endif
};
static int spufs_signal2_open(struct inode *inode, struct file *file)
@@ -743,11 +742,20 @@ static ssize_t spufs_signal2_write(struc
return 4;
}
-#ifdef CONFIG_SPUFS_MMAP
+#if SPUFS_MMAP_4K
static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
- return spufs_ps_nopage(vma, address, type, 0x1c000);
+#if PAGE_SIZE == 0x1000
+ return spufs_ps_nopage(vma, address, type, 0x1c000, 0x1000);
+#elif PAGE_SIZE == 0x10000
+ /* For 64k pages, both signal1 and signal2 can be used to mmap the whole
+ * signal 1 and 2 area
+ */
+ return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000);
+#else
+#error unsupported page size
+#endif
}
static struct vm_operations_struct spufs_signal2_mmap_vmops = {
@@ -767,15 +775,15 @@ static int spufs_signal2_mmap(struct fil
vma->vm_ops = &spufs_signal2_mmap_vmops;
return 0;
}
-#endif
+#else /* SPUFS_MMAP_4K */
+#define spufs_signal2_mmap NULL
+#endif /* !SPUFS_MMAP_4K */
static struct file_operations spufs_signal2_fops = {
.open = spufs_signal2_open,
.read = spufs_signal2_read,
.write = spufs_signal2_write,
-#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_signal2_mmap,
-#endif
};
static void spufs_signal1_type_set(void *data, u64 val)
@@ -824,11 +832,11 @@ static u64 spufs_signal2_type_get(void *
DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
spufs_signal2_type_set, "%llu");
-#ifdef CONFIG_SPUFS_MMAP
+#if SPUFS_MMAP_4K
static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
- return spufs_ps_nopage(vma, address, type, 0x0000);
+ return spufs_ps_nopage(vma, address, type, 0x0000, 0x1000);
}
static struct vm_operations_struct spufs_mss_mmap_vmops = {
@@ -837,17 +845,12 @@ static struct vm_operations_struct spufs
/*
* mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
- * Mapping this area requires that the application have CAP_SYS_RAWIO,
- * as these registers require special care when read/writing.
*/
static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma)
{
if (!(vma->vm_flags & VM_SHARED))
return -EINVAL;
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
-
vma->vm_flags |= VM_RESERVED;
vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
| _PAGE_NO_CACHE | _PAGE_GUARDED);
@@ -855,7 +858,9 @@ static int spufs_mss_mmap(struct file *f
vma->vm_ops = &spufs_mss_mmap_vmops;
return 0;
}
-#endif
+#else /* SPUFS_MMAP_4K */
+#define spufs_mss_mmap NULL
+#endif /* !SPUFS_MMAP_4K */
static int spufs_mss_open(struct inode *inode, struct file *file)
{
@@ -867,17 +872,54 @@ static int spufs_mss_open(struct inode *
static struct file_operations spufs_mss_fops = {
.open = spufs_mss_open,
-#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_mss_mmap,
-#endif
+};
+
+static struct page *spufs_psmap_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ return spufs_ps_nopage(vma, address, type, 0x0000, 0x20000);
+}
+
+static struct vm_operations_struct spufs_psmap_mmap_vmops = {
+ .nopage = spufs_psmap_mmap_nopage,
+};
+
+/*
+ * mmap support for full problem state area [0x00000 - 0x1ffff].
+ */
+static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+ | _PAGE_NO_CACHE | _PAGE_GUARDED);
+
+ vma->vm_ops = &spufs_psmap_mmap_vmops;
+ return 0;
+}
+
+static int spufs_psmap_open(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+
+ file->private_data = i->i_ctx;
+ return nonseekable_open(inode, file);
+}
+
+static struct file_operations spufs_psmap_fops = {
+ .open = spufs_psmap_open,
+ .mmap = spufs_psmap_mmap,
};
-#ifdef CONFIG_SPUFS_MMAP
+#if SPUFS_MMAP_4K
static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
- return spufs_ps_nopage(vma, address, type, 0x3000);
+ return spufs_ps_nopage(vma, address, type, 0x3000, 0x1000);
}
static struct vm_operations_struct spufs_mfc_mmap_vmops = {
@@ -886,17 +928,12 @@ static struct vm_operations_struct spufs
/*
* mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
- * Mapping this area requires that the application have CAP_SYS_RAWIO,
- * as these registers require special care when read/writing.
*/
static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma)
{
if (!(vma->vm_flags & VM_SHARED))
return -EINVAL;
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
-
vma->vm_flags |= VM_RESERVED;
vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
| _PAGE_NO_CACHE | _PAGE_GUARDED);
@@ -904,7 +941,9 @@ static int spufs_mfc_mmap(struct file *f
vma->vm_ops = &spufs_mfc_mmap_vmops;
return 0;
}
-#endif
+#else /* SPUFS_MMAP_4K */
+#define spufs_mfc_mmap NULL
+#endif /* !SPUFS_MMAP_4K */
static int spufs_mfc_open(struct inode *inode, struct file *file)
{
@@ -1194,9 +1233,7 @@ static struct file_operations spufs_mfc_
.flush = spufs_mfc_flush,
.fsync = spufs_mfc_fsync,
.fasync = spufs_mfc_fasync,
-#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_mfc_mmap,
-#endif
};
static void spufs_npc_set(void *data, u64 val)
@@ -1368,5 +1405,6 @@ struct tree_descr spufs_dir_contents[] =
{ "event_mask", &spufs_event_mask_ops, 0666, },
{ "srr0", &spufs_srr0_ops, 0666, },
{ "phys-id", &spufs_id_ops, 0666, },
+ { "psmap", &spufs_psmap_fops, 0666, },
{},
};
Index: linux-cell/arch/powerpc/platforms/cell/Kconfig
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/Kconfig 2006-09-29 15:04:30.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/Kconfig 2006-09-29 15:04:46.000000000 +1000
@@ -16,11 +16,6 @@ config SPU_BASE
bool
default n
-config SPUFS_MMAP
- bool
- depends on SPU_FS && SPARSEMEM
- default y
-
config CBE_RAS
bool "RAS features for bare metal Cell BE"
default y
^ permalink raw reply
* RE: [PATCH 11/12] Add MPC8360EMDS default dts file
From: Li Yang-r58472 @ 2006-09-29 7:46 UTC (permalink / raw)
To: Vitaly Bordug; +Cc: linuxppc-dev, paulus
In-Reply-To: <20060928173816.168d4cc2@vitb.ru.mvista.com>
> -----Original Message-----
> From: Vitaly Bordug [mailto:vbordug@ru.mvista.com]
> Sent: Thursday, September 28, 2006 9:38 PM
> To: Li Yang-r58472
> Cc: paulus@samba.org; galak@kernel.crashing.org;
linuxppc-dev@ozlabs.org
> Subject: Re: [PATCH 11/12] Add MPC8360EMDS default dts file
>=20
> On Thu, 28 Sep 2006 16:19:30 +0800
> Li Yang <leoli@freescale.com> wrote:
>=20
> > + muram@10000 {
> > + device_type =3D "muram";
> > + ranges =3D <0 00010000 0000c000>;
> > +
> > + data-only@0{
> > + reg =3D <0 c000>;
> > + };
> > + };
> > +
>=20
> Why not to have reg property, showing the allocation ranges? data-only
seems
> redundant as a node...
The reason why I added this node is to put the address under "muram"
bus. If I put the reg in muram node, the address will be offset to QE
base. But what the driver needs is the offset to MURAM base. IMHO,
this approach is clearer logically.
- Leo
^ permalink raw reply
* Re: [PATCH] Cell interrupt rework (final)
From: Arnd Bergmann @ 2006-09-29 7:51 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: linuxppc-dev list, Paul Mackerras, cbe-oss-dev@ozlabs.org
In-Reply-To: <1159506029.15792.18.camel@localhost.localdomain>
On Friday 29 September 2006 07:00, Benjamin Herrenschmidt wrote:
> This patch reworks the cell iic interrupt handling so that:
>=20
> =A0- Node ID is back in the interrupt number (only one IRQ host is created
> for all nodes). This allows interrupts from sources on another node to
> be routed non-locally. This will allow possibly one day to fix maxcpus=3D1
> or 2 and still get interrupts from devices on BE 1. (A bit more fixing
> is needed for that) and it will allow us to implement actual affinity
> control of external interrupts.
>=20
> =A0- Added handling of the IO exceptions interrupts (badly named, but I
> re-used the name initially used by STI). Those are the interrupts
> exposed by IIC_ISR and IIC_IRR, such as the IOC translation exception,
> performance monitor, etc... Those get their special numbers in the IRQ
> number space and are internally implemented as a cascade on unit 0xe,
> class 1 of each node.
>=20
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
^ permalink raw reply
* Re: [PATCH] powerpc: cell spu problem state mapping updates
From: Arnd Bergmann @ 2006-09-29 7:52 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: linuxppc-dev list, Paul Mackerras, cbe-oss-dev@ozlabs.org
In-Reply-To: <1159506605.15792.24.camel@localhost.localdomain>
On Friday 29 September 2006 07:10, Benjamin Herrenschmidt wrote:
> This patch adds a new "psmap" file to spufs that allows mmap of all of
> the problem state mapping of SPEs. It is compatible with 64k pages. In
> addition, it removes mmap ability of individual files when using 64k
> pages, with the exception of signal1 and signal2 which will both map the
> entire 64k page holding both registers. It also removes
> CONFIG_SPUFS_MMAP as there is no point in not building mmap support in
> spufs.
>
> It goes along a separate patch to libspe implementing usage of that new
> file to access problem state registers.
>
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
^ permalink raw reply
* [PATCH] IBM GPIO driver for PowerPC 4xx is back from the dead
From: Jean-Baptiste Maneyrol @ 2006-09-29 7:46 UTC (permalink / raw)
To: linuxppc-embedded
Here is a patch for linux 2.6.18 that makes come back the old ibm gpio
driver from 2.6.10.
It is mainly useful for compatibility with old linux 2.4 from Montavista
I think, because direct memory access seems the new way to go.
Signed-off-by: Jean-Baptiste Maneyrol
<jean-baptiste.maneyrol@teamlog.com>
Jean-Baptiste Maneyrol
Teamlog - France
^ permalink raw reply
* [PATCH] IBM GPIO driver for PowerPC 4xx is back from the dead
From: Jean-Baptiste Maneyrol @ 2006-09-29 8:29 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 346 bytes --]
Here is a patch for linux 2.6.18 that makes come back the old ibm gpio
driver from 2.6.10.
It is mainly useful for compatibility with old linux 2.4 from Montavista
I think, because direct memory access seems the new way to go.
Signed-off-by: Jean-Baptiste Maneyrol
<jean-baptiste.maneyrol@teamlog.com>
Jean-Baptiste Maneyrol
Teamlog - France
[-- Attachment #2: ibm_gpio.patch --]
[-- Type: text/x-patch, Size: 12617 bytes --]
diff -Naur linux-2.6.18_gpio/drivers/char/ibm_gpio.c tlgate_gpio/drivers/char/ibm_gpio.c
--- linux-2.6.18_gpio/drivers/char/ibm_gpio.c 1970-01-01 01:00:00.000000000 +0100
+++ tlgate_gpio/drivers/char/ibm_gpio.c 2006-09-28 16:46:42.000000000 +0200
@@ -0,0 +1,349 @@
+/*
+ * FILE NAME ibm_gpio.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ * API for IBM PowerPC 4xx GPIO device.
+ * Driver for IBM PowerPC 4xx GPIO device.
+ *
+ * Armin Kuster akuster@pacbell.net
+ * Sept, 2001
+ *
+ * Orignial driver
+ * Author: MontaVista Software, Inc. <source@mvista.com>
+ * Frank Rowand <frank_rowand@mvista.com>
+ * Debbie Chu <debbie_chu@mvista.com>
+ *
+ * Copyright 2000,2001,2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * TODO: devfs
+ *
+ * Version: 02/01/12 - Armin
+ * converted to ocp and using ioremap
+ *
+ * 1.2 02/21/01 - Armin
+ * minor compiler warning fixes
+ *
+ * 1.3 02/22/01 - Armin
+ * added apm
+ *
+ * 1.4 05/07/02 - Armin/David Mueller
+ * coverted to core_ocp[];
+ *
+ * 1.5 05/25/02 - Armin
+ * name change from *_driver to *_dev
+ *
+ * 1.6 06/04/02 - Matt Porter
+ * ioremap paddr. Comment as 4xx generic driver.
+ * Fix header to be userland safe and locate in
+ * an accessible area. Add ioctl to configure
+ * multiplexed GPIO pins.
+ *
+ * 1.7 07/25/02 - Armin
+ * added CPM to enable/disable in init/exit
+ *
+ */
+
+#define VUFX "07.25.02"
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <asm/ibm_gpio.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ocp.h>
+#include <asm/ibm4xx.h>
+
+struct miscdevice ibm_gpio_miscdev;
+static struct gpio_regs *gpiop;
+
+int
+ibm_gpio_config(__u32 device, __u32 mask, __u32 data)
+{
+ u32 cfg_reg;
+
+ if (device != 0)
+ return -ENXIO;
+
+#ifdef CONFIG_40x
+#ifdef DCRN_CHCR0
+ /*
+ * PPC405 uses CPC0_CR0 to select multiplexed GPIO pins.
+ */
+ cfg_reg = mfdcr(DCRN_CHCR0);
+ cfg_reg = (cfg_reg & ~mask) | (data & mask);
+ mtdcr(DCRN_CHCR0, cfg_reg);
+#endif
+#elif CONFIG_440GP
+ /*
+ * PPC440GP uses CPC0_GPIO to select multiplexed GPIO pins.
+ */
+ cfg_reg = mfdcr(DCRN_CPC0_GPIO);
+ cfg_reg = (cfg_reg & ~mask) | (data & mask);
+ mtdcr(DCRN_CPC0_GPIO, cfg_reg);
+#elif CONFIG_440GX
+ /*
+ * PPC440GX uses SDR0_PFC0 to select multiplexed GPIO pins
+ */
+ cfg_reg = SDR_READ(DCRN_SDR_PFC0);
+ cfg_reg = (cfg_reg & ~mask) | (data & mask);
+ SDR_WRITE(DCRN_SDR_PFC0, cfg_reg);
+#else
+#error This driver is only supported on PPC40x and PPC440 CPUs
+#endif
+
+ return 0;
+}
+
+int
+ibm_gpio_tristate(__u32 device, __u32 mask, __u32 data)
+{
+ if (device != 0)
+ return -ENXIO;
+ gpiop->tcr = (gpiop->tcr & ~mask) | (data & mask);
+ return 0;
+}
+
+int
+ibm_gpio_open_drain(__u32 device, __u32 mask, __u32 data)
+{
+ if (device != 0)
+ return -ENXIO;
+ gpiop->odr = (gpiop->odr & ~mask) | (data & mask);
+
+ return 0;
+}
+
+int
+ibm_gpio_in(__u32 device, __u32 mask, volatile __u32 * data)
+{
+ if (device != 0)
+ return -ENXIO;
+ gpiop->tcr = gpiop->tcr & ~mask;
+ eieio();
+
+ /*
+ ** If the previous state was OUT, and gpiop->ir is read once, then the
+ ** data that was being OUTput will be read. One way to get the right
+ ** data is to read gpiop->ir twice.
+ */
+
+ *data = gpiop->ir;
+ *data = gpiop->ir & mask;
+ eieio();
+ return 0;
+}
+
+int
+ibm_gpio_out(__u32 device, __u32 mask, __u32 data)
+{
+ if (device != 0)
+ return -ENXIO;
+ gpiop->or = (gpiop->or & ~mask) | (data & mask);
+ eieio();
+ gpiop->tcr = gpiop->tcr | mask;
+ eieio();
+ return 0;
+}
+
+static int
+ibm_gpio_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int
+ibm_gpio_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int
+ibm_gpio_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ static struct ibm_gpio_ioctl_data ioctl_data;
+ int status;
+
+ switch (cmd) {
+ case IBMGPIO_IN:
+ if (copy_from_user(&ioctl_data,
+ (struct ibm_gpio_ioctl_data *) arg,
+ sizeof (ioctl_data))) {
+ return -EFAULT;
+ }
+
+ status = ibm_gpio_in(ioctl_data.device,
+ ioctl_data.mask, &ioctl_data.data);
+ if (status != 0)
+ return status;
+
+ if (copy_to_user((struct ibm_gpio_ioctl_data *) arg,
+ &ioctl_data, sizeof (ioctl_data))) {
+ return -EFAULT;
+ }
+
+ break;
+
+ case IBMGPIO_OUT:
+ if (copy_from_user(&ioctl_data,
+ (struct ibm_gpio_ioctl_data *) arg,
+ sizeof (ioctl_data))) {
+ return -EFAULT;
+ }
+
+ return ibm_gpio_out(ioctl_data.device,
+ ioctl_data.mask, ioctl_data.data);
+
+ break;
+
+ case IBMGPIO_OPEN_DRAIN:
+ if (copy_from_user(&ioctl_data,
+ (struct ibm_gpio_ioctl_data *) arg,
+ sizeof (ioctl_data))) {
+ return -EFAULT;
+ }
+
+ return ibm_gpio_open_drain(ioctl_data.device,
+ ioctl_data.mask, ioctl_data.data);
+
+ break;
+
+ case IBMGPIO_TRISTATE:
+ if (copy_from_user(&ioctl_data,
+ (struct ibm_gpio_ioctl_data *) arg,
+ sizeof (ioctl_data)))
+ return -EFAULT;
+
+ return ibm_gpio_tristate(ioctl_data.device,
+ ioctl_data.mask, ioctl_data.data);
+
+ break;
+
+ case IBMGPIO_CFG:
+ if (copy_from_user(&ioctl_data,
+ (struct ibm_gpio_ioctl_data *) arg,
+ sizeof (ioctl_data)))
+ return -EFAULT;
+
+ return ibm_gpio_config(ioctl_data.device,
+ ioctl_data.mask, ioctl_data.data);
+
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+
+ }
+ return 0;
+}
+
+static struct file_operations ibm_gpio_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = ibm_gpio_ioctl,
+ .open = ibm_gpio_open,
+ .release = ibm_gpio_release,
+};
+
+static int __init
+ibm_gpio_probe(struct ocp_device *ocp)
+{
+ ibm_gpio_miscdev.minor = GPIO_MINOR;
+ ibm_gpio_miscdev.name = ocp->name;
+ ibm_gpio_miscdev.fops = &ibm_gpio_fops;
+ misc_register(&ibm_gpio_miscdev);
+
+ if (!request_mem_region(ocp->def->paddr, sizeof(struct gpio_regs), "ibm_gpio"))
+ return -EBUSY;
+
+ gpiop = (struct gpio_regs *) ioremap(ocp->def->paddr,
+ sizeof(struct gpio_regs));
+ if (!gpiop) {
+ release_mem_region(ocp->def->paddr, sizeof(struct gpio_regs));
+ return -ENOMEM;
+ }
+
+ printk("GPIO #%d at 0x%lx\n", ocp->def->index,
+ (unsigned long) gpiop);
+
+ return 0;
+}
+
+static void __exit
+ibm_gpio_remove(struct ocp_device *ocp)
+{
+ misc_deregister(&ibm_gpio_miscdev);
+
+ iounmap(gpiop);
+ gpiop = NULL;
+
+ release_mem_region(ocp->def->paddr, sizeof(struct gpio_regs));
+}
+
+static struct ocp_device_id ibm_gpio_ids[] __devinitdata =
+{
+ { .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_GPIO },
+ { .vendor = OCP_VENDOR_INVALID }
+};
+
+MODULE_DEVICE_TABLE(ocp, ibm_gpio_ids);
+
+static struct ocp_driver ibm_gpio_driver =
+{
+ .name = "ibm_gpio",
+ .id_table = ibm_gpio_ids,
+ .probe = ibm_gpio_probe,
+ .remove = __devexit_p(ibm_gpio_remove),
+#if defined(CONFIG_PM)
+ .suspend = NULL,
+ .resume = NULL,
+#endif
+};
+
+static int __init
+ibm_gpio_init(void)
+{
+ printk("IBM GPIO driver version %s\n", VUFX);
+ return ocp_register_driver(&ibm_gpio_driver);
+}
+
+static void __exit
+ibm_gpio_exit(void)
+{
+ ocp_unregister_driver(&ibm_gpio_driver);
+}
+
+module_init(ibm_gpio_init);
+module_exit(ibm_gpio_exit);
+
+EXPORT_SYMBOL(ibm_gpio_tristate);
+EXPORT_SYMBOL(ibm_gpio_open_drain);
+EXPORT_SYMBOL(ibm_gpio_in);
+EXPORT_SYMBOL(ibm_gpio_out);
+
+MODULE_LICENSE("GPL");
diff -Naur linux-2.6.18_gpio/drivers/char/Kconfig tlgate_gpio/drivers/char/Kconfig
--- linux-2.6.18_gpio/drivers/char/Kconfig 2006-09-28 16:47:53.000000000 +0200
+++ tlgate_gpio/drivers/char/Kconfig 2006-09-28 16:50:15.000000000 +0200
@@ -936,6 +936,15 @@
To compile this driver as a module, choose M here: the
module will be called mwave.
+config IBM_GPIO
+ tristate "IBM PowerPC 4xx GPIO Support"
+ depends on IBM_OCP
+ help
+ Give userspace access to the GPIO pins on the PowerPC
+ 4xx processors.
+
+ If compiled as a module, it will be called ibm_gpio.
+
config SCx200_GPIO
tristate "NatSemi SCx200 GPIO Support"
depends on SCx200
diff -Naur linux-2.6.18_gpio/drivers/char/Makefile tlgate_gpio/drivers/char/Makefile
--- linux-2.6.18_gpio/drivers/char/Makefile 2006-09-28 16:47:57.000000000 +0200
+++ tlgate_gpio/drivers/char/Makefile 2006-09-28 16:46:42.000000000 +0200
@@ -81,6 +81,7 @@
obj-$(CONFIG_PPDEV) += ppdev.o
obj-$(CONFIG_NWBUTTON) += nwbutton.o
obj-$(CONFIG_NWFLASH) += nwflash.o
+obj-$(CONFIG_IBM_GPIO) += ibm_gpio.o
obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o
obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o
obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o
diff -Naur linux-2.6.18_gpio/include/asm-ppc/ibm_gpio.h tlgate_gpio/include/asm-ppc/ibm_gpio.h
--- linux-2.6.18_gpio/include/asm-ppc/ibm_gpio.h 1970-01-01 01:00:00.000000000 +0100
+++ tlgate_gpio/include/asm-ppc/ibm_gpio.h 2006-09-28 16:47:09.000000000 +0200
@@ -0,0 +1,71 @@
+/*
+ * FILE NAME ibm_ocp_gpio.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ * Generic gpio.
+ *
+ * Armin Kuster akuster@pacbell.net
+ * Sept, 2001
+ *
+ * Orignial driver
+ * Author: MontaVista Software, Inc. <source@mvista.com>
+ * Frank Rowand <frank_rowand@mvista.com>
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __IBM_OCP_GPIO_H
+#define __IBM_OCP_GPIO_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+
+typedef struct gpio_regs {
+ u32 or;
+ u32 tcr;
+ u32 pad[4];
+ u32 odr;
+ u32 ir;
+} gpio_t;
+
+#define GPIO_MINOR 185
+
+#endif /* __KERNEL__ */
+
+struct ibm_gpio_ioctl_data {
+ __u32 device;
+ __u32 mask;
+ __u32 data;
+};
+
+#define IBMGPIO_IOCTL_BASE 'Z'
+
+#define IBMGPIO_IN _IOWR(IBMGPIO_IOCTL_BASE, 0, struct ibm_gpio_ioctl_data)
+#define IBMGPIO_OUT _IOW (IBMGPIO_IOCTL_BASE, 1, struct ibm_gpio_ioctl_data)
+#define IBMGPIO_OPEN_DRAIN _IOW (IBMGPIO_IOCTL_BASE, 2, struct ibm_gpio_ioctl_data)
+#define IBMGPIO_TRISTATE _IOW (IBMGPIO_IOCTL_BASE, 3, struct ibm_gpio_ioctl_data)
+#define IBMGPIO_CFG _IOW (IBMGPIO_IOCTL_BASE, 4, struct ibm_gpio_ioctl_data)
+
+#endif
^ permalink raw reply
* RE: Running Linux on Avnet's FX12 Evaluation Board
From: Jaap de Jong @ 2006-09-29 8:17 UTC (permalink / raw)
To: linuxppc-embedded
Hi,
I had to declare the ddr_sdram as plb_ddr instead of opb_ddr...
Jaap
-----Original Message-----
Hello,
I am trying to run a Linuxppc 2.4 kernel (20051021) on an IBM Powerpc
405, I have compiled it according to the instructions on
http://www.itee.uq.edu.au/~jwilliams/mblaze-uclinux/uclinux_powerpc/#lin
uxppc-2,
I load it into the ram using the Xilinx Microprocessor Debug (XMD)
Engine and try to run it, but it seems to have some trouble with the
memory:
^ permalink raw reply
* Re: [PATCH] IBM GPIO driver for PowerPC 4xx is back from the dead
From: Arnd Bergmann @ 2006-09-29 9:06 UTC (permalink / raw)
To: linuxppc-embedded; +Cc: Jean-Baptiste Maneyrol
In-Reply-To: <1159518565.9269.1.camel@jb-portable>
On Friday 29 September 2006 10:29, Jean-Baptiste Maneyrol wrote:
> diff -Naur linux-2.6.18_gpio/drivers/char/ibm_gpio.c tlgate_gpio/drivers/=
char/ibm_gpio.c
> --- linux-2.6.18_gpio/drivers/char/ibm_gpio.c=A0=A0=A01970-01-01 01:00:00=
=2E000000000 +0100
> +++ tlgate_gpio/drivers/char/ibm_gpio.c=A02006-09-28 16:46:42.000000000 +=
0200
> @@ -0,0 +1,349 @@
> +/*
> + * FILE NAME ibm_gpio.c
<insert usual comment about removing the file name from the file>
> + * BRIEF MODULE DESCRIPTION
> + * =A0API for IBM PowerPC 4xx GPIO device.
> + * =A0Driver for IBM PowerPC 4xx GPIO device.
> + *
> + * =A0Armin Kuster akuster@pacbell.net
> + * =A0Sept, 2001
> + *
> + * =A0Orignial driver
> + * =A0Author: MontaVista Software, Inc. =A0<source@mvista.com>
> + * =A0 =A0 =A0 =A0 =A0Frank Rowand <frank_rowand@mvista.com>
> + * =A0 =A0 =A0 =A0 =A0Debbie Chu =A0 <debbie_chu@mvista.com>
> + *
> + * Copyright 2000,2001,2002 MontaVista Software Inc.
Any new copyright year?
> + *=A0=A0=A0=A0=A0TODO: devfs
surely not.
> + *=A0=A0=A0=A0=A0Version: 02/01/12 - Armin
> + *=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 conver=
ted to ocp and using ioremap
> + *
> + *=A0=A0=A0=A0=A01.2 02/21/01 - Armin
> + *=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0minor compiler warning fixes
> + *
> + *=A0=A0=A0=A0=A01.3 02/22/01 - Armin
> + *=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0added apm
> + *
> + *=A0=A0=A0=A0=A01.4 05/07/02 - Armin/David Mueller
> + *=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0coverted to core_ocp[];
> + *
> + *=A0=A0=A0=A0=A01.5 05/25/02 - Armin
> + *=A0=A0=A0=A0=A0 name change from *_driver to *_dev
> + *
> + *=A0=A0=A0=A0=A01.6 06/04/02 - Matt Porter
> + *=A0=A0=A0=A0=A0ioremap paddr. Comment as 4xx generic driver.
> + *=A0=A0=A0=A0=A0Fix header to be userland safe and locate in
> + *=A0=A0=A0=A0=A0an accessible area. =A0Add ioctl to configure
> + *=A0=A0=A0=A0=A0multiplexed GPIO pins.
> + *
> + *=A0=A0=A0=A0=A01.7 07/25/02 - Armin
> + *=A0=A0=A0=A0=A0added CPM to enable/disable in init/exit
kill that changelog
> + */
> +
> +#define VUFX "07.25.02"
should be MODULE_VERSION()
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/kernel.h>
> +#include <linux/miscdevice.h>
> +#include <linux/init.h>
> +#include <linux/ioctl.h>
> +#include <linux/fs.h>
> +#include <asm/ibm_gpio.h>
> +#include <asm/uaccess.h>
> +#include <asm/io.h>
> +#include <asm/machdep.h>
> +#include <asm/ocp.h>
> +#include <asm/ibm4xx.h>
> +
> +struct miscdevice ibm_gpio_miscdev;
> +static struct gpio_regs *gpiop;
> +
> +int
> +ibm_gpio_config(__u32 device, __u32 mask, __u32 data)
any symbols should be static. Function arguments are not
visible to users, so they should be 'u32' instead of '__u32'.
> +{
> +=A0=A0=A0=A0=A0=A0=A0u32 cfg_reg;
> +
> +=A0=A0=A0=A0=A0=A0=A0if (device !=3D 0)
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -ENXIO;
> +
> +#ifdef CONFIG_40x
> +#ifdef DCRN_CHCR0
> +=A0=A0=A0=A0=A0=A0=A0/*
> +=A0=A0=A0=A0=A0=A0=A0 * PPC405 uses CPC0_CR0 to select multiplexed GPIO =
pins.
> +=A0=A0=A0=A0=A0=A0=A0 */
> +=A0=A0=A0=A0=A0=A0=A0cfg_reg =3D mfdcr(DCRN_CHCR0);
> +=A0=A0=A0=A0=A0=A0=A0cfg_reg =3D (cfg_reg & ~mask) | (data & mask);
> +=A0=A0=A0=A0=A0=A0=A0mtdcr(DCRN_CHCR0, cfg_reg);
> +#endif
> +#elif CONFIG_440GP
> +=A0=A0=A0=A0=A0=A0=A0/*
> +=A0=A0=A0=A0=A0=A0=A0 * PPC440GP uses CPC0_GPIO to select multiplexed GP=
IO pins.
> +=A0=A0=A0=A0=A0=A0=A0 */
> +=A0=A0=A0=A0=A0=A0=A0cfg_reg =3D mfdcr(DCRN_CPC0_GPIO);
> +=A0=A0=A0=A0=A0=A0=A0cfg_reg =3D (cfg_reg & ~mask) | (data & mask);
> +=A0=A0=A0=A0=A0=A0=A0mtdcr(DCRN_CPC0_GPIO, cfg_reg);
> +#elif CONFIG_440GX
> +=A0=A0=A0=A0=A0=A0=A0/*
> +=A0=A0=A0=A0=A0=A0=A0 * PPC440GX uses SDR0_PFC0 to select multiplexed GP=
IO pins
> +=A0=A0=A0=A0=A0=A0=A0 */
> +=A0=A0=A0=A0=A0=A0=A0cfg_reg =3D SDR_READ(DCRN_SDR_PFC0);
> +=A0=A0=A0=A0=A0=A0=A0cfg_reg =3D (cfg_reg & ~mask) | (data & mask);
> +=A0=A0=A0=A0=A0=A0=A0SDR_WRITE(DCRN_SDR_PFC0, cfg_reg);
> +#else
> +#error This driver is only supported on PPC40x and PPC440 CPUs
> +#endif
This prevents building a single kernel for multiple 440 version.
Please use a run-time check, or better get the necessary information
from the device tree.
> +int
> +ibm_gpio_in(__u32 device, __u32 mask, volatile __u32 * data)
> +{
> +=A0=A0=A0=A0=A0=A0=A0if (device !=3D 0)
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -ENXIO;
> +=A0=A0=A0=A0=A0=A0=A0gpiop->tcr =3D gpiop->tcr & ~mask;
> +=A0=A0=A0=A0=A0=A0=A0eieio();
> +
> +=A0=A0=A0=A0=A0=A0=A0/*
> +=A0=A0=A0=A0=A0=A0=A0 =A0 ** If the previous state was OUT, and gpiop->i=
r is read once, then the
> +=A0=A0=A0=A0=A0=A0=A0 =A0 ** data that was being OUTput will be read. =
=A0One way to get the right
> +=A0=A0=A0=A0=A0=A0=A0 =A0 ** data is to read gpiop->ir twice.
> +=A0=A0=A0=A0=A0=A0=A0 */
> +
> +=A0=A0=A0=A0=A0=A0=A0*data =3D gpiop->ir;
> +=A0=A0=A0=A0=A0=A0=A0*data =3D gpiop->ir & mask;
> +=A0=A0=A0=A0=A0=A0=A0eieio();
> +=A0=A0=A0=A0=A0=A0=A0return 0;
> +}
Don't just assign *data, make that an __iomem pointer and use
an appropriate accessor function (out_be32 or such).
> +
> +static int
> +ibm_gpio_open(struct inode *inode, struct file *file)
> +{
> +=A0=A0=A0=A0=A0=A0=A0return 0;
> +}
> +
> +static int
> +ibm_gpio_release(struct inode *inode, struct file *file)
> +{
> +=A0=A0=A0=A0=A0=A0=A0return 0;
> +}
You don't need these.
> +static int
> +ibm_gpio_ioctl(struct inode *inode, struct file *file,
> +=A0=A0=A0=A0=A0=A0=A0 =A0 =A0 =A0 unsigned int cmd, unsigned long arg)
> +{
> +=A0=A0=A0=A0=A0=A0=A0static struct ibm_gpio_ioctl_data ioctl_data;
> +=A0=A0=A0=A0=A0=A0=A0int status;
> +
> +=A0=A0=A0=A0=A0=A0=A0switch (cmd) {
> +=A0=A0=A0=A0=A0=A0=A0case IBMGPIO_IN:
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0if (copy_from_user(&ioctl_d=
ata,
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=
=A0=A0=A0=A0=A0=A0=A0 =A0 (struct ibm_gpio_ioctl_data *) arg,
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=
=A0=A0=A0=A0=A0=A0=A0 =A0 sizeof (ioctl_data))) {
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0ret=
urn -EFAULT;
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0}
Just do the copy_from_user() once, in the beginning here, instead
of each case.
> +
> +static int __init
> +ibm_gpio_probe(struct ocp_device *ocp)
> +{
> +=A0=A0=A0=A0=A0=A0=A0ibm_gpio_miscdev.minor =3D GPIO_MINOR;
> +=A0=A0=A0=A0=A0=A0=A0ibm_gpio_miscdev.name =3D ocp->name;
> +=A0=A0=A0=A0=A0=A0=A0ibm_gpio_miscdev.fops =3D &ibm_gpio_fops;
> +=A0=A0=A0=A0=A0=A0=A0misc_register(&ibm_gpio_miscdev);
> +
> +=A0=A0=A0=A0=A0=A0=A0if (!request_mem_region(ocp->def->paddr, sizeof(str=
uct gpio_regs), "ibm_gpio"))
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -EBUSY;
> +=A0=A0=A0=A0=A0=A0=A0
> +=A0=A0=A0=A0=A0=A0=A0gpiop =3D (struct gpio_regs *) ioremap(ocp->def->pa=
ddr,
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0siz=
eof(struct gpio_regs));
> +=A0=A0=A0=A0=A0=A0=A0if (!gpiop) {
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0release_mem_region(ocp->def=
=2D>paddr, sizeof(struct gpio_regs));
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -ENOMEM;
> +=A0=A0=A0=A0=A0=A0=A0}
> +=A0=A0=A0=A0=A0=A0=A0
> +=A0=A0=A0=A0=A0=A0=A0printk("GPIO #%d at 0x%lx\n", ocp->def->index,
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0(un=
signed long) gpiop);
> +
> +=A0=A0=A0=A0=A0=A0=A0return 0;
> +}
> +
> +static void __exit
> +ibm_gpio_remove(struct ocp_device *ocp)
> +{
> +=A0=A0=A0=A0=A0=A0=A0misc_deregister(&ibm_gpio_miscdev);
> +
> +=A0=A0=A0=A0=A0=A0=A0iounmap(gpiop);
> +=A0=A0=A0=A0=A0=A0=A0gpiop =3D NULL;
> +=A0=A0=A0=A0=A0=A0=A0
> +=A0=A0=A0=A0=A0=A0=A0release_mem_region(ocp->def->paddr, sizeof(struct g=
pio_regs));
> +}
> +
> +static struct ocp_device_id ibm_gpio_ids[] __devinitdata =3D
> +{
> +=A0=A0=A0=A0=A0=A0=A0{ .vendor =3D OCP_VENDOR_IBM, .function =3D OCP_FUN=
C_GPIO },
> +=A0=A0=A0=A0=A0=A0=A0{ .vendor =3D OCP_VENDOR_INVALID }
> +};
> +
> +MODULE_DEVICE_TABLE(ocp, ibm_gpio_ids);
> +
> +static struct ocp_driver ibm_gpio_driver =3D
> +{
> +=A0=A0=A0=A0=A0=A0=A0.name =A0 =A0 =A0 =A0 =A0 =3D "ibm_gpio",
> +=A0=A0=A0=A0=A0=A0=A0.id_table =A0 =A0 =A0 =3D ibm_gpio_ids,
> +=A0=A0=A0=A0=A0=A0=A0.probe =A0 =A0 =A0 =A0 =A0=3D ibm_gpio_probe,
> +=A0=A0=A0=A0=A0=A0=A0.remove =A0 =A0 =A0 =A0 =3D __devexit_p(ibm_gpio_re=
move),
> +#if defined(CONFIG_PM)
> +=A0=A0=A0=A0=A0=A0=A0.suspend =A0 =A0 =A0 =A0=3D NULL,
> +=A0=A0=A0=A0=A0=A0=A0.resume =A0 =A0 =A0 =A0 =3D NULL,
> +#endif
> +};
> +
> +static int __init
> +ibm_gpio_init(void)
> +{
> +=A0=A0=A0=A0=A0=A0=A0printk("IBM GPIO driver version %s\n", VUFX);
> +=A0=A0=A0=A0=A0=A0=A0return ocp_register_driver(&ibm_gpio_driver);
> +}
> +
> +static void __exit
> +ibm_gpio_exit(void)
> +{
> +=A0=A0=A0=A0=A0=A0=A0ocp_unregister_driver(&ibm_gpio_driver);
> +}
ocp will die a painful death soon, when 440 has been converted over
to use the device tree and of_device.
> +EXPORT_SYMBOL(ibm_gpio_tristate);
> +EXPORT_SYMBOL(ibm_gpio_open_drain);
> +EXPORT_SYMBOL(ibm_gpio_in);
> +EXPORT_SYMBOL(ibm_gpio_out);
Why export these at all? They don't seem to be used elsewhere?
If you need to export them, make it EXPORT_SYMBOL_GPL and put that
line directly under the functions.
> +
> +struct ibm_gpio_ioctl_data {
> + =A0 =A0 =A0 =A0__u32 device;
> + =A0 =A0 =A0 =A0__u32 mask;
> + =A0 =A0 =A0 =A0__u32 data;
> +};
> +
> +#define IBMGPIO_IOCTL_BASE=A0=A0=A0=A0=A0'Z'
> +
> +#define IBMGPIO_IN=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0_IOWR(IBMGPIO_I=
OCTL_BASE, 0, struct ibm_gpio_ioctl_data)
> +#define IBMGPIO_OUT=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0_IOW (IBMGPIO_IOC=
TL_BASE, 1, struct ibm_gpio_ioctl_data)
> +#define IBMGPIO_OPEN_DRAIN=A0=A0=A0=A0=A0_IOW (IBMGPIO_IOCTL_BASE, 2, st=
ruct ibm_gpio_ioctl_data)
> +#define IBMGPIO_TRISTATE=A0=A0=A0=A0=A0=A0=A0_IOW (IBMGPIO_IOCTL_BASE, 3=
, struct ibm_gpio_ioctl_data)
> +#define IBMGPIO_CFG=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0_IOW (IBMGPIO_IOC=
TL_BASE, 4, struct ibm_gpio_ioctl_data)
Is that the same ioctl interface as for the other gpio drivers?
> +#endif
^ permalink raw reply
* [PATCH] Fix rheap alignment problem
From: Li Yang @ 2006-09-29 10:15 UTC (permalink / raw)
To: paulus; +Cc: linuxppc-dev
Honor alignment parameter in the rheap allocator. This is
needed by qe_lib.
Remove compile warning.
Signed-off-by: Pantelis Antoniou <pantelis@embeddedalley.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Acked-by: Kumar Galak <galak@kernel.crashing.org>
---
arch/powerpc/lib/Makefile | 1 +
arch/powerpc/lib/rheap.c | 24 ++++++++++++++++++++----
include/asm-ppc/rheap.h | 4 ++++
3 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index ff70964..fe61c92 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -14,6 +14,7 @@ endif
obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \
memcpy_64.o usercopy_64.o mem_64.o string.o \
strcase.o
+obj-$(CONFIG_QUICC_ENGINE) += rheap.o
obj-$(CONFIG_PPC_ISERIES) += e2a.o
obj-$(CONFIG_XMON) += sstep.o
diff --git a/arch/powerpc/lib/rheap.c b/arch/powerpc/lib/rheap.c
index 31e5118..57bf991 100644
--- a/arch/powerpc/lib/rheap.c
+++ b/arch/powerpc/lib/rheap.c
@@ -423,17 +423,21 @@ void *rh_detach_region(rh_info_t * info,
return (void *)s;
}
-void *rh_alloc(rh_info_t * info, int size, const char *owner)
+void *rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owner)
{
struct list_head *l;
rh_block_t *blk;
rh_block_t *newblk;
void *start;
- /* Validate size */
- if (size <= 0)
+ /* Validate size, (must be power of two) */
+ if (size <= 0 || (alignment & (alignment - 1)) != 0)
return ERR_PTR(-EINVAL);
+ /* given alignment larger that default rheap alignment */
+ if (alignment > info->alignment)
+ size += alignment - 1;
+
/* Align to configured alignment */
size = (size + (info->alignment - 1)) & ~(info->alignment - 1);
@@ -476,15 +480,27 @@ void *rh_alloc(rh_info_t * info, int siz
attach_taken_block(info, newblk);
+ /* for larger alignment return fixed up pointer */
+ /* this is no problem with the deallocator since */
+ /* we scan for pointers that lie in the blocks */
+ if (alignment > info->alignment)
+ start = (void *)(((unsigned long)start + alignment - 1) &
+ ~(alignment - 1));
+
return start;
}
+void *rh_alloc(rh_info_t * info, int size, const char *owner)
+{
+ return rh_alloc_align(info, size, info->alignment, owner);
+}
+
/* allocate at precisely the given address */
void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
{
struct list_head *l;
rh_block_t *blk, *newblk1, *newblk2;
- unsigned long s, e, m, bs, be;
+ unsigned long s, e, m, bs = 0, be = 0;
/* Validate size */
if (size <= 0)
diff --git a/include/asm-ppc/rheap.h b/include/asm-ppc/rheap.h
index e6ca1f6..65b9322 100644
--- a/include/asm-ppc/rheap.h
+++ b/include/asm-ppc/rheap.h
@@ -62,6 +62,10 @@ extern int rh_attach_region(rh_info_t *
/* Detach a free region */
extern void *rh_detach_region(rh_info_t * info, void *start, int size);
+/* Allocate the given size from the remote heap (with alignment) */
+extern void *rh_alloc_align(rh_info_t * info, int size, int alignment,
+ const char *owner);
+
/* Allocate the given size from the remote heap */
extern void *rh_alloc(rh_info_t * info, int size, const char *owner);
^ permalink raw reply related
* [PATCH 0/9] Add support for QE and 8360EMDS board -v3
From: Li Yang @ 2006-09-29 10:34 UTC (permalink / raw)
To: paulus, Kumar; +Cc: linuxppc-dev
Paul,
The series of patches add generic QE infrastructure called
qe_lib, and MPC8360EMDS board support. Qe_lib is used by
QE device drivers such as ucc_geth driver.
This version updates QE interrupt controller to use new irq
mapping mechanism, addresses all the comments received with
last submission and includes some style fixes.
v2: Change to use device tree for BCSR and MURAM;
Remove I/O port interrupt handling code as it is not generic
enough.
v3: Address comments from Kumar; Update definition of several
device tree nodes; Copyright style change.
- Leo
^ permalink raw reply
* [PATCH 1/9] qe_lib: Add common files
From: Li Yang @ 2006-09-29 10:35 UTC (permalink / raw)
To: paulus; +Cc: linuxppc-dev
Signed-off-by: Shlomi Gridish <gridish@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
---
arch/powerpc/Kconfig | 12 +
arch/powerpc/sysdev/Makefile | 1
arch/powerpc/sysdev/qe_lib/Kconfig | 29 ++
arch/powerpc/sysdev/qe_lib/Makefile | 8 +
arch/powerpc/sysdev/qe_lib/qe_common.c | 362 ++++++++++++++++++++++++
include/asm-powerpc/qe.h | 492 ++++++++++++++++++++++++++++++++
6 files changed, 904 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 694b0c6..16bc605 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -355,6 +355,16 @@ config APUS
<http://linux-apus.sourceforge.net/>.
endchoice
+config QUICC_ENGINE
+ bool
+ depends on PPC_MPC836x
+ default y
+ help
+ The QE(QUICC Engine) is a new generation of coprocessor on
+ Freescale embedded CPUs(like CPM in older chips). Selecting
+ this option means that you wish to build a kernel for a machine
+ with QE coprocessor on it.
+
config PPC_PSERIES
depends on PPC_MULTIPLATFORM && PPC64
bool "IBM pSeries & new (POWER5-based) iSeries"
@@ -1047,6 +1057,8 @@ # XXX source "arch/ppc/8xx_io/Kconfig"
# XXX source "arch/ppc/8260_io/Kconfig"
+source "arch/powerpc/sysdev/qe_lib/Kconfig"
+
source "arch/powerpc/platforms/iseries/Kconfig"
source "lib/Kconfig"
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index e5e999e..c6e5b31 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
obj-$(CONFIG_FSL_SOC) += fsl_soc.o
obj-$(CONFIG_PPC_TODC) += todc.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
+obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
ifeq ($(CONFIG_PPC_MERGE),y)
obj-$(CONFIG_PPC_I8259) += i8259.o
diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig
new file mode 100644
index 0000000..28487e4
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/Kconfig
@@ -0,0 +1,29 @@
+#
+# QE Communication options
+#
+
+menu "QE Options"
+ depends on QUICC_ENGINE
+
+config UCC_SLOW
+ bool "UCC Slow Protocols Support"
+ default n
+ select UCC
+ help
+ This option provides qe_lib support to UCC slow
+ protocols: UART, BISYNC, QMC
+
+config UCC_FAST
+ bool "UCC Fast Protocols Support"
+ default n
+ select UCC
+ help
+ This option provides qe_lib support to UCC fast
+ protocols: HDLC, Ethernet, ATM, transparent
+
+config UCC
+ bool
+ default y if UCC_FAST || UCC_SLOW
+
+endmenu
+
diff --git a/arch/powerpc/sysdev/qe_lib/Makefile b/arch/powerpc/sysdev/qe_lib/Makefile
new file mode 100644
index 0000000..9a54a81
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the linux ppc-specific parts of QE
+#
+obj-$(CONFIG_QUICC_ENGINE)+= qe_common.o qe.o qe_ic.o qe_io.o
+
+obj-$(CONFIG_UCC) += ucc.o
+obj-$(CONFIG_UCC_SLOW) += ucc_slow.o
+obj-$(CONFIG_UCC_FAST) += ucc_fast.o ucc_slow.o
diff --git a/arch/powerpc/sysdev/qe_lib/qe_common.c b/arch/powerpc/sysdev/qe_lib/qe_common.c
new file mode 100644
index 0000000..516c186
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/qe_common.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: Shlomi Gridish <gridish@freescale.com>
+ * Li Yang <leoli@freescale.com>
+ * Based on cpm2_common.c from Dan Malek (dmalek@jlc.net)
+ *
+ * Description:
+ * General Purpose functions for the global management of the
+ * QUICC Engine (QE).
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+#include <asm/prom.h>
+#include <asm/rheap.h>
+
+/* QE snum state
+*/
+typedef enum qe_snum_state {
+ QE_SNUM_STATE_USED, /* used */
+ QE_SNUM_STATE_FREE /* free */
+} qe_snum_state_e;
+
+/* QE snum
+*/
+typedef struct qe_snum {
+ u8 num; /* snum */
+ qe_snum_state_e state; /* state */
+} qe_snum_t;
+
+/* We allocate this here because it is used almost exclusively for
+ * the communication processor devices.
+ */
+EXPORT_SYMBOL(qe_immr);
+qe_map_t *qe_immr = NULL;
+static qe_snum_t snums[QE_NUM_OF_SNUM]; /* Dynamically allocated SNUMs */
+
+static void qe_snums_init(void);
+static void qe_muram_init(void);
+static int qe_sdma_init(void);
+
+static DEFINE_SPINLOCK(qe_lock);
+
+void qe_reset(void)
+{
+ if (qe_immr == NULL)
+ qe_immr = (qe_map_t *) ioremap(get_qe_base(), QE_IMMAP_SIZE);
+
+ qe_snums_init();
+
+ qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
+ (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
+
+ /* Reclaim the MURAM memory for our use. */
+ qe_muram_init();
+
+ if (qe_sdma_init())
+ panic("sdma init failed!");
+}
+
+EXPORT_SYMBOL(qe_issue_cmd);
+int qe_issue_cmd(uint cmd, uint device, u8 mcn_protocol, u32 cmd_input)
+{
+ unsigned long flags;
+ u32 cecr;
+ u8 mcn_shift = 0, dev_shift = 0;
+
+ spin_lock_irqsave(&qe_lock, flags);
+ if (cmd == QE_RESET) {
+ out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG));
+ } else {
+ if (cmd == QE_ASSIGN_PAGE) {
+ /* Here device is the SNUM, not sub-block */
+ dev_shift = QE_CR_SNUM_SHIFT;
+ } else if (cmd == QE_ASSIGN_RISC) {
+ /* Here device is the SNUM, and mcnProtocol is
+ * e_QeCmdRiscAssignment value */
+ dev_shift = QE_CR_SNUM_SHIFT;
+ mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT;
+ } else {
+ if (device == QE_CR_SUBBLOCK_USB)
+ mcn_shift = QE_CR_MCN_USB_SHIFT;
+ else
+ mcn_shift = QE_CR_MCN_NORMAL_SHIFT;
+ }
+
+ out_be32(&qe_immr->cp.cecdr,
+ immrbar_virt_to_phys((void *)cmd_input));
+ out_be32(&qe_immr->cp.cecr,
+ (cmd | QE_CR_FLG | ((u32) device << dev_shift) | (u32)
+ mcn_protocol << mcn_shift));
+ }
+
+ /* wait for the QE_CR_FLG to clear */
+ do {
+ cecr = in_be32(&qe_immr->cp.cecr);
+ } while (cecr & QE_CR_FLG);
+ spin_unlock_irqrestore(&qe_lock, flags);
+
+ return 0;
+}
+
+/* Set a baud rate generator. This needs lots of work. There are
+ * 16 BRGs, which can be connected to the QE channels or output
+ * as clocks. The BRGs are in two different block of internal
+ * memory mapped space.
+ * The baud rate clock is the system clock divided by something.
+ * It was set up long ago during the initial boot phase and is
+ * is given to us.
+ * Baud rate clocks are zero-based in the driver code (as that maps
+ * to port numbers). Documentation uses 1-based numbering.
+ */
+static unsigned int brg_clk = 0;
+
+unsigned int get_brg_clk(void)
+{
+ struct device_node *qe;
+ if (brg_clk)
+ return brg_clk;
+
+ qe = of_find_node_by_type(NULL, "qe");
+ if (qe) {
+ unsigned int size;
+ u32 *prop = (u32 *) get_property(qe, "brg-frequency", &size);
+ brg_clk = *prop;
+ of_node_put(qe);
+ };
+ return brg_clk;
+}
+
+/* This function is used by UARTS, or anything else that uses a 16x
+ * oversampled clock.
+ */
+void qe_setbrg(uint brg, uint rate)
+{
+ volatile uint *bp;
+ u32 divisor;
+ int div16 = 0;
+
+ bp = (uint *) & qe_immr->brg.brgc1;
+ bp += brg;
+
+ divisor = (get_brg_clk() / rate);
+ if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
+ div16 = 1;
+ divisor /= 16;
+ }
+
+ *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
+ if (div16)
+ *bp |= QE_BRGC_DIV16;
+}
+
+static void qe_snums_init(void)
+{
+ int i;
+
+ /* Initialize the SNUMs array. */
+ for (i = 0; i < QE_NUM_OF_SNUM; i++)
+ snums[i].state = QE_SNUM_STATE_FREE;
+
+ /* Initialize SNUMs (thread serial numbers) according to QE
+ * spec chapter 4, SNUM table */
+ i = 0;
+ snums[i++].num = 0x04;
+ snums[i++].num = 0x05;
+ snums[i++].num = 0x0C;
+ snums[i++].num = 0x0D;
+ snums[i++].num = 0x14;
+ snums[i++].num = 0x15;
+ snums[i++].num = 0x1C;
+ snums[i++].num = 0x1D;
+ snums[i++].num = 0x24;
+ snums[i++].num = 0x25;
+ snums[i++].num = 0x2C;
+ snums[i++].num = 0x2D;
+ snums[i++].num = 0x34;
+ snums[i++].num = 0x35;
+ snums[i++].num = 0x88;
+ snums[i++].num = 0x89;
+ snums[i++].num = 0x98;
+ snums[i++].num = 0x99;
+ snums[i++].num = 0xA8;
+ snums[i++].num = 0xA9;
+ snums[i++].num = 0xB8;
+ snums[i++].num = 0xB9;
+ snums[i++].num = 0xC8;
+ snums[i++].num = 0xC9;
+ snums[i++].num = 0xD8;
+ snums[i++].num = 0xD9;
+ snums[i++].num = 0xE8;
+ snums[i++].num = 0xE9;
+}
+
+int qe_get_snum(void)
+{
+ unsigned long flags;
+ int snum = -EBUSY;
+ int i;
+
+ spin_lock_irqsave(&qe_lock, flags);
+ for (i = 0; i < QE_NUM_OF_SNUM; i++) {
+ if (snums[i].state == QE_SNUM_STATE_FREE) {
+ snums[i].state = QE_SNUM_STATE_USED;
+ snum = snums[i].num;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&qe_lock, flags);
+
+ return snum;
+}
+
+EXPORT_SYMBOL(qe_get_snum);
+
+void qe_put_snum(u8 snum)
+{
+ int i;
+
+ for (i = 0; i < QE_NUM_OF_SNUM; i++) {
+ if (snums[i].num == snum) {
+ snums[i].state = QE_SNUM_STATE_FREE;
+ break;
+ }
+ }
+}
+
+EXPORT_SYMBOL(qe_put_snum);
+
+static int qe_sdma_init(void)
+{
+ sdma_t *sdma = &qe_immr->sdma;
+ uint sdma_buf_offset;
+
+ if (!sdma)
+ return -ENODEV;
+
+ /* allocate 2 internal temporary buffers (512 bytes size each) for
+ * the SDMA */
+ sdma_buf_offset = qe_muram_alloc(512 * 2, 64);
+ if (IS_MURAM_ERR(sdma_buf_offset))
+ return -ENOMEM;
+
+ out_be32(&sdma->sdebcr, sdma_buf_offset & QE_SDEBCR_BA_MASK);
+ out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK | (0x1 >>
+ QE_SDMR_CEN_SHIFT)));
+
+ return 0;
+}
+
+/*
+ * muram_alloc / muram_free bits.
+ */
+static DEFINE_SPINLOCK(qe_muram_lock);
+
+/* 16 blocks should be enough to satisfy all requests
+ * until the memory subsystem goes up... */
+static rh_block_t qe_boot_muram_rh_block[16];
+static rh_info_t qe_muram_info;
+
+static void qe_muram_init(void)
+{
+ struct device_node *np;
+ u32 address;
+ u64 size;
+ unsigned int flags;
+
+ /* initialize the info header */
+ rh_init(&qe_muram_info, 1,
+ sizeof(qe_boot_muram_rh_block) /
+ sizeof(qe_boot_muram_rh_block[0]), qe_boot_muram_rh_block);
+
+ /* Attach the usable muram area */
+ /* XXX: This is a subset of the available muram. It
+ * varies with the processor and the microcode patches activated.
+ */
+ if ((np = of_find_node_by_name(NULL, "data-only")) != NULL) {
+ address = *of_get_address(np, 0, &size, &flags);
+ of_node_put(np);
+ rh_attach_region(&qe_muram_info,
+ (void *)address, (int)size);
+ }
+}
+
+/* This function returns an index into the MURAM area.
+ */
+uint qe_muram_alloc(uint size, uint align)
+{
+ void *start;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qe_muram_lock, flags);
+ start = rh_alloc_align(&qe_muram_info, size, align, "QE");
+ spin_unlock_irqrestore(&qe_muram_lock, flags);
+
+ return (uint) start;
+}
+
+EXPORT_SYMBOL(qe_muram_alloc);
+
+int qe_muram_free(uint offset)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qe_muram_lock, flags);
+ ret = rh_free(&qe_muram_info, (void *)offset);
+ spin_unlock_irqrestore(&qe_muram_lock, flags);
+
+ return ret;
+}
+
+EXPORT_SYMBOL(qe_muram_free);
+
+/* not sure if this is ever needed */
+uint qe_muram_alloc_fixed(uint offset, uint size)
+{
+ void *start;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qe_muram_lock, flags);
+ start =
+ rh_alloc_fixed(&qe_muram_info, (void *)offset, size, "commproc");
+ spin_unlock_irqrestore(&qe_muram_lock, flags);
+
+ return (uint) start;
+}
+
+EXPORT_SYMBOL(qe_muram_alloc_fixed);
+
+void qe_muram_dump(void)
+{
+ rh_dump(&qe_muram_info);
+}
+
+EXPORT_SYMBOL(qe_muram_dump);
+
+void *qe_muram_addr(uint offset)
+{
+ return (void *)&qe_immr->muram[offset];
+}
+
+EXPORT_SYMBOL(qe_muram_addr);
diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h
new file mode 100644
index 0000000..8578a9b
--- /dev/null
+++ b/include/asm-powerpc/qe.h
@@ -0,0 +1,492 @@
+/*
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: Shlomi Gridish <gridish@freescale.com>
+ * Li Yang <leoli@freescale.com>
+ *
+ * Description:
+ * QUICC Engine (QE) external definitions and structure.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#ifdef CONFIG_QUICC_ENGINE
+#ifdef __KERNEL__
+#ifndef __QE_H__
+#define __QE_H__
+
+#include <asm/immap_qe.h>
+
+static inline long IS_MURAM_ERR(const uint offset)
+{
+ return (uint) offset > (uint) - 1000L;
+}
+
+#define QE_NUM_OF_SNUM 28
+#define QE_NUM_OF_BRGS 16
+#define QE_NUM_OF_PORTS 1024
+
+/* Memory partitions
+*/
+#define MEM_PART_SYSTEM 0
+#define MEM_PART_SECONDARY 1
+#define MEM_PART_MURAM 2
+
+/* Export QE common operations */
+extern void qe_reset(void);
+extern int par_io_init(struct device_node *np);
+extern int par_io_of_config(struct device_node *np);
+
+/* QE internal APIs */
+int qe_issue_cmd(uint cmd, uint device, u8 mcn_protocol, u32 cmd_input);
+void qe_setbrg(uint brg, uint rate);
+int qe_get_snum(void);
+void qe_put_snum(u8 snum);
+uint qe_muram_alloc(uint size, uint align);
+int qe_muram_free(uint offset);
+uint qe_muram_alloc_fixed(uint offset, uint size);
+void qe_muram_dump(void);
+void *qe_muram_addr(uint offset);
+/* Buffer descriptors.
+*/
+typedef struct qe_bd {
+ u16 status;
+ u16 length;
+ u32 buf;
+} __attribute__ ((packed)) qe_bd_t;
+
+#define QE_SIZEOF_BD sizeof(qe_bd_t)
+
+#define BD_STATUS_MASK 0xffff0000
+#define BD_LENGTH_MASK 0x0000ffff
+
+#define BD_BUFFER_ARG(bd) ((qe_bd_t *)bd)->buf
+#define BD_BUFFER_CLEAR(bd) out_be32(&(BD_BUFFER_ARG(bd)), 0);
+#define BD_BUFFER(bd) in_be32(&(BD_BUFFER_ARG(bd)))
+#define BD_STATUS_AND_LENGTH_SET(bd, val) out_be32((u32*)bd, val)
+#define BD_STATUS_AND_LENGTH(bd) in_be32((u32*)bd)
+#define BD_BUFFER_SET(bd, buffer) out_be32(&(BD_BUFFER_ARG(bd)), \
+ (u32)(buffer))
+/* Macro for retrieving the following BD.
+ example:
+ next = BD_GET_NEXT( currBd, bdStatus, bdBase, SIZEOF_MY_BD, T_W ) */
+#define BD_GET_NEXT( curr_bd, bd_status, bd_base, bd_len, last_bd ) \
+ ( (!((bd_status) & (last_bd))) ? ((curr_bd)+(bd_len)) : (bd_base) )
+
+/* Alignments
+*/
+#define QE_INTR_TABLE_ALIGN 16 /* ??? */
+#define QE_ALIGNMENT_OF_BD 8
+#define QE_ALIGNMENT_OF_PRAM 64
+
+/* RISC allocation
+*/
+typedef enum qe_risc_allocation {
+ QE_RISC_ALLOCATION_RISC1 = 1, /* RISC 1 */
+ QE_RISC_ALLOCATION_RISC2 = 2, /* RISC 2 */
+ QE_RISC_ALLOCATION_RISC1_AND_RISC2 = 3 /* Dynamically choose RISC 1 or
+ RISC 2 */
+} qe_risc_allocation_e;
+
+/* QE extended filtering Table Lookup Key Size
+*/
+typedef enum qe_fltr_tbl_lookup_key_size {
+ QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES
+ = 0x3f, /* LookupKey parsed by the Generate LookupKey
+ CMD is truncated to 8 bytes */
+ QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES
+ = 0x5f, /* LookupKey parsed by the Generate LookupKey
+ CMD is truncated to 16 bytes */
+} qe_fltr_tbl_lookup_key_size_e;
+
+/* QE FLTR extended filtering Largest External Table Lookup Key Size
+*/
+typedef enum qe_fltr_largest_external_tbl_lookup_key_size_ {
+ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE
+ = 0x0,/* not used */
+ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES
+ = QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES, /* 8 bytes */
+ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES
+ = QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES /* 16 bytes */
+} qe_fltr_largest_external_tbl_lookup_key_size_e;
+
+/* structure representing QE parameter RAM
+*/
+typedef struct qe_timer_tables {
+ u16 tm_base; /* QE timer table base adr */
+ u16 tm_ptr; /* QE timer table pointer */
+ u16 r_tmr; /* QE timer mode register */
+ u16 r_tmv; /* QE timer valid register */
+ u32 tm_cmd; /* QE timer cmd register */
+ u32 tm_cnt; /* QE timer internal cnt */
+} __attribute__ ((packed)) qe_timer_tables_t;
+
+#define QE_FLTR_TAD_SIZE 8
+
+/* QE extended filtering Termination Action Descriptor (TAD)
+*/
+typedef struct qe_fltr_tad {
+ u8 serialized[QE_FLTR_TAD_SIZE];
+} __attribute__ ((packed)) qe_fltr_tad_t;
+
+/* Communication Direction.
+*/
+typedef enum comm_dir {
+ COMM_DIR_NONE = 0,
+ COMM_DIR_RX = 1,
+ COMM_DIR_TX = 2,
+ COMM_DIR_RX_AND_TX = 3
+} comm_dir_e;
+
+/* Clocks and GRG's
+*/
+typedef enum qe_clock {
+ QE_CLK_NONE = 0
+ , QE_BRG1 /* Baud Rate Generator 1 */
+ , QE_BRG2 /* Baud Rate Generator 2 */
+ , QE_BRG3 /* Baud Rate Generator 3 */
+ , QE_BRG4 /* Baud Rate Generator 4 */
+ , QE_BRG5 /* Baud Rate Generator 5 */
+ , QE_BRG6 /* Baud Rate Generator 6 */
+ , QE_BRG7 /* Baud Rate Generator 7 */
+ , QE_BRG8 /* Baud Rate Generator 8 */
+ , QE_BRG9 /* Baud Rate Generator 9 */
+ , QE_BRG10 /* Baud Rate Generator 10 */
+ , QE_BRG11 /* Baud Rate Generator 11 */
+ , QE_BRG12 /* Baud Rate Generator 12 */
+ , QE_BRG13 /* Baud Rate Generator 13 */
+ , QE_BRG14 /* Baud Rate Generator 14 */
+ , QE_BRG15 /* Baud Rate Generator 15 */
+ , QE_BRG16 /* Baud Rate Generator 16 */
+ , QE_CLK1 /* Clock 1 */
+ , QE_CLK2 /* Clock 2 */
+ , QE_CLK3 /* Clock 3 */
+ , QE_CLK4 /* Clock 4 */
+ , QE_CLK5 /* Clock 5 */
+ , QE_CLK6 /* Clock 6 */
+ , QE_CLK7 /* Clock 7 */
+ , QE_CLK8 /* Clock 8 */
+ , QE_CLK9 /* Clock 9 */
+ , QE_CLK10 /* Clock 10 */
+ , QE_CLK11 /* Clock 11 */
+ , QE_CLK12 /* Clock 12 */
+ , QE_CLK13 /* Clock 13 */
+ , QE_CLK14 /* Clock 14 */
+ , QE_CLK15 /* Clock 15 */
+ , QE_CLK16 /* Clock 16 */
+ , QE_CLK17 /* Clock 17 */
+ , QE_CLK18 /* Clock 18 */
+ , QE_CLK19 /* Clock 19 */
+ , QE_CLK20 /* Clock 20 */
+ , QE_CLK21 /* Clock 21 */
+ , QE_CLK22 /* Clock 22 */
+ , QE_CLK23 /* Clock 23 */
+ , QE_CLK24 /* Clock 24 */
+ , QE_CLK_DUMMY
+} qe_clock_e;
+
+/* QE CMXUCR Registers.
+ * There are two UCCs represented in each of the four CMXUCR registers.
+ * These values are for the UCC in the LSBs
+ */
+#define QE_CMXUCR_MII_ENET_MNG 0x00007000
+#define QE_CMXUCR_MII_ENET_MNG_SHIFT 12
+#define QE_CMXUCR_GRANT 0x00008000
+#define QE_CMXUCR_TSA 0x00004000
+#define QE_CMXUCR_BKPT 0x00000100
+#define QE_CMXUCR_TX_CLK_SRC_MASK 0x0000000F
+
+/* QE CMXGCR Registers.
+*/
+#define QE_CMXGCR_MII_ENET_MNG 0x00007000
+#define QE_CMXGCR_MII_ENET_MNG_SHIFT 12
+#define QE_CMXGCR_USBCS 0x0000000f
+
+/* QE CECR Commands.
+*/
+#define QE_CR_FLG 0x00010000
+#define QE_RESET 0x80000000
+#define QE_INIT_TX_RX 0x00000000
+#define QE_INIT_RX 0x00000001
+#define QE_INIT_TX 0x00000002
+#define QE_ENTER_HUNT_MODE 0x00000003
+#define QE_STOP_TX 0x00000004
+#define QE_GRACEFUL_STOP_TX 0x00000005
+#define QE_RESTART_TX 0x00000006
+#define QE_CLOSE_RX_BD 0x00000007
+#define QE_SWITCH_COMMAND 0x00000007
+#define QE_SET_GROUP_ADDRESS 0x00000008
+#define QE_START_IDMA 0x00000009
+#define QE_MCC_STOP_RX 0x00000009
+#define QE_ATM_TRANSMIT 0x0000000a
+#define QE_HPAC_CLEAR_ALL 0x0000000b
+#define QE_GRACEFUL_STOP_RX 0x0000001a
+#define QE_RESTART_RX 0x0000001b
+#define QE_HPAC_SET_PRIORITY 0x0000010b
+#define QE_HPAC_STOP_TX 0x0000020b
+#define QE_HPAC_STOP_RX 0x0000030b
+#define QE_HPAC_GRACEFUL_STOP_TX 0x0000040b
+#define QE_HPAC_GRACEFUL_STOP_RX 0x0000050b
+#define QE_HPAC_START_TX 0x0000060b
+#define QE_HPAC_START_RX 0x0000070b
+#define QE_USB_STOP_TX 0x0000000a
+#define QE_USB_RESTART_TX 0x0000000b
+#define QE_QMC_STOP_TX 0x0000000c
+#define QE_QMC_STOP_RX 0x0000000d
+#define QE_SS7_SU_FIL_RESET 0x0000000e
+/* jonathbr added from here down for 83xx */
+#define QE_RESET_BCS 0x0000000a
+#define QE_MCC_INIT_TX_RX_16 0x00000003
+#define QE_MCC_STOP_TX 0x00000004
+#define QE_MCC_INIT_TX_1 0x00000005
+#define QE_MCC_INIT_RX_1 0x00000006
+#define QE_MCC_RESET 0x00000007
+#define QE_SET_TIMER 0x00000008
+#define QE_RANDOM_NUMBER 0x0000000c
+#define QE_ATM_MULTI_THREAD_INIT 0x00000011
+#define QE_ASSIGN_PAGE 0x00000012
+#define QE_ADD_REMOVE_HASH_ENTRY 0x00000013
+#define QE_START_FLOW_CONTROL 0x00000014
+#define QE_STOP_FLOW_CONTROL 0x00000015
+#define QE_ASSIGN_PAGE_TO_DEVICE 0x00000016
+
+#define QE_ASSIGN_RISC 0x00000010
+#define QE_CR_MCN_NORMAL_SHIFT 6
+#define QE_CR_MCN_USB_SHIFT 4
+#define QE_CR_MCN_RISC_ASSIGN_SHIFT 8
+#define QE_CR_SNUM_SHIFT 17
+
+/* QE CECR Sub Block - sub block of QE command.
+*/
+#define QE_CR_SUBBLOCK_INVALID 0x00000000
+#define QE_CR_SUBBLOCK_USB 0x03200000
+#define QE_CR_SUBBLOCK_UCCFAST1 0x02000000
+#define QE_CR_SUBBLOCK_UCCFAST2 0x02200000
+#define QE_CR_SUBBLOCK_UCCFAST3 0x02400000
+#define QE_CR_SUBBLOCK_UCCFAST4 0x02600000
+#define QE_CR_SUBBLOCK_UCCFAST5 0x02800000
+#define QE_CR_SUBBLOCK_UCCFAST6 0x02a00000
+#define QE_CR_SUBBLOCK_UCCFAST7 0x02c00000
+#define QE_CR_SUBBLOCK_UCCFAST8 0x02e00000
+#define QE_CR_SUBBLOCK_UCCSLOW1 0x00000000
+#define QE_CR_SUBBLOCK_UCCSLOW2 0x00200000
+#define QE_CR_SUBBLOCK_UCCSLOW3 0x00400000
+#define QE_CR_SUBBLOCK_UCCSLOW4 0x00600000
+#define QE_CR_SUBBLOCK_UCCSLOW5 0x00800000
+#define QE_CR_SUBBLOCK_UCCSLOW6 0x00a00000
+#define QE_CR_SUBBLOCK_UCCSLOW7 0x00c00000
+#define QE_CR_SUBBLOCK_UCCSLOW8 0x00e00000
+#define QE_CR_SUBBLOCK_MCC1 0x03800000
+#define QE_CR_SUBBLOCK_MCC2 0x03a00000
+#define QE_CR_SUBBLOCK_MCC3 0x03000000
+#define QE_CR_SUBBLOCK_IDMA1 0x02800000
+#define QE_CR_SUBBLOCK_IDMA2 0x02a00000
+#define QE_CR_SUBBLOCK_IDMA3 0x02c00000
+#define QE_CR_SUBBLOCK_IDMA4 0x02e00000
+#define QE_CR_SUBBLOCK_HPAC 0x01e00000
+#define QE_CR_SUBBLOCK_SPI1 0x01400000
+#define QE_CR_SUBBLOCK_SPI2 0x01600000
+#define QE_CR_SUBBLOCK_RAND 0x01c00000
+#define QE_CR_SUBBLOCK_TIMER 0x01e00000
+#define QE_CR_SUBBLOCK_GENERAL 0x03c00000
+
+/* QE CECR Protocol - For non-MCC, specifies mode for QE CECR command.
+*/
+#define QE_CR_PROTOCOL_UNSPECIFIED 0x00 /* For all other protocols */
+#define QE_CR_PROTOCOL_HDLC_TRANSPARENT 0x00
+#define QE_CR_PROTOCOL_ATM_POS 0x0A
+#define QE_CR_PROTOCOL_ETHERNET 0x0C
+#define QE_CR_PROTOCOL_L2_SWITCH 0x0D
+
+/* BMR byte order
+*/
+#define QE_BMR_BYTE_ORDER_BO_PPC 0x08 /* powerpc little endian */
+#define QE_BMR_BYTE_ORDER_BO_MOT 0x10 /* motorola big endian */
+#define QE_BMR_BYTE_ORDER_BO_MAX 0x18
+
+/* BRG configuration register
+*/
+#define QE_BRGC_ENABLE 0x00010000
+#define QE_BRGC_DIVISOR_SHIFT 1
+#define QE_BRGC_DIVISOR_MAX 0xFFF
+#define QE_BRGC_DIV16 1
+/* QE Timers registers */
+#define QE_GTCFR1_PCAS 0x80
+#define QE_GTCFR1_STP2 0x20
+#define QE_GTCFR1_RST2 0x10
+#define QE_GTCFR1_GM2 0x08
+#define QE_GTCFR1_GM1 0x04
+#define QE_GTCFR1_STP1 0x02
+#define QE_GTCFR1_RST1 0x01
+
+/* SDMA registers */
+#define QE_SDSR_BER1 0x02000000
+#define QE_SDSR_BER2 0x01000000
+
+#define QE_SDMR_GLB_1_MSK 0x80000000
+#define QE_SDMR_ADR_SEL 0x20000000
+#define QE_SDMR_BER1_MSK 0x02000000
+#define QE_SDMR_BER2_MSK 0x01000000
+#define QE_SDMR_EB1_MSK 0x00800000
+#define QE_SDMR_ER1_MSK 0x00080000
+#define QE_SDMR_ER2_MSK 0x00040000
+#define QE_SDMR_CEN_MASK 0x0000E000
+#define QE_SDMR_SBER_1 0x00000200
+#define QE_SDMR_SBER_2 0x00000200
+#define QE_SDMR_EB1_PR_MASK 0x000000C0
+#define QE_SDMR_ER1_PR 0x00000008
+
+#define QE_SDMR_CEN_SHIFT 13
+#define QE_SDMR_EB1_PR_SHIFT 6
+
+#define QE_SDTM_MSNUM_SHIFT 24
+
+#define QE_SDEBCR_BA_MASK 0x01FFFFFF
+
+/* UPC
+*/
+#define UPGCR_PROTOCOL 0x80000000 /* protocol ul2 or pl2 */
+#define UPGCR_TMS 0x40000000 /* Transmit master/slave mode */
+#define UPGCR_RMS 0x20000000 /* Receive master/slave mode */
+#define UPGCR_ADDR 0x10000000 /* Master MPHY Addr multiplexing */
+#define UPGCR_DIAG 0x01000000 /* Diagnostic mode */
+
+/* UCC
+*/
+#define UCC_GUEMR_MODE_MASK_RX 0x02
+#define UCC_GUEMR_MODE_MASK_TX 0x01
+#define UCC_GUEMR_MODE_FAST_RX 0x02
+#define UCC_GUEMR_MODE_FAST_TX 0x01
+#define UCC_GUEMR_MODE_SLOW_RX 0x00
+#define UCC_GUEMR_MODE_SLOW_TX 0x00
+#define UCC_GUEMR_SET_RESERVED3 0x10 /* Bit 3 in the guemr is reserved but
+ must be set 1 */
+
+/* structure representing UCC SLOW parameter RAM
+*/
+typedef struct ucc_slow_pram {
+ u16 rbase; /* RX BD base address */
+ u16 tbase; /* TX BD base address */
+ u8 rfcr; /* Rx function code */
+ u8 tfcr; /* Tx function code */
+ u16 mrblr; /* Rx buffer length */
+ u32 rstate; /* Rx internal state */
+ u32 rptr; /* Rx internal data pointer */
+ u16 rbptr; /* rb BD Pointer */
+ u16 rcount; /* Rx internal byte count */
+ u32 rtemp; /* Rx temp */
+ u32 tstate; /* Tx internal state */
+ u32 tptr; /* Tx internal data pointer */
+ u16 tbptr; /* Tx BD pointer */
+ u16 tcount; /* Tx byte count */
+ u32 ttemp; /* Tx temp */
+ u32 rcrc; /* temp receive CRC */
+ u32 tcrc; /* temp transmit CRC */
+} __attribute__ ((packed)) ucc_slow_pram_t;
+
+/* General UCC SLOW Mode Register (GUMRH & GUMRL)
+*/
+#define UCC_SLOW_GUMR_H_CRC16 0x00004000
+#define UCC_SLOW_GUMR_H_CRC16CCITT 0x00000000
+#define UCC_SLOW_GUMR_H_CRC32CCITT 0x00008000
+#define UCC_SLOW_GUMR_H_REVD 0x00002000
+#define UCC_SLOW_GUMR_H_TRX 0x00001000
+#define UCC_SLOW_GUMR_H_TTX 0x00000800
+#define UCC_SLOW_GUMR_H_CDP 0x00000400
+#define UCC_SLOW_GUMR_H_CTSP 0x00000200
+#define UCC_SLOW_GUMR_H_CDS 0x00000100
+#define UCC_SLOW_GUMR_H_CTSS 0x00000080
+#define UCC_SLOW_GUMR_H_TFL 0x00000040
+#define UCC_SLOW_GUMR_H_RFW 0x00000020
+#define UCC_SLOW_GUMR_H_TXSY 0x00000010
+#define UCC_SLOW_GUMR_H_4SYNC 0x00000004
+#define UCC_SLOW_GUMR_H_8SYNC 0x00000008
+#define UCC_SLOW_GUMR_H_16SYNC 0x0000000c
+#define UCC_SLOW_GUMR_H_RTSM 0x00000002
+#define UCC_SLOW_GUMR_H_RSYN 0x00000001
+
+#define UCC_SLOW_GUMR_L_TCI 0x10000000
+#define UCC_SLOW_GUMR_L_RINV 0x02000000
+#define UCC_SLOW_GUMR_L_TINV 0x01000000
+#define UCC_SLOW_GUMR_L_TEND 0x00020000
+#define UCC_SLOW_GUMR_L_ENR 0x00000020
+#define UCC_SLOW_GUMR_L_ENT 0x00000010
+
+/* General UCC FAST Mode Register
+*/
+#define UCC_FAST_GUMR_TCI 0x20000000
+#define UCC_FAST_GUMR_TRX 0x10000000
+#define UCC_FAST_GUMR_TTX 0x08000000
+#define UCC_FAST_GUMR_CDP 0x04000000
+#define UCC_FAST_GUMR_CTSP 0x02000000
+#define UCC_FAST_GUMR_CDS 0x01000000
+#define UCC_FAST_GUMR_CTSS 0x00800000
+#define UCC_FAST_GUMR_TXSY 0x00020000
+#define UCC_FAST_GUMR_RSYN 0x00010000
+#define UCC_FAST_GUMR_RTSM 0x00002000
+#define UCC_FAST_GUMR_REVD 0x00000400
+#define UCC_FAST_GUMR_ENR 0x00000020
+#define UCC_FAST_GUMR_ENT 0x00000010
+
+/* Slow UCC Event Register (UCCE)
+*/
+#define UCC_SLOW_UCCE_GLR 0x1000
+#define UCC_SLOW_UCCE_GLT 0x0800
+#define UCC_SLOW_UCCE_DCC 0x0400
+#define UCC_SLOW_UCCE_FLG 0x0200
+#define UCC_SLOW_UCCE_AB 0x0200
+#define UCC_SLOW_UCCE_IDLE 0x0100
+#define UCC_SLOW_UCCE_GRA 0x0080
+#define UCC_SLOW_UCCE_TXE 0x0010
+#define UCC_SLOW_UCCE_RXF 0x0008
+#define UCC_SLOW_UCCE_CCR 0x0008
+#define UCC_SLOW_UCCE_RCH 0x0008
+#define UCC_SLOW_UCCE_BSY 0x0004
+#define UCC_SLOW_UCCE_TXB 0x0002
+#define UCC_SLOW_UCCE_TX 0x0002
+#define UCC_SLOW_UCCE_RX 0x0001
+#define UCC_SLOW_UCCE_GOV 0x0001
+#define UCC_SLOW_UCCE_GUN 0x0002
+#define UCC_SLOW_UCCE_GINT 0x0004
+#define UCC_SLOW_UCCE_IQOV 0x0008
+
+#define UCC_SLOW_UCCE_HDLC_SET (UCC_SLOW_UCCE_TXE|UCC_SLOW_UCCE_BSY| \
+ UCC_SLOW_UCCE_GRA|UCC_SLOW_UCCE_TXB|UCC_SLOW_UCCE_RXF| \
+ UCC_SLOW_UCCE_DCC|UCC_SLOW_UCCE_GLT|UCC_SLOW_UCCE_GLR)
+#define UCC_SLOW_UCCE_ENET_SET (UCC_SLOW_UCCE_TXE|UCC_SLOW_UCCE_BSY| \
+ UCC_SLOW_UCCE_GRA|UCC_SLOW_UCCE_TXB|UCC_SLOW_UCCE_RXF)
+#define UCC_SLOW_UCCE_TRANS_SET (UCC_SLOW_UCCE_TXE|UCC_SLOW_UCCE_BSY| \
+ UCC_SLOW_UCCE_GRA|UCC_SLOW_UCCE_TX |UCC_SLOW_UCCE_RX | \
+ UCC_SLOW_UCCE_DCC|UCC_SLOW_UCCE_GLT|UCC_SLOW_UCCE_GLR)
+#define UCC_SLOW_UCCE_UART_SET (UCC_SLOW_UCCE_BSY|UCC_SLOW_UCCE_GRA| \
+ UCC_SLOW_UCCE_TXB|UCC_SLOW_UCCE_TX |UCC_SLOW_UCCE_RX | \
+ UCC_SLOW_UCCE_GLT|UCC_SLOW_UCCE_GLR)
+#define UCC_SLOW_UCCE_QMC_SET (UCC_SLOW_UCCE_IQOV|UCC_SLOW_UCCE_GINT| \
+ UCC_SLOW_UCCE_GUN|UCC_SLOW_UCCE_GOV)
+
+#define UCC_SLOW_UCCE_OTHER (UCC_SLOW_UCCE_TXE|UCC_SLOW_UCCE_BSY| \
+ UCC_SLOW_UCCE_GRA|UCC_SLOW_UCCE_DCC|UCC_SLOW_UCCE_GLT| \
+ UCC_SLOW_UCCE_GLR)
+
+#define UCC_SLOW_INTR_TX UCC_SLOW_UCCE_TXB
+#define UCC_SLOW_INTR_RX (UCC_SLOW_UCCE_RXF | UCC_SLOW_UCCE_RX)
+#define UCC_SLOW_INTR (UCC_SLOW_INTR_TX | UCC_SLOW_INTR_RX)
+
+/* Transmit On Demand (UTORD)
+*/
+#define UCC_SLOW_TOD 0x8000
+#define UCC_FAST_TOD 0x8000
+
+/* Function code masks.
+*/
+#define FC_GBL 0x20
+#define FC_DTB_LCL 0x02
+#define UCC_FAST_FUNCTION_CODE_GBL 0x20
+#define UCC_FAST_FUNCTION_CODE_DTB_LCL 0x02
+#define UCC_FAST_FUNCTION_CODE_BDB_LCL 0x01
+
+#endif /* __QE_H__ */
+#endif /* __KERNEL__ */
+#endif /* CONFIG_QUICC_ENGINE */
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox