* [PATCH 2/6] 85xxCDS: Allow 8259 cascade to share an MPIC interrupt line.
From: Randy Vinson @ 2007-07-20 18:56 UTC (permalink / raw)
To: linuxppc-dev@ozlabs.org, Kumar Gala
>From c9e25f41ca444d77f5527c1442550e70c46b9383 Mon Sep 17 00:00:00 2001
From: Randy Vinson <rvinson@mvista.com>
Date: Wed, 6 Jun 2007 16:26:15 -0700
Subject: [PATCH] 85xxCDS: Allow 8259 cascade to share an MPIC interrupt line.
The Freescale MPC8555CDS and MPC8548CDS reference hardware has a legacy
8259 interrupt controller pair contained within a VIA VT82C686B Southbridge
on the main carrier board. The processor complex plugs into the carrier
card using a PCI slot which limits the available interrupts to the
INTA-INTD PCI interrupts. The output of the 8259 cascade pair is routed
through a gate array and connected to the PCI INTA interrupt line.
The normal interrupt chaining hook (set_irq_chained_handler) does
not allow sharing of the chained interrupt which prevents the
use of PCI INTA by PCI devices. This patch allows the 8259 cascade
pair to share their interrupt line with PCI devices.
NOTE: The addition of the .end routine for the MPIC is not strictly
necessary for this patch. It's there so this code will run from within
the threaded interrupt context used by the Real Time patch.
Signed-off-by: Randy Vinson <rvinson@mvista.com>
---
arch/powerpc/platforms/85xx/Kconfig | 1 +
arch/powerpc/platforms/85xx/mpc85xx_cds.c | 37 ++++++++++++++++++++++++----
arch/powerpc/sysdev/mpic.c | 1 +
3 files changed, 33 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 526ddde..e771d19 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -18,6 +18,7 @@ config MPC8560_ADS
config MPC85xx_CDS
bool "Freescale MPC85xx CDS"
select DEFAULT_UIMAGE
+ select PPC_I8259
help
This option enables support for the MPC85xx CDS board
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index 8046acb..1db6c81 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -24,6 +24,7 @@
#include <linux/seq_file.h>
#include <linux/initrd.h>
#include <linux/module.h>
+#include <linux/interrupt.h>
#include <linux/fsl_devices.h>
#include <asm/system.h>
@@ -94,16 +95,30 @@ static void __init mpc85xx_cds_pci_irq_fixup(struct pci_dev *dev)
}
#ifdef CONFIG_PPC_I8259
-#warning The i8259 PIC support is currently broken
-static void mpc85xx_8259_cascade(unsigned int irq, struct irq_desc *desc)
+static void mpc85xx_8259_cascade_handler(unsigned int irq,
+ struct irq_desc *desc)
{
unsigned int cascade_irq = i8259_irq();
if (cascade_irq != NO_IRQ)
+ /* handle an interrupt from the 8259 */
generic_handle_irq(cascade_irq);
- desc->chip->eoi(irq);
+ /* check for any interrupts from the shared IRQ line */
+ handle_fasteoi_irq(irq, desc);
}
+
+static irqreturn_t mpc85xx_8259_cascade_action(int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+
+static struct irqaction mpc85xxcds_8259_irqaction = {
+ .handler = mpc85xx_8259_cascade_action,
+ .flags = IRQF_SHARED,
+ .mask = CPU_MASK_NONE,
+ .name = "8259 cascade",
+};
#endif /* PPC_I8259 */
#endif /* CONFIG_PCI */
@@ -112,7 +127,7 @@ static void __init mpc85xx_cds_pic_init(void)
struct mpic *mpic;
struct resource r;
struct device_node *np = NULL;
-#ifdef CONFIG_PPC_I8259
+#if defined(CONFIG_PPC_I8259) && defined(CONFIG_PCI)
struct device_node *cascade_node = NULL;
int cascade_irq;
#endif
@@ -140,7 +155,7 @@ static void __init mpc85xx_cds_pic_init(void)
mpic_init(mpic);
-#ifdef CONFIG_PPC_I8259
+#if defined(CONFIG_PPC_I8259) && defined(CONFIG_PCI)
/* Initialize the i8259 controller */
for_each_node_by_type(np, "interrupt-controller")
if (of_device_is_compatible(np, "chrp,iic")) {
@@ -162,7 +177,17 @@ static void __init mpc85xx_cds_pic_init(void)
i8259_init(cascade_node, 0);
of_node_put(cascade_node);
- set_irq_chained_handler(cascade_irq, mpc85xx_8259_cascade);
+ /*
+ * Hook the interrupt to make sure desc->action is never NULL.
+ * This is required to ensure that the interrupt does not get
+ * disabled when the last user of the shared IRQ line frees their
+ * interrupt.
+ */
+ if (setup_irq(cascade_irq, &mpc85xxcds_8259_irqaction))
+ printk(KERN_ERR "Failed to setup cascade interrupt\n");
+ else
+ /* Success. Connect our low-level cascade handler. */
+ set_irq_handler(cascade_irq, mpc85xx_8259_cascade_handler);
#endif /* CONFIG_PPC_I8259 */
}
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 75aad38..14e3d1d 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -836,6 +836,7 @@ static struct irq_chip mpic_irq_chip = {
.mask = mpic_mask_irq,
.unmask = mpic_unmask_irq,
.eoi = mpic_end_irq,
+ .end = mpic_unmask_irq,
.set_type = mpic_set_irq_type,
};
--
1.5.2.2.549.gaeb59
^ permalink raw reply related
* [PATCH 1/6] 85xxCDS: Skip the fake PCI bridge (FPGA)
From: Randy Vinson @ 2007-07-20 18:56 UTC (permalink / raw)
To: linuxppc-dev@ozlabs.org, Kumar Gala
>From 83bfbe730b1fad2ac9b22d33990e7378d920e844 Mon Sep 17 00:00:00 2001
From: Randy Vinson <rvinson@mvista.com>
Date: Fri, 20 Jul 2007 11:18:26 -0700
Subject: [PATCH] 85xxCDS: Skip the fake PCI bridge (FPGA)
The 85xxCDS has an FPGA that incorrectly appears as a PCI-to-PCI bridge.
This patch adds a fixup routine that will skip the bridge. With the fixup
in place, the existing exclude routine is no longer needed.
Note: This code was originally part of a larger patch posted by Andy Fleming.
The original patch also contained changes which handled the 85xx PCI Express
host bridge. The host bridge changes have been submitted in a new form, but
the FPGA changes in this patch were lost in the process.
Signed-off-by Randy Vinson <rvinson@mvista.com>
---
arch/powerpc/kernel/pci_32.c | 13 ++++++++++++-
arch/powerpc/platforms/85xx/mpc85xx_cds.c | 16 ----------------
2 files changed, 12 insertions(+), 17 deletions(-)
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index bfcfa14..05c2ebd 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -80,7 +80,18 @@ fixup_cpc710_pci64(struct pci_dev* dev)
dev->resource[1].start = dev->resource[1].end = 0;
dev->resource[1].flags = 0;
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64);
+
+static void __devinit skip_fake_bridge(struct pci_dev *dev)
+{
+ /* Make it an error to skip the fake bridge
+ * in pci_setup_device() in probe.c */
+ dev->hdr_type = 0x7f;
+}
+DECLARE_PCI_FIXUP_EARLY(0x1957, 0x3fff, skip_fake_bridge);
+DECLARE_PCI_FIXUP_EARLY(0x3fff, 0x1957, skip_fake_bridge);
+DECLARE_PCI_FIXUP_EARLY(0xff3f, 0x5719, skip_fake_bridge);
+
static void
pcibios_fixup_resources(struct pci_dev *dev)
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index 2539bb5..8046acb 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -53,21 +53,6 @@ static volatile u8 *cadmus;
#ifdef CONFIG_PCI
-#define ARCADIA_HOST_BRIDGE_IDSEL 17
-#define ARCADIA_2ND_BRIDGE_IDSEL 3
-
-static int mpc85xx_exclude_device(struct pci_controller *hose,
- u_char bus, u_char devfn)
-{
- /* We explicitly do not go past the Tundra 320 Bridge */
- if ((bus == 1) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL))
- return PCIBIOS_DEVICE_NOT_FOUND;
- if ((bus == 0) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL))
- return PCIBIOS_DEVICE_NOT_FOUND;
- else
- return PCIBIOS_SUCCESSFUL;
-}
-
static void __init mpc85xx_cds_pci_irq_fixup(struct pci_dev *dev)
{
u_char c;
@@ -226,7 +211,6 @@ static void __init mpc85xx_cds_setup_arch(void)
fsl_add_bridge(np, 1);
}
ppc_md.pci_irq_fixup = mpc85xx_cds_pci_irq_fixup;
- ppc_md.pci_exclude_device = mpc85xx_exclude_device;
#endif
}
--
1.5.2.2.549.gaeb59
^ permalink raw reply related
* [PATCH 0/6] 85xxCDS: MPC8548CDS Updates and Bug Fixes
From: Randy Vinson @ 2007-07-20 18:56 UTC (permalink / raw)
To: linuxppc-dev@ozlabs.org, Kumar Gala
Greetings,
This patch series contains updates to the MPC8548CDS DTS
and fixes several PCI-related bugs. I'm not 100% sure the
DTS changes are in the proper form, so I'd appreciate any
corrections. Note that some of these patches have been
posted previously.
These patches are based on Kumar's for_paulus branch.
Thanks,
Randy Vinson
^ permalink raw reply
* Re: [patch 1/3] m68k/mac: Make mac_hid_mouse_emulate_buttons() declaration visible
From: Dmitry Torokhov @ 2007-07-20 18:51 UTC (permalink / raw)
To: Adrian Bunk
Cc: linux-m68k, linux-kernel, linuxppc-dev, Geert Uytterhoeven,
linux-input, Andrew Morton
In-Reply-To: <20070720183503.GC3801@stusta.de>
On 7/20/07, Adrian Bunk <bunk@stusta.de> wrote:
> On Fri, Jul 20, 2007 at 01:47:36PM -0400, Dmitry Torokhov wrote:
> > Hi Geert,
> >
> > On 7/20/07, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> >> From: Geert Uytterhoeven <geert@linux-m68k.org>
> >>
> >> m68k/mac: Make mac_hid_mouse_emulate_buttons() declaration visible
> >>
> >> drivers/char/keyboard.c: In function 'kbd_keycode':
> >> drivers/char/keyboard.c:1142: error: implicit declaration of function
> >> 'mac_hid_mouse_emulate_buttons'
> >>
> >> The forward declaration of mac_hid_mouse_emulate_buttons() is not visible
> >> on
> >> m68k because it's hidden in the middle of a big #ifdef block.
> >>
> >> Move it to <linux/hid.h>, correct the type of the second parameter, and
> >> include <linux/hid.h> where needed.
> >
> > linux/hid.h contains definitions needed for drivers speaking HID
> > protocol, I don't think we want to put quirks for legacy keyboard
> > driver there. I'd just move the #ifdef within drivers/char/keyboard.c
> > for now.
> >...
>
> If you only move it you will keep the bug of the wrong second parameter.
>
> But if you move it to any header file gcc is able to figure out such
> errors itself instead of them being nasty runtime errors.
>
> Such prototypes in C files are really bad since (like in this case) they
> prevent the finding of bugs. It doesn't matter which header file you put
> the prototype into (it can even be a new one), but it belongs into a
> header file.
>
I am OK with adding a new header file. I was just saying that placing
that declaration in linux/hid.h makes about the same sense as putting
it into linux/scsi.h
--
Dmitry
^ permalink raw reply
* Re: [PATCH 04/14] spufs: add spu stats in sysfs and ctx stat file in spufs
From: Scott Wood @ 2007-07-20 18:50 UTC (permalink / raw)
To: Andrew Morton; +Cc: linuxppc-dev
In-Reply-To: <20070720114421.0760cc5b.akpm@linux-foundation.org>
Andrew Morton wrote:
> And what's up with all these powerpc people sending out patchbombs after
> the merge window has opened? Formally, _all_ of this:
I can't speak for the ones you listed, but in my case, I had people
asking about the patches and posting conflicting things, so I wanted to
get it out for review. I had no real expectation of it making it into
2.6.23.
-Scott
^ permalink raw reply
* Re: [PATCH 04/14] spufs: add spu stats in sysfs and ctx stat file in spufs
From: Andrew Morton @ 2007-07-20 18:44 UTC (permalink / raw)
To: Jeremy Kerr; +Cc: Andre Detsch, paulus, cbe-oss-dev, linuxppc-dev
In-Reply-To: <11849088851210-git-send-email-jk@ozlabs.org>
On Fri, 20 Jul 2007 15:21:15 +1000
Jeremy Kerr <jk@ozlabs.org> wrote:
> This patch exports per-context statistics in spufs as long as spu
> statistics in sysfs.
>
> It was formed by merging:
> "spufs: add spu stats in sysfs" From: Christoph Hellwig
> "spufs: add stat file to spufs" From: Christoph Hellwig
> "spufs: fix libassist accounting" From: Jeremy Kerr
> "spusched: fix spu utilization statistics" From: Luke Browning
> And some adjustments by myself, after suggestions on cbe-oss-dev.
>
> Having separate patches was making the review process harder
> than it should, as we end up integrating spus and ctx statistics
> accounting much more than it was on the first implementation.
I hit some rejects here due to Maynard Johnson and Bob Nelson's oprofile
patches. It was relatively simple to fix up, but there may of course be
clashes in intent as well, so please check it all over carefully when it
lands in mainline.
I'll get all the ps3/spufs/etc stuff into Linus later today.
And what's up with all these powerpc people sending out patchbombs after
the merge window has opened? Formally, _all_ of this:
oprofile-enable-spu-switch-notification-to-detect-currently-active-spu-tasks.patch
oprofile-add-support-to-oprofile-for-profiling-cell-be-spus.patch
ps3-disk-storage-driver.patch
ps3-disk-storage-driver-use-correct-bio-vector-size.patch
ps3-disk-storage-driver-updates-after-final-review.patch
ps3-bd-dvd-cd-rom-storage-driver.patch
ps3-bd-dvd-cd-rom-storage-driver-updates-after-final-review.patch
ps3-flash-rom-storage-driver.patch
ps3-flash-rom-storage-driver-updates-after-final-review.patch
ps3-fix-build-with-32-bit-toolchains.patch
ps3fb-enable-vt_hw_console_binding-for-proper-kexec.patch
ps3fb-shrink-default-virtual-frame-buffer-size-from-18-to-9-mib.patch
ps3fb-set-fbinfo_reads_fast-to-speed-up-text-console-scrolling.patch
spufs-avoid-unexpectedly-restaring-mfc-during-context-save.patch
spufs-make-signal-notification-files-readonly-for-nosched-contexts.patch
spufs-remove-spurious-warn_on-for-spu_deactivate-for-nosched-contexts.patch
spufs-add-spu-stats-in-sysfs-and-ctx-stat-file-in-spufs.patch
spufs-make-sure-context-are-scheduled-again-after-spu_acquire_saved.patch
spufs-fix-array-size-of-channel-index.patch
spufs-remove-needless-context-save-restore-code.patch
spufs-fix-decr_status-meanings.patch
spufs-fix-read-and-write-for-decr_status-file.patch
spufs-limit-saving-mfc_cntl-bits.patch
spufs-dont-halt-decrementer-at-restore-step-47.patch
spufs-change-decrementer-restore-timing.patch
spufs-remove-unused-file-argument-from-spufs_run_spu.patch
spufs-use-find_first_bit-instead-of-sched_find_first_bit.patch
should be pushed back into 2.6.24 because it all arrived too late.
I guess you're all doing that to Paul on a regular basis. Bad.
^ permalink raw reply
* Re: [patch 1/3] m68k/mac: Make mac_hid_mouse_emulate_buttons() declaration visible
From: Adrian Bunk @ 2007-07-20 18:35 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: linux-m68k, linux-kernel, linuxppc-dev, Geert Uytterhoeven,
linux-input, Andrew Morton
In-Reply-To: <d120d5000707201047y2d22167co882a10176d79fce4@mail.gmail.com>
On Fri, Jul 20, 2007 at 01:47:36PM -0400, Dmitry Torokhov wrote:
> Hi Geert,
>
> On 7/20/07, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>> From: Geert Uytterhoeven <geert@linux-m68k.org>
>>
>> m68k/mac: Make mac_hid_mouse_emulate_buttons() declaration visible
>>
>> drivers/char/keyboard.c: In function 'kbd_keycode':
>> drivers/char/keyboard.c:1142: error: implicit declaration of function
>> 'mac_hid_mouse_emulate_buttons'
>>
>> The forward declaration of mac_hid_mouse_emulate_buttons() is not visible
>> on
>> m68k because it's hidden in the middle of a big #ifdef block.
>>
>> Move it to <linux/hid.h>, correct the type of the second parameter, and
>> include <linux/hid.h> where needed.
>
> linux/hid.h contains definitions needed for drivers speaking HID
> protocol, I don't think we want to put quirks for legacy keyboard
> driver there. I'd just move the #ifdef within drivers/char/keyboard.c
> for now.
>...
If you only move it you will keep the bug of the wrong second parameter.
But if you move it to any header file gcc is able to figure out such
errors itself instead of them being nasty runtime errors.
Such prototypes in C files are really bad since (like in this case) they
prevent the finding of bugs. It doesn't matter which header file you put
the prototype into (it can even be a new one), but it belongs into a
header file.
> Dmitry
cu
Adrian
--
"Is there not promise of rain?" Ling Tan asked suddenly out
of the darkness. There had been need of rain for many days.
"Only a promise," Lao Er said.
Pearl S. Buck - Dragon Seed
^ permalink raw reply
* Re: [patch 1/3] m68k/mac: Make mac_hid_mouse_emulate_buttons() declaration visible
From: Dmitry Torokhov @ 2007-07-20 17:47 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: linux-input, linuxppc-dev, Andrew Morton, linux-m68k,
linux-kernel
In-Reply-To: <20070720164323.625963918@mail.of.borg>
Hi Geert,
On 7/20/07, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> From: Geert Uytterhoeven <geert@linux-m68k.org>
>
> m68k/mac: Make mac_hid_mouse_emulate_buttons() declaration visible
>
> drivers/char/keyboard.c: In function 'kbd_keycode':
> drivers/char/keyboard.c:1142: error: implicit declaration of function 'mac_hid_mouse_emulate_buttons'
>
> The forward declaration of mac_hid_mouse_emulate_buttons() is not visible on
> m68k because it's hidden in the middle of a big #ifdef block.
>
> Move it to <linux/hid.h>, correct the type of the second parameter, and
> include <linux/hid.h> where needed.
linux/hid.h contains definitions needed for drivers speaking HID
protocol, I don't think we want to put quirks for legacy keyboard
driver there. I'd just move the #ifdef within drivers/char/keyboard.c
for now.
BTW, I don't think that mac button emulation will work well when x86
evdev-based driver gains popularity - it "grabs" the device and so no
event will flow through keyboard driver... We'd need a new solution...
--
Dmitry
^ permalink raw reply
* Re: Problem faced while using workqueue in the character driver.
From: David Hawkins @ 2007-07-20 17:18 UTC (permalink / raw)
To: Misbah khan; +Cc: linuxppc-embedded
In-Reply-To: <11705912.post@talk.nabble.com>
Hi Misbah,
> I am working on a character driver for FPGA, in which i am using a blocked
> read call on workqueue. The read call will be unblocked by the Interrupt
> from the Fpga to PPC Cpu.
>
> The problem is that if the process is in blocked mode and then an Interrupt
> occurs the system gives kernel Panic where as it get unblocked and start
> reading the data but very soon it gets crashed.
>
> Please send me your suggessins regarding the mentioned problem.
Er, without seeing the code, its a bit difficult to suggest
anything.
Perhaps you are using work-queues incorrectly?
Take a look at:
simple_work_queue.c
In the tar-ball
http://www.ovro.caltech.edu/~dwh/correlator/software/driver_design.tar.gz
Which is described in:
http://www.ovro.caltech.edu/~dwh/correlator/pdf/LNX-723-Hawkins.pdf
There's also a more complex 'COBRA driver' here:
http://www.ovro.caltech.edu/~dwh/correlator/cobra_docs.html
Having an example of a working driver that uses work-queues
might help you.
Dave
^ permalink raw reply
* Re: SDRAM failures on MPC5200B
From: Florian A. Voegel @ 2007-07-20 17:39 UTC (permalink / raw)
To: lokowich; +Cc: linuxppc-embedded
In-Reply-To: <46A0D76E.4030101@acdstar.com>
Hi,
Considering the age of the U-Boot version you're using, it's most likely the problem with the SD-RAM controller of the 5200B. Later U-Boot versions fix this I think by writing a value of 4 to the register at MBAR+0x0190, which does _something_ to resolve the problem. It worked for us. However, we still had problems with SD-RAM in conjunction with other components, so we switched to DDR which has worked flawlessly so far - you might want to consider doing the same.
Greets,
Florian Voegel
Carangul.Tech
On Fri, 20 Jul 2007 10:40:30 -0500
lokowich <lokowich@acdstar.com> wrote:
> We're working on bringing up a MPC5200B version of our original MPC5200
> board using U-Boot 1.1.4 configured for Icecube/Lite5200B. Other than
> the CPU, the board is identical. The bootloader crashes just after
> relocation to RAM, often with a Program Check Exception, typically a
> memory corruption issue. I noticed failures at different stages after
> relocation based on content, suggesting problems with upper SDRAM. If I
> force the initram to 1/2 the determined size (64MB instead of 128MB),
> then everything works well through kernel load and initialization.
> We've added termination resistors to improve AD signals, to no avail.
> Memory tests work fine too. Any help is appreciated.
>
> Thanks,
> Mark Lokowich
> Systems Engineer
> Advanced Communication Design
> 7901 12th Ave. So.
> Bloomington, MN 55425
> 952-854-4000
> lokowich@acdstar.com
>
> This email was Anti Virus checked by Astaro Security Gateway. http://www.astaro.com
>
>
^ permalink raw reply
* Re: SDRAM failures on MPC5200B
From: Rafal Jaworowski @ 2007-07-20 16:46 UTC (permalink / raw)
To: lokowich; +Cc: linuxppc-embedded
In-Reply-To: <46A0D76E.4030101@acdstar.com>
lokowich wrote:
> We're working on bringing up a MPC5200B version of our original MPC5200
> board using U-Boot 1.1.4 configured for Icecube/Lite5200B. Other than
> the CPU, the board is identical. The bootloader crashes just after
> relocation to RAM, often with a Program Check Exception, typically a
> memory corruption issue. I noticed failures at different stages after
> relocation based on content, suggesting problems with upper SDRAM. If I
> force the initram to 1/2 the determined size (64MB instead of 128MB),
> then everything works well through kernel load and initialization.
> We've added termination resistors to improve AD signals, to no avail.
> Memory tests work fine too. Any help is appreciated.
>
Assuming your RAM chips are fine, are you setting the SDelay register
(MBAR + 0x0190)? If not, this can lead to a strange hangs similar to the
described. For details please see the current U-Boot's initdram() for
icecube, and AN3221.
Rafal
^ permalink raw reply
* Re: Kmalloc returns which address
From: Scott Wood @ 2007-07-20 16:58 UTC (permalink / raw)
To: Misbah khan; +Cc: linuxppc-embedded
In-Reply-To: <11705981.post@talk.nabble.com>
Misbah khan wrote:
> hi Suresh
>
> In linux kmelloc returns the pointer to virtual address not the physical
> address, to return to the physical address there is different function
> called ioremap
>
> for eg :-
> char *buf_tx =kmalloc(100,GFP_KERNEL); // Tx buffer
> char *buf_rx=kmalloc(100,GFP_KERNEL); // Rx buffer
>
> ptr_tx=ioremap( buf_tx,100);
> ptr_rx=ioremap(buf_rx,100);
That's a really easy way to cause a machine check.
-Scott
^ permalink raw reply
* Re: [PATCH] [updated] PHY fixed driver: rework release path and update phy_id notation
From: Scott Wood @ 2007-07-20 16:47 UTC (permalink / raw)
To: Andrew Morton; +Cc: netdev, linux-kernel, Jeff Garzik, linuxppc-dev
In-Reply-To: <20070720005702.b2b644e7.akpm@linux-foundation.org>
On Fri, Jul 20, 2007 at 12:57:02AM -0700, Andrew Morton wrote:
> On Fri, 20 Jul 2007 11:50:39 +0400 Vitaly Bordug <vitb@kernel.crashing.org> wrote:
> > On Thu, 19 Jul 2007 23:23:37 -0700
> > Andrew Morton wrote:
> > > Shouldn't these be runtime options (ie: module parameters)?
> > >
> > I thought about it but this thing is more like the one that will never tend/required to change while\
> > configured.. Will add if you see it appropriate though.
>
> 99% of users don't compile their own kernels: their vendor will have to
> make this decision for them, and it sounds like any decision which they
> make will be wrong for some of their users?
This is mostly of use on embedded hardware where the kernel will be
rebuilt by someone who knows the hardware... That said, I don't see why
it needs to be configured at all. Couldn't it use an idr table instead?
-Scott
^ permalink raw reply
* Re: [PATCH 3/4] mpc8349emitx: Add chosen node for default stdout path
From: Jerry Van Baren @ 2007-07-20 16:46 UTC (permalink / raw)
To: Scott Wood; +Cc: u-boot-users, linuxppc-dev
In-Reply-To: <46A0DF76.90409@freescale.com>
Scott Wood wrote:
> Jerry Van Baren wrote:
>> Scott Wood wrote:
>>> Kim Phillips wrote:
>>>> The LIBFDT implementation replaces any existing /chosen with its fixed
>>>> up version.
>>
>> Sort of. If /chosen doesn't exist, it creates it.
>>
>> If /chosen exists and "force" parameter is false, it doesn't touch it.
>> If "force" is true, it creates or fixes up properties. The "bootm"
>> command passes in force == false. The "fdt" command passes in force ==
>> true.
>>
>> The "force" parameter was added to sort of emulate the previous bootm
>> command behavior (but behave better in the case where /chosen already
>> existed).
>
> The problem is that "force" is node-granular, rather than
> property-granular -- If I add a /chosen/linux,stdout-path in the
> original dts (or via an fdt command), then bootm will decline to add
> bootargs and initrd information to the /chosen node.
>
> -Scott
Hi Scott,
Yes, making "force" property-granular makes more sense. I'll add that
to my u-boot-fdt repo.
FWIIW, my original proposal (and code) was to *REMOVE* the automagic
modifications of the fdt blob from the bootm command. My original
proposal was to replace "bootm" in scripts (or in the user's fingers)
with "fdt chosen && fdt env && fdt bd_t && bootm" (or an appropriate
combination thereof). I was shouted down. ;-)
IMHO, having bootm modify the fdt blob is a poor practice. Bootm's
mandate is to boot an image from memory, it *shouldn't* be to rewrite
the fdt blob. Unfortunately, we had an existing practice (poor, IMHO)
of having bootm rewrite the fdt blob and so the current implementation
was done to meet the "user expectation" of bootm "just working" without
needing to add "fdt xyz" before the bootm command.
gvb
(wipes the foamy spit off his face)
^ permalink raw reply
* [patch 1/3] m68k/mac: Make mac_hid_mouse_emulate_buttons() declaration visible
From: Geert Uytterhoeven @ 2007-07-20 16:40 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-input, linuxppc-dev, linux-m68k, Dmitry Torokhov,
linux-kernel
In-Reply-To: <20070720164043.523003359@mail.of.borg>
From: Geert Uytterhoeven <geert@linux-m68k.org>
m68k/mac: Make mac_hid_mouse_emulate_buttons() declaration visible
drivers/char/keyboard.c: In function 'kbd_keycode':
drivers/char/keyboard.c:1142: error: implicit declaration of function 'mac_hid_mouse_emulate_buttons'
The forward declaration of mac_hid_mouse_emulate_buttons() is not visible on
m68k because it's hidden in the middle of a big #ifdef block.
Move it to <linux/hid.h>, correct the type of the second parameter, and
include <linux/hid.h> where needed.
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
---
drivers/char/keyboard.c | 5 +----
drivers/macintosh/mac_hid.c | 1 +
include/linux/hid.h | 3 +++
3 files changed, 5 insertions(+), 4 deletions(-)
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -41,6 +41,7 @@
#include <linux/sysrq.h>
#include <linux/input.h>
#include <linux/reboot.h>
+#include <linux/hid.h>
extern void ctrl_alt_del(void);
@@ -1022,10 +1023,6 @@ static const unsigned short x86_keycodes
308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330,
332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 };
-#ifdef CONFIG_MAC_EMUMOUSEBTN
-extern int mac_hid_mouse_emulate_buttons(int, int, int);
-#endif /* CONFIG_MAC_EMUMOUSEBTN */
-
#ifdef CONFIG_SPARC
static int sparc_l1_a_state = 0;
extern void sun_do_break(void);
--- a/drivers/macintosh/mac_hid.c
+++ b/drivers/macintosh/mac_hid.c
@@ -13,6 +13,7 @@
#include <linux/sysctl.h>
#include <linux/input.h>
#include <linux/module.h>
+#include <linux/hid.h>
static struct input_dev *emumousebtn;
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -522,6 +522,9 @@ int usbhid_quirks_init(char **quirks_par
void usbhid_quirks_exit(void);
void usbhid_fixup_report_descriptor(const u16, const u16, char *, unsigned, char **);
+/* mac hid */
+extern int mac_hid_mouse_emulate_buttons(int, unsigned int, int);
+
#ifdef CONFIG_HID_FF
int hid_ff_init(struct hid_device *hid);
--
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Bug in PowerPC math emulator (stfiwx)
From: Jean-Denis Boyer @ 2007-07-20 16:07 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 1232 bytes --]
Hi,
I encountered a problem while running "valgrind" on my 8323E based
system, running kernel 2.6.19.7. My userland program performs a few
floating point operations at initialization, which is normally handled
by the math emulator. But when running it through valgrind, the VEX will
"regenerate" code dynamically, and internally uses instruction "stfiwx".
Here is a disassembly of that instruction taken from gdb.
0x42336e64: stfiwx f15,0,r1
Although this instruction is valid, the math-emulator rejects it as
invalid. I looked into arch/powerpc/math-emu/math.c, and this is caused
by the second argument which is 0 (rA=0).
In fact, it appears to me that the case XE and XEU are swapped. The
argument rA=0 is invalid for the instructions which updates rA after
computing the effective address, but this is checked in the XE case
instead of XEU.
In attachement, there is a patch for this. The valgrind is very happy
with it now.
There is also a test program (fputest.c) which no longer produces a
SIGILL with the patch.
P.S.: Please CC me cause I'm not on your mailing list.
Sincerely,
Jean-Denis Boyer, Eng.
Mediatrix Telecom, a division of Media5 Corporation
(819)829-8749 x241
[-- Attachment #2: math.patch --]
[-- Type: application/octet-stream, Size: 589 bytes --]
--- linux.orig/arch/powerpc/math-emu/math.c 2006-11-29 16:57:37.000000000 -0500
+++ linux/arch/powerpc/math-emu/math.c 2007-07-20 11:55:30.000000000 -0400
@@ -405,7 +405,7 @@
op1 = (void *)¤t->thread.fpr[(insn >> 11) & 0x1f];
break;
- case XE:
+ case XEU:
idx = (insn >> 16) & 0x1f;
if (!idx)
goto illegal;
@@ -414,7 +414,7 @@
op1 = (void *)(regs->gpr[idx] + regs->gpr[(insn >> 11) & 0x1f]);
break;
- case XEU:
+ case XE:
idx = (insn >> 16) & 0x1f;
op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f];
op1 = (void *)((idx ? regs->gpr[idx] : 0)
[-- Attachment #3: fputest.c --]
[-- Type: application/octet-stream, Size: 143 bytes --]
#include <stdio.h>
int main()
{
int i, *p;
p = &i;
asm volatile("stfiwx 15,0,%0" : "=r"(p));
printf("%d\n", i);
return 0;
}
^ permalink raw reply
* Re: [PATCH 3/4] mpc8349emitx: Add chosen node for default stdout path
From: Scott Wood @ 2007-07-20 16:14 UTC (permalink / raw)
To: Jerry Van Baren; +Cc: linuxppc-dev
In-Reply-To: <46A01733.6080609@gmail.com>
Jerry Van Baren wrote:
> Scott Wood wrote:
>> Kim Phillips wrote:
>>> The LIBFDT implementation replaces any existing /chosen with its fixed
>>> up version.
>
>
> Sort of. If /chosen doesn't exist, it creates it.
>
> If /chosen exists and "force" parameter is false, it doesn't touch it.
> If "force" is true, it creates or fixes up properties. The "bootm"
> command passes in force == false. The "fdt" command passes in force ==
> true.
>
> The "force" parameter was added to sort of emulate the previous bootm
> command behavior (but behave better in the case where /chosen already
> existed).
The problem is that "force" is node-granular, rather than
property-granular -- If I add a /chosen/linux,stdout-path in the
original dts (or via an fdt command), then bootm will decline to add
bootargs and initrd information to the /chosen node.
-Scott
^ permalink raw reply
* [RFC 1/1] lro: Generic Large Receive Offload for TCP traffic
From: Jan-Bernd Themann @ 2007-07-20 15:41 UTC (permalink / raw)
To: netdev
Cc: Thomas Klein, Jan-Bernd Themann, linux-kernel, linux-ppc,
Christoph Raisch, Marcus Eder, Stefan Roscher, David Miller
Generic LRO patch
Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
---
include/linux/inet_lro.h | 154 +++++++++++++
net/ipv4/inet_lro.c | 549 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 703 insertions(+), 0 deletions(-)
create mode 100644 include/linux/inet_lro.h
create mode 100644 net/ipv4/inet_lro.c
diff --git a/include/linux/inet_lro.h b/include/linux/inet_lro.h
new file mode 100644
index 0000000..2680ecf
--- /dev/null
+++ b/include/linux/inet_lro.h
@@ -0,0 +1,154 @@
+/*
+ * linux/include/linux/inet_lro.h
+ *
+ * Large Receive Offload (ipv4 / tcp)
+ *
+ * (C) Copyright IBM Corp. 2007
+ *
+ * Authors:
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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 __INET_LRO_H_
+#define __INET_LRO_H_
+
+#include <net/ip.h>
+#include <net/tcp.h>
+
+#define LRO_IPV4 1
+#define LRO_TCP 2
+
+/*
+ * LRO descriptor for a tcp session
+ */
+struct net_lro_desc {
+ struct sk_buff *parent;
+ struct sk_buff *last_skb;
+ struct skb_frag_struct *next_frag;
+ struct iphdr *iph;
+ struct tcphdr *tcph;
+ struct vlan_group *vgrp;
+ __wsum data_csum;
+ u32 tcp_rcv_tsecr;
+ u32 tcp_rcv_tsval;
+ u32 tcp_ack;
+ u32 tcp_next_seq;
+ u32 skb_tot_frags_len;
+ u16 ip_tot_len;
+ u16 tcp_saw_tstamp; /* timestamps enabled */
+ u16 tcp_window;
+ u16 vlan_tag;
+ int pkt_aggr_cnt; /* counts aggregated packets */
+ int vlan_packet;
+ int active;
+};
+
+/*
+ * Large Receive Offload (LRO) Manager
+ *
+ * Fields must be set by driver
+ */
+
+struct net_lro_mgr {
+ struct net_device *dev; /* Required for receive in page mode */
+ u32 ip_summed; /* Options to be set in generated SKB in page mode */
+ int max_desc; /* Max number of LRO descriptors */
+ int max_aggr; /* Max number of LRO packets to be aggregated */
+
+ struct net_lro_desc *lro_arr; /* Array of LRO descriptors */
+
+ /*
+ * Optimized driver functions
+ *
+ * get_skb_header: returns tcp and ip header for packet in SKB
+ */
+ int (*get_skb_header)(struct sk_buff *skb, void **ip_hdr,
+ void **tcpudp_hdr, u64 *hdr_flags, void *priv);
+
+ /*
+ * get_frag_header: returns mac, tcp and ip header for packet in SKB
+ *
+ * @hdr_flags: Indicate what kind of LRO has to be done
+ * (IPv4/IPv6/TCP/UDP)
+ */
+ int (*get_frag_header)(struct skb_frag_struct *frag, void **mac_hdr,
+ void **ip_hdr, void **tcpudp_hdr, u64 *hdr_flags,
+ void *priv);
+};
+
+/*
+ * Processes a SKB
+ *
+ * @lro_mgr: LRO manager to use
+ * @skb: SKB to aggregate
+ * @priv: Private data that may be used by driver functions
+ * (for example get_tcp_ip_hdr)
+ */
+
+void lro_receive_skb(struct net_lro_mgr *lro_mgr,
+ struct sk_buff *skb,
+ void *priv);
+
+/*
+ * Processes a SKB with VLAN HW acceleration support
+ */
+
+void lro_vlan_hwaccel_receive_skb(struct net_lro_mgr *lro_mgr,
+ struct sk_buff *skb,
+ struct vlan_group *vgrp,
+ u16 vlan_tag,
+ void *priv);
+
+/*
+ * Processes a fragment list
+ *
+ * This functions aggregate fragments and generate SKBs do pass
+ * the packets to the stack.
+ *
+ * @lro_mgr: LRO manager to use
+ * @frags: Fragment to be processed. Must contain entire header in first
+ * element.
+ * @len: Length of received data
+ * @true_size: Actual size of memory the fragment is consuming
+ * @priv: Private data that may be used by driver functions
+ * (for example get_tcp_ip_hdr)
+ */
+
+void lro_receive_frags(struct net_lro_mgr *lro_mgr,
+ struct skb_frag_struct *frags,
+ int len, int true_size, void *priv);
+
+void lro_vlan_hwaccel_receive_frags(struct net_lro_mgr *lro_mgr,
+ struct skb_frag_struct *frags,
+ int len,
+ int true_size,
+ struct vlan_group *vgrp,
+ u16 vlan_tag,
+ void *priv);
+
+/*
+ * Forward all aggregated SKBs held by lro_mgr to network stack
+ */
+
+void lro_flush_all(struct net_lro_mgr *lro_mgr);
+
+void lro_flush_pkt(struct net_lro_mgr *lro_mgr,
+ struct iphdr *iph, struct tcphdr *tcph);
+
+#endif
diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c
new file mode 100644
index 0000000..9eac24d
--- /dev/null
+++ b/net/ipv4/inet_lro.c
@@ -0,0 +1,549 @@
+/*
+ * linux/net/ipv4/inet_lro.c
+ *
+ * Large Receive Offload (ipv4 / tcp)
+ *
+ * (C) Copyright IBM Corp. 2007
+ *
+ * Authors:
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ */
+
+
+#include <linux/module.h>
+#include <linux/if_vlan.h>
+
+#include <linux/inet_lro.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jan-Bernd Themann <themann@de.ibm.com>");
+MODULE_DESCRIPTION("Large Receive Offload (ipv4 / tcp)");
+
+#define TCP_HDR_LEN(tcph) (tcph->doff << 2)
+#define IP_HDR_LEN(iph) (iph->ihl << 2)
+#define TCP_PAYLOAD_LENGTH(iph, tcph) \
+(ntohs(iph->tot_len) - IP_HDR_LEN(iph) - TCP_HDR_LEN(tcph))
+
+#define IPH_LEN_WO_OPTIONS 5
+#define TCPH_LEN_WO_OPTIONS 5
+#define TCPH_LEN_W_TIMESTAMP 8
+
+/*
+ * Basic tcp checks whether packet is suitable for LRO
+ */
+
+static int lro_tcp_ip_check(struct iphdr *iph, struct tcphdr *tcph,
+ int len, struct net_lro_desc *lro_desc)
+{
+ /* check ip header: packet length */
+ if (ntohs(iph->tot_len) > len)
+ return -1;
+
+ if (TCP_PAYLOAD_LENGTH(iph, tcph) == 0)
+ return -1;
+
+ if (iph->ihl != IPH_LEN_WO_OPTIONS)
+ return -1;
+
+ if (tcph->cwr || tcph->ece || tcph->urg || !tcph->ack
+ || tcph->rst || tcph->syn || tcph->fin)
+ return -1;
+
+ if (INET_ECN_is_ce(ipv4_get_dsfield(iph)))
+ return -1;
+
+ if (tcph->doff != TCPH_LEN_WO_OPTIONS
+ && tcph->doff != TCPH_LEN_W_TIMESTAMP)
+ return -1;
+
+ /* check tcp options (only timestamp allowed) */
+ if (tcph->doff == TCPH_LEN_W_TIMESTAMP) {
+ u32 *topt = (u32 *)(tcph + 1);
+
+ if (*topt != htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+ | (TCPOPT_TIMESTAMP << 8)
+ | TCPOLEN_TIMESTAMP))
+ return -1;
+
+ /* timestamp should be in right order */
+ topt++;
+ if (lro_desc && after(ntohl(lro_desc->tcp_rcv_tsval),
+ ntohl(*topt)))
+ return -1;
+
+ /* timestamp reply should not be zero */
+ topt++;
+ if (*topt == 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+static void lro_update_tcp_ip_header(struct net_lro_desc *lro_desc)
+{
+ struct iphdr *iph = lro_desc->iph;
+ struct tcphdr *tcph = lro_desc->tcph;
+ u32 *p;
+ __wsum tcp_hdr_csum;
+
+ tcph->ack_seq = lro_desc->tcp_ack;
+ tcph->window = lro_desc->tcp_window;
+
+ if (lro_desc->tcp_saw_tstamp) {
+ p = (u32 *)(tcph + 1);
+ *(p+2) = lro_desc->tcp_rcv_tsecr;
+ }
+
+ iph->tot_len = htons(lro_desc->ip_tot_len);
+
+ iph->check = 0;
+ iph->check = ip_fast_csum((u8 *)lro_desc->iph, iph->ihl);
+
+ tcph->check = 0;
+ tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), 0);
+ lro_desc->data_csum = csum_add(lro_desc->data_csum, tcp_hdr_csum);
+ tcph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+ htons(lro_desc->ip_tot_len) -
+ IP_HDR_LEN(iph), IPPROTO_TCP,
+ lro_desc->data_csum);
+
+}
+
+static __wsum lro_tcp_data_csum(struct iphdr *iph, struct tcphdr *tcph, int len)
+{
+ __wsum tcp_csum;
+ __wsum tcp_hdr_csum;
+ __wsum tcp_ps_hdr_csum;
+
+ tcp_csum = ~csum_unfold(tcph->check);
+ tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), tcp_csum);
+
+ tcp_ps_hdr_csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
+ len + TCP_HDR_LEN(tcph),
+ IPPROTO_TCP, 0);
+
+ return csum_sub(csum_sub(tcp_csum, tcp_hdr_csum),
+ tcp_ps_hdr_csum);
+
+}
+
+static void lro_init_desc(struct net_lro_desc *lro_desc, struct sk_buff *skb,
+ struct iphdr *iph, struct tcphdr *tcph,
+ u16 vlan_tag, struct vlan_group *vgrp)
+{
+ int nr_frags;
+ u32 *ptr;
+ u32 tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph);
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ lro_desc->parent = skb;
+ lro_desc->next_frag = &(skb_shinfo(skb)->frags[nr_frags]);
+ lro_desc->iph = iph;
+ lro_desc->tcph = tcph;
+ lro_desc->tcp_next_seq = ntohl(tcph->seq) + tcp_data_len;
+ lro_desc->tcp_ack = ntohl(tcph->ack_seq);
+ lro_desc->tcp_window = tcph->window;
+
+ lro_desc->pkt_aggr_cnt = 1;
+ lro_desc->ip_tot_len = ntohs(iph->tot_len);
+
+ if (tcph->doff == 8) {
+ ptr = (u32 *)(tcph+1);
+ lro_desc->tcp_saw_tstamp = 1;
+ lro_desc->tcp_rcv_tsval = *(ptr+1);
+ lro_desc->tcp_rcv_tsecr = *(ptr+2);
+ }
+
+ lro_desc->vgrp = vgrp;
+ lro_desc->vlan_tag = vlan_tag;
+ lro_desc->active = 1;
+
+ lro_desc->data_csum = lro_tcp_data_csum(iph, tcph,
+ tcp_data_len);
+}
+
+static inline void lro_clear_desc(struct net_lro_desc *lro_desc)
+{
+ memset(lro_desc, 0, sizeof(struct net_lro_desc));
+}
+
+static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph,
+ struct tcphdr *tcph, int tcp_data_len)
+{
+ struct sk_buff *parent = lro_desc->parent;
+ u32 *topt;
+
+ lro_desc->pkt_aggr_cnt++;
+ lro_desc->ip_tot_len += tcp_data_len;
+ lro_desc->tcp_next_seq += tcp_data_len;
+ lro_desc->tcp_window = tcph->window;
+ lro_desc->tcp_ack = tcph->ack_seq;
+
+ /* don't update tcp_rcv_tsval, would not work with PAWS */
+ if (lro_desc->tcp_saw_tstamp) {
+ topt = (u32 *) (tcph + 1);
+ lro_desc->tcp_rcv_tsecr = *(topt + 2);
+ }
+
+ parent->len += tcp_data_len;
+ parent->data_len += tcp_data_len;
+
+ lro_desc->data_csum = csum_add(lro_desc->data_csum,
+ lro_tcp_data_csum(iph, tcph,
+ tcp_data_len));
+ return;
+}
+
+static void lro_add_packet(struct net_lro_desc *lro_desc, struct sk_buff *skb,
+ struct iphdr *iph, struct tcphdr *tcph)
+{
+ struct sk_buff *parent = lro_desc->parent;
+ int tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph);
+
+ lro_add_common(lro_desc, iph, tcph, tcp_data_len);
+
+ skb_pull(skb, (skb->len - tcp_data_len));
+ parent->truesize += skb->truesize;
+
+ if (lro_desc->last_skb)
+ lro_desc->last_skb->next = skb;
+ else
+ skb_shinfo(parent)->frag_list = skb;
+
+ lro_desc->last_skb = skb;
+ return;
+}
+
+static void lro_add_frags(struct net_lro_desc *lro_desc,
+ int len, int hlen, int truesize,
+ struct skb_frag_struct *skb_frags,
+ struct iphdr *iph, struct tcphdr *tcph)
+{
+ struct sk_buff *skb = lro_desc->parent;
+ int tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph);
+
+ lro_add_common(lro_desc, iph, tcph, tcp_data_len);
+
+ skb->truesize += truesize;
+
+ skb_frags[0].page_offset += hlen;
+ skb_frags[0].size -= hlen;
+
+ while (tcp_data_len > 0) {
+ *(lro_desc->next_frag) = *skb_frags;
+ tcp_data_len -= skb_frags->size;
+ lro_desc->next_frag++;
+ skb_frags++;
+ skb_shinfo(skb)->nr_frags++;
+ }
+
+ return;
+}
+
+static int lro_check_tcp_conn(struct net_lro_desc *lro_desc,
+ struct iphdr *iph,
+ struct tcphdr *tcph)
+{
+ if ((lro_desc->iph->saddr != iph->saddr)
+ || (lro_desc->iph->daddr != iph->daddr)
+ || (lro_desc->tcph->source != tcph->source)
+ || (lro_desc->tcph->dest != tcph->dest))
+ return -1;
+ return 0;
+}
+
+static struct net_lro_desc *lro_get_desc(struct net_lro_mgr *mgr,
+ struct net_lro_desc *lro_arr,
+ struct iphdr *iph,
+ struct tcphdr *tcph)
+{
+ struct net_lro_desc *lro_desc = NULL;
+ struct net_lro_desc *tmp;
+ int max_desc = mgr->max_desc;
+ int i;
+
+ for (i = 0; i < max_desc; i++) {
+ tmp = &lro_arr[i];
+ if (tmp->active)
+ if (!lro_check_tcp_conn(tmp, iph, tcph)) {
+ lro_desc = tmp;
+ goto out;
+ }
+ }
+
+ for (i = 0; i < max_desc; i++) {
+ if(!lro_arr[i].active) {
+ lro_desc = &lro_arr[i];
+ goto out;
+ }
+ }
+
+out:
+ return lro_desc;
+}
+
+static void lro_flush(struct net_lro_desc *lro_desc)
+{
+ if (lro_desc->pkt_aggr_cnt > 1)
+ lro_update_tcp_ip_header(lro_desc);
+
+ if (lro_desc->vgrp)
+ vlan_hwaccel_receive_skb(lro_desc->parent, lro_desc->vgrp,
+ lro_desc->vlan_tag);
+ else
+ netif_receive_skb(lro_desc->parent);
+
+ lro_clear_desc(lro_desc);
+}
+
+void lro_flush_all(struct net_lro_mgr *lro_mgr)
+{
+ int i;
+ struct net_lro_desc *lro_desc = lro_mgr->lro_arr;
+
+ for (i = 0; i < lro_mgr->max_desc; i++) {
+ if (lro_desc[i].active)
+ lro_flush(&lro_desc[i]);
+ }
+}
+EXPORT_SYMBOL(lro_flush_all);
+
+int __lro_proc_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb,
+ struct vlan_group *vgrp, u16 vlan_tag, void *priv)
+{
+ struct net_lro_desc *lro_desc;
+ struct iphdr *iph;
+ struct tcphdr *tcph;
+ u64 flags;
+
+ if (!lro_mgr->get_skb_header
+ || lro_mgr->get_skb_header(skb, (void *)&iph, (void *)&tcph,
+ &flags, priv))
+ goto out;
+
+ if (!(flags & LRO_IPV4) || !(flags & LRO_TCP))
+ goto out;
+
+ lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph);
+ if (!lro_desc)
+ goto out;
+
+ if (!lro_desc->active) { /* start new lro session */
+ if (lro_tcp_ip_check(iph, tcph, skb->len, NULL))
+ goto out;
+
+ lro_init_desc(lro_desc, skb, iph, tcph, vlan_tag, vgrp);
+ return 0;
+ }
+
+ if (lro_desc->tcp_next_seq != ntohl(tcph->seq))
+ goto out2;
+
+ if (lro_tcp_ip_check(iph, tcph, skb->len, lro_desc))
+ goto out2;
+
+ lro_add_packet(lro_desc, skb, iph, tcph);
+
+ if (lro_desc->pkt_aggr_cnt >= lro_mgr->max_aggr)
+ lro_flush(lro_desc);
+
+ return 0;
+
+out2: /* send aggregated SKBs to stack */
+ lro_flush(lro_desc);
+
+out: /* Original SKB has to be posted to stack */
+ return 1;
+}
+
+void lro_receive_skb(struct net_lro_mgr *lro_mgr,
+ struct sk_buff *skb,
+ void *priv)
+{
+ if (__lro_proc_skb(lro_mgr, skb, NULL, 0, priv))
+ netif_receive_skb(skb);
+}
+EXPORT_SYMBOL(lro_receive_skb);
+
+void lro_vlan_hwaccel_receive_skb(struct net_lro_mgr *lro_mgr,
+ struct sk_buff *skb,
+ struct vlan_group *vgrp,
+ u16 vlan_tag,
+ void *priv)
+{
+ if (__lro_proc_skb(lro_mgr, skb, vgrp, vlan_tag, priv))
+ vlan_hwaccel_receive_skb(skb, vgrp, vlan_tag);
+}
+EXPORT_SYMBOL(lro_vlan_hwaccel_receive_skb);
+
+#define LRO_MIN_PG_HLEN 80
+
+struct sk_buff *lro_gen_skb(struct net_lro_mgr *lro_mgr,
+ struct skb_frag_struct *frags,
+ int len, int true_size,
+ void *mac_hdr,
+ int hlen)
+{
+ struct sk_buff *skb;
+ struct skb_frag_struct *skb_frags;
+ int data_len = len;
+
+ skb = netdev_alloc_skb(lro_mgr->dev, hlen);
+ if (!skb)
+ return NULL;
+
+ skb->len = len;
+ skb->data_len = len - hlen;
+ skb->truesize += true_size;
+ skb->tail += hlen;
+
+ memcpy(skb->data, mac_hdr, hlen);
+
+ skb_frags = skb_shinfo(skb)->frags;
+ while (data_len > 0) {
+ *skb_frags = *frags;
+ data_len -= frags->size;
+ skb_frags++;
+ frags++;
+ skb_shinfo(skb)->nr_frags++;
+ }
+
+ skb_shinfo(skb)->frags[0].page_offset += hlen;
+ skb_shinfo(skb)->frags[0].size -= hlen;
+
+ skb->ip_summed = lro_mgr->ip_summed;
+ skb->protocol = eth_type_trans(skb, lro_mgr->dev);
+ return skb;
+}
+
+struct sk_buff *__lro_proc_segment(struct net_lro_mgr *lro_mgr,
+ struct skb_frag_struct *frags,
+ int len, int true_size,
+ struct vlan_group *vgrp,
+ u16 vlan_tag, void *priv)
+{
+ struct net_lro_desc *lro_desc;
+ struct iphdr *iph;
+ struct tcphdr *tcph;
+ struct sk_buff *skb;
+ void *mac_hdr;
+ u64 flags;
+ int hdr_len = 0;
+
+ if (!lro_mgr->get_frag_header
+ || lro_mgr->get_frag_header(frags, (void *)&mac_hdr, (void *)&iph,
+ (void *)&tcph, &flags, priv)) {
+ mac_hdr = page_address(frags->page) + frags->page_offset;
+ goto out1;
+ }
+
+ if (!(flags & LRO_IPV4) || !(flags & LRO_TCP))
+ goto out1;
+
+ lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph);
+ if (!lro_desc)
+ goto out1;
+
+ hdr_len = (int)((void *)(tcph) + TCP_HDR_LEN(tcph) - mac_hdr);
+
+ if (!lro_desc->active) { /* start new lro session */
+ if (lro_tcp_ip_check(iph, tcph, len, NULL))
+ goto out1;
+
+ skb = lro_gen_skb(lro_mgr, frags,
+ len, true_size, mac_hdr,
+ max(hdr_len, LRO_MIN_PG_HLEN));
+ if (!skb)
+ goto out;
+
+ iph = (void *)(skb->data);
+ tcph = (void *)((u8 *)skb->data + IP_HDR_LEN(iph));
+
+ lro_init_desc(lro_desc, skb, iph, tcph, 0, NULL);
+ return 0;
+ }
+
+ if (lro_desc->tcp_next_seq != ntohl(tcph->seq))
+ goto out2;
+
+ if (lro_tcp_ip_check(iph, tcph, len, lro_desc))
+ goto out2;
+
+ lro_add_frags(lro_desc, len, hdr_len, true_size, frags, iph, tcph);
+
+ if ((skb_shinfo(lro_desc->parent)->nr_frags >= lro_mgr->max_aggr) ||
+ lro_desc->parent->len > 65535) /* good idea? */
+ lro_flush(lro_desc);
+
+ return NULL;
+
+out2: /* send aggregated packets to the stack */
+ lro_flush(lro_desc);
+
+out1: /* Original packet has to be posted to the stack */
+ skb = lro_gen_skb(lro_mgr, frags,
+ len, true_size, mac_hdr,
+ max(hdr_len, LRO_MIN_PG_HLEN));
+out:
+ return skb;
+}
+
+void lro_receive_frags(struct net_lro_mgr *lro_mgr,
+ struct skb_frag_struct *frags,
+ int len, int true_size, void *priv)
+{
+ struct sk_buff *skb;
+
+ skb = __lro_proc_segment(lro_mgr, frags, len, true_size, NULL, 0, priv);
+ if(skb)
+ netif_receive_skb(skb);
+}
+
+EXPORT_SYMBOL(lro_receive_frags);
+
+void lro_vlan_hwaccel_receive_frags(struct net_lro_mgr *lro_mgr,
+ struct skb_frag_struct *frags,
+ int len,
+ int true_size,
+ struct vlan_group *vgrp,
+ u16 vlan_tag,
+ void *priv)
+{
+ struct sk_buff *skb;
+
+ skb = __lro_proc_segment(lro_mgr, frags, len, true_size, vgrp,
+ vlan_tag, priv);
+ if(skb)
+ vlan_hwaccel_receive_skb(skb, vgrp, vlan_tag);
+}
+
+EXPORT_SYMBOL(lro_vlan_hwaccel_receive_frags);
+
+void lro_flush_pkt(struct net_lro_mgr *lro_mgr,
+ struct iphdr *iph, struct tcphdr *tcph)
+{
+ struct net_lro_desc *lro_desc;
+
+ lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph);
+ if (lro_desc->active)
+ lro_flush(lro_desc);
+}
+
+EXPORT_SYMBOL(lro_flush_pkt);
--
1.5.2
^ permalink raw reply related
* [RFC 0/1] lro: Generic Large Receive Offload for TCP traffic
From: Jan-Bernd Themann @ 2007-07-20 15:41 UTC (permalink / raw)
To: netdev
Cc: Thomas Klein, Jeff Garzik, Jan-Bernd Themann, linux-kernel,
linux-ppc, Christoph Raisch, Marcus Eder, Stefan Roscher,
David Miller
Hi,
Thanks a lot for your comments so far.
This generic LRO patch differs from the last one in several points.
A new interface for a "receive in pages" mode has been added and tested
with an eHEA prototype. Seems to work well.
Does this extended interface seem to be sufficient?
Below some more explanations:
Thanks,
Jan-Bernd
Changes to http://www.spinics.net/lists/netdev/msg35490.html :
- Interfaces are changed to allow later support for IPv6 / UDP
- New interface to support "receive in pages"
- TCP checksums are updated properly
- TCP packets with push flag are aggregated now
- Timestamps are now compared using after()
The additional interface to support "receive in pages":
void lro_receive_frags(struct net_lro_mgr *lro_mgr,
struct skb_frag_struct *frags,
int len, int true_size, void *priv);
void lro_vlan_hwaccel_receive_frags(struct net_lro_mgr *lro_mgr,
struct skb_frag_struct *frags,
int len,
int true_size,
struct vlan_group *vgrp,
u16 vlan_tag,
void *priv);
These functions generate SKBs only for the first packet of an
LRO session. The next fragment list to be aggregated will be
added in the fragment list of that SKB.
The reason why this is a smart approach is described in:
http://www.spinics.net/lists/netdev/msg35634.html
All other packets that do not match the LRO requirements are
put in an SKB and sent to the stack.
Packets that are received in an extra buffer (small packets) and
thus not in an skb fragment can be sent by the driver to the stack
after flushing the appropriate LRO sessions:
void lro_flush_pkt(struct net_lro_mgr *lro_mgr,
struct iphdr *iph, struct tcphdr *tcph);
or
void lro_flush_all(struct net_lro_mgr *lro_mgr);
^ permalink raw reply
* SDRAM failures on MPC5200B
From: lokowich @ 2007-07-20 15:40 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 927 bytes --]
We're working on bringing up a MPC5200B version of our original MPC5200
board using U-Boot 1.1.4 configured for Icecube/Lite5200B. Other than
the CPU, the board is identical. The bootloader crashes just after
relocation to RAM, often with a Program Check Exception, typically a
memory corruption issue. I noticed failures at different stages after
relocation based on content, suggesting problems with upper SDRAM. If I
force the initram to 1/2 the determined size (64MB instead of 128MB),
then everything works well through kernel load and initialization.
We've added termination resistors to improve AD signals, to no avail.
Memory tests work fine too. Any help is appreciated.
Thanks,
Mark Lokowich
Systems Engineer
Advanced Communication Design
7901 12th Ave. So.
Bloomington, MN 55425
952-854-4000
lokowich@acdstar.com
This email was Anti Virus checked by Astaro Security Gateway. http://www.astaro.com
[-- Attachment #2: Type: text/html, Size: 1324 bytes --]
^ permalink raw reply
* PS3: Fix build with 32-bit toolchains
From: Geoff Levand @ 2007-07-20 15:31 UTC (permalink / raw)
To: akpm; +Cc: linuxppc-dev, Paul Mackerras, Arnd Bergmann
In-Reply-To: <469FDBDC.5030700@am.sony.com>
The PS3 bootwrapper files use instructions only available on
64-bit CPUs. Add the code generation directive '.machine "ppc64"'
for toolchains configured for 32-bit CPUs.
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
---
Hi Andrew,
It seems Paul is out on holiday, so I'm sending this to you.
This fixes a build error in Linus' current tree for a few
32 bit powerpc platforms. It had some review on the
linuxppc-dev ML, and Grant Likely reported it fixed the
problem.
-Geoff
arch/powerpc/boot/ps3-head.S | 2 ++
arch/powerpc/boot/ps3-hvcall.S | 2 ++
2 files changed, 4 insertions(+)
--- a/arch/powerpc/boot/ps3-head.S
+++ b/arch/powerpc/boot/ps3-head.S
@@ -20,6 +20,8 @@
#include "ppc_asm.h"
+ .machine "ppc64"
+
.text
/*
--- a/arch/powerpc/boot/ps3-hvcall.S
+++ b/arch/powerpc/boot/ps3-hvcall.S
@@ -20,6 +20,8 @@
#include "ppc_asm.h"
+ .machine "ppc64"
+
/*
* The PS3 hypervisor uses a 64 bit "C" language calling convention.
* The routines here marshal arguments between the 32 bit wrapper
^ permalink raw reply
* Re: Interrupts on xilinx ml403
From: Grant Likely @ 2007-07-20 15:12 UTC (permalink / raw)
To: Mirek23; +Cc: linuxppc-embedded
In-Reply-To: <11708607.post@talk.nabble.com>
On 7/20/07, Mirek23 <miroslaw.dach@psi.ch> wrote:
> Does it mean that DIP Switches do not use INTC interrupt controller?
> How to handle the DIP Switches interrupt?
> Does the Interrupt handler routine have to acknowledge the interrupt from
> Dip Switches?
It probably means that the GPIO irq out line is not hooked up to your
INTC in the system.mhs file.
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply
* Re: [PATCH] powerpc: mpc5200 low power mode, .globl fix
From: Grant Likely @ 2007-07-20 15:09 UTC (permalink / raw)
To: Domen Puncer; +Cc: Linux PPC Mailing List, Paul Mackerras
In-Reply-To: <20070720105550.GA1385@moe.telargo.com>
On 7/20/07, Domen Puncer <domen.puncer@telargo.com> wrote:
> flush_data_cache doesn't need to be global, and can cause problems.
> Thanks to Milton Miller for noticing this.
>
>
> Signed-off-by: Domen Puncer <domen.puncer@telargo.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Paulus, can you pick this up please?
> ---
> arch/powerpc/platforms/52xx/lite5200_sleep.S | 1 -
> 1 file changed, 1 deletion(-)
>
> Index: work-powerpc.git/arch/powerpc/platforms/52xx/lite5200_sleep.S
> ===================================================================
> --- work-powerpc.git.orig/arch/powerpc/platforms/52xx/lite5200_sleep.S
> +++ work-powerpc.git/arch/powerpc/platforms/52xx/lite5200_sleep.S
> @@ -400,7 +400,6 @@ restore_regs:
> * Flush data cache
> * Do this by just reading lots of stuff into the cache.
> */
> - .globl flush_data_cache
> flush_data_cache:
> lis r3,CONFIG_KERNEL_START@h
> ori r3,r3,CONFIG_KERNEL_START@l
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195
^ permalink raw reply
* [PATCH 5/5] ehca: Support small QP queues
From: Hoang-Nam Nguyen @ 2007-07-20 14:04 UTC (permalink / raw)
To: Roland Dreier, linux-kernel, linuxppc-dev, openib-general
Cc: fenkes, raisch, stefan.roscher
From: Stefan Roscher <stefan.roscher at de.ibm.com>
Date: Fri, 20 Jul 2007 13:59:14 +0200
Subject: [PATCH 5/5] IB/ehca: Small QP queues
eHCA2 supports QP queues that can be as small as 512 bytes. This greatly
reduces memory overhead for consumers that use lots of QPs with small queues
(e.g. RDMA-only QPs). Apart from dealing with firmware, this code needs to
manage bite-sized chunks of kernel pages, making sure that no kernel page is
shared between different protection domains.
Signed-off-by: Hoang-Nam Nguyen <hnguyen@de.ibm.com>
---
drivers/infiniband/hw/ehca/ehca_classes.h | 41 ++++--
drivers/infiniband/hw/ehca/ehca_cq.c | 8 +-
drivers/infiniband/hw/ehca/ehca_eq.c | 8 +-
drivers/infiniband/hw/ehca/ehca_main.c | 14 ++-
drivers/infiniband/hw/ehca/ehca_pd.c | 25 +++-
drivers/infiniband/hw/ehca/ehca_qp.c | 163 +++++++++++++---------
drivers/infiniband/hw/ehca/ehca_uverbs.c | 2 +-
drivers/infiniband/hw/ehca/hcp_if.c | 30 +++--
drivers/infiniband/hw/ehca/ipz_pt_fn.c | 222 ++++++++++++++++++++++-------
drivers/infiniband/hw/ehca/ipz_pt_fn.h | 26 +++-
10 files changed, 379 insertions(+), 160 deletions(-)
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 63b8b9f..3725aa8 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -43,7 +43,6 @@
#ifndef __EHCA_CLASSES_H__
#define __EHCA_CLASSES_H__
-
struct ehca_module;
struct ehca_qp;
struct ehca_cq;
@@ -129,6 +128,10 @@ struct ehca_pd {
struct ib_pd ib_pd;
struct ipz_pd fw_pd;
u32 ownpid;
+ /* small queue mgmt */
+ struct mutex lock;
+ struct list_head free[2];
+ struct list_head full[2];
};
enum ehca_ext_qp_type {
@@ -307,6 +310,8 @@ int ehca_init_av_cache(void);
void ehca_cleanup_av_cache(void);
int ehca_init_mrmw_cache(void);
void ehca_cleanup_mrmw_cache(void);
+int ehca_init_small_qp_cache(void);
+void ehca_cleanup_small_qp_cache(void);
extern rwlock_t ehca_qp_idr_lock;
extern rwlock_t ehca_cq_idr_lock;
@@ -324,7 +329,7 @@ struct ipzu_queue_resp {
u32 queue_length; /* queue length allocated in bytes */
u32 pagesize;
u32 toggle_state;
- u32 dummy; /* padding for 8 byte alignment */
+ u32 offset; /* save offset within a page for small_qp */
};
struct ehca_create_cq_resp {
@@ -366,15 +371,29 @@ enum ehca_ll_comp_flags {
LLQP_COMP_MASK = 0x60,
};
+struct ehca_alloc_queue_parms {
+ /* input parameters */
+ int max_wr;
+ int max_sge;
+ int page_size;
+ int is_small;
+
+ /* output parameters */
+ u16 act_nr_wqes;
+ u8 act_nr_sges;
+ u32 queue_size; /* bytes for small queues, pages otherwise */
+};
+
struct ehca_alloc_qp_parms {
-/* input parameters */
+ struct ehca_alloc_queue_parms squeue;
+ struct ehca_alloc_queue_parms rqueue;
+
+ /* input parameters */
enum ehca_service_type servicetype;
+ int qp_storage;
int sigtype;
enum ehca_ext_qp_type ext_type;
enum ehca_ll_comp_flags ll_comp_flags;
-
- int max_send_wr, max_recv_wr;
- int max_send_sge, max_recv_sge;
int ud_av_l_key_ctl;
u32 token;
@@ -384,18 +403,10 @@ struct ehca_alloc_qp_parms {
u32 srq_qpn, srq_token, srq_limit;
-/* output parameters */
+ /* output parameters */
u32 real_qp_num;
struct ipz_qp_handle qp_handle;
struct h_galpas galpas;
-
- u16 act_nr_send_wqes;
- u16 act_nr_recv_wqes;
- u8 act_nr_recv_sges;
- u8 act_nr_send_sges;
-
- u32 nr_rq_pages;
- u32 nr_sq_pages;
};
int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp);
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 9e87883..5746787 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -190,8 +190,8 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
goto create_cq_exit2;
}
- ipz_rc = ipz_queue_ctor(&my_cq->ipz_queue, param.act_pages,
- EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0);
+ ipz_rc = ipz_queue_ctor(NULL, &my_cq->ipz_queue, param.act_pages,
+ EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0, 0);
if (!ipz_rc) {
ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%x device=%p",
ipz_rc, device);
@@ -285,7 +285,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
return cq;
create_cq_exit4:
- ipz_queue_dtor(&my_cq->ipz_queue);
+ ipz_queue_dtor(NULL, &my_cq->ipz_queue);
create_cq_exit3:
h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
@@ -359,7 +359,7 @@ int ehca_destroy_cq(struct ib_cq *cq)
"ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num);
return ehca2ib_return_code(h_ret);
}
- ipz_queue_dtor(&my_cq->ipz_queue);
+ ipz_queue_dtor(NULL, &my_cq->ipz_queue);
kmem_cache_free(cq_cache, my_cq);
return 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c
index 4825975..1d41faa 100644
--- a/drivers/infiniband/hw/ehca/ehca_eq.c
+++ b/drivers/infiniband/hw/ehca/ehca_eq.c
@@ -86,8 +86,8 @@ int ehca_create_eq(struct ehca_shca *shca,
return -EINVAL;
}
- ret = ipz_queue_ctor(&eq->ipz_queue, nr_pages,
- EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0);
+ ret = ipz_queue_ctor(NULL, &eq->ipz_queue, nr_pages,
+ EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0, 0);
if (!ret) {
ehca_err(ib_dev, "Can't allocate EQ pages eq=%p", eq);
goto create_eq_exit1;
@@ -145,7 +145,7 @@ int ehca_create_eq(struct ehca_shca *shca,
return 0;
create_eq_exit2:
- ipz_queue_dtor(&eq->ipz_queue);
+ ipz_queue_dtor(NULL, &eq->ipz_queue);
create_eq_exit1:
hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
@@ -181,7 +181,7 @@ int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq)
ehca_err(&shca->ib_device, "Can't free EQ resources.");
return -EINVAL;
}
- ipz_queue_dtor(&eq->ipz_queue);
+ ipz_queue_dtor(NULL, &eq->ipz_queue);
return 0;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 3bd7afb..e09a2ae 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -181,6 +181,12 @@ static int ehca_create_slab_caches(void)
goto create_slab_caches5;
}
+ ret = ehca_init_small_qp_cache();
+ if (ret) {
+ ehca_gen_err("Cannot create small queue SLAB cache.");
+ goto create_slab_caches6;
+ }
+
#ifdef CONFIG_PPC_64K_PAGES
ctblk_cache = kmem_cache_create("ehca_cache_ctblk",
EHCA_PAGESIZE, H_CB_ALIGNMENT,
@@ -188,12 +194,15 @@ static int ehca_create_slab_caches(void)
NULL, NULL);
if (!ctblk_cache) {
ehca_gen_err("Cannot create ctblk SLAB cache.");
- ehca_cleanup_mrmw_cache();
- goto create_slab_caches5;
+ ehca_cleanup_small_qp_cache();
+ goto create_slab_caches6;
}
#endif
return 0;
+create_slab_caches6:
+ ehca_cleanup_mrmw_cache();
+
create_slab_caches5:
ehca_cleanup_av_cache();
@@ -211,6 +220,7 @@ create_slab_caches2:
static void ehca_destroy_slab_caches(void)
{
+ ehca_cleanup_small_qp_cache();
ehca_cleanup_mrmw_cache();
ehca_cleanup_av_cache();
ehca_cleanup_qp_cache();
diff --git a/drivers/infiniband/hw/ehca/ehca_pd.c b/drivers/infiniband/hw/ehca/ehca_pd.c
index 79d0591..79d5bc8 100644
--- a/drivers/infiniband/hw/ehca/ehca_pd.c
+++ b/drivers/infiniband/hw/ehca/ehca_pd.c
@@ -49,6 +49,7 @@ struct ib_pd *ehca_alloc_pd(struct ib_device *device,
struct ib_ucontext *context, struct ib_udata *udata)
{
struct ehca_pd *pd;
+ int i;
pd = kmem_cache_zalloc(pd_cache, GFP_KERNEL);
if (!pd) {
@@ -58,6 +59,11 @@ struct ib_pd *ehca_alloc_pd(struct ib_device *device,
}
pd->ownpid = current->tgid;
+ for (i = 0; i < 2; i++) {
+ INIT_LIST_HEAD(&pd->free[i]);
+ INIT_LIST_HEAD(&pd->full[i]);
+ }
+ mutex_init(&pd->lock);
/*
* Kernel PD: when device = -1, 0
@@ -81,6 +87,9 @@ int ehca_dealloc_pd(struct ib_pd *pd)
{
u32 cur_pid = current->tgid;
struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
+ int i, leftovers = 0;
+ extern struct kmem_cache *small_qp_cache;
+ struct ipz_small_queue_page *page, *tmp;
if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
my_pd->ownpid != cur_pid) {
@@ -89,8 +98,20 @@ int ehca_dealloc_pd(struct ib_pd *pd)
return -EINVAL;
}
- kmem_cache_free(pd_cache,
- container_of(pd, struct ehca_pd, ib_pd));
+ for (i = 0; i < 2; i++) {
+ list_splice(&my_pd->full[i], &my_pd->free[i]);
+ list_for_each_entry_safe(page, tmp, &my_pd->free[i], list) {
+ leftovers = 1;
+ free_page(page->page);
+ kmem_cache_free(small_qp_cache, page);
+ }
+ }
+
+ if (leftovers)
+ ehca_warn(pd->device,
+ "Some small queue pages were not freed");
+
+ kmem_cache_free(pd_cache, my_pd);
return 0;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index b916d9c..6c6f9d9 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -275,34 +275,39 @@ static inline void queue2resp(struct ipzu_queue_resp *resp,
resp->toggle_state = queue->toggle_state;
}
-static inline int ll_qp_msg_size(int nr_sge)
-{
- return 128 << nr_sge;
-}
-
/*
* init_qp_queue initializes/constructs r/squeue and registers queue pages.
*/
static inline int init_qp_queue(struct ehca_shca *shca,
+ struct ehca_pd *pd,
struct ehca_qp *my_qp,
struct ipz_queue *queue,
int q_type,
u64 expected_hret,
- int nr_q_pages,
- int wqe_size,
- int nr_sges)
+ struct ehca_alloc_queue_parms *parms,
+ int wqe_size)
{
- int ret, cnt, ipz_rc;
+ int ret, cnt, ipz_rc, nr_q_pages;
void *vpage;
u64 rpage, h_ret;
struct ib_device *ib_dev = &shca->ib_device;
struct ipz_adapter_handle ipz_hca_handle = shca->ipz_hca_handle;
- if (!nr_q_pages)
+ if (!parms->queue_size)
return 0;
- ipz_rc = ipz_queue_ctor(queue, nr_q_pages, EHCA_PAGESIZE,
- wqe_size, nr_sges);
+ if (parms->is_small) {
+ nr_q_pages = 1;
+ ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages,
+ 128 << parms->page_size,
+ wqe_size, parms->act_nr_sges, 1);
+ } else {
+ nr_q_pages = parms->queue_size;
+ ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages,
+ EHCA_PAGESIZE, wqe_size,
+ parms->act_nr_sges, 0);
+ }
+
if (!ipz_rc) {
ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%x",
ipz_rc);
@@ -323,7 +328,7 @@ static inline int init_qp_queue(struct ehca_shca *shca,
h_ret = hipz_h_register_rpage_qp(ipz_hca_handle,
my_qp->ipz_qp_handle,
NULL, 0, q_type,
- rpage, 1,
+ rpage, parms->is_small ? 0 : 1,
my_qp->galpas.kernel);
if (cnt == (nr_q_pages - 1)) { /* last page! */
if (h_ret != expected_hret) {
@@ -354,10 +359,45 @@ static inline int init_qp_queue(struct ehca_shca *shca,
return 0;
init_qp_queue1:
- ipz_queue_dtor(queue);
+ ipz_queue_dtor(pd, queue);
return ret;
}
+static inline int ehca_calc_wqe_size(int act_nr_sge, int is_llqp)
+{
+ if (is_llqp)
+ return 128 << act_nr_sge;
+ else
+ return offsetof(struct ehca_wqe,
+ u.nud.sg_list[act_nr_sge]);
+}
+
+static void ehca_determine_small_queue(struct ehca_alloc_queue_parms *queue,
+ int req_nr_sge, int is_llqp)
+{
+ u32 wqe_size, q_size;
+ int act_nr_sge = req_nr_sge;
+
+ if (!is_llqp)
+ /* round up #SGEs so WQE size is a power of 2 */
+ for (act_nr_sge = 4; act_nr_sge <= 252;
+ act_nr_sge = 4 + 2 * act_nr_sge)
+ if (act_nr_sge >= req_nr_sge)
+ break;
+
+ wqe_size = ehca_calc_wqe_size(act_nr_sge, is_llqp);
+ q_size = wqe_size * (queue->max_wr + 1);
+
+ if (q_size <= 512)
+ queue->page_size = 2;
+ else if (q_size <= 1024)
+ queue->page_size = 3;
+ else
+ queue->page_size = 0;
+
+ queue->is_small = (queue->page_size != 0);
+}
+
/*
* Create an ib_qp struct that is either a QP or an SRQ, depending on
* the value of the is_srq parameter. If init_attr and srq_init_attr share
@@ -553,10 +593,20 @@ static struct ehca_qp *internal_create_qp(
if (my_qp->recv_cq)
parms.recv_cq_handle = my_qp->recv_cq->ipz_cq_handle;
- parms.max_send_wr = init_attr->cap.max_send_wr;
- parms.max_recv_wr = init_attr->cap.max_recv_wr;
- parms.max_send_sge = max_send_sge;
- parms.max_recv_sge = max_recv_sge;
+ parms.squeue.max_wr = init_attr->cap.max_send_wr;
+ parms.rqueue.max_wr = init_attr->cap.max_recv_wr;
+ parms.squeue.max_sge = max_send_sge;
+ parms.rqueue.max_sge = max_recv_sge;
+
+ if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)
+ && !(context && udata)) { /* no small QP support in userspace ATM */
+ ehca_determine_small_queue(
+ &parms.squeue, max_send_sge, is_llqp);
+ ehca_determine_small_queue(
+ &parms.rqueue, max_recv_sge, is_llqp);
+ parms.qp_storage =
+ (parms.squeue.is_small || parms.rqueue.is_small);
+ }
h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms);
if (h_ret != H_SUCCESS) {
@@ -570,50 +620,33 @@ static struct ehca_qp *internal_create_qp(
my_qp->ipz_qp_handle = parms.qp_handle;
my_qp->galpas = parms.galpas;
+ swqe_size = ehca_calc_wqe_size(parms.squeue.act_nr_sges, is_llqp);
+ rwqe_size = ehca_calc_wqe_size(parms.rqueue.act_nr_sges, is_llqp);
+
switch (qp_type) {
case IB_QPT_RC:
- if (!is_llqp) {
- swqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
- (parms.act_nr_send_sges)]);
- rwqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
- (parms.act_nr_recv_sges)]);
- } else { /* for LLQP we need to use msg size, not wqe size */
- swqe_size = ll_qp_msg_size(max_send_sge);
- rwqe_size = ll_qp_msg_size(max_recv_sge);
- parms.act_nr_send_sges = 1;
- parms.act_nr_recv_sges = 1;
- }
- break;
- case IB_QPT_UC:
- swqe_size = offsetof(struct ehca_wqe,
- u.nud.sg_list[parms.act_nr_send_sges]);
- rwqe_size = offsetof(struct ehca_wqe,
- u.nud.sg_list[parms.act_nr_recv_sges]);
+ if (is_llqp) {
+ parms.squeue.act_nr_sges = 1;
+ parms.rqueue.act_nr_sges = 1;
+ }
break;
-
case IB_QPT_UD:
case IB_QPT_GSI:
case IB_QPT_SMI:
+ /* UD circumvention */
if (is_llqp) {
- swqe_size = ll_qp_msg_size(parms.act_nr_send_sges);
- rwqe_size = ll_qp_msg_size(parms.act_nr_recv_sges);
- parms.act_nr_send_sges = 1;
- parms.act_nr_recv_sges = 1;
+ parms.squeue.act_nr_sges = 1;
+ parms.rqueue.act_nr_sges = 1;
} else {
- /* UD circumvention */
- parms.act_nr_send_sges -= 2;
- parms.act_nr_recv_sges -= 2;
- swqe_size = offsetof(struct ehca_wqe, u.ud_av.sg_list[
- parms.act_nr_send_sges]);
- rwqe_size = offsetof(struct ehca_wqe, u.ud_av.sg_list[
- parms.act_nr_recv_sges]);
+ parms.squeue.act_nr_sges -= 2;
+ parms.rqueue.act_nr_sges -= 2;
}
if (IB_QPT_GSI == qp_type || IB_QPT_SMI == qp_type) {
- parms.act_nr_send_wqes = init_attr->cap.max_send_wr;
- parms.act_nr_recv_wqes = init_attr->cap.max_recv_wr;
- parms.act_nr_send_sges = init_attr->cap.max_send_sge;
- parms.act_nr_recv_sges = init_attr->cap.max_recv_sge;
+ parms.squeue.act_nr_wqes = init_attr->cap.max_send_wr;
+ parms.rqueue.act_nr_wqes = init_attr->cap.max_recv_wr;
+ parms.squeue.act_nr_sges = init_attr->cap.max_send_sge;
+ parms.rqueue.act_nr_sges = init_attr->cap.max_recv_sge;
ib_qp_num = (qp_type == IB_QPT_SMI) ? 0 : 1;
}
@@ -626,10 +659,9 @@ static struct ehca_qp *internal_create_qp(
/* initialize r/squeue and register queue pages */
if (HAS_SQ(my_qp)) {
ret = init_qp_queue(
- shca, my_qp, &my_qp->ipz_squeue, 0,
+ shca, my_pd, my_qp, &my_qp->ipz_squeue, 0,
HAS_RQ(my_qp) ? H_PAGE_REGISTERED : H_SUCCESS,
- parms.nr_sq_pages, swqe_size,
- parms.act_nr_send_sges);
+ &parms.squeue, swqe_size);
if (ret) {
ehca_err(pd->device, "Couldn't initialize squeue "
"and pages ret=%x", ret);
@@ -639,9 +671,8 @@ static struct ehca_qp *internal_create_qp(
if (HAS_RQ(my_qp)) {
ret = init_qp_queue(
- shca, my_qp, &my_qp->ipz_rqueue, 1,
- H_SUCCESS, parms.nr_rq_pages, rwqe_size,
- parms.act_nr_recv_sges);
+ shca, my_pd, my_qp, &my_qp->ipz_rqueue, 1,
+ H_SUCCESS, &parms.rqueue, rwqe_size);
if (ret) {
ehca_err(pd->device, "Couldn't initialize rqueue "
"and pages ret=%x", ret);
@@ -671,10 +702,10 @@ static struct ehca_qp *internal_create_qp(
}
init_attr->cap.max_inline_data = 0; /* not supported yet */
- init_attr->cap.max_recv_sge = parms.act_nr_recv_sges;
- init_attr->cap.max_recv_wr = parms.act_nr_recv_wqes;
- init_attr->cap.max_send_sge = parms.act_nr_send_sges;
- init_attr->cap.max_send_wr = parms.act_nr_send_wqes;
+ init_attr->cap.max_recv_sge = parms.rqueue.act_nr_sges;
+ init_attr->cap.max_recv_wr = parms.rqueue.act_nr_wqes;
+ init_attr->cap.max_send_sge = parms.squeue.act_nr_sges;
+ init_attr->cap.max_send_wr = parms.squeue.act_nr_wqes;
my_qp->init_attr = *init_attr;
/* NOTE: define_apq0() not supported yet */
@@ -708,6 +739,8 @@ static struct ehca_qp *internal_create_qp(
resp.ext_type = my_qp->ext_type;
resp.qkey = my_qp->qkey;
resp.real_qp_num = my_qp->real_qp_num;
+ resp.ipz_rqueue.offset = my_qp->ipz_rqueue.offset;
+ resp.ipz_squeue.offset = my_qp->ipz_squeue.offset;
if (HAS_SQ(my_qp))
queue2resp(&resp.ipz_squeue, &my_qp->ipz_squeue);
if (HAS_RQ(my_qp))
@@ -724,11 +757,11 @@ static struct ehca_qp *internal_create_qp(
create_qp_exit4:
if (HAS_RQ(my_qp))
- ipz_queue_dtor(&my_qp->ipz_rqueue);
+ ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
create_qp_exit3:
if (HAS_SQ(my_qp))
- ipz_queue_dtor(&my_qp->ipz_squeue);
+ ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
create_qp_exit2:
hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
@@ -1735,9 +1768,9 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
}
if (HAS_RQ(my_qp))
- ipz_queue_dtor(&my_qp->ipz_rqueue);
+ ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
if (HAS_SQ(my_qp))
- ipz_queue_dtor(&my_qp->ipz_squeue);
+ ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
kmem_cache_free(qp_cache, my_qp);
return 0;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
index 05c4157..4bc687f 100644
--- a/drivers/infiniband/hw/ehca/ehca_uverbs.c
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -149,7 +149,7 @@ static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue,
ehca_gen_err("vm_insert_page() failed rc=%x", ret);
return ret;
}
- start += PAGE_SIZE;
+ start += PAGE_SIZE;
}
vma->vm_private_data = mm_count;
(*mm_count)++;
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c
index 358796c..fdbfebe 100644
--- a/drivers/infiniband/hw/ehca/hcp_if.c
+++ b/drivers/infiniband/hw/ehca/hcp_if.c
@@ -52,10 +52,13 @@
#define H_ALL_RES_QP_ENHANCED_OPS EHCA_BMASK_IBM(9, 11)
#define H_ALL_RES_QP_PTE_PIN EHCA_BMASK_IBM(12, 12)
#define H_ALL_RES_QP_SERVICE_TYPE EHCA_BMASK_IBM(13, 15)
+#define H_ALL_RES_QP_STORAGE EHCA_BMASK_IBM(16, 17)
#define H_ALL_RES_QP_LL_RQ_CQE_POSTING EHCA_BMASK_IBM(18, 18)
#define H_ALL_RES_QP_LL_SQ_CQE_POSTING EHCA_BMASK_IBM(19, 21)
#define H_ALL_RES_QP_SIGNALING_TYPE EHCA_BMASK_IBM(22, 23)
#define H_ALL_RES_QP_UD_AV_LKEY_CTRL EHCA_BMASK_IBM(31, 31)
+#define H_ALL_RES_QP_SMALL_SQ_PAGE_SIZE EHCA_BMASK_IBM(32, 35)
+#define H_ALL_RES_QP_SMALL_RQ_PAGE_SIZE EHCA_BMASK_IBM(36, 39)
#define H_ALL_RES_QP_RESOURCE_TYPE EHCA_BMASK_IBM(56, 63)
#define H_ALL_RES_QP_MAX_OUTST_SEND_WR EHCA_BMASK_IBM(0, 15)
@@ -299,6 +302,11 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
| EHCA_BMASK_SET(H_ALL_RES_QP_PTE_PIN, 0)
| EHCA_BMASK_SET(H_ALL_RES_QP_SERVICE_TYPE, parms->servicetype)
| EHCA_BMASK_SET(H_ALL_RES_QP_SIGNALING_TYPE, parms->sigtype)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_STORAGE, parms->qp_storage)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_SMALL_SQ_PAGE_SIZE,
+ parms->squeue.page_size)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_SMALL_RQ_PAGE_SIZE,
+ parms->rqueue.page_size)
| EHCA_BMASK_SET(H_ALL_RES_QP_LL_RQ_CQE_POSTING,
!!(parms->ll_comp_flags & LLQP_RECV_COMP))
| EHCA_BMASK_SET(H_ALL_RES_QP_LL_SQ_CQE_POSTING,
@@ -309,13 +317,13 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
max_r10_reg =
EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_SEND_WR,
- parms->max_send_wr + 1)
+ parms->squeue.max_wr + 1)
| EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_RECV_WR,
- parms->max_recv_wr + 1)
+ parms->rqueue.max_wr + 1)
| EHCA_BMASK_SET(H_ALL_RES_QP_MAX_SEND_SGE,
- parms->max_send_sge)
+ parms->squeue.max_sge)
| EHCA_BMASK_SET(H_ALL_RES_QP_MAX_RECV_SGE,
- parms->max_recv_sge);
+ parms->rqueue.max_sge);
r11 = EHCA_BMASK_SET(H_ALL_RES_QP_SRQ_QP_TOKEN, parms->srq_token);
@@ -335,17 +343,17 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
parms->qp_handle.handle = outs[0];
parms->real_qp_num = (u32)outs[1];
- parms->act_nr_send_wqes =
+ parms->squeue.act_nr_wqes =
(u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_SEND_WR, outs[2]);
- parms->act_nr_recv_wqes =
+ parms->rqueue.act_nr_wqes =
(u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_RECV_WR, outs[2]);
- parms->act_nr_send_sges =
+ parms->squeue.act_nr_sges =
(u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_SEND_SGE, outs[3]);
- parms->act_nr_recv_sges =
+ parms->rqueue.act_nr_sges =
(u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_RECV_SGE, outs[3]);
- parms->nr_sq_pages =
+ parms->squeue.queue_size =
(u32)EHCA_BMASK_GET(H_ALL_RES_QP_SQUEUE_SIZE_PAGES, outs[4]);
- parms->nr_rq_pages =
+ parms->rqueue.queue_size =
(u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]);
if (ret == H_SUCCESS)
@@ -497,7 +505,7 @@ u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
const u64 count,
const struct h_galpa galpa)
{
- if (count != 1) {
+ if (count > 1) {
ehca_gen_err("Page counter=%lx", count);
return H_PARAMETER;
}
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
index 9606f13..6506501 100644
--- a/drivers/infiniband/hw/ehca/ipz_pt_fn.c
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
@@ -40,6 +40,11 @@
#include "ehca_tools.h"
#include "ipz_pt_fn.h"
+#include "ehca_classes.h"
+
+#define PAGES_PER_KPAGE (PAGE_SIZE >> EHCA_PAGESHIFT)
+
+struct kmem_cache *small_qp_cache;
void *ipz_qpageit_get_inc(struct ipz_queue *queue)
{
@@ -49,7 +54,7 @@ void *ipz_qpageit_get_inc(struct ipz_queue *queue)
queue->current_q_offset -= queue->pagesize;
ret = NULL;
}
- if (((u64)ret) % EHCA_PAGESIZE) {
+ if (((u64)ret) % queue->pagesize) {
ehca_gen_err("ERROR!! not at PAGE-Boundary");
return NULL;
}
@@ -83,80 +88,195 @@ int ipz_queue_abs_to_offset(struct ipz_queue *queue, u64 addr, u64 *q_offset)
return -EINVAL;
}
-int ipz_queue_ctor(struct ipz_queue *queue,
- const u32 nr_of_pages,
- const u32 pagesize, const u32 qe_size, const u32 nr_of_sg)
+#if PAGE_SHIFT < EHCA_PAGESHIFT
+#error Kernel pages must be at least as large than eHCA pages (4K) !
+#endif
+
+/*
+ * allocate pages for queue:
+ * outer loop allocates whole kernel pages (page aligned) and
+ * inner loop divides a kernel page into smaller hca queue pages
+ */
+static int alloc_queue_pages(struct ipz_queue *queue, const u32 nr_of_pages)
{
- int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT;
- int f;
+ int k, f = 0;
+ u8 *kpage;
- if (pagesize > PAGE_SIZE) {
- ehca_gen_err("FATAL ERROR: pagesize=%x is greater "
- "than kernel page size", pagesize);
- return 0;
- }
- if (!pages_per_kpage) {
- ehca_gen_err("FATAL ERROR: invalid kernel page size. "
- "pages_per_kpage=%x", pages_per_kpage);
- return 0;
- }
- queue->queue_length = nr_of_pages * pagesize;
- queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
- if (!queue->queue_pages) {
- ehca_gen_err("ERROR!! didn't get the memory");
- return 0;
- }
- memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
- /*
- * allocate pages for queue:
- * outer loop allocates whole kernel pages (page aligned) and
- * inner loop divides a kernel page into smaller hca queue pages
- */
- f = 0;
while (f < nr_of_pages) {
- u8 *kpage = (u8 *)get_zeroed_page(GFP_KERNEL);
- int k;
+ kpage = (u8 *)get_zeroed_page(GFP_KERNEL);
if (!kpage)
- goto ipz_queue_ctor_exit0; /*NOMEM*/
- for (k = 0; k < pages_per_kpage && f < nr_of_pages; k++) {
- (queue->queue_pages)[f] = (struct ipz_page *)kpage;
+ goto out;
+
+ for (k = 0; k < PAGES_PER_KPAGE && f < nr_of_pages; k++) {
+ queue->queue_pages[f] = (struct ipz_page *)kpage;
kpage += EHCA_PAGESIZE;
f++;
}
}
+ return 1;
- queue->current_q_offset = 0;
+out:
+ for (f = 0; f < nr_of_pages && queue->queue_pages[f];
+ f += PAGES_PER_KPAGE)
+ free_page((unsigned long)(queue->queue_pages)[f]);
+ return 0;
+}
+
+static int alloc_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd)
+{
+ int order = ilog2(queue->pagesize) - 9;
+ struct ipz_small_queue_page *page;
+ unsigned long bit;
+
+ mutex_lock(&pd->lock);
+
+ if (!list_empty(&pd->free[order]))
+ page = list_entry(pd->free[order].next,
+ struct ipz_small_queue_page, list);
+ else {
+ page = kmem_cache_zalloc(small_qp_cache, GFP_KERNEL);
+ if (!page)
+ goto out;
+
+ page->page = get_zeroed_page(GFP_KERNEL);
+ if (!page->page) {
+ kmem_cache_free(small_qp_cache, page);
+ goto out;
+ }
+
+ list_add(&page->list, &pd->free[order]);
+ }
+
+ bit = find_first_zero_bit(page->bitmap, IPZ_SPAGE_PER_KPAGE >> order);
+ __set_bit(bit, page->bitmap);
+ page->fill++;
+
+ if (page->fill == IPZ_SPAGE_PER_KPAGE >> order)
+ list_move(&page->list, &pd->full[order]);
+
+ mutex_unlock(&pd->lock);
+
+ queue->queue_pages[0] = (void *)(page->page | (bit << (order + 9)));
+ queue->small_page = page;
+ return 1;
+
+out:
+ ehca_err(pd->ib_pd.device, "failed to allocate small queue page");
+ return 0;
+}
+
+static void free_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd)
+{
+ int order = ilog2(queue->pagesize) - 9;
+ struct ipz_small_queue_page *page = queue->small_page;
+ unsigned long bit;
+ int free_page = 0;
+
+ bit = ((unsigned long)queue->queue_pages[0] & PAGE_MASK)
+ >> (order + 9);
+
+ mutex_lock(&pd->lock);
+
+ __clear_bit(bit, page->bitmap);
+ page->fill--;
+
+ if (page->fill == 0) {
+ list_del(&page->list);
+ free_page = 1;
+ }
+
+ if (page->fill == (IPZ_SPAGE_PER_KPAGE >> order) - 1)
+ /* the page was full until we freed the chunk */
+ list_move_tail(&page->list, &pd->free[order]);
+
+ mutex_unlock(&pd->lock);
+
+ if (free_page) {
+ free_page(page->page);
+ kmem_cache_free(small_qp_cache, page);
+ }
+}
+
+int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue,
+ const u32 nr_of_pages, const u32 pagesize,
+ const u32 qe_size, const u32 nr_of_sg,
+ int is_small)
+{
+ if (pagesize > PAGE_SIZE) {
+ ehca_gen_err("FATAL ERROR: pagesize=%x "
+ "is greater than kernel page size", pagesize);
+ return 0;
+ }
+
+ /* init queue fields */
+ queue->queue_length = nr_of_pages * pagesize;
+ queue->pagesize = pagesize;
queue->qe_size = qe_size;
queue->act_nr_of_sg = nr_of_sg;
- queue->pagesize = pagesize;
+ queue->current_q_offset = 0;
queue->toggle_state = 1;
- return 1;
+ queue->small_page = NULL;
- ipz_queue_ctor_exit0:
- ehca_gen_err("Couldn't get alloc pages queue=%p f=%x nr_of_pages=%x",
- queue, f, nr_of_pages);
- for (f = 0; f < nr_of_pages; f += pages_per_kpage) {
- if (!(queue->queue_pages)[f])
- break;
- free_page((unsigned long)(queue->queue_pages)[f]);
+ /* allocate queue page pointers */
+ queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
+ if (!queue->queue_pages) {
+ ehca_gen_err("Couldn't allocate queue page list");
+ return 0;
}
+ memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
+
+ /* allocate actual queue pages */
+ if (is_small) {
+ if (!alloc_small_queue_page(queue, pd))
+ goto ipz_queue_ctor_exit0;
+ } else
+ if (!alloc_queue_pages(queue, nr_of_pages))
+ goto ipz_queue_ctor_exit0;
+
+ return 1;
+
+ipz_queue_ctor_exit0:
+ ehca_gen_err("Couldn't alloc pages queue=%p "
+ "nr_of_pages=%x", queue, nr_of_pages);
+ vfree(queue->queue_pages);
+
return 0;
}
-int ipz_queue_dtor(struct ipz_queue *queue)
+int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue)
{
- int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT;
- int g;
- int nr_pages;
+ int i, nr_pages;
if (!queue || !queue->queue_pages) {
ehca_gen_dbg("queue or queue_pages is NULL");
return 0;
}
- nr_pages = queue->queue_length / queue->pagesize;
- for (g = 0; g < nr_pages; g += pages_per_kpage)
- free_page((unsigned long)(queue->queue_pages)[g]);
+
+ if (queue->small_page)
+ free_small_queue_page(queue, pd);
+ else {
+ nr_pages = queue->queue_length / queue->pagesize;
+ for (i = 0; i < nr_pages; i += PAGES_PER_KPAGE)
+ free_page((unsigned long)queue->queue_pages[i]);
+ }
+
vfree(queue->queue_pages);
return 1;
}
+
+int ehca_init_small_qp_cache(void)
+{
+ small_qp_cache = kmem_cache_create("ehca_cache_small_qp",
+ sizeof(struct ipz_small_queue_page),
+ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (!small_qp_cache)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void ehca_cleanup_small_qp_cache(void)
+{
+ kmem_cache_destroy(small_qp_cache);
+}
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
index 39a4f64..c6937a0 100644
--- a/drivers/infiniband/hw/ehca/ipz_pt_fn.h
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
@@ -51,11 +51,25 @@
#include "ehca_tools.h"
#include "ehca_qes.h"
+struct ehca_pd;
+struct ipz_small_queue_page;
+
/* struct generic ehca page */
struct ipz_page {
u8 entries[EHCA_PAGESIZE];
};
+#define IPZ_SPAGE_PER_KPAGE (PAGE_SIZE / 512)
+
+struct ipz_small_queue_page {
+ unsigned long page;
+ unsigned long bitmap[IPZ_SPAGE_PER_KPAGE / BITS_PER_LONG];
+ int fill;
+ void *mapped_addr;
+ u32 mmap_count;
+ struct list_head list;
+};
+
/* struct generic queue in linux kernel virtual memory (kv) */
struct ipz_queue {
u64 current_q_offset; /* current queue entry */
@@ -66,7 +80,8 @@ struct ipz_queue {
u32 queue_length; /* queue length allocated in bytes */
u32 pagesize;
u32 toggle_state; /* toggle flag - per page */
- u32 dummy3; /* 64 bit alignment */
+ u32 offset; /* save offset within page for small_qp */
+ struct ipz_small_queue_page *small_page;
};
/*
@@ -188,9 +203,10 @@ struct ipz_qpt {
* see ipz_qpt_ctor()
* returns true if ok, false if out of memory
*/
-int ipz_queue_ctor(struct ipz_queue *queue, const u32 nr_of_pages,
- const u32 pagesize, const u32 qe_size,
- const u32 nr_of_sg);
+int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue,
+ const u32 nr_of_pages, const u32 pagesize,
+ const u32 qe_size, const u32 nr_of_sg,
+ int is_small);
/*
* destructor for a ipz_queue_t
@@ -198,7 +214,7 @@ int ipz_queue_ctor(struct ipz_queue *queue, const u32 nr_of_pages,
* see ipz_queue_ctor()
* returns true if ok, false if queue was NULL-ptr of free failed
*/
-int ipz_queue_dtor(struct ipz_queue *queue);
+int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue);
/*
* constructor for a ipz_qpt_t,
--
1.5.2
^ permalink raw reply related
* Interrupts on xilinx ml403
From: Mirek23 @ 2007-07-20 13:52 UTC (permalink / raw)
To: linuxppc-embedded
Dear All,
I use linux kernel 2.6 on ppc405 of my Avnet (xilinx like ml403)
evaluation board.
I have setup the virtex-4 FPGA to deal with Themac and Serial interfaces. As
input/output devices I have chosen 8 LEDs and DIP Switches.
With such a configuration I am able to control from Linux user applications
via GPIO driver the LEDs and DIP Switches.
Right now I just wanted to make use of the interrupts. I have configured the
Dip switches to use interrupt. The interrupt accoures when the DIP Switches
state has changed.
In the BSP generated by EDK 9.1 I see that macro :
#define XPAR_DIP_SWITCHES_8BIT_INTERRUPT_PRESENT 1
has changed from zero to one.
The macro XPAR_INTC_MAX_NUM_INTR_INPUTS is set to 1 as it was before. This
is due to the fact that
TEMAC uses one interrupt line.
Does it mean that DIP Switches do not use INTC interrupt controller?
How to handle the DIP Switches interrupt?
Does the Interrupt handler routine have to acknowledge the interrupt from
Dip Switches?
Many thanks in advance for any hint on that.
Best Regards
Mirek
--
View this message in context: http://www.nabble.com/Interrupts-on-xilinx-ml403-tf4117226.html#a11708607
Sent from the linuxppc-embedded mailing list archive at Nabble.com.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox