LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: Take 2: [RFC] Debugging with a HW probe.
From: Milton Miller @ 2006-08-22  6:04 UTC (permalink / raw)
  To: Jimi Xenidis; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <E1G9jpY-0004Nv-2d@kmac.watson.ibm.com>


On Aug 14, 2006, at 5:16 AM, Jimi Xenidis jimix at watson.ibm.com  
wrote:

> A rework of the original patch, some on and off list comments had
> suggested that this be a generic service, and to make it very hard
> to unintentionally turn it on.  I fact we should make sure that the
> feature is indeed turned off.
>
> Any suggestions on how to operate on the HID bits of all CPUs based on
> the value of the config _and_ 'hw_probe_enabled' would be welcom.
>
> I'd also like to wait for Olof's:
>   http://ozlabs.org/pipermail/linuxppc-dev/2006-August/025024.html
> patch to make it to the tree (or not).
>
> Signed-off-by: Jimi Xenidis <jimix at watson.ibm.com>

[sorry for the list archive patch munging]

> ---
> diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
> index e29ef77..bc4cdf9 100644
> --- a/arch/powerpc/Kconfig.debug
> +++ b/arch/powerpc/Kconfig.debug
> @@ -61,6 +61,17 @@ config KGDB_CONSOLE
>           over the gdb stub.
>           If unsure, say N.
>
> +config ENABLE_HW_PROBE
> +       bool "Allow instructions that contact a hardware probe 
> (dangerous)"
> +       depends on PPC64

Not having this depend on DEBUGGER but in the middle of things that do 
will
get you scorn from the auto-indenting police.

Since we can only call this from xmon, should it depend on XMON (and be
placed after that)?

> +       help
> +         If you enable this AND you add "hwprobe" to the cmdline, the
> +         processor will enable instructions that contact the hardware
> +         probe.  These instructions ca be used in all processor modes

can

> +         _including_ user mode and are only useful for kernel

not sure this _highlighting_ is used elsewhere in Kconfig help ...

Should we mention that a hardware probe is required to continue 
exectuion?
In other words, its not just contact, but signal and wait for a hw 
probe?

> +         development and debugging.  DO NOT enable this unless you
> +         plan to use it.
> +
>  config XMON
>         bool "Include xmon kernel debugger"
>         depends on DEBUGGER && !PPC_ISERIES
> diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
> index bf2005b..02c5b83 100644
> --- a/arch/powerpc/kernel/prom.c
> +++ b/arch/powerpc/kernel/prom.c
> @@ -68,6 +68,9 @@ int __initdata iommu_is_off;
>  int __initdata iommu_force_on;
>  unsigned long tce_alloc_start, tce_alloc_end;
>  #endif
> +#ifdef CONFIG_ENABLE_HW_PROBE
> +int hw_probe_enabled;
> +#endif
>
>  typedef u32 cell_t;
>
> @@ -693,6 +696,11 @@ #ifdef CONFIG_PPC64
>         if (of_get_flat_dt_prop(node, "linux,iommu-force-on", NULL) != 
> NULL)
>                 iommu_force_on = 1;
>  #endif
> +#ifdef CONFIG_HW_PROBE_ENABLE
> +       if (of_get_flat_dt_prop(node, "linux,hw-probe-enable", NULL) 
> != NULL) {
> +               hw_probe_enabled = 1;
> +               DBG("HW Probe will be enabled\n");
> +#endif

No.  [see next comment]

>
>         /* mem=x on the command line is the preferred mechanism */
>         lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL);
> diff --git a/arch/powerpc/kernel/prom_init.c 
> b/arch/powerpc/kernel/prom_init.c
> index 90972ef..26428de 100644
> --- a/arch/powerpc/kernel/prom_init.c
> +++ b/arch/powerpc/kernel/prom_init.c
> @@ -587,6 +587,14 @@ #ifdef CONFIG_PPC64
>                         RELOC(iommu_force_on) = 1;
>         }
>  #endif
> +#ifdef CONFIG_HW_PROBE_ENABLE
> +       opt = strstr(RELOC(prom_cmd_line), RELOC("hwprobe"));
> +       if (opt) {
> +               prom_printf("WARNING! HW Probe will be activated!\n");
> +               prom_setprop(_prom->chosen, "/chosen",
> +                            "linux,hw-probe-enable", NULL, 0);
> +       }
> +#endif
>  }

Please, PLEASE do NOT do this.

prom_init.c is only used by one of the many flat device tree generators,
namely the open-firmware client.  Adding a property like this requires 
us
to update all the other clients.

And there is no reason to parse it this early.

Instead, parse it from the command line like the other early parsing.

I thing a generic early_param would be fine.  However, xmon_init is an
early_parm in setup-common, so if you really require it before the first
call, then you could parse it next to mem= at the bottom of
early_init_dt_scan_chosen.

Which .h is hw_probe_enabled in?  (none?)

>
>  #ifdef CONFIG_PPC_PSERIES
> diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
> index 179b10c..51a1e4e 100644
> --- a/arch/powerpc/xmon/xmon.c
> +++ b/arch/powerpc/xmon/xmon.c
> @@ -189,7 +189,12 @@ #endif
>    dd   dump double values\n\
>    dr   dump stream of raw bytes\n\
>    e    print exception information\n\
> -  f    flush cache\n\
> +  f    flush cache\n"
> +#ifdef CONFIG_ENABLE_HW_PROBE
> +  "\
> +  H     Contact hardware probe, if available\n"
> +#endif
> +  "\

While this style does keep the lines aligned in the source, it adds 
veritcal
almost-whitespace.  And I notice a different choice was made at the 
bottom.

>    la   lookup symbol+offset of specified address\n\
>    ls   lookup address of specified symbol\n\
>    m    examine/change memory\n\
> @@ -217,6 +222,18 @@ #endif
>    zh   halt\n"
>  ;
>
> +#ifdef CONFIG_ENABLE_HW_PROBE
> +/* try to keep this funtion from being inlined so its easier to move
> + * around the ATTN instruction */
> +extern int hw_probe_enabled;
> +static noinline void xmon_hw_probe(void)
> +{
> +       if (!hw_probe_enabled)
> +               return;
> +       ATTN();
> +}
> +#endif
> +
>  static struct pt_regs *xmon_regs;
>
>  static inline void sync(void)
> @@ -819,6 +836,11 @@ #endif /* CONFIG_SMP */
>                         if (cpu_cmd())
>                                 return 0;
>                         break;
> +#ifdef CONFIG_ENABLE_HW_PROBE
> +               case 'H':
> +                       xmon_hw_probe();
> +                       break;
> +#endif
>                 case 'z':
>                         bootcmds();
>                         break;
> diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
> index cf73475..478097e 100644
> --- a/include/asm-powerpc/reg.h
> +++ b/include/asm-powerpc/reg.h
> @@ -207,6 +207,13 @@ #define SPRN_EAR   0x11A           /* External 
> Addr
>  #define SPRN_HASH1     0x3D2           /* Primary Hash Address 
> Register */
>  #define SPRN_HASH2     0x3D3           /* Secondary Hash Address 
> Resgister */
>  #define SPRN_HID0      0x3F0           /* Hardware Implementation 
> Register 0 */
> +#ifdef __ASSEMBLY__
> +#define HID0_QATTN     (1<<35)         /* Sup. Proc. attn insn all 
> threads */
> +#define HID0_ATTN      (1<<32)         /* Sup. Proc. attn insn */
> +#else
> +#define HID0_QATTN     (1UL<<35)       /* Sup. Proc. attn insn all 
> threads */
> +#define HID0_ATTN      (1UL<<32)       /* Sup. Proc. attn insn */
> +#endif
>  #define HID0_EMCP      (1<<31)         /* Enable Machine Check pin */
>  #define HID0_EBA       (1<<29)         /* Enable Bus Address Parity */
>  #define HID0_EBD       (1<<28)         /* Enable Bus Data Parity */
> @@ -641,6 +648,13 @@ extern void ppc64_runlatch_off(void);
>  extern unsigned long scom970_read(unsigned int address);
>  extern void scom970_write(unsigned int address, unsigned long value);
>
> +/*
> + * Support Processor Attention Instruction instroduced in POWER
> + * architecture processors as of RS64, tho may not be supported by
> + * POWER 3.
> + */
> +#define ATTN() asm volatile("attn; nop")
> +


Fairly certian POWER3 does NOT implement this, but I don't have book IV 
handy.
Does one of the processors require the nop ?



>  #else
>  #define ppc64_runlatch_on()
>  #define ppc64_runlatch_off()
>

milton

^ permalink raw reply

* Re: Take 2: [RFC] Debugging with a HW probe.
From: Michael Ellerman @ 2006-08-22  7:13 UTC (permalink / raw)
  To: Milton Miller; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <aa3478a76dd7fb5bff781350a7538fb0@bga.com>

[-- Attachment #1: Type: text/plain, Size: 2684 bytes --]

On Tue, 2006-08-22 at 01:04 -0500, Milton Miller wrote:
> On Aug 14, 2006, at 5:16 AM, Jimi Xenidis jimix at watson.ibm.com  
> > @@ -693,6 +696,11 @@ #ifdef CONFIG_PPC64
> >         if (of_get_flat_dt_prop(node, "linux,iommu-force-on", NULL) != 
> > NULL)
> >                 iommu_force_on = 1;
> >  #endif
> > +#ifdef CONFIG_HW_PROBE_ENABLE
> > +       if (of_get_flat_dt_prop(node, "linux,hw-probe-enable", NULL) 
> > != NULL) {
> > +               hw_probe_enabled = 1;
> > +               DBG("HW Probe will be enabled\n");
> > +#endif
> 
> No.  [see next comment]
> 
> >
> >         /* mem=x on the command line is the preferred mechanism */
> >         lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL);
> > diff --git a/arch/powerpc/kernel/prom_init.c 
> > b/arch/powerpc/kernel/prom_init.c
> > index 90972ef..26428de 100644
> > --- a/arch/powerpc/kernel/prom_init.c
> > +++ b/arch/powerpc/kernel/prom_init.c
> > @@ -587,6 +587,14 @@ #ifdef CONFIG_PPC64
> >                         RELOC(iommu_force_on) = 1;
> >         }
> >  #endif
> > +#ifdef CONFIG_HW_PROBE_ENABLE
> > +       opt = strstr(RELOC(prom_cmd_line), RELOC("hwprobe"));
> > +       if (opt) {
> > +               prom_printf("WARNING! HW Probe will be activated!\n");
> > +               prom_setprop(_prom->chosen, "/chosen",
> > +                            "linux,hw-probe-enable", NULL, 0);
> > +       }
> > +#endif
> >  }
> 
> Please, PLEASE do NOT do this.
> 
> prom_init.c is only used by one of the many flat device tree generators,
> namely the open-firmware client.  Adding a property like this requires 
> us
> to update all the other clients.
> 
> And there is no reason to parse it this early.
> 
> Instead, parse it from the command line like the other early parsing.
> 
> I thing a generic early_param would be fine.  However, xmon_init is an
> early_parm in setup-common, so if you really require it before the first
> call, then you could parse it next to mem= at the bottom of
> early_init_dt_scan_chosen.

What Milton said, we learnt that the hard way with kexec :)

Except that we don't do mem= in early_init_dt_scan_chosen anymore (get a
newer kernel Milton!).

The early_param parsing is done very early, and the xmon= parsing does
not jump into xmon, it waits until a little later before doing it. So an
early_param should be fine, ie. it will be parsed before xmon ever runs.

cheers

-- 
Michael Ellerman
IBM OzLabs

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

* Re: [PATCH 2/2] uninorth: Add module param 'aperture' for aperture size
From: Benjamin Herrenschmidt @ 2006-08-22  7:25 UTC (permalink / raw)
  To: Michel Dänzer; +Cc: linuxppc-dev
In-Reply-To: <1156176559.16513.78.camel@thor.lorrainebruecke.local>

On Mon, 2006-08-21 at 18:09 +0200, Michel Dänzer wrote:

> In contrast to most if not all PC BIOSes, OpenFirmware (OF) on PowerMacs with
> UniNorth bridges does not allow changing the aperture size. The size set up by
> OF is usually 16 MB, which is too low for graphics intensive environments.
> Hence, add a module parameter that allows changing the aperture size at driver
> initialization time. When the parameter is not specified, the default is still
> to leave the size unchanged, usually as set up by OF.

The right fix is to allow changing it by the driver ... can't we do it
such that AGPSize will work & change it ? The firmware doesn't actually
configure it at all I suspect... those 16M are basically 
what the HW comes up with as a default setting (unless the firmware runs
some diagnostics and sets it as a result of these). It's basically
expected that we set it ourselves and a module option doesn't seem like
a terribly good idea to me...

Maybe we should just have the driver default to something more sensible
in addition to what AGPSize comes from userland ? like 64M ?

Ben.

^ permalink raw reply

* ioremap() fails for >64 MB
From: Phil Nitschke @ 2006-08-22  7:41 UTC (permalink / raw)
  To: linuxppc-embedded

Hi all,

I have 2 GB memory on a 7448 processor, and want to reserve a huge chunk
of it at boot-time, then ioremap() it into the kernel space inside a
device driver.  So far I've succeeded with 64 MB, but can't go any
higher, as mm/vmalloc.c tells me: "allocation failed: out of vmalloc
space - use vmalloc=<size> to increase size."

So I tried adding a vmalloc line to the kernel command line as follows:
Kernel cmd line: root=/dev/nfs rw mem=1920M vmalloc=1024M nfsroot=... 

After booting the processor, here is my memory arrangement:

bash-3.00# cat /proc/meminfo 
MemTotal:      1943232 kB
MemFree:       1910508 kB
...
HighTotal:     1179648 kB
HighFree:      1154608 kB
LowTotal:       763584 kB
LowFree:        755900 kB
...
VmallocTotal:   145024 kB
VmallocUsed:     65944 kB
VmallocChunk:    78972 kB

After inserting my device driver module (which ioremap()s 64 MB),
meminfo is as follows:

bash-3.00# cat /proc/meminfo 
MemTotal:      1943232 kB
MemFree:       1916512 kB
...
HighTotal:     1179648 kB
HighFree:      1160748 kB
LowTotal:       763584 kB
LowFree:        755764 kB
...
VmallocTotal:   145024 kB
VmallocUsed:    133568 kB
VmallocChunk:    10364 kB

So the vmalloc=<size> argument has made no difference.  What do I need
to do to make this work?

TIA,

-- 
Phil

bash-3.00# uname -a
Linux arty9 2.6.16-pmppc744x #211 Fri Aug 18 19:03:36 CST 2006 ppc ppc
ppc GNU/Linux

^ permalink raw reply

* Re: [PATCH 0/6] Sizing zones and holes in an architecture independent manner V9
From: Mel Gorman @ 2006-08-22  8:38 UTC (permalink / raw)
  To: Keith Mannthey
  Cc: akpm, tony.luck, linuxppc-dev, ak, bob.picco,
	Linux Kernel Mailing List, Linux Memory Management List
In-Reply-To: <a762e240608211152x5d4f11f0wd26f7e3d75d38e0a@mail.gmail.com>

On Mon, 21 Aug 2006, Keith Mannthey wrote:

> On 8/21/06, Mel Gorman <mel@csn.ul.ie> wrote:
>> This is V9 of the patchset to size zones and memory holes in an
>> architecture-independent manner. It booted successfully on 5 different
>> machines (arches were x86, x86_64, ppc64 and ia64) in a number of different
>> configurations and successfully built a kernel. If it fails on any machine,
>> booting with loglevel=8 and the console log should tell me what went wrong.
>> 
>
> I am wondering why this new api didn't cleanup the pfn_to_nid code
> path as well. Arches are left to still keep another set of
> nid-start-end info around. We are sending info like
>

pfn_to_nid() is used at runtime and the early_node_map[] is deleted by 
then. As this step, I only want to get the initialisation correct. What 
can be replaced is the architecture-specific early_pfn_to_nid() function 
which I did for power and x86.

> add_active_range(unsigned int nid, unsigned long start_pfn, unsigned
> long end_pfn)
>
> With this info making a common pnf_to_nid seems to be of intrest so we
> don't have to keep redundant information in both generic and arch
> specific data structures.
>

To implement a common one of interest, the array would have to be 
converted to a linked list at the end of boot so it could be modified by 
memory hot-add, then pfn_to_nid() would walk the linked list rather than 
the existing array. pfn_valid() would probably be replaced as well. 
However, this is going to be slower (if more accurate in some cases) than 
the existing pfn_valid() and so I would treat it as a separate issue.

> Are you intending the hot-add memory code path to call add_active_range or 
> ???
>

Not at this time. I want to make sure the memory initialisation is right 
before dealing with additional complications.

> Thanks,
> Keith
>

-- 
Mel Gorman
Part-time Phd Student                          Linux Technology Center
University of Limerick                         IBM Dublin Software Lab

^ permalink raw reply

* Re: ioremap() fails for >64 MB
From: Alex Zeffertt @ 2006-08-22  8:50 UTC (permalink / raw)
  To: Phil.Nitschke; +Cc: linuxppc-embedded
In-Reply-To: <1156232469.26041.19.camel@caxton.int.avalon.com.au>

Phil Nitschke wrote:
> Hi all,
> 
> I have 2 GB memory on a 7448 processor, and want to reserve a huge chunk
> of it at boot-time, then ioremap() it into the kernel space inside a
> device driver.  So far I've succeeded with 64 MB, but can't go any
> higher, as mm/vmalloc.c tells me: "allocation failed: out of vmalloc
> space - use vmalloc=<size> to increase size."
> 

I remember reading in Linux Device Drivers that you can use the bigphysarea
patch to allocate large memory, as long as you do it at boot time.  It seems
it's been ported to 2.6 too:

	http://lwn.net/Articles/111132/

Alex

^ permalink raw reply

* Re: PPC beginner questions
From: David H. Lynch Jr. @ 2006-08-22  8:53 UTC (permalink / raw)
  To: Wade Maxfield; +Cc: ppc
In-Reply-To: <45a1b53e0608210651s4f5de382w77e092463dbbf5b7@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 2994 bytes --]

Wade Maxfield wrote:
>
>   I'm new to the PPC and I have a few questions.  I have written a 
> driver in the past for the X86 family, using i/o ports, but it was
> kernel 2.0 and i/o ports are not mmu handled.
>   I've been looking through the archive and I am slowly growing more
> confused.
    The PPC MMU is pretty simple compared to the x86.
    Basically the MMU unit is a peice of hardware that maps "virtual"
addresses to "physical" addresses.
    Its use is enabled/disabled by two bits in the PPC Machine Status
register - 1 for instructions, 1 for data.
    The MMU itself is basically a 64 entry lookup table. Virtual address
X corresponds to physical address Y.
    When a request is made for an address that is not in the 64 entry
MMU table things become more complex
     - an exception is generated and code inside Linux searches its
tables to find the correct entry to stuff into the MMU.
    NORMALLY there is no correspondence between physical addresses and
virtual ones. But it is possible (and might be useful for debugging) to
stuff an entry
    where physical=virtual. If you look inside head_4xx.S for
CONFIG_SERIAL_TEXT_DEBUG or something like that you should see how to do it.
    However manually stuffed entries in the MMU will eventually get
blown away. I spent a week trying to trace a problem caused by that down.


>
>   We are using Xilinx with PPC built in.
>
>    The PPC has a memory management unit.  All of the IP we've added is
> mapped to physical addresses.
>
>    1. Can I access the memory the peripherasl are mapped to directly
> within the driver without going through functions?
>        if NOT, then Do I use
>           1. ioremap(),
    Once you have done the ioremap(), you can use the address returned
exactly the way you would have used the physical address previously.


>           2. request_mem_region(),
>           3. request_region()
>           4. something else?
>
>    2.  Are there any gotcha's with the ppc 405 that Xilinx uses that I
> should know about?
    Are you doing board bringup ?
    If you are not bringing up a new board - then the big gotcha's
should already be covered.
    If you are doing board bringup - I would recommend following the
existing xilinx packages closely.
>
>
> thanks,
> wade
>
>  
> ------------------------------------------------------------------------
>
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded


-- 
Dave Lynch 					  	    DLA Systems
Software Development:  				         Embedded Linux
717.627.3770 	       dhlii@dlasys.net 	  http://www.dlasys.net
fax: 1.253.369.9244 			           Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.

"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein


[-- Attachment #2: Type: text/html, Size: 4574 bytes --]

^ permalink raw reply

* Re: [PATCH 2/2] uninorth: Add module param 'aperture' for aperture size
From: Michel Dänzer @ 2006-08-22  8:55 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, davej
In-Reply-To: <1156231536.21752.100.camel@localhost.localdomain>

On Tue, 2006-08-22 at 17:25 +1000, Benjamin Herrenschmidt wrote:
> On Mon, 2006-08-21 at 18:09 +0200, Michel Dänzer wrote:
> 
> > In contrast to most if not all PC BIOSes, OpenFirmware (OF) on PowerMacs with
> > UniNorth bridges does not allow changing the aperture size. The size set up by
> > OF is usually 16 MB, which is too low for graphics intensive environments.
> > Hence, add a module parameter that allows changing the aperture size at driver
> > initialization time. When the parameter is not specified, the default is still
> > to leave the size unchanged, usually as set up by OF.
> 
> The right fix is to allow changing it by the driver ... can't we do it
> such that AGPSize will work & change it ? 

Not sure, but it seems like the aperture size is fixed at backend
initialization time, i.e. in the driver's probe hook.


> It's basically expected that we set it ourselves and a module option 
> doesn't seem like a terribly good idea to me...

Well, wasn't it you who suggested this? :)


> Maybe we should just have the driver default to something more sensible
> in addition to what AGPSize comes from userland ? like 64M ?

Might be a good idea.


-- 
Earthling Michel Dänzer           |          http://tungstengraphics.com
Libre software enthusiast         |          Debian, X and DRI developer

^ permalink raw reply

* Re: Broken Firewire 400/SCSI on ppc Powerbook5,8
From: Stefan Richter @ 2006-08-22  8:58 UTC (permalink / raw)
  To: Bill Fink; +Cc: linux1394-devel, linuxppc-dev
In-Reply-To: <20060819201849.5e8d6e6c.billfink@mindspring.com>

Bill Fink wrote:
>> > on my desktop PowerMac systems, I need a "sleep 2"
>> > before the modprobe for sbp2, to get my Firewire disks to work
>> > properly.
[...]
> First of all this was on a somewhat older 2.6.11.8 kernel without
> any hotplug (I'll probably be trying this again soon with a newer
> 2.6.15-rc5 kernel).  And I was actually booting off this Firewire
> disk.  Without the pause I would get:
[...]
> Then it wouldn't be able to mount the root filesystem, which would
> be followed shortly by a kernel panic.
> 
> If I put the "sleep 2" before the "modprobe sbp2" then everything
> works.  There's a message about initializing SCSI emulation for SBP-2,
> followed by the discovery of the Firewire disk and the creation of
> the sda device, which then allows the successful mounting of the
> root filesystem.
> 
> Here's the full linuxrc nash script from the initrd for the working case:
> 
> #!/bin/nash
> 
> mount -t proc /proc /proc
> setquiet
> echo Mounted /proc filesystem
> echo Mounting sysfs
> mount -t sysfs none /sys
> echo "Loading ieee1394.ko module"
> insmod /lib/ieee1394.ko
> echo "Loading ohci1394.ko module"
> insmod /lib/ohci1394.ko
> sleep 2
> echo "Loading raw1394.ko module"
> insmod /lib/raw1394.ko
> echo "Loading sbp2.ko module"
> insmod /lib/sbp2.ko
> echo Creating block devices
> mkdevices /dev
> echo Creating root device
> mkrootdev /dev/root
> umount /sys
> echo 0x0100 > /proc/sys/kernel/real-root-dev
> echo Mounting root filesystem
> mount -o defaults --ro -t ext3 /dev/root /sysroot
> pivot_root /sysroot /sysroot/initrd
> umount /initrd/proc
> 
> The disk is an 80 GB LaCie Firewire disk, reported by the kernel as:
[...]

OK. Mounting the root FS from a FireWire disk is a somewhat different
matter from normal hotplug. I can see why you need the few seconds pause
between when ohci1394 is loaded and when sbp2 is loaded. With this
pause, it is very likely that ieee1394 was able to discover and scan the
disk's node before sbp2 is loaded. AFAIU, "insmod sbp2" will therefore
not only load the sbp2 code but will also execute sbp2's device probe
routine (i.e. SBP-2 login, creation of the SCSI device, SCSI inquiry,
and attachment of the sd driver to it) before "insmod sbp2" exits.

Another approach would be to put a basically complete hotplug userland
into the initrd and then wait for the disk with the root FS to appear.
(The disk is e.g. known by its FireWire GUID.) Then you wouldn't need
the hardcoded pause to wait until after the SBP-2 disk made its
configuration ROM available and ieee1394 scanned it.

BTW, a few improvements WRT device recognition went into nearly each of
the Linux releases since 2.6.11. I think they are not relevant to most
or all LaCie disks though.

Discovery of SBP-2 devices will always remain an asynchronous
non-deterministic process anyway. But this is true for all SCSI
transports and interconnects. It's just that most other SCSI
interconnect drivers' initialization routines hold off until they fully
scanned their bus --- which makes sense at least for SCSI interconnects
which are not hotplug capable.

Recently there were patches sent to the Linux SCSI mailinglist that add
optional asynchronous and parallelized bus scanning to all of these
traditional drivers too. Emphasis lies on parallelized since this is
primarily meant to speed up the boot process of systems with many SCSI
buses. There is also a callback to notify the system when all buses are
done with scanning in order to know when to proceed with mounting of
filesystems. I have not yet looked into if this can sensibly used in
sbp2. I also didn't watch the merge status of these SCSI patches.
-- 
Stefan Richter
-=====-=-==- =--- =-==-
http://arcgraph.de/sr/

^ permalink raw reply

* Re: [PATCH] Add adder87x board support to 2.6.x
From: Bryan O'Donoghue @ 2006-08-22  9:23 UTC (permalink / raw)
  To: Bryan O'Donoghue; +Cc: linuxppc-embedded
In-Reply-To: <20060821204320.GD16290@mag.az.mvista.com>

Mark A. Greer wrote:
> Bryan,
> 
> If you're not already on the linuxppc-dev mailing list, you should be.
> The 'ppc' tree is deprecated and all new work should be happening in the
> 'powerpc' tree (as in arch/powerpc).

Ah... I saw recent activity in the ppc tree and assumed it was still the 
place to do 8xx development.

> The odds of this being accepted are slim but either way, you should read
> the mail archive and get involved in the powerpc migration.
> 
> Mark

No worries Mark, perhaps the thing to do is to do a board port based on 
the powerpc tree instead.

Bryan

-- 
Quidquid latine dictum sit, altum sonatur.
- Whatever is said in Latin sounds profound.

^ permalink raw reply

* Re: [PATCH 3/6] POWERPC: move the generic cpm2 stuff to the powerpc
From: Vitaly Bordug @ 2006-08-22 10:02 UTC (permalink / raw)
  To: Sergei Shtylyov; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <44DE1FA1.2040604@ru.mvista.com>

On Sat, 12 Aug 2006 22:36:17 +0400
Sergei Shtylyov wrote:

> Hello.
> 
> Vitaly Bordug wrote:
> > This moves the cpm2 common code and PIC stuff to the powerpc. Most
> > of the files were just copied from ppc/, with minor tuning to make
> > it compile, and, subsequently, work.
> > 
> > Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
> 
> [...]
> 
> > diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h
> > index f6a7ff0..876974e 100644
> > --- a/include/asm-ppc/cpm2.h
> > +++ b/include/asm-ppc/cpm2.h
> [...]
> > @@ -1186,7 +1190,7 @@ #define PC3_DIRC1	(PC3_TXDAT)
> >  #define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128))
> >  #define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0)
> >  #define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1)
> > -#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(2)
> > +#define FCC3_MEM_OFFSET FCC_MEM_OFFSET(2)
> >  
> >  #endif /* __CPM2__ */
> >  #endif /* __KERNEL__ */
> 
>     Alas, this last hunk doesn't apply to powerpc.git. Shouldn't it
> be in some other patch instead?

This whole patch series depends on the fs_enet PALification series, that 
is accepted to netdev tree at least, according to the last mail from Andrew Morton.

Hence, it will be auto-fixed shortly. Next time I'll submit the preceding stuff
as well to prevent confusion.
> 
> WBR, Sergei
> 
> 

^ permalink raw reply

* [PATCH ] powerpc: Add tsi108/9 and non standard mpic support
From: Zang Roy-r61911 @ 2006-08-22 10:07 UTC (permalink / raw)
  To: Paul Mackerras, Benjamin Herrenschmidt
  Cc: linuxppc-dev list, Yang Xin-Xin-r48390, Alexandre.Bounine

The patch adds new hardware information table for mpic. This=20
enables mpic code to deal with mpic controller with=20
hardware behavior difference.

CONFIG_MPIC_WEIRD is introduced in the code.
If a board with non standard mpic controller,  it can select the
CONFIG_MPIC_WEIRD with board and add its hardware information
in the array mpic_infos.

TSI108/109 PIC takes the first index of weird  hardware information=20
table:) .  The table can be extended. The Tsi108/109 PIC looks like=20
standard OpenPIC but, in fact, is different in registers mapping and
behavior.

The patch does not affect the behavior of standard mpic.
CONFIG_MPIC_WEIRD
excludes the weird mpic code when building standard mpic.
   =20
Signed-off-by: Alexandre Bounine <alexandreb@tundra.com>
Signed-off-by: Roy Zang	<tie-fei.zang@freescale.com>=20

---
 arch/powerpc/Kconfig         |    8 +-
 arch/powerpc/sysdev/Makefile |    1=20
 arch/powerpc/sysdev/mpic.c   |  187
+++++++++++++++++++++++++++++-------------
 include/asm-powerpc/mpic.h   |  114 ++++++++++++++++++++++++++
 4 files changed, 252 insertions(+), 58 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index abb325e..c88b647 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -440,11 +440,15 @@ config U3_DART
 	default n
=20
 config MPIC
-	depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE || PPC_CHRP \
-			       || MPC7448HPC2
+	depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE || PPC_CHRP
 	bool
 	default y
=20
+config MPIC_WEIRD
+	depends on MPC7448HPC2
+	bool
+	default y
+=09
 config PPC_RTAS
 	bool
 	default n
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index cebfae2..8ae887b 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -3,6 +3,7 @@ EXTRA_CFLAGS			+=3D -mno-minimal-toc
 endif
=20
 obj-$(CONFIG_MPIC)		+=3D mpic.o
+obj-$(CONFIG_MPIC_WEIRD)	+=3D mpic.o
 obj-$(CONFIG_PPC_INDIRECT_PCI)	+=3D indirect_pci.o
 obj-$(CONFIG_PPC_MPC106)	+=3D grackle.o
 obj-$(CONFIG_BOOKE)		+=3D dcr.o
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 6e0281a..78e0515 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -54,6 +54,55 @@ #define distribute_irqs	(0)
 #endif
 #endif
=20
+#ifdef CONFIG_MPIC_WEIRD
+static u32 mpic_infos[][INDEX_MPIC_WEIRD_END] =3D {
+	[0] =3D {	/* Tsi108/109 PIC */
+		TSI108_GREG_BASE,
+		TSI108_GREG_FEATURE_0,
+		TSI108_GREG_GLOBAL_CONF_0,
+		TSI108_GREG_VENDOR_ID,
+		TSI108_GREG_IPI_VECTOR_PRI_0,
+		TSI108_GREG_IPI_STRIDE,
+		TSI108_GREG_SPURIOUS,
+		TSI108_GREG_TIMER_FREQ,
+
+		TSI108_TIMER_BASE,
+		TSI108_TIMER_STRIDE,
+		TSI108_TIMER_CURRENT_CNT,
+		TSI108_TIMER_BASE_CNT,
+		TSI108_TIMER_VECTOR_PRI,
+		TSI108_TIMER_DESTINATION,
+
+		TSI108_CPU_BASE,
+		TSI108_CPU_STRIDE,
+		TSI108_CPU_IPI_DISPATCH_0,
+		TSI108_CPU_IPI_DISPATCH_STRIDE,
+		TSI108_CPU_CURRENT_TASK_PRI,
+		TSI108_CPU_WHOAMI,
+		TSI108_CPU_INTACK,
+		TSI108_CPU_EOI,
+
+		TSI108_IRQ_BASE,
+		TSI108_IRQ_STRIDE,
+		TSI108_IRQ_VECTOR_PRI,
+		TSI108_VECPRI_VECTOR_MASK,
+		TSI108_VECPRI_POLARITY_POSITIVE,
+		TSI108_VECPRI_POLARITY_NEGATIVE,
+		TSI108_VECPRI_SENSE_LEVEL,
+		TSI108_VECPRI_SENSE_EDGE,
+		TSI108_VECPRI_POLARITY_MASK,
+		TSI108_VECPRI_SENSE_MASK,
+		TSI108_IRQ_DESTINATION
+	},
+};
+#endif
+
+#ifdef CONFIG_MPIC_WEIRD
+#define MPIC_INFO(name) mpic->hw_set[INDEX_##name]
+#else
+#define MPIC_INFO(name) MPIC_##name
+#endif
+
 /*
  * Register accessor functions
  */
@@ -80,7 +129,8 @@ static inline void _mpic_write(unsigned=20
 static inline u32 _mpic_ipi_read(struct mpic *mpic, unsigned int ipi)
 {
 	unsigned int be =3D (mpic->flags & MPIC_BIG_ENDIAN) !=3D 0;
-	unsigned int offset =3D MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10);
+	unsigned int offset =3D MPIC_INFO(GREG_IPI_VECTOR_PRI_0) +
+			      (ipi * MPIC_INFO(GREG_IPI_STRIDE));
=20
 	if (mpic->flags & MPIC_BROKEN_IPI)
 		be =3D !be;
@@ -89,7 +139,8 @@ static inline u32 _mpic_ipi_read(struct=20
=20
 static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi,
u32 value)
 {
-	unsigned int offset =3D MPIC_GREG_IPI_VECTOR_PRI_0 + (ipi * 0x10);
+	unsigned int offset =3D MPIC_INFO(GREG_IPI_VECTOR_PRI_0) +
+			      (ipi * MPIC_INFO(GREG_IPI_STRIDE));
=20
 	_mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->gregs, offset,
value);
 }
@@ -120,7 +171,7 @@ static inline u32 _mpic_irq_read(struct=20
 	unsigned int	idx =3D src_no & mpic->isu_mask;
=20
 	return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN,
mpic->isus[isu],
-			  reg + (idx * MPIC_IRQ_STRIDE));
+			  reg + (idx * MPIC_INFO(IRQ_STRIDE)));
 }
=20
 static inline void _mpic_irq_write(struct mpic *mpic, unsigned int
src_no,
@@ -130,7 +181,7 @@ static inline void _mpic_irq_write(struc
 	unsigned int	idx =3D src_no & mpic->isu_mask;
=20
 	_mpic_write(mpic->flags & MPIC_BIG_ENDIAN, mpic->isus[isu],
-		    reg + (idx * MPIC_IRQ_STRIDE), value);
+		    reg + (idx * MPIC_INFO(IRQ_STRIDE)), value);
 }
=20
 #define mpic_read(b,r)		_mpic_read(mpic->flags &
MPIC_BIG_ENDIAN,(b),(r))
@@ -156,8 +207,8 @@ static void __init mpic_test_broken_ipi(
 {
 	u32 r;
=20
-	mpic_write(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0,
MPIC_VECPRI_MASK);
-	r =3D mpic_read(mpic->gregs, MPIC_GREG_IPI_VECTOR_PRI_0);
+	mpic_write(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0),
MPIC_VECPRI_MASK);
+	r =3D mpic_read(mpic->gregs, MPIC_INFO(GREG_IPI_VECTOR_PRI_0));
=20
 	if (r =3D=3D le32_to_cpu(MPIC_VECPRI_MASK)) {
 		printk(KERN_INFO "mpic: Detected reversed IPI
registers\n");
@@ -394,8 +445,8 @@ static inline struct mpic * mpic_from_ir
 /* Send an EOI */
 static inline void mpic_eoi(struct mpic *mpic)
 {
-	mpic_cpu_write(MPIC_CPU_EOI, 0);
-	(void)mpic_cpu_read(MPIC_CPU_WHOAMI);
+	mpic_cpu_write(MPIC_INFO(CPU_EOI), 0);
+	(void)mpic_cpu_read(MPIC_INFO(CPU_WHOAMI));
 }
=20
 #ifdef CONFIG_SMP
@@ -419,8 +470,8 @@ static void mpic_unmask_irq(unsigned int
=20
 	DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq,
src);
=20
-	mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
-		       mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
+	mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI),
+		       mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) &
 		       ~MPIC_VECPRI_MASK);
 	/* make sure mask gets to controller before we return to user */
 	do {
@@ -428,7 +479,7 @@ static void mpic_unmask_irq(unsigned int
 			printk(KERN_ERR "mpic_enable_irq timeout\n");
 			break;
 		}
-	} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
MPIC_VECPRI_MASK);
+	} while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) &
MPIC_VECPRI_MASK);=09
 }
=20
 static void mpic_mask_irq(unsigned int irq)
@@ -439,8 +490,8 @@ static void mpic_mask_irq(unsigned int i
=20
 	DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
=20
-	mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
-		       mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
+	mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI),
+		       mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) |
 		       MPIC_VECPRI_MASK);
=20
 	/* make sure mask gets to controller before we return to user */
@@ -449,7 +500,7 @@ static void mpic_mask_irq(unsigned int i
 			printk(KERN_ERR "mpic_enable_irq timeout\n");
 			break;
 		}
-	} while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
MPIC_VECPRI_MASK));
+	} while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) &
MPIC_VECPRI_MASK));
 }
=20
 static void mpic_end_irq(unsigned int irq)
@@ -560,24 +611,32 @@ static void mpic_set_affinity(unsigned i
=20
 	cpus_and(tmp, cpumask, cpu_online_map);
=20
-	mpic_irq_write(src, MPIC_IRQ_DESTINATION,
+	mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION),
 		       mpic_physmask(cpus_addr(tmp)[0]));=09
 }
=20
+#ifdef CONFIG_MPIC_WEIRD
+static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int
type)
+#else
 static unsigned int mpic_type_to_vecpri(unsigned int type)
+#endif
 {
 	/* Now convert sense value */
 	switch(type & IRQ_TYPE_SENSE_MASK) {
 	case IRQ_TYPE_EDGE_RISING:
-		return MPIC_VECPRI_SENSE_EDGE |
MPIC_VECPRI_POLARITY_POSITIVE;
+		return MPIC_INFO(VECPRI_SENSE_EDGE) |
+		       MPIC_INFO(VECPRI_POLARITY_POSITIVE);
 	case IRQ_TYPE_EDGE_FALLING:
 	case IRQ_TYPE_EDGE_BOTH:
-		return MPIC_VECPRI_SENSE_EDGE |
MPIC_VECPRI_POLARITY_NEGATIVE;
+		return MPIC_INFO(VECPRI_SENSE_EDGE) |
+		       MPIC_INFO(VECPRI_POLARITY_NEGATIVE);
 	case IRQ_TYPE_LEVEL_HIGH:
-		return MPIC_VECPRI_SENSE_LEVEL |
MPIC_VECPRI_POLARITY_POSITIVE;
+		return MPIC_INFO(VECPRI_SENSE_LEVEL) |
+		       MPIC_INFO(VECPRI_POLARITY_POSITIVE);
 	case IRQ_TYPE_LEVEL_LOW:
 	default:
-		return MPIC_VECPRI_SENSE_LEVEL |
MPIC_VECPRI_POLARITY_NEGATIVE;
+		return MPIC_INFO(VECPRI_SENSE_LEVEL) |
+		       MPIC_INFO(VECPRI_POLARITY_NEGATIVE);
 	}
 }
=20
@@ -609,13 +668,18 @@ static int mpic_set_irq_type(unsigned in
 		vecpri =3D MPIC_VECPRI_POLARITY_POSITIVE |
 			MPIC_VECPRI_SENSE_EDGE;
 	else
+#ifdef CONFIG_MPIC_WEIRD
+		vecpri =3D mpic_type_to_vecpri(mpic, flow_type);
+#else
 		vecpri =3D mpic_type_to_vecpri(flow_type);
+#endif=09
=20
-	vold =3D mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI);
-	vnew =3D vold & ~(MPIC_VECPRI_POLARITY_MASK |
MPIC_VECPRI_SENSE_MASK);
+	vold =3D mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
+	vnew =3D vold & ~(MPIC_INFO(VECPRI_POLARITY_MASK) |=20
+			MPIC_INFO(VECPRI_SENSE_MASK));
 	vnew |=3D vecpri;
 	if (vold !=3D vnew)
-		mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, vnew);
+		mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew);
=20
 	return 0;
 }
@@ -797,18 +861,23 @@ #endif /* CONFIG_SMP */
 	mpic->isu_size =3D isu_size;
 	mpic->irq_count =3D irq_count;
 	mpic->num_sources =3D 0; /* so far */
+=09
+#ifdef CONFIG_MPIC_WEIRD
+	mpic->hw_set =3D mpic_infos[MPIC_GET_MOD_ID(flags)];
+#endif
=20
 	/* Map the global registers */
-	mpic->gregs =3D ioremap(phys_addr + MPIC_GREG_BASE, 0x1000);
-	mpic->tmregs =3D mpic->gregs + ((MPIC_TIMER_BASE - MPIC_GREG_BASE)
>> 2);
+	mpic->gregs =3D ioremap(phys_addr + MPIC_INFO(GREG_BASE), 0x1000);
+	mpic->tmregs =3D mpic->gregs +
+		       ((MPIC_INFO(TIMER_BASE) - MPIC_INFO(GREG_BASE))
>> 2);
 	BUG_ON(mpic->gregs =3D=3D NULL);
=20
 	/* Reset */
 	if (flags & MPIC_WANTS_RESET) {
-		mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0,
-			   mpic_read(mpic->gregs,
MPIC_GREG_GLOBAL_CONF_0)
+		mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
+			   mpic_read(mpic->gregs,
MPIC_INFO(GREG_GLOBAL_CONF_0))
 			   | MPIC_GREG_GCONF_RESET);
-		while( mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0)
+		while( mpic_read(mpic->gregs,
MPIC_INFO(GREG_GLOBAL_CONF_0))
 		       & MPIC_GREG_GCONF_RESET)
 			mb();
 	}
@@ -817,7 +886,7 @@ #endif /* CONFIG_SMP */
 	 * MPICs, num sources as well. On ISU MPICs, sources are counted
 	 * as ISUs are added
 	 */
-	reg =3D mpic_read(mpic->gregs, MPIC_GREG_FEATURE_0);
+	reg =3D mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0));
 	mpic->num_cpus =3D ((reg & MPIC_GREG_FEATURE_LAST_CPU_MASK)
 			  >> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1;
 	if (isu_size =3D=3D 0)
@@ -826,16 +895,16 @@ #endif /* CONFIG_SMP */
=20
 	/* Map the per-CPU registers */
 	for (i =3D 0; i < mpic->num_cpus; i++) {
-		mpic->cpuregs[i] =3D ioremap(phys_addr + MPIC_CPU_BASE +
-					   i * MPIC_CPU_STRIDE, 0x1000);
+		mpic->cpuregs[i] =3D ioremap(phys_addr +
MPIC_INFO(CPU_BASE) +
+					   i * MPIC_INFO(CPU_STRIDE),
0x1000);
 		BUG_ON(mpic->cpuregs[i] =3D=3D NULL);
 	}
=20
 	/* Initialize main ISU if none provided */
 	if (mpic->isu_size =3D=3D 0) {
 		mpic->isu_size =3D mpic->num_sources;
-		mpic->isus[0] =3D ioremap(phys_addr + MPIC_IRQ_BASE,
-					MPIC_IRQ_STRIDE *
mpic->isu_size);
+		mpic->isus[0] =3D ioremap(phys_addr + MPIC_INFO(IRQ_BASE),
+					MPIC_INFO(IRQ_STRIDE) *
mpic->isu_size);
 		BUG_ON(mpic->isus[0] =3D=3D NULL);
 	}
 	mpic->isu_shift =3D 1 + __ilog2(mpic->isu_size - 1);
@@ -879,7 +948,8 @@ void __init mpic_assign_isu(struct mpic=20
=20
 	BUG_ON(isu_num >=3D MPIC_MAX_ISU);
=20
-	mpic->isus[isu_num] =3D ioremap(phys_addr, MPIC_IRQ_STRIDE *
mpic->isu_size);
+	mpic->isus[isu_num] =3D ioremap(phys_addr,
+				      MPIC_INFO(IRQ_STRIDE) *
mpic->isu_size);
 	if ((isu_first + mpic->isu_size) > mpic->num_sources)
 		mpic->num_sources =3D isu_first + mpic->isu_size;
 }
@@ -904,14 +974,16 @@ void __init mpic_init(struct mpic *mpic)
 	printk(KERN_INFO "mpic: Initializing for %d sources\n",
mpic->num_sources);
=20
 	/* Set current processor priority to max */
-	mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf);
+	mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
=20
 	/* Initialize timers: just disable them all */
 	for (i =3D 0; i < 4; i++) {
 		mpic_write(mpic->tmregs,
-			   i * MPIC_TIMER_STRIDE +
MPIC_TIMER_DESTINATION, 0);
+			   i * MPIC_INFO(TIMER_STRIDE) +
+			   MPIC_INFO(TIMER_DESTINATION), 0);
 		mpic_write(mpic->tmregs,
-			   i * MPIC_TIMER_STRIDE +
MPIC_TIMER_VECTOR_PRI,
+			   i * MPIC_INFO(TIMER_STRIDE) +=20
+			   MPIC_INFO(TIMER_VECTOR_PRI),
 			   MPIC_VECPRI_MASK |
 			   (MPIC_VEC_TIMER_0 + i));
 	}
@@ -940,21 +1012,23 @@ void __init mpic_init(struct mpic *mpic)
 			(8 << MPIC_VECPRI_PRIORITY_SHIFT);
 	=09
 		/* init hw */
-		mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri);
-		mpic_irq_write(i, MPIC_IRQ_DESTINATION,
+		mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
+		mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION),
 			       1 << hard_smp_processor_id());
 	}
 =09
 	/* Init spurrious vector */
-	mpic_write(mpic->gregs, MPIC_GREG_SPURIOUS, MPIC_VEC_SPURRIOUS);
+	mpic_write(mpic->gregs, MPIC_INFO(GREG_SPURIOUS),
MPIC_VEC_SPURRIOUS);
=20
-	/* Disable 8259 passthrough */
-	mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0,
-		   mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_0)
+	/* Disable 8259 passthrough, if supported */
+#ifndef CONFIG_MPIC_WEIRD
+	mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
+		   mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
 		   | MPIC_GREG_GCONF_8259_PTHROU_DIS);
+#endif
=20
 	/* Set current processor priority to 0 */
-	mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0);
+	mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0);
 }
=20
 void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio)
@@ -997,9 +1071,9 @@ void mpic_irq_set_priority(unsigned int=20
 		mpic_ipi_write(src - MPIC_VEC_IPI_0,
 			       reg | (pri <<
MPIC_VECPRI_PRIORITY_SHIFT));
 	} else {
-		reg =3D mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI)
+		reg =3D mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI))
 			& ~MPIC_VECPRI_PRIORITY_MASK;
-		mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
+		mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI),
 			       reg | (pri <<
MPIC_VECPRI_PRIORITY_SHIFT));
 	}
 	spin_unlock_irqrestore(&mpic_lock, flags);
@@ -1017,7 +1091,7 @@ unsigned int mpic_irq_get_priority(unsig
 	if (is_ipi)
 		reg =3D mpic_ipi_read(src =3D MPIC_VEC_IPI_0);
 	else
-		reg =3D mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI);
+		reg =3D mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
 	spin_unlock_irqrestore(&mpic_lock, flags);
 	return (reg & MPIC_VECPRI_PRIORITY_MASK) >>
MPIC_VECPRI_PRIORITY_SHIFT;
 }
@@ -1043,12 +1117,12 @@ #ifdef CONFIG_SMP
  	 */
 	if (distribute_irqs) {
 	 	for (i =3D 0; i < mpic->num_sources ; i++)
-			mpic_irq_write(i, MPIC_IRQ_DESTINATION,
-				mpic_irq_read(i, MPIC_IRQ_DESTINATION) |
msk);
+			mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION),
+				mpic_irq_read(i,
MPIC_INFO(IRQ_DESTINATION)) | msk);
 	}
=20
 	/* Set current processor priority to 0 */
-	mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0);
+	mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0);
=20
 	spin_unlock_irqrestore(&mpic_lock, flags);
 #endif /* CONFIG_SMP */
@@ -1058,7 +1132,7 @@ int mpic_cpu_get_priority(void)
 {
 	struct mpic *mpic =3D mpic_primary;
=20
-	return mpic_cpu_read(MPIC_CPU_CURRENT_TASK_PRI);
+	return mpic_cpu_read(MPIC_INFO(CPU_CURRENT_TASK_PRI));
 }
=20
 void mpic_cpu_set_priority(int prio)
@@ -1066,7 +1140,7 @@ void mpic_cpu_set_priority(int prio)
 	struct mpic *mpic =3D mpic_primary;
=20
 	prio &=3D MPIC_CPU_TASKPRI_MASK;
-	mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, prio);
+	mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), prio);
 }
=20
 /*
@@ -1088,11 +1162,11 @@ void mpic_teardown_this_cpu(int secondar
=20
 	/* let the mpic know we don't want intrs.  */
 	for (i =3D 0; i < mpic->num_sources ; i++)
-		mpic_irq_write(i, MPIC_IRQ_DESTINATION,
-			mpic_irq_read(i, MPIC_IRQ_DESTINATION) & ~msk);
+		mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION),
+			mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION)) &
~msk);
=20
 	/* Set current processor priority to max */
-	mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf);
+	mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
=20
 	spin_unlock_irqrestore(&mpic_lock, flags);
 }
@@ -1108,7 +1182,8 @@ #ifdef DEBUG_IPI
 	DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no);
 #endif
=20
-	mpic_cpu_write(MPIC_CPU_IPI_DISPATCH_0 + ipi_no * 0x10,
+	mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) +
+		       ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE),
 		       mpic_physmask(cpu_mask &
cpus_addr(cpu_online_map)[0]));
 }
=20
@@ -1116,7 +1191,7 @@ unsigned int mpic_get_one_irq(struct mpi
 {
 	u32 src;
=20
-	src =3D mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK;
+	src =3D mpic_cpu_read(MPIC_INFO(CPU_INTACK)) &
MPIC_INFO(VECPRI_VECTOR_MASK);
 #ifdef DEBUG_LOW
 	DBG("%s: get_one_irq(): %d\n", mpic->name, src);
 #endif
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
index eb241c9..faebdf2 100644
--- a/include/asm-powerpc/mpic.h
+++ b/include/asm-powerpc/mpic.h
@@ -41,6 +41,7 @@ #define MPIC_GREG_IPI_VECTOR_PRI_0	0x000
 #define MPIC_GREG_IPI_VECTOR_PRI_1	0x000b0
 #define MPIC_GREG_IPI_VECTOR_PRI_2	0x000c0
 #define MPIC_GREG_IPI_VECTOR_PRI_3	0x000d0
+#define MPIC_GREG_IPI_STRIDE		0x10
 #define MPIC_GREG_SPURIOUS		0x000e0
 #define MPIC_GREG_TIMER_FREQ		0x000f0
=20
@@ -68,6 +69,7 @@ #define MPIC_CPU_IPI_DISPATCH_0		0x00040
 #define MPIC_CPU_IPI_DISPATCH_1		0x00050
 #define MPIC_CPU_IPI_DISPATCH_2		0x00060
 #define MPIC_CPU_IPI_DISPATCH_3		0x00070
+#define MPIC_CPU_IPI_DISPATCH_STRIDE	0x00010
 #define MPIC_CPU_CURRENT_TASK_PRI	0x00080
 #define 	MPIC_CPU_TASKPRI_MASK			0x0000000f
 #define MPIC_CPU_WHOAMI			0x00090
@@ -114,6 +116,103 @@ #define MPIC_VEC_TIMER_2	249
 #define MPIC_VEC_TIMER_1	248
 #define MPIC_VEC_TIMER_0	247
=20
+#ifdef CONFIG_MPIC_WEIRD
+/*
+ * Tsi108 implementation of MPIC has many differences from the original
one
+ */
+
+/*
+ * Global registers
+ */
+
+#define TSI108_GREG_BASE		0x00000
+#define TSI108_GREG_FEATURE_0		0x00000
+#define TSI108_GREG_GLOBAL_CONF_0	0x00004
+#define TSI108_GREG_VENDOR_ID		0x0000c
+#define TSI108_GREG_IPI_VECTOR_PRI_0	0x00204		/* Doorbell 0 */
+#define TSI108_GREG_IPI_STRIDE		0x0c
+#define TSI108_GREG_SPURIOUS		0x00010
+#define TSI108_GREG_TIMER_FREQ		0x00014
+
+/*
+ * Timer registers
+ */
+#define TSI108_TIMER_BASE		0x0030
+#define TSI108_TIMER_STRIDE		0x10
+#define TSI108_TIMER_CURRENT_CNT	0x00000
+#define TSI108_TIMER_BASE_CNT		0x00004
+#define TSI108_TIMER_VECTOR_PRI		0x00008
+#define TSI108_TIMER_DESTINATION	0x0000c
+
+/*
+ * Per-Processor registers
+ */
+#define TSI108_CPU_BASE			0x00300
+#define TSI108_CPU_STRIDE		0x00040
+#define TSI108_CPU_IPI_DISPATCH_0	0x00200
+#define TSI108_CPU_IPI_DISPATCH_STRIDE	0x00000
+#define TSI108_CPU_CURRENT_TASK_PRI	0x00000
+#define TSI108_CPU_WHOAMI		0xffffffff
+#define TSI108_CPU_INTACK		0x00004
+#define TSI108_CPU_EOI			0x00008
+
+/*
+ * Per-source registers
+ */
+#define TSI108_IRQ_BASE			0x00100
+#define TSI108_IRQ_STRIDE		0x00008
+#define TSI108_IRQ_VECTOR_PRI		0x00000
+#define TSI108_VECPRI_VECTOR_MASK	0x000000ff
+#define TSI108_VECPRI_POLARITY_POSITIVE	0x01000000
+#define TSI108_VECPRI_POLARITY_NEGATIVE	0x00000000
+#define TSI108_VECPRI_SENSE_LEVEL	0x02000000
+#define TSI108_VECPRI_SENSE_EDGE	0x00000000
+#define TSI108_VECPRI_POLARITY_MASK	0x01000000
+#define TSI108_VECPRI_SENSE_MASK	0x02000000
+#define TSI108_IRQ_DESTINATION		0x00004
+
+/* weird mpic variable index in the HW info array */
+enum MPIC_WEIRD_INDEX {
+	INDEX_GREG_BASE =3D 0,	/* Offset of global registers from MPIC
base */
+	INDEX_GREG_FEATURE_0,	/* FRR0 offset from base */
+	INDEX_GREG_GLOBAL_CONF_0, /* Global Config register offset from
base */
+	INDEX_GREG_VENDOR_ID,	/* VID register offset from base */
+	INDEX_GREG_IPI_VECTOR_PRI_0,	/* IPI Vector/Priority Registers
*/
+	INDEX_GREG_IPI_STRIDE, 		/* IPI Vector/Priority Registers
spacing */
+	INDEX_GREG_SPURIOUS,		/* Spurious Vector Register */
+	INDEX_GREG_TIMER_FREQ,	/* Global Timer Frequency Reporting
Register */
+
+	INDEX_TIMER_BASE,		/* Global Timer Registers base
*/
+	INDEX_TIMER_STRIDE,		/* Global Timer Registers
spacing */
+	INDEX_TIMER_CURRENT_CNT,	/* Global Timer Current Count
Register */
+	INDEX_TIMER_BASE_CNT,		/* Global Timer Base Count
Register */
+	INDEX_TIMER_VECTOR_PRI,		/* Global Timer Vector/Priority
Register */
+	INDEX_TIMER_DESTINATION,	/* Global Timer Destination
Register */
+
+	INDEX_CPU_BASE,	/* Offset of cpu base */
+	INDEX_CPU_STRIDE,	/* Cpu register spacing*/
+	INDEX_CPU_IPI_DISPATCH_0,	/* IPI 0 Dispatch Command
Register */
+	INDEX_CPU_IPI_DISPATCH_STRIDE,	/* IPI Dispatch spacing */
+	INDEX_CPU_CURRENT_TASK_PRI,/* Processor Current Task Priority
Register */
+	INDEX_CPU_WHOAMI,	/* Who Am I Register */
+	INDEX_CPU_INTACK,	/* Interrupt Acknowledge Register */
+	INDEX_CPU_EOI,		/* End of Interrupt Register */
+
+	INDEX_IRQ_BASE,	/* Interrupt registers base */
+	INDEX_IRQ_STRIDE,	/* Interrupt registers spacing */
+	INDEX_IRQ_VECTOR_PRI,	/* Interrupt Vector/Priority Register */
+	INDEX_VECPRI_VECTOR_MASK,	/* Interrupt Vector Mask */
+	INDEX_VECPRI_POLARITY_POSITIVE,	/* Interrupt Positive Polarity
bit */
+	INDEX_VECPRI_POLARITY_NEGATIVE,	/* Interrupt Negative Polarity
bit */
+	INDEX_VECPRI_SENSE_LEVEL,	/* Interrupt Level Sense bit */
+	INDEX_VECPRI_SENSE_EDGE,	/* Interrupt edge Sense bit */
+	INDEX_VECPRI_POLARITY_MASK, /* Interrupt Polarity mask */
+	INDEX_VECPRI_SENSE_MASK, /* Interrupt sense mask */
+	INDEX_IRQ_DESTINATION,	/* Interrupt Destination Register */
+	INDEX_MPIC_WEIRD_END	/* Size of the hw info array */
+};
+#endif
+
 #ifdef CONFIG_MPIC_BROKEN_U3
 /* Fixup table entry */
 struct mpic_irq_fixup
@@ -170,6 +269,11 @@ #endif
 	volatile u32 __iomem	*tmregs;
 	volatile u32 __iomem	*cpuregs[MPIC_MAX_CPUS];
 	volatile u32 __iomem	*isus[MPIC_MAX_ISU];
+=09
+#ifdef CONFIG_MPIC_WEIRD
+	/* Pointer to HW info array */
+	u32	*hw_set;
+#endif
=20
 	/* link */
 	struct mpic		*next;
@@ -189,6 +293,16 @@ #define MPIC_BROKEN_IPI
0x00000008
 /* MPIC wants a reset */
 #define MPIC_WANTS_RESET		0x00000010
=20
+#ifdef CONFIG_MPIC_WEIRD
+/* Spurious vector requires EOI */
+#define MPIC_SPV_EOI			0x00000020
+/* MPIC HW modification ID */
+#define MPIC_MOD_ID_MASK		0x00000f00
+#define MPIC_MOD_ID(val)		(((val) << 8) &
MPIC_MOD_ID_MASK)
+#define MPIC_GET_MOD_ID(flags)		(((flags) & MPIC_MOD_ID_MASK) >>
8)
+#define	MPIC_ID_TSI108		0	/* Tsi108/109 PIC */
+#endif
+
 /* Allocate the controller structure and setup the linux irq descs
  * for the range if interrupts passed in. No HW initialization is
  * actually performed.
--=20
1.4.0

^ permalink raw reply related

* Re: [PATCH 6/6] [RFC] POWERPC: generic CPM2 peripherals rehaul with cpm2_map mechanism
From: Vitaly Bordug @ 2006-08-22 10:13 UTC (permalink / raw)
  To: Sergei Shtylyov; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <44DE379C.5030901@ru.mvista.com>

On Sun, 13 Aug 2006 00:18:36 +0400
Sergei Shtylyov wrote:

> Hello.
> 
> Vitaly Bordug wrote:
> 
> > Incorporating the new way of cpm2 immr access, introduced in the
> > previous patch, into CPM2 peripheral devices (fs_enet and
> > cpm_uart). Both ppc and powerpc approved working( real actions
> > taken in powerpc only, ppc just has a wrapper to keep init stuff
> > consistent).
> 
> > Signed-off-by: Vitaly Bordug <vbordug@ru.mvista.com>
> 
>     Hm, I got 4 rejects here. :-/
> 
> > diff --git a/arch/ppc/platforms/mpc8272ads_setup.c
> > b/arch/ppc/platforms/mpc8272ads_setup.c index 2a35fe2..d5d36c3
> > 100644 --- a/arch/ppc/platforms/mpc8272ads_setup.c
> > +++ b/arch/ppc/platforms/mpc8272ads_setup.c
> > @@ -103,7 +103,7 @@ static struct fs_platform_info mpc82xx_e
> >  	},
> >  };
> >  
> > -static void init_fcc1_ioports(void)
> > +static void init_fcc1_ioports(struct fs_platform_info*)
> >  {
> >  	struct io_port *io;
> >  	u32 tempval;
> 
>     This one get rejected as well.
> 
> > diff --git a/arch/ppc/platforms/mpc866ads_setup.c
> > b/arch/ppc/platforms/mpc866ads_setup.c index e12cece..5f130dc 100644
> > --- a/arch/ppc/platforms/mpc866ads_setup.c
> > +++ b/arch/ppc/platforms/mpc866ads_setup.c
> [...]
> > @@ -194,7 +194,7 @@ static void setup_scc1_ioports(void)
> >  
> >  }
> >  
> > -static void setup_smc1_ioports(void)
> > +static void setup_smc1_ioports(struct fs_uart_platform_info*)
> >  {
> >  	immap_t *immap = (immap_t *) IMAP_ADDR;
> >  	unsigned *bcsr_io;
> 
>     And this one...
> 
> > diff --git a/arch/ppc/platforms/mpc885ads_setup.c
> > b/arch/ppc/platforms/mpc885ads_setup.c index 5dfa4e6..bf388ed 100644
> > --- a/arch/ppc/platforms/mpc885ads_setup.c
> > +++ b/arch/ppc/platforms/mpc885ads_setup.c
> [...]
> > @@ -315,7 +315,7 @@ static void __init mpc885ads_fixup_scc_e
> >  	mpc885ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1);
> >  }
> >  
> > -static void setup_smc1_ioports(void)
> > +static void setup_smc1_ioports(struct fs_uart_platform_info*)
> >  {
> >          immap_t *immap = (immap_t *) IMAP_ADDR;
> >          unsigned *bcsr_io;
> 
>      And this...
> 
> > diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h
> > index bd6623a..220cc2d 100644
> > --- a/include/asm-ppc/cpm2.h
> > +++ b/include/asm-ppc/cpm2.h
> > @@ -1196,5 +1196,58 @@ #define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0
> >  #define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1)
> >  #define FCC3_MEM_OFFSET FCC_MEM_OFFSET(2)
> >  
> > +/* Clocks and GRG's */
> > +
> > +enum cpm_clk_dir {
> > +	CPM_CLK_RX,
> > +	CPM_CLK_TX,
> > +	CPM_CLK_RTX
> > +};
> > +
> > +enum cpm_clk_target {
> > +	CPM_CLK_SCC1,
> > +	CPM_CLK_SCC2,
> > +	CPM_CLK_SCC3,
> > +	CPM_CLK_SCC4,
> > +	CPM_CLK_FCC1,
> > +	CPM_CLK_FCC2,
> > +	CPM_CLK_FCC3
> > +};
> > +
> > +enum cpm_clk {
> > +	CPM_CLK_NONE = 0,
> > +	CPM_BRG1,	/* Baud Rate Generator  1 */
> > +	CPM_BRG2,	/* Baud Rate Generator  2 */
> > +	CPM_BRG3,	/* Baud Rate Generator  3 */
> > +	CPM_BRG4,	/* Baud Rate Generator  4 */
> > +	CPM_BRG5,	/* Baud Rate Generator  5 */
> > +	CPM_BRG6,	/* Baud Rate Generator  6 */
> > +	CPM_BRG7,	/* Baud Rate Generator  7 */
> > +	CPM_BRG8,	/* Baud Rate Generator  8 */
> > +	CPM_CLK1,	/* Clock  1 */
> > +	CPM_CLK2,	/* Clock  2 */
> > +	CPM_CLK3,	/* Clock  3 */
> > +	CPM_CLK4,	/* Clock  4 */
> > +	CPM_CLK5,	/* Clock  5 */
> > +	CPM_CLK6,	/* Clock  6 */
> > +	CPM_CLK7,	/* Clock  7 */
> > +	CPM_CLK8,	/* Clock  8 */
> > +	CPM_CLK9,	/* Clock  9 */
> > +	CPM_CLK10,	/* Clock 10 */
> > +	CPM_CLK11,	/* Clock 11 */
> > +	CPM_CLK12,	/* Clock 12 */
> > +	CPM_CLK13,	/* Clock 13 */
> > +	CPM_CLK14,	/* Clock 14 */
> > +	CPM_CLK15,	/* Clock 15 */
> > +	CPM_CLK16,	/* Clock 16 */
> > +	CPM_CLK17,	/* Clock 17 */
> > +	CPM_CLK18,	/* Clock 18 */
> > +	CPM_CLK19,	/* Clock 19 */
> > +	CPM_CLK20,	/* Clock 20 */
> > +	CPM_CLK_DUMMY
> > +};
> > +
> > +extern int cpm2_clk_setup(enum cpm_clk_target target, int clock,
> > int mode); +
> >  #endif /* __CPM2__ */
> >  #endif /* __KERNEL__ */
> 
>     And this file refuses to be patched altogether...
>     With these rejects fixed, everything seems fine, though.

The same note - the mis-sync because preceding fs_enet overhaul and update are missing before the stuff above.

Taking into accordance Kumar's opinion to put this on hold until the next kernel release, the whole thing should settle down pretty shortly hereby before upstream merge. Meanwhile, we'll catch up the issues and scrub
the code in general. Hopefully, with netdev things merged, we'll get back to the only powerpc.git base which will simplify following them up.



> 
> WBR, Sergei
> 
> 

^ permalink raw reply

* RE: ML40X, ppc 405 crash
From: alva @ 2006-08-22 10:52 UTC (permalink / raw)
  To: 'Wade Maxfield', 'ppc'
In-Reply-To: <45a1b53e0608211434n2c61167i8952ab8737f102cc@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 8053 bytes --]

So can u access your NFS mapped partition? If you can access every FILEs
on the partition, running updatedb  ought to index the NFS partition
also. Then “locate fixdep” is just to find the local indexed database
and display the matched result --- I just don’t understand the problem.
Please state more what have you done in order to let us help you.

 

 

-----Original Message-----
From: linuxppc-embedded-bounces+vows_siu=yahoo.com.hk@ozlabs.org
[mailto:linuxppc-embedded-bounces+vows_siu=yahoo.com.hk@ozlabs.org] On
Behalf Of Wade Maxfield
Sent: Tuesday, August 22, 2006 5:34 AM
To: ppc
Subject: ML40X, ppc 405 crash

 


  I was running NFS on ML40X.  I did a "updatedb" and then immediately,
"locate fixdep"

  I got the following crash

root@ml403:/home/moduletest# updatedb
locate fixdep
eth0: Could not transmit buffer. 
eth0: Could not transmit buffer.
eth0: Could not transmit buffer.
Oops: kernel access of bad area, sig: 11 [#1]
PREEMPT
NIP: C01D0F74 LR: C01D0910 SP: C28B1930 REGS: c28b1880 TRAP: 0300    Not
tainted
MSR: 00029030 EE: 1 PR: 0 FP: 0 ME: 1 IR/DR: 11 
DAR: 00000004, DSISR: 00800000
TASK = c0b034c0[5097] 'frcode' THREAD: c28b0000
Last syscall: 234
GPR00: 00000000 C28B1930 C0B034C0 C35E3200 C03CC380 C276E810 000005E8
C3CE8880
GPR08: 00000002 00000000 C3CE890C 00000000 33003599 10018E04 100C3208
C02DCE08 
GPR16: C00DB1CC C02DCE08 00000002 0000000A C28B1DF8 C02E0000 C02A0000
C3A30940
GPR24: 00000000 00000000 00000000 C3A30940 00000000 C35E3200 C3CE8880
C03A8800
NIP [c01d0f74] pfifo_fast_dequeue+0x40/0x74
LR [c01d0910] qdisc_restart+0x30/0x2b4 
Call trace:
 [c01c1e94] dev_queue_xmit+0x264/0x318
 [c01dd8dc] ip_finish_output+0x140/0x2cc
 [c01dddb0] ip_queue_xmit+0x348/0x53c
 [c01ef628] tcp_transmit_skb+0x324/0x7f8
 [c01f05fc] tcp_write_xmit+0x14c/0x31c 
 [c01ed360] __tcp_data_snd_check+0xc8/0xfc
 [c01ed9a4] tcp_rcv_established+0x2c0/0x8ac
 [c01f7250] tcp_v4_do_rcv+0x184/0x374
 [c01f7d9c] tcp_v4_rcv+0x95c/0xa4c
 [c01da000] ip_local_deliver+0x120/0x298
 [c01da86c] ip_rcv+0x400/0x508 
 [c01c2614] netif_receive_skb+0x24c/0x2fc
 [c01c276c] process_backlog+0xa8/0x1a0
 [c01c2908] net_rx_action+0xa4/0x1cc
 [c001bef4] ___do_softirq+0x7c/0x114
Kernel panic - not syncing: Aiee, killing interrupt handler! 
 <0>Rebooting in 180 seconds..
------------------------------------------------------------------------
------------------------------------------------------------------------
-----

Here is the kernel build and boot information.  (I use the demo compact
flash disk image shipped with the ml403 as an intermediate. I've not yet
been able to get a small enough build to fit on 412 meg using your
tools.) 

Linux version 2.6.10_mvl401-ml40x (HYPERLINK
"mailto:root@localhost.localdomain"root@localhost.localdomain) (gcc
version 3.4.3 (MontaV
ista 3.4.3-25.0.107.0601076 2006-07-21)) #1 Fri Aug 18 14:43:45 CDT 2006

Xilinx ML40x Reference System (Virtex-4 FX)
Port by MontaVista Software, Inc. (HYPERLINK
"mailto:source@mvista.com"source@mvista.com)
Built 1 zonelists
Kernel command line: console=ttyS0,115200 ip=on root=/dev/xsysace2 rw 
Xilinx INTC #0 at 0xD1000FC0 mapped to 0xFDFFEFC0
PID hash table entries: 512 (order: 9, 8192 bytes)
hr_time_init: arch_to_nsec = 6990506, nsec_to_arch = 1288490158
Console: colour dummy device 80x25
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes) 
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
Memory: 61824k available (2244k kernel code, 640k data, 140k init, 0k
highmem)
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
spawn_desched_task(00000000) 
desched cpu_callback 3/00000000
ksoftirqd started up.
desched cpu_callback 2/00000000
desched thread 0 started up.
NET: Registered protocol family 16
Registering platform device 'xilinx_emac.0'. Parent at platform 
Registering platform device 'xilinx_fb.0'. Parent at platform
Registering platform device 'xilinx_sysace.0'. Parent at platform
Registering platform device 'xilinx_iic.0'. Parent at platform
Registering platform device 'xilinx_gpio.0'. Parent at platform 
Registering platform device 'xilinx_gpio.1'. Parent at platform
Registering platform device 'xilinx_gpio.2'. Parent at platform
Registering platform device 'xilinx_ps2.0'. Parent at platform
Registering platform device 'xilinx_ps2.1'. Parent at platform 
Installing knfsd (copyright (C) 1996 HYPERLINK
"mailto:okir@monad.swb.de"okir@monad.swb.de).
Console: switching to colour frame buffer device 80x30
xgpio #0 at 0x90000000 mapped to 0xC505C000
xgpio #1 at 0x90001000 mapped to 0xC505E000 
xgpio #2 at 0x90002000 mapped to 0xC5060000
xilinx_ps2 #0 at 0xA9000000 mapped to 0xC5062000
xilinx_ps2 #1 at 0xA9001000 mapped to 0xC5064000
Serial: 8250/16550 driver $Revision: 1.90 $ 5 ports, IRQ sharing
disabled 
Registering platform device 'serial8250'. Parent at platform
ttyS0 at MMIO 0x0 (irq = 9) is a 16450
io scheduler noop registered
io scheduler anticipatory registered
io scheduler deadline registered
io scheduler cfq registered 
RAMDISK driver initialized: 16 RAM disks of 8192K size 1024 blocksize
loop: loaded (max 8 devices)
elevator: using anticipatory as default io scheduler
System ACE at 0xCF000000 mapped to 0xC5066000, irq=3, 500472KB 
 xsysace: xsysace1 xsysace2
PPP generic driver version 2.4.2
PPP Deflate Compression module registered
NET: Registered protocol family 24
xemac 0: using fifo mode.
eth0: Xilinx EMAC #0 at 0x60000000 mapped to 0xC5068000, irq=0 
i2c /dev entries driver
xilinx_iic.0 #0 at 0xA8000000 mapped to 0xC506E000, irq=6
mice: PS/2 mouse device common for all mice
atkbd.c: keyboard reset failed on xilinxps2/serio0
atkbd.c: keyboard reset failed on xilinxps2/serio1 
NET: Registered protocol family 2
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 4096 bind 8192)
NET: Registered protocol family 1
NET: Registered protocol family 17 
Sending DHCP requests ., OK
IP-Config: Got DHCP answer from HYPERLINK "http://0.0.0.0"0.0.0.0, my
address is HYPERLINK "http://172.17.6.49"172.17.6.49
IP-Config: Complete:
      device=eth0, addr=HYPERLINK "http://172.17.6.49" 172.17.6.49,
mask=HYPERLINK "http://255.255.254.0"255.255.254.0, gw=HYPERLINK
"http://172.17.7.254"172.17.7.254,
     host=HYPERLINK "http://172.17.6.49"172.17.6.49, domain=HYPERLINK
"http://precisiondrilling.com" precisiondrilling.com, nis-domain=(none),
     bootserver=HYPERLINK "http://0.0.0.0"0.0.0.0, rootserver=HYPERLINK
"http://0.0.0.0"0.0.0.0, rootpath=
EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended 
VFS: Mounted root (ext2 filesystem).
Freeing unused kernel memory: 140k init
INIT: version 2.78 booting
Activating swap...
Checking all file systems...
fsck 1.27 (8-Mar-2002)
Calculating module dependencies... depmod: QM_MODULES: Function not
implemented 

done.
Loading modules:
modprobe: QM_MODULES: Function not implemented

Mounting local filesystems...
nothing was mounted
Cleaning: /etc/network/ifstate.
Setting up IP spoofing protection: rp_filter. 
Disable TCP/IP Explicit Congestion Notification: done.
Configuring network interfaces: done.
Starting portmap daemon: portmap.
Starting dhcpcd on eth0
Running ntpdate to synchronize clock.
Cleaning: /tmp /var/lock /var/rundhcpcd[775]: dhcpConfig: ioctl
SIOCADDRT: File exists 

.
INIT: Entering runlevel: 3
Starting kernel log daemon: klogd.
Starting system log daemon: syslogd.
Hostname: ml403.
Creating barrier for shutdown
Starting X11 session for user 'linux'
Welcome to the ML403 Evaluation Board 
(C) 2004 Xilinx, Inc - Systems Engineering Group







--
No virus found in this incoming message.
Checked by AVG Free Edition.
Version: 7.1.405 / Virus Database: 268.11.4/424 - Release Date:
2006/8/21


-- 
No virus found in this outgoing message.
Checked by AVG Free Edition.
Version: 7.1.405 / Virus Database: 268.11.4/424 - Release Date:
2006/8/21
 

[-- Attachment #2: Type: text/html, Size: 11821 bytes --]

^ permalink raw reply

* Re: [PATCH 4/6] POWERPC: add support of mpc8560 eval board
From: Vitaly Bordug @ 2006-08-22 11:03 UTC (permalink / raw)
  To: Andy Fleming; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <6A1F08CA-2FAE-4BE6-82BF-30F35053483C@freescale.com>

On Thu, 17 Aug 2006 15:04:11 -0500
Andy Fleming wrote:

> 
> On Aug 11, 2006, at 19:10, Vitaly Bordug wrote:
> 
> 
> >
> > diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/ 
> > boot/dts/mpc8560ads.dts
> > new file mode 100644
> > index 0000000..f6ccb99
> > --- /dev/null
> > +++ b/arch/powerpc/boot/dts/mpc8560ads.dts
> > @@ -0,0 +1,310 @@
> >
> > +
> > +		ethernet@24000 {
> > +			device_type = "network";
> > +			model = "TSEC";
> > +			compatible = "gianfar";
> > +			reg = <24000 1000>;
> > +			address = [ 00 00 0C 00 00 FD ];
> > +			interrupts = <d 0 e 0 12 0>;
> 
> Your sense values are wrong here.  Should be "2"
> ie - interrupts = <d 2 e 2 12 2>;
> 
Here and below: 
those were derived from the original dts's an since it worked "as it is" I didn't fairly care atm.

It is clear, that the spec itself is 100% non-contradictory and consistent, so my main concern was to make-it-work. And, those stuff seems not to be taken into account (may be wrong `tho, haven't really looked into,
Ben ?

) 

> 
> > +			interrupt-parent = <40000>;
> > +			phy-handle = <2452000>;
> > +		};
> > +
> > +		ethernet@25000 {
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +			device_type = "network";
> > +			model = "TSEC";
> > +			compatible = "gianfar";
> > +			reg = <25000 1000>;
> > +			address = [ 00 00 0C 00 01 FD ];
> > +			interrupts = <13 0 14 0 18 0>;
> 
> 
> Here, too
>
ditto 
> > +		pic@40000 {
> > +			linux,phandle = <40000>;
> > +			interrupt-controller;
> > +			#address-cells = <0>;
> > +			#interrupt-cells = <2>;
> > +			reg = <40000 20100>;
> > +			built-in;
> > +			device_type = "mpic";
> 
> This is wrong.  It should be "open-pic";
> 
I am recalling nogo with open-pic here... I agree with Segher, we'll make this 100% clear and follow that 
further.
> > +		};
> > +		
> > +		cpm@e0000000 {
> 
> I'm going to leave this to others to discuss, since I'm not a CPM  
> expert.  But you may want to double-check your interrupt sense  
> values, and make sure the encodings are right.
> 
> 

I am completely open to the comments here..

And my guess is that the irq thing should be clarified and re-synced
with spec. All I can say currently - it works for me so may be used at least as reference 
for the stuff alike. If the cpm2 description got settle down, I'll update the spec in relevance 
and hope to make other inconsistencies (irq-related, obsoleted stuff etc. ) addressed.
> > diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/ 
> > platforms/85xx/Kconfig
> > index 454fc53..3d440de 100644
> > --- a/arch/powerpc/platforms/85xx/Kconfig
> > +++ b/arch/powerpc/platforms/85xx/Kconfig
> > @@ -11,6 +11,12 @@ config MPC8540_ADS
> >  	help
> >  	  This option enables support for the MPC 8540 ADS board
> >
> > +config MPC8560_ADS
> > +	bool "Freescale MPC8560 ADS"
> > +	select DEFAULT_UIMAGE
> > +	help
> > +	  This option enables support for the MPC 8560 ADS board
> > +
> 
> 
> If at all possible, I think that the 8560 shouldn't be a config  
> option.  It's just an 85xx ADS, and use the dts to distinguish.  But  
> keeping separate defconfigs seems like a good idea.
> 
> 
Agreed.
> 
> > diff --git a/arch/powerpc/platforms/85xx/mpc8540_ads.h b/arch/ 
> > powerpc/platforms/85xx/mpc8540_ads.h
> > index c0d56d2..670abaf 100644
> > --- a/arch/powerpc/platforms/85xx/mpc8540_ads.h
> > +++ b/arch/powerpc/platforms/85xx/mpc8540_ads.h
> > @@ -6,6 +6,10 @@
> >   * Maintainer: Kumar Gala <kumar.gala@freescale.com>
> >   *
> >   * Copyright 2004 Freescale Semiconductor Inc.
> > + *
> > + * 2006 (c) MontaVista Software, Inc.
> > + * Vitaly Bordug <vbordug@ru.mvista.com>
> > + *	Merged to arch/powerpc
> >   *
> >   * 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
> > @@ -24,10 +28,10 @@ #define BCSR_ADDR
> > ((uint)0xf8000000) #define BCSR_SIZE		((uint)(32 *
> > 1024))
> >
> >  /* PCI interrupt controller */
> > -#define PIRQA		MPC85xx_IRQ_EXT1
> > -#define PIRQB		MPC85xx_IRQ_EXT2
> > -#define PIRQC		MPC85xx_IRQ_EXT3
> > -#define PIRQD		MPC85xx_IRQ_EXT4
> > +#define PIRQA		49
> > +#define PIRQB		50
> > +#define PIRQC		51
> > +#define PIRQD		52
> 
> 
> Wha?!  I can't imagine any reason this change would be acceptable.   
> Especially since your patch needs to apply against a tree with the  
> new irq code, which doesn't need such hard-coded values.  We get
> them from the dts.
> 
> 
Tend to be cleanup_miss, the same as note below.

> > diff --git a/arch/powerpc/platforms/85xx/mpc8560_ads.h b/arch/ 
> > powerpc/platforms/85xx/mpc8560_ads.h
> 
> This file should be able to go away, now, and get merged with  
> mpc8540_ads.h.  While we're at it, mpc8540_ads.h should become  
> mpc85xx_ads.h
> 
> 
> > diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/ 
> > platforms/85xx/mpc85xx.h
> > index b44db62..4fe613e 100644
> > --- a/arch/powerpc/platforms/85xx/mpc85xx.h
> > +++ b/arch/powerpc/platforms/85xx/mpc85xx.h
> > @@ -16,3 +16,4 @@
> >
> >  extern void mpc85xx_restart(char *);
> >  extern int add_bridge(struct device_node *dev);
> > +extern void mpc85xx_pcibios_fixup(void);
> 
> Why is this being "exported"?
>
To make it compile :) will be fixed in the reordering in the next respin. 
 
> > diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/ 
> > powerpc/platforms/85xx/mpc85xx_ads.c
> > index d0cfcdb..974e035 100644
> > --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
> > +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
> > @@ -4,6 +4,10 @@
> >   * Maintained by Kumar Gala (see MAINTAINERS for contact
> > information) *
> >   * Copyright 2005 Freescale Semiconductor Inc.
> > + *
> > + * 2006 (c) MontaVista Software, Inc.
> > + * Vitaly Bordug <vbordug@ru.mvista.com>
> > + * 	Merged to arch/powerpc
> 
> This comment is confusing.  This file was already "merged".   
> Regardless, I believe there's a general policy against putting
> change logs in the header.
> 
The last line is extra here - copy-paste thing. I added the upper line to make it clear that though I've created the file(s) in powerpc/, that is only "merge" thing, which is not quite right for this particular file, sorry about that. 

> 
> >
> > @@ -47,19 +59,19 @@ static u_char mpc85xx_ads_openpic_initse
> >  	MPC85XX_INTERNAL_IRQ_SENSES,
> >  	0x0,			/* External  0: */
> >  #if defined(CONFIG_PCI)
> > -	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext
> > 1: PCI slot 0 */
> > -	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext
> > 2: PCI slot 1 */
> > -	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext
> > 3: PCI slot 2 */
> > -	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext
> > 4: PCI slot 3 */
> > +	IRQ_TYPE_LEVEL_LOW, 	/* Ext 1: PCI slot 0 */
> > +	IRQ_TYPE_LEVEL_LOW, 	/* Ext 2: PCI slot 1 */
> > +	IRQ_TYPE_LEVEL_LOW, 	/* Ext 3: PCI slot 2 */
> > +	IRQ_TYPE_LEVEL_LOW, 	/* Ext 4: PCI slot 3 */
> >  #else
> >  	0x0,			/* External  1: */
> >  	0x0,			/* External  2: */
> >  	0x0,			/* External  3: */
> >  	0x0,			/* External  4: */
> >  #endif
> > -	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/*
> > External 5: PHY */
> > +	IRQ_TYPE_LEVEL_LOW,  	/* External  5: PHY */
> >  	0x0,			/* External  6: */
> > -	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/*
> > External 7: PHY */
> > +	IRQ_TYPE_LEVEL_LOW,  	/* External  7: PHY */
> >  	0x0,			/* External  8: */
> >  	0x0,			/* External  9: */
> >  	0x0,			/* External 10: */
> 
> 
> This isn't how interrupt senses are supposed to be done now.  They  
> should be gotten from the device tree.  This whole array can be
> deleted.
> 
>
Here and below about PCI irq stuff - OK. 
 
> > @@ -74,40 +86,109 @@ #ifdef CONFIG_PCI
> >  int
> >  mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel,
> > unsigned char pin)
> >  {
> 
> This whole function can be deleted.
> 
> > +	struct device_node * pci_OF;
> > +	struct irq_map_of_mask {
> > +		unsigned int idsel_msk;
> > +		unsigned int slot_msk;
> > +		unsigned int offset_irqs_msk;
> > +		unsigned int line_msk;
> > +	} *ip;
> > +	int i;
> > +	struct irq_of_table_s {
> > +		struct {
> > +			unsigned int idsel;
> > +			unsigned int slot;
> > +			unsigned int offset_irqs;
> > +			unsigned int line;
> > +			unsigned int parent;
> > +			unsigned int table_item;
> > +			unsigned int ext_irqs;
> > +		} idsel[1];
> > +	}* irq_of_table;
> > +
> > +
> > +	pci_OF = of_find_node_by_type(NULL, "pci");
> > +	if (pci_OF) {
> > +		unsigned long max_idsel = 0;
> > +		unsigned long min_idsel = 0xffffffff;
> > +		unsigned long irqs_per_slot = 0;
> > +		unsigned int idsel_ = 0;
> > +		unsigned int line;
> > +		unsigned int* irq;
> > +		unsigned int ip_len;
> > +		unsigned int irq_table_len;
> > +		unsigned int irq_len;
> > +
> > +		ip = (struct irq_map_of_mask*)get_property(pci_OF,
> > "interrupt- map-mask", &ip_len);
> > +
> > +		irq_of_table = (struct
> > irq_of_table_s*)get_property(pci_OF, "interrupt-map",
> > &irq_table_len); +
> > +		irq = (unsigned int*)get_property(pci_OF,
> > "interrupts", &irq_len); +
> > +		if (ip && irq_of_table && irq && ip_len &&
> > irq_table_len && irq_len ) {
> > +			for (i=0;
> > i<irq_table_len/sizeof(irq_of_table->idsel[0]); i++) {
> > +				line = irq_of_table->idsel[i].line
> > & ip->line_msk;
> > +				idsel_ =
> > (irq_of_table->idsel[i].idsel & ip->idsel_msk) >> 11; +
> > +				irqs_per_slot = (line >
> > irqs_per_slot) ? line : irqs_per_slot;
> > +				min_idsel =  (idsel_ <
> > min_idsel) ? idsel_ : min_idsel;
> > +				max_idsel =  (idsel_ >
> > max_idsel) ? idsel_ : max_idsel;
> > +			}
> > +
> > +			do {
> > +				char pci_irq_table[max_idsel -
> > min_idsel + 1][irqs_per_slot]; +
> > +				memset(&pci_irq_table[0][0], 0,
> > sizeof(pci_irq_table));
> > +				for (i =
> > irq_table_len/sizeof(irq_of_table->idsel[0]) - 1;  
> > i>=0;  i--) {
> > +					idsel_ =
> > (irq_of_table->idsel[i].idsel & ip->idsel_msk) >> 11; +
> > +					line =
> > irq_of_table->idsel[i].line & ip->line_msk;
> > +					pci_irq_table[idsel_ -
> > min_idsel][line-1] =
> > +
> > irq_of_table->idsel[i].table_item;
> > +				}
> > +
> > +				return PCI_IRQ_TABLE_LOOKUP;
> > +			} while(0);
> > +		} else {
> > +			printk(KERN_INFO "%s: device tree
> > ERROR\n",__func__);
> > +			return -1;
> > +		}
> > +	} else {
> > +		static char pci_irq_table[][4] =
> > +		    /*
> > +		     * This is little evil, but works around the
> > fact
> > +		     * that revA boards have IDSEL starting at 18
> > +		     * and others boards (older) start at 12
> > +		     *
> > +		     *      PCI IDSEL/INTPIN->INTLINE
> > +		     *       A      B      C      D
> > +		     */
> > +		{
> > +			{PIRQA, PIRQB, PIRQC, PIRQD},	/*
> > IDSEL 2 */
> > +			{PIRQD, PIRQA, PIRQB, PIRQC},
> > +			{PIRQC, PIRQD, PIRQA, PIRQB},
> > +			{PIRQB, PIRQC, PIRQD, PIRQA},	/*
> > IDSEL 5 */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{PIRQA, PIRQB, PIRQC, PIRQD},	/*
> > IDSEL 12 */
> > +			{PIRQD, PIRQA, PIRQB, PIRQC},
> > +			{PIRQC, PIRQD, PIRQA, PIRQB},
> > +			{PIRQB, PIRQC, PIRQD, PIRQA},	/*
> > IDSEL 15 */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{PIRQA, PIRQB, PIRQC, PIRQD},	/*
> > IDSEL 18 */
> > +			{PIRQD, PIRQA, PIRQB, PIRQC},
> > +			{PIRQC, PIRQD, PIRQA, PIRQB},
> > +			{PIRQB, PIRQC, PIRQD, PIRQA},	/*
> > IDSEL 21 */
> > +		};
> > +
> > +		const long min_idsel = 2, max_idsel = 21,
> > irqs_per_slot = 4;
> > +		return PCI_IRQ_TABLE_LOOKUP;
> > +	}
> 
> 
> Is there some reason you reimplemented code that already exists for  
> mapping PCI interrupts?  Delete this function, and instead add:
> 
> void __init
> mpc85xx_pcibios_fixup(void)
> {
>          struct pci_dev *dev = NULL;
> 
>          for_each_pci_dev(dev)
>                  pci_read_irq_line(dev);
> }
> 
> Hm.  I see you added that function to pci.c.  Anyway, you don't need  
> the map_irq function anymore
> 
> 
> 
> > +	mpic_set_default_senses(mpic1,
> > +				mpc85xx_ads_openpic_initsenses,
> > +
> > sizeof(mpc85xx_ads_openpic_initsenses)); +
> 
> No.  We have parse_and_map to handle this.
> 
> >  	mpic_init(mpic1);
> > +	of_node_put(np);
> 
> Are we definitely supposed to release the of nodes after we call  
> init?  Actually, it looks like you can put that after mpic_alloc().   
> mpic_alloc() grabs a reference, so we don't need it after that.
> 

Looks like true, but I'll double-check this anyway.
> 
> >
> >  /*
> >   * Setup the architecture
> >   */
> 
> There should probably be an #ifdef CONFIG_CPM2 here
> 
ok
> > +static void init_fcc_ioports(void)
> 
> ...
> 
> 
> 
> > diff --git a/include/asm-powerpc/mpc85xx.h b/include/asm-powerpc/ 
> > mpc85xx.h
> 
> This file really needs to be cleaned up.  Most of the stuff in here  
> can go.
> 
My guess to separate the "cleanup_obsolete" and "add_new_stuff" in some ways, it it does not prevent stuff from work. Note that there are still a lot of confusion with ppc/powerpc header mix. So "cleanup" patch should be carefully tested with both ppc and powerpc. I am aware that mpc85xx.h exist in both instances, these are just generic thoughts.


Thanks for the comments and review.

> Andy
> 
> 

^ permalink raw reply

* Re: [PATCH 4/6] POWERPC: add support of mpc8560 eval board
From: Vitaly Bordug @ 2006-08-22 11:13 UTC (permalink / raw)
  To: Andy Fleming; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <6A1F08CA-2FAE-4BE6-82BF-30F35053483C@freescale.com>

On Thu, 17 Aug 2006 15:04:11 -0500
Andy Fleming wrote:

> 
> On Aug 11, 2006, at 19:10, Vitaly Bordug wrote:
> 
> 
> >
> > diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/ 
> > boot/dts/mpc8560ads.dts
> > new file mode 100644
> > index 0000000..f6ccb99
> > --- /dev/null
> > +++ b/arch/powerpc/boot/dts/mpc8560ads.dts
> > @@ -0,0 +1,310 @@
> >
> > +
> > +		ethernet@24000 {
> > +			device_type = "network";
> > +			model = "TSEC";
> > +			compatible = "gianfar";
> > +			reg = <24000 1000>;
> > +			address = [ 00 00 0C 00 00 FD ];
> > +			interrupts = <d 0 e 0 12 0>;
> 
> Your sense values are wrong here.  Should be "2"
> ie - interrupts = <d 2 e 2 12 2>;
> 
Here and below: 
those were derived from the original dts's an since it worked "as it is" I didn't fairly care atm.

It is clear, that the spec itself is 100% non-contradictory and consistent, so my main concern was to make-it-work. And, those stuff seems not to be taken into account (may be wrong `tho, haven't really looked into,
Ben ?

) 

> 
> > +			interrupt-parent = <40000>;
> > +			phy-handle = <2452000>;
> > +		};
> > +
> > +		ethernet@25000 {
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +			device_type = "network";
> > +			model = "TSEC";
> > +			compatible = "gianfar";
> > +			reg = <25000 1000>;
> > +			address = [ 00 00 0C 00 01 FD ];
> > +			interrupts = <13 0 14 0 18 0>;
> 
> 
> Here, too
>
ditto 
> > +		pic@40000 {
> > +			linux,phandle = <40000>;
> > +			interrupt-controller;
> > +			#address-cells = <0>;
> > +			#interrupt-cells = <2>;
> > +			reg = <40000 20100>;
> > +			built-in;
> > +			device_type = "mpic";
> 
> This is wrong.  It should be "open-pic";
> 
I am recalling nogo with open-pic here... I agree with Segher, we'll make this 100% clear and follow that 
further.
> > +		};
> > +		
> > +		cpm@e0000000 {
> 
> I'm going to leave this to others to discuss, since I'm not a CPM  
> expert.  But you may want to double-check your interrupt sense  
> values, and make sure the encodings are right.
> 
> 

I am completely open to the comments here..

And my guess is that the irq thing should be clarified and re-synced
with spec. All I can say currently - it works for me so may be used at least as reference 
for the stuff alike. If the cpm2 description got settle down, I'll update the spec in relevance 
and hope to make other inconsistencies (irq-related, obsoleted stuff etc. ) addressed.
> > diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/ 
> > platforms/85xx/Kconfig
> > index 454fc53..3d440de 100644
> > --- a/arch/powerpc/platforms/85xx/Kconfig
> > +++ b/arch/powerpc/platforms/85xx/Kconfig
> > @@ -11,6 +11,12 @@ config MPC8540_ADS
> >  	help
> >  	  This option enables support for the MPC 8540 ADS board
> >
> > +config MPC8560_ADS
> > +	bool "Freescale MPC8560 ADS"
> > +	select DEFAULT_UIMAGE
> > +	help
> > +	  This option enables support for the MPC 8560 ADS board
> > +
> 
> 
> If at all possible, I think that the 8560 shouldn't be a config  
> option.  It's just an 85xx ADS, and use the dts to distinguish.  But  
> keeping separate defconfigs seems like a good idea.
> 
> 
Agreed.
> 
> > diff --git a/arch/powerpc/platforms/85xx/mpc8540_ads.h b/arch/ 
> > powerpc/platforms/85xx/mpc8540_ads.h
> > index c0d56d2..670abaf 100644
> > --- a/arch/powerpc/platforms/85xx/mpc8540_ads.h
> > +++ b/arch/powerpc/platforms/85xx/mpc8540_ads.h
> > @@ -6,6 +6,10 @@
> >   * Maintainer: Kumar Gala <kumar.gala@freescale.com>
> >   *
> >   * Copyright 2004 Freescale Semiconductor Inc.
> > + *
> > + * 2006 (c) MontaVista Software, Inc.
> > + * Vitaly Bordug <vbordug@ru.mvista.com>
> > + *	Merged to arch/powerpc
> >   *
> >   * 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
> > @@ -24,10 +28,10 @@ #define BCSR_ADDR
> > ((uint)0xf8000000) #define BCSR_SIZE		((uint)(32 *
> > 1024))
> >
> >  /* PCI interrupt controller */
> > -#define PIRQA		MPC85xx_IRQ_EXT1
> > -#define PIRQB		MPC85xx_IRQ_EXT2
> > -#define PIRQC		MPC85xx_IRQ_EXT3
> > -#define PIRQD		MPC85xx_IRQ_EXT4
> > +#define PIRQA		49
> > +#define PIRQB		50
> > +#define PIRQC		51
> > +#define PIRQD		52
> 
> 
> Wha?!  I can't imagine any reason this change would be acceptable.   
> Especially since your patch needs to apply against a tree with the  
> new irq code, which doesn't need such hard-coded values.  We get
> them from the dts.
> 
> 
Tend to be cleanup_miss, the same as note below.

> > diff --git a/arch/powerpc/platforms/85xx/mpc8560_ads.h b/arch/ 
> > powerpc/platforms/85xx/mpc8560_ads.h
> 
> This file should be able to go away, now, and get merged with  
> mpc8540_ads.h.  While we're at it, mpc8540_ads.h should become  
> mpc85xx_ads.h
> 
> 
> > diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/ 
> > platforms/85xx/mpc85xx.h
> > index b44db62..4fe613e 100644
> > --- a/arch/powerpc/platforms/85xx/mpc85xx.h
> > +++ b/arch/powerpc/platforms/85xx/mpc85xx.h
> > @@ -16,3 +16,4 @@
> >
> >  extern void mpc85xx_restart(char *);
> >  extern int add_bridge(struct device_node *dev);
> > +extern void mpc85xx_pcibios_fixup(void);
> 
> Why is this being "exported"?
>
To make it compile :) will be fixed in the reordering in the next respin. 
 
> > diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/ 
> > powerpc/platforms/85xx/mpc85xx_ads.c
> > index d0cfcdb..974e035 100644
> > --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
> > +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
> > @@ -4,6 +4,10 @@
> >   * Maintained by Kumar Gala (see MAINTAINERS for contact
> > information) *
> >   * Copyright 2005 Freescale Semiconductor Inc.
> > + *
> > + * 2006 (c) MontaVista Software, Inc.
> > + * Vitaly Bordug <vbordug@ru.mvista.com>
> > + * 	Merged to arch/powerpc
> 
> This comment is confusing.  This file was already "merged".   
> Regardless, I believe there's a general policy against putting
> change logs in the header.
> 
The last line is extra here - copy-paste thing. I added the upper line to make it clear that though I've created the file(s) in powerpc/, that is only "merge" thing, which is not quite right for this particular file, sorry about that. 

> 
> >
> > @@ -47,19 +59,19 @@ static u_char mpc85xx_ads_openpic_initse
> >  	MPC85XX_INTERNAL_IRQ_SENSES,
> >  	0x0,			/* External  0: */
> >  #if defined(CONFIG_PCI)
> > -	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext
> > 1: PCI slot 0 */
> > -	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext
> > 2: PCI slot 1 */
> > -	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext
> > 3: PCI slot 2 */
> > -	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext
> > 4: PCI slot 3 */
> > +	IRQ_TYPE_LEVEL_LOW, 	/* Ext 1: PCI slot 0 */
> > +	IRQ_TYPE_LEVEL_LOW, 	/* Ext 2: PCI slot 1 */
> > +	IRQ_TYPE_LEVEL_LOW, 	/* Ext 3: PCI slot 2 */
> > +	IRQ_TYPE_LEVEL_LOW, 	/* Ext 4: PCI slot 3 */
> >  #else
> >  	0x0,			/* External  1: */
> >  	0x0,			/* External  2: */
> >  	0x0,			/* External  3: */
> >  	0x0,			/* External  4: */
> >  #endif
> > -	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/*
> > External 5: PHY */
> > +	IRQ_TYPE_LEVEL_LOW,  	/* External  5: PHY */
> >  	0x0,			/* External  6: */
> > -	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/*
> > External 7: PHY */
> > +	IRQ_TYPE_LEVEL_LOW,  	/* External  7: PHY */
> >  	0x0,			/* External  8: */
> >  	0x0,			/* External  9: */
> >  	0x0,			/* External 10: */
> 
> 
> This isn't how interrupt senses are supposed to be done now.  They  
> should be gotten from the device tree.  This whole array can be
> deleted.
> 
>
Here and below about PCI irq stuff - OK. 
 
> > @@ -74,40 +86,109 @@ #ifdef CONFIG_PCI
> >  int
> >  mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel,
> > unsigned char pin)
> >  {
> 
> This whole function can be deleted.
> 
> > +	struct device_node * pci_OF;
> > +	struct irq_map_of_mask {
> > +		unsigned int idsel_msk;
> > +		unsigned int slot_msk;
> > +		unsigned int offset_irqs_msk;
> > +		unsigned int line_msk;
> > +	} *ip;
> > +	int i;
> > +	struct irq_of_table_s {
> > +		struct {
> > +			unsigned int idsel;
> > +			unsigned int slot;
> > +			unsigned int offset_irqs;
> > +			unsigned int line;
> > +			unsigned int parent;
> > +			unsigned int table_item;
> > +			unsigned int ext_irqs;
> > +		} idsel[1];
> > +	}* irq_of_table;
> > +
> > +
> > +	pci_OF = of_find_node_by_type(NULL, "pci");
> > +	if (pci_OF) {
> > +		unsigned long max_idsel = 0;
> > +		unsigned long min_idsel = 0xffffffff;
> > +		unsigned long irqs_per_slot = 0;
> > +		unsigned int idsel_ = 0;
> > +		unsigned int line;
> > +		unsigned int* irq;
> > +		unsigned int ip_len;
> > +		unsigned int irq_table_len;
> > +		unsigned int irq_len;
> > +
> > +		ip = (struct irq_map_of_mask*)get_property(pci_OF,
> > "interrupt- map-mask", &ip_len);
> > +
> > +		irq_of_table = (struct
> > irq_of_table_s*)get_property(pci_OF, "interrupt-map",
> > &irq_table_len); +
> > +		irq = (unsigned int*)get_property(pci_OF,
> > "interrupts", &irq_len); +
> > +		if (ip && irq_of_table && irq && ip_len &&
> > irq_table_len && irq_len ) {
> > +			for (i=0;
> > i<irq_table_len/sizeof(irq_of_table->idsel[0]); i++) {
> > +				line = irq_of_table->idsel[i].line
> > & ip->line_msk;
> > +				idsel_ =
> > (irq_of_table->idsel[i].idsel & ip->idsel_msk) >> 11; +
> > +				irqs_per_slot = (line >
> > irqs_per_slot) ? line : irqs_per_slot;
> > +				min_idsel =  (idsel_ <
> > min_idsel) ? idsel_ : min_idsel;
> > +				max_idsel =  (idsel_ >
> > max_idsel) ? idsel_ : max_idsel;
> > +			}
> > +
> > +			do {
> > +				char pci_irq_table[max_idsel -
> > min_idsel + 1][irqs_per_slot]; +
> > +				memset(&pci_irq_table[0][0], 0,
> > sizeof(pci_irq_table));
> > +				for (i =
> > irq_table_len/sizeof(irq_of_table->idsel[0]) - 1;  
> > i>=0;  i--) {
> > +					idsel_ =
> > (irq_of_table->idsel[i].idsel & ip->idsel_msk) >> 11; +
> > +					line =
> > irq_of_table->idsel[i].line & ip->line_msk;
> > +					pci_irq_table[idsel_ -
> > min_idsel][line-1] =
> > +
> > irq_of_table->idsel[i].table_item;
> > +				}
> > +
> > +				return PCI_IRQ_TABLE_LOOKUP;
> > +			} while(0);
> > +		} else {
> > +			printk(KERN_INFO "%s: device tree
> > ERROR\n",__func__);
> > +			return -1;
> > +		}
> > +	} else {
> > +		static char pci_irq_table[][4] =
> > +		    /*
> > +		     * This is little evil, but works around the
> > fact
> > +		     * that revA boards have IDSEL starting at 18
> > +		     * and others boards (older) start at 12
> > +		     *
> > +		     *      PCI IDSEL/INTPIN->INTLINE
> > +		     *       A      B      C      D
> > +		     */
> > +		{
> > +			{PIRQA, PIRQB, PIRQC, PIRQD},	/*
> > IDSEL 2 */
> > +			{PIRQD, PIRQA, PIRQB, PIRQC},
> > +			{PIRQC, PIRQD, PIRQA, PIRQB},
> > +			{PIRQB, PIRQC, PIRQD, PIRQA},	/*
> > IDSEL 5 */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{PIRQA, PIRQB, PIRQC, PIRQD},	/*
> > IDSEL 12 */
> > +			{PIRQD, PIRQA, PIRQB, PIRQC},
> > +			{PIRQC, PIRQD, PIRQA, PIRQB},
> > +			{PIRQB, PIRQC, PIRQD, PIRQA},	/*
> > IDSEL 15 */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{0, 0, 0, 0},	/* -- */
> > +			{PIRQA, PIRQB, PIRQC, PIRQD},	/*
> > IDSEL 18 */
> > +			{PIRQD, PIRQA, PIRQB, PIRQC},
> > +			{PIRQC, PIRQD, PIRQA, PIRQB},
> > +			{PIRQB, PIRQC, PIRQD, PIRQA},	/*
> > IDSEL 21 */
> > +		};
> > +
> > +		const long min_idsel = 2, max_idsel = 21,
> > irqs_per_slot = 4;
> > +		return PCI_IRQ_TABLE_LOOKUP;
> > +	}
> 
> 
> Is there some reason you reimplemented code that already exists for  
> mapping PCI interrupts?  Delete this function, and instead add:
> 
> void __init
> mpc85xx_pcibios_fixup(void)
> {
>          struct pci_dev *dev = NULL;
> 
>          for_each_pci_dev(dev)
>                  pci_read_irq_line(dev);
> }
> 
> Hm.  I see you added that function to pci.c.  Anyway, you don't need  
> the map_irq function anymore
> 
> 
> 
> > +	mpic_set_default_senses(mpic1,
> > +				mpc85xx_ads_openpic_initsenses,
> > +
> > sizeof(mpc85xx_ads_openpic_initsenses)); +
> 
> No.  We have parse_and_map to handle this.
> 
> >  	mpic_init(mpic1);
> > +	of_node_put(np);
> 
> Are we definitely supposed to release the of nodes after we call  
> init?  Actually, it looks like you can put that after mpic_alloc().   
> mpic_alloc() grabs a reference, so we don't need it after that.
> 

Looks like true, but I'll double-check this anyway.
> 
> >
> >  /*
> >   * Setup the architecture
> >   */
> 
> There should probably be an #ifdef CONFIG_CPM2 here
> 
ok
> > +static void init_fcc_ioports(void)
> 
> ...
> 
> 
> 
> > diff --git a/include/asm-powerpc/mpc85xx.h b/include/asm-powerpc/ 
> > mpc85xx.h
> 
> This file really needs to be cleaned up.  Most of the stuff in here  
> can go.
> 
My guess to separate the "cleanup_obsolete" and "add_new_stuff" in some ways, it it does not prevent stuff from work. Note that there are still a lot of confusion with ppc/powerpc header mix. So "cleanup" patch should be carefully tested with both ppc and powerpc. I am aware that mpc85xx.h exist in both instances, these are just generic thoughts.


Thanks for the comments and review.

> Andy
> 
> 

^ permalink raw reply

* Re: Take 2: [RFC] Debugging with a HW probe.
From: Jimi Xenidis @ 2006-08-22 12:12 UTC (permalink / raw)
  To: Milton Miller; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <aa3478a76dd7fb5bff781350a7538fb0@bga.com>


On Aug 22, 2006, at 2:04 AM, Milton Miller wrote:

>
> On Aug 14, 2006, at 5:16 AM, Jimi Xenidis jimix at watson.ibm.com   
> wrote:
>>
>> Signed-off-by: Jimi Xenidis <jimix at watson.ibm.com>
>
> [sorry for the list archive patch munging]
>
>> ---
>> diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
>> index e29ef77..bc4cdf9 100644
>> --- a/arch/powerpc/Kconfig.debug
>> +++ b/arch/powerpc/Kconfig.debug
>> @@ -61,6 +61,17 @@ config KGDB_CONSOLE
>>           over the gdb stub.
>>           If unsure, say N.
>>
>> +config ENABLE_HW_PROBE
>> +       bool "Allow instructions that contact a hardware probe  
>> (dangerous)"
>> +       depends on PPC64
>
> Not having this depend on DEBUGGER but in the middle of things that  
> do will
> get you scorn from the auto-indenting police.
ACK

>
> Since we can only call this from xmon, should it depend on XMON  
> (and be
> placed after that)?

If the HW probe is available, XMON will use it.
However, enabling the HW probe also means that I can (as a developer)  
insert ATTN() anywhere in my code and have the probe stop there. I  
even have kernels where BUG() contains ATTN(), but thats another patch.

>
>> +       help
>> +         If you enable this AND you add "hwprobe" to the cmdline,  
>> the
>> +         processor will enable instructions that contact the  
>> hardware
>> +         probe.  These instructions ca be used in all processor  
>> modes
>
> can
ACK

>
>> +         _including_ user mode and are only useful for kernel
>
> not sure this _highlighting_ is used elsewhere in Kconfig help ...

I was looking for an example and found "_will not boot_" in this very  
file.

>
> Should we mention that a hardware probe is required to continue  
> exectuion?
> In other words, its not just contact, but signal and wait for a hw  
> probe?
Hows this?
          If you enable this AND you add "hwprobe" to the cmdline, the
          processor will enable instructions that signal and wait for
          the hardware probe, _stopping_ the processor.  These
          instructions can be used in all processor modes _including_
          user mode and are only useful for kernel development and
          debugging.  DO NOT enable this unless you plan to use it.  If
          you DO NOT have a hardware probe, answer N.

[snip]
>> --- a/arch/powerpc/kernel/prom_init.c
>> +++ b/arch/powerpc/kernel/prom_init.c
>> @@ -587,6 +587,14 @@ #ifdef CONFIG_PPC64
>>                         RELOC(iommu_force_on) = 1;
>>         }
>>  #endif
>> +#ifdef CONFIG_HW_PROBE_ENABLE
>> +       opt = strstr(RELOC(prom_cmd_line), RELOC("hwprobe"));
>> +       if (opt) {
>> +               prom_printf("WARNING! HW Probe will be activated! 
>> \n");
>> +               prom_setprop(_prom->chosen, "/chosen",
>> +                            "linux,hw-probe-enable", NULL, 0);
>> +       }
>> +#endif
>>  }
>
> Please, PLEASE do NOT do this.

Ok, I won't. I somehow missed "early_param()" that should do just fine.

>
> Which .h is hw_probe_enabled in?  (none?)

Correct, this RFC is to get valuable feedback (thank you), the  
setting the global is the current goal, I'm waiting for some other  
patches from other people to get in before we start going after HID  
bits that this global, may or may not be part of.

>
>>
>>  #ifdef CONFIG_PPC_PSERIES
>> diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
>> index 179b10c..51a1e4e 100644
>> --- a/arch/powerpc/xmon/xmon.c
>> +++ b/arch/powerpc/xmon/xmon.c
>> @@ -189,7 +189,12 @@ #endif
>>    dd   dump double values\n\
>>    dr   dump stream of raw bytes\n\
>>    e    print exception information\n\
>> -  f    flush cache\n\
>> +  f    flush cache\n"
>> +#ifdef CONFIG_ENABLE_HW_PROBE
>> +  "\
>> +  H     Contact hardware probe, if available\n"
>> +#endif
>> +  "\
>
> While this style does keep the lines aligned in the source, it adds  
> veritcal
> almost-whitespace.

Are you expressing "dislike"?

>   And I notice a different choice was made at the bottom.
I borrowed from the CONFIG_SMP above and avoided putting '"' in col 0  
but am happy to compress.

[snip]
>> @@ -641,6 +648,13 @@ extern void ppc64_runlatch_off(void);
>>  extern unsigned long scom970_read(unsigned int address);
>>  extern void scom970_write(unsigned int address, unsigned long  
>> value);
>>
>> +/*
>> + * Support Processor Attention Instruction instroduced in POWER
>> + * architecture processors as of RS64, tho may not be supported by
>> + * POWER 3.
>> + */
>> +#define ATTN() asm volatile("attn; nop")
>> +
>
>
> Fairly certian POWER3 does NOT implement this, but I don't have  
> book IV handy.
The book4 mentions "BPUBKT" and when asked no one could give a  
definite answerm, I figured I'd try an see at some point.  Having  
said that, you give me a s/Fairly/Absolutely/ and its GONE!

> Does one of the processors require the nop ?

The nop is there so that once in the probe, depending on your probe  
interface, you can easily skip it by adding 4 to the PC knowing you  
would get a nop.  This is not entirely necessary but some processor/ 
probes have a PC and a "next PC".  I have had little experience with  
this probe and wanted to make sure I had something to set both to if  
it was needed.

Thanks for your feedback.
-JX

^ permalink raw reply

* RE: Gianfar eth driver on 8540 ppc - for 2.4 and 2.6 : different outputs - i have made some progress.
From: Prashant Yendigeri @ 2006-08-22 12:18 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <OF3EFEEE4F.C1FFA5F2-ON652571CD.00345D42-652571CD.003481A2@lntinfotech.com>

[-- Attachment #1: Type: text/plain, Size: 7342 bytes --]

Hi,

Finally i have reached a position, where the PHY is detected . Now i am 
using kernel version 2.6.14.4 and the gianfar_driver and phy driver seem 
to be ok

But my problem now is after the PHY is detected (correctly) I don't get 
messages like Speed, Full or half duplex, link is up etc. 
This means that the driver is not completely up, right ? 

What might be the problem ? 

I am loading gianfar driver as a loadable module, but the marvell and 
generic phy driver are built into the kernel.

This is my output :
/ # ifconfig eth0 172.28.8.254 up
eth0: PHY is Marvell 88E1101/88E1111 (1410c62)

But after this no output, like Speed, etc.
I checked the code, this info is in a function , gfar_phy_change which 
inturn is setup in a PHY change work queue called INIT_WORK. All of this 
code is in 
drivers/net/gianfar.c

Regards,
-prashant 



Prashant Yendigeri <Prashant.Yendigeri@lntinfotech.com> 
Sent by: 
linuxppc-embedded-bounces+prashant.yendigeri=lntinfotech.com@ozlabs.org
08/17/2006 03:03 PM

To
Ho Jeffrey-r26191 <r26191@freescale.com>
cc
linuxppc-embedded@ozlabs.org
Subject
RE: Gianfar eth driver on 8540 ppc - for 2.4 and 2.6 : different outputs







Hi, 
This is what i am getting from u-boot print messages : 

U-Boot 1.1.0(pq3-20040423-r1) (May  5 2006 - 08:56:54) 

Freescale PowerPC 
    Core: E500, Version: 2.0, (0x80200020) 
    System: 8540, Version: 2.0, (0x80300020) 
    Clocks: CPU: 660 MHz, CCB: 264 MHz, DDR: 132 MHz, LBC:  66 MHz 
    L1 D-cache 32KB, L1 I-cache 32KB enabled. 
Board: Freescale EVAL8540 Board 
        CPU: 660 MHz 
        CCB: 264 MHz 
        DDR: 132 MHz 
        LBC: 66 MHz 
L1 D-cache 32KB, L1 I-cache 32KB enabled. 
I2C:   ready 
DRAM:  256 MB 
FLASH:  8 MB 
L2 cache enabled: 256KB 
In:    serial 
Out:   serial 
Err:   serial 
Net:   Freescale ENET0: PHY is Marvell 88E1011S (1410c62) 
Freescale ENET1: PHY is Marvell 88E1011S (1410c62) 
Freescale ENET2: PHY is Intel LXT971A (1378e2) 
Freescale ENET0, Freescale ENET1, Freescale ENET2 
Hit any key to stop autoboot:  0 
MPC8540EVAL=> 
MPC8540EVAL=> 

This seems to me it is a old board from GDATECH . Data sheet not available 
for this. 


-prashant 


Ho Jeffrey-r26191 <r26191@freescale.com> 
08/12/2006 06:32 AM 


To
"'Prashant Yendigeri'" <Prashant.Yendigeri@lntinfotech.com>, Kumar Gala 
<galak@kernel.crashing.org> 
cc
linuxppc-embedded@ozlabs.org 
Subject
RE: Gianfar eth driver on 8540 ppc - for 2.4 and 2.6 : different outputs








Hi

>>>>[   34.041809] 0:00 not found 
SIOCSIFFLAGS: No[   34.044526] eth0: Could not attach to PHY 
such device 
SIOCSIFFLAGS: No such device 
>>>>>  eth0: PHY is Generic MII (ffffffff)
_______________________________________________________
Can you quickly check if you have the right phy id written in your 
platform file for your board?

Regards, 
Jeffrey Ho 
Freescale Semiconductor HK Ltd 





________________________________

                From: 
linuxppc-embedded-bounces+r26191=freescale.com@ozlabs.org 
[mailto:linuxppc-embedded-bounces+r26191=freescale.com@ozlabs.org] On 
Behalf Of Prashant Yendigeri
                Sent: Friday, August 11, 2006 7:21 PM
                To: Kumar Gala
                Cc: linuxppc-embedded@ozlabs.org
                Subject: Re: Gianfar eth driver on 8540 ppc - for 2.4 and 
2.6 : different outputs
 
 

                Hi, 
 
                Downloaded 2.6.16.26 and booted up and got this : 
 
                / # ifconfig eth0 172.28.8.254 up 
                [   34.034596] 0:00 not found 
                [   34.037330] eth0: Could not attach to PHY 
                [   34.041809] 0:00 not found 
                SIOCSIFFLAGS: No[   34.044526] eth0: Could not attach to 
PHY 
                 such device 
                SIOCSIFFLAGS: No such device 
 
                I had enabled all the PHY devices in .config and also 
tried only with Marvell phy enabled. 
 
                Kernel boot messages : 
                [    2.296555] Gianfar MII Bus: probed 
                [    2.301789] eth0: Gianfar Ethernet Controller Version 
1.2, 00:01:af:07:9b:8a 
 
                [    2.309039] eth0: Running with NAPI disabled 
                [    2.313307] eth0: 64/64 RX/TX BD ring size 
                [    2.318498] eth1: Gianfar Ethernet Controller Version 
1.2, 00:00:00:00:72:6f 
 
                [    2.325738] eth1: Running with NAPI disabled 
                [    2.330006] eth1: 64/64 RX/TX BD ring size 
                [    2.335198] eth2: Gianfar Ethernet Controller Version 
1.2, 6f:74:3d:2f:64:65 
 
                [    2.342377] eth2: Running with NAPI disabled 
                [    2.346662] eth2: 64/64 RX/TX BD ring size 
                [    2.351586] Marvell 88E1101: Registered new driver 
                [    2.357010] Davicom DM9161E: Registered new driver 
                [    2.362443] Davicom DM9131: Registered new driver 
                [    2.367775] Cicada Cis8204: Registered new driver 
                [    2.373136] LXT970: Registered new driver 
                [    2.377794] LXT971: Registered new driver 
                [    2.382461] QS6612: Registered new driver 
 
 
                Regards, 
                Prashant 
 
 
 
 
 
 
                Kumar Gala <galak@kernel.crashing.org> 

                08/11/2006 09:40 AM 

 
                                 To
                                 Prashant Yendigeri 
<Prashant.Yendigeri@lntinfotech.com> 
                                 cc
                                 linuxppc-embedded@ozlabs.org 
                                 Subject
                                 Re: Gianfar eth driver on 8540 ppc - for 
2.4 and 2.6 : different outputs

 




 
                On Aug 10, 2006, at 6:18 AM, Prashant Yendigeri wrote:
 
                >
                > Hi,
                >
                > The gianfar driver of 2.6.12 and 2.4.20 give different 
outputs on 
                > the same PPC 8540 board.
                >
                > What could be the reason ?
                >
                > Output on 2.4.20 :
                > /root # ifconfig eth0 172.28.8.254 up
                > eth0: PHY is Marvell 88E1011S (1410c62)
                > eth0: Auto-negotiation done
                > eth0: Half Duplex
                > eth0: Speed 10BT
                > eth0: Link is up
                >
                > Output on 2.6.12
                > / # ifconfig eth0 172.28.8.254 up
                >  eth0: PHY is Generic MII (ffffffff)
 
                It looks like your 2.6.12 kernel isn't handling the PHY 
correctly. 
                I'd recommend upgrading to something newer which has the 
phylib 
                (can't remember which 2.6 that went into).
 
                - kumar
 
 ______________________________________________________________________
 
 
 ______________________________________________________________________
 


______________________________________________________________________


______________________________________________________________________

______________________________________________________________________
_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded


______________________________________________________________________

[-- Attachment #2: Type: text/html, Size: 17108 bytes --]

^ permalink raw reply

* RE: Gianfar eth driver on 8540 ppc - for 2.4 and 2.6 : different outputs - i have made some progress.
From: Prashant Yendigeri @ 2006-08-22 12:54 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <OF4994B4A2.853A7058-ON652571D2.0042D6D3-652571D2.0043A270@lntinfotech.com>

[-- Attachment #1: Type: text/plain, Size: 8065 bytes --]

Hi,
I made a small change in arch/ppc/platforms/85xx/mpc8540*c . I changed the 
phyid value of TSEC1 to 4 and TSEC2 to 5. And it started working.

-Prashant 



Prashant Yendigeri <Prashant.Yendigeri@lntinfotech.com> 
Sent by: 
linuxppc-embedded-bounces+prashant.yendigeri=lntinfotech.com@ozlabs.org
08/22/2006 05:48 PM

To
linuxppc-embedded@ozlabs.org
cc

Subject
RE: Gianfar eth driver on 8540 ppc - for 2.4 and 2.6 : different outputs - 
i have made some progress.







Hi, 

Finally i have reached a position, where the PHY is detected . Now i am 
using kernel version 2.6.14.4 and the gianfar_driver and phy driver seem 
to be ok 

But my problem now is after the PHY is detected (correctly) I don't get 
messages like Speed, Full or half duplex, link is up etc. 
This means that the driver is not completely up, right ? 

What might be the problem ? 

I am loading gianfar driver as a loadable module, but the marvell and 
generic phy driver are built into the kernel. 

This is my output : 
/ # ifconfig eth0 172.28.8.254 up 
eth0: PHY is Marvell 88E1101/88E1111 (1410c62) 

But after this no output, like Speed, etc. 
I checked the code, this info is in a function , gfar_phy_change which 
inturn is setup in a PHY change work queue called INIT_WORK. All of this 
code is in 
drivers/net/gianfar.c 

Regards, 
-prashant 


Prashant Yendigeri <Prashant.Yendigeri@lntinfotech.com> 
Sent by: 
linuxppc-embedded-bounces+prashant.yendigeri=lntinfotech.com@ozlabs.org 
08/17/2006 03:03 PM 


To
Ho Jeffrey-r26191 <r26191@freescale.com> 
cc
linuxppc-embedded@ozlabs.org 
Subject
RE: Gianfar eth driver on 8540 ppc - for 2.4 and 2.6 : different outputs









Hi, 
This is what i am getting from u-boot print messages : 

U-Boot 1.1.0(pq3-20040423-r1) (May  5 2006 - 08:56:54) 

Freescale PowerPC 
   Core: E500, Version: 2.0, (0x80200020) 
   System: 8540, Version: 2.0, (0x80300020) 
   Clocks: CPU: 660 MHz, CCB: 264 MHz, DDR: 132 MHz, LBC:  66 MHz 
   L1 D-cache 32KB, L1 I-cache 32KB enabled. 
Board: Freescale EVAL8540 Board 
       CPU: 660 MHz 
       CCB: 264 MHz 
       DDR: 132 MHz 
       LBC: 66 MHz 
L1 D-cache 32KB, L1 I-cache 32KB enabled. 
I2C:   ready 
DRAM:  256 MB 
FLASH:  8 MB 
L2 cache enabled: 256KB 
In:    serial 
Out:   serial 
Err:   serial 
Net:   Freescale ENET0: PHY is Marvell 88E1011S (1410c62) 
Freescale ENET1: PHY is Marvell 88E1011S (1410c62) 
Freescale ENET2: PHY is Intel LXT971A (1378e2) 
Freescale ENET0, Freescale ENET1, Freescale ENET2 
Hit any key to stop autoboot:  0 
MPC8540EVAL=> 
MPC8540EVAL=> 

This seems to me it is a old board from GDATECH . Data sheet not available 
for this. 


-prashant 

Ho Jeffrey-r26191 <r26191@freescale.com> 
08/12/2006 06:32 AM 


To
"'Prashant Yendigeri'" <Prashant.Yendigeri@lntinfotech.com>, Kumar Gala 
<galak@kernel.crashing.org> 
cc
linuxppc-embedded@ozlabs.org 
Subject
RE: Gianfar eth driver on 8540 ppc - for 2.4 and 2.6 : different outputs










Hi

>>>>[   34.041809] 0:00 not found 
SIOCSIFFLAGS: No[   34.044526] eth0: Could not attach to PHY 
such device 
SIOCSIFFLAGS: No such device 
>>>>>  eth0: PHY is Generic MII (ffffffff)
_______________________________________________________
Can you quickly check if you have the right phy id written in your 
platform file for your board?

Regards, 
Jeffrey Ho 
Freescale Semiconductor HK Ltd 





________________________________

               From: 
linuxppc-embedded-bounces+r26191=freescale.com@ozlabs.org 
[mailto:linuxppc-embedded-bounces+r26191=freescale.com@ozlabs.org] On 
Behalf Of Prashant Yendigeri
               Sent: Friday, August 11, 2006 7:21 PM
               To: Kumar Gala
               Cc: linuxppc-embedded@ozlabs.org
               Subject: Re: Gianfar eth driver on 8540 ppc - for 2.4 and 
2.6 : different outputs
 
 

               Hi, 
 
               Downloaded 2.6.16.26 and booted up and got this : 
 
               / # ifconfig eth0 172.28.8.254 up 
               [   34.034596] 0:00 not found 
               [   34.037330] eth0: Could not attach to PHY 
               [   34.041809] 0:00 not found 
               SIOCSIFFLAGS: No[   34.044526] eth0: Could not attach to 
PHY 
                such device 
               SIOCSIFFLAGS: No such device 
 
               I had enabled all the PHY devices in .config and also tried 
only with Marvell phy enabled. 
 
               Kernel boot messages : 
               [    2.296555] Gianfar MII Bus: probed 
               [    2.301789] eth0: Gianfar Ethernet Controller Version 
1.2, 00:01:af:07:9b:8a 
 
               [    2.309039] eth0: Running with NAPI disabled 
               [    2.313307] eth0: 64/64 RX/TX BD ring size 
               [    2.318498] eth1: Gianfar Ethernet Controller Version 
1.2, 00:00:00:00:72:6f 
 
               [    2.325738] eth1: Running with NAPI disabled 
               [    2.330006] eth1: 64/64 RX/TX BD ring size 
               [    2.335198] eth2: Gianfar Ethernet Controller Version 
1.2, 6f:74:3d:2f:64:65 
 
               [    2.342377] eth2: Running with NAPI disabled 
               [    2.346662] eth2: 64/64 RX/TX BD ring size 
               [    2.351586] Marvell 88E1101: Registered new driver 
               [    2.357010] Davicom DM9161E: Registered new driver 
               [    2.362443] Davicom DM9131: Registered new driver 
               [    2.367775] Cicada Cis8204: Registered new driver 
               [    2.373136] LXT970: Registered new driver 
               [    2.377794] LXT971: Registered new driver 
               [    2.382461] QS6612: Registered new driver 
 
 
               Regards, 
               Prashant 
 
 
 
 
 
 
               Kumar Gala <galak@kernel.crashing.org> 

               08/11/2006 09:40 AM 

 
                                To
                                Prashant Yendigeri 
<Prashant.Yendigeri@lntinfotech.com> 
                                cc
                                linuxppc-embedded@ozlabs.org 
                                Subject
                                Re: Gianfar eth driver on 8540 ppc - for 
2.4 and 2.6 : different outputs

 




 
               On Aug 10, 2006, at 6:18 AM, Prashant Yendigeri wrote:
 
               >
               > Hi,
               >
               > The gianfar driver of 2.6.12 and 2.4.20 give different 
outputs on 
               > the same PPC 8540 board.
               >
               > What could be the reason ?
               >
               > Output on 2.4.20 :
               > /root # ifconfig eth0 172.28.8.254 up
               > eth0: PHY is Marvell 88E1011S (1410c62)
               > eth0: Auto-negotiation done
               > eth0: Half Duplex
               > eth0: Speed 10BT
               > eth0: Link is up
               >
               > Output on 2.6.12
               > / # ifconfig eth0 172.28.8.254 up
               >  eth0: PHY is Generic MII (ffffffff)
 
               It looks like your 2.6.12 kernel isn't handling the PHY 
correctly. 
               I'd recommend upgrading to something newer which has the 
phylib 
               (can't remember which 2.6 that went into).
 
               - kumar
 
 ______________________________________________________________________
 
 
 ______________________________________________________________________
 


______________________________________________________________________


______________________________________________________________________

______________________________________________________________________
_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded 

______________________________________________________________________

______________________________________________________________________
_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded


______________________________________________________________________

[-- Attachment #2: Type: text/html, Size: 18503 bytes --]

^ permalink raw reply

* [2.6.19 PATCH 0/7] ehea: IBM eHEA Ethernet Device Driver
From: Jan-Bernd Themann @ 2006-08-22 12:50 UTC (permalink / raw)
  To: netdev
  Cc: Thomas Klein, Jan-Bernd Themann, linux-kernel, linux-ppc,
	Christoph Raisch, Marcus Eder

Hi,

this is our current version of the IBM eHEA Ethernet Device Driver.
Thanks for the quick and helpful comments so far. Further comments
are highly appreciated.

Things we are currently working on:
=2D Implementation of promiscious mode support


Thanks,
Jan-Bernd

Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
Changelog-by: =A0Jan-Bernd Themann <themann@de.ibm.com>

Differences to patch set http://www.spinics.net/lists/netdev/msg12326.html

Changelog:

=2D Error recovery
=2D improvements according to mailing list comments


 drivers/net/Kconfig             |    9=20
 drivers/net/Makefile            |    1=20
 drivers/net/ehea/Makefile       |    7=20
 drivers/net/ehea/ehea.h         |  437 ++++++
 drivers/net/ehea/ehea_ethtool.c |  244 +++
 drivers/net/ehea/ehea_hcall.h   |   51=20
 drivers/net/ehea/ehea_hw.h      |  290 ++++
 drivers/net/ehea/ehea_main.c    | 2636 +++++++++++++++++++++++++++++++++++=
+++++
 drivers/net/ehea/ehea_phyp.c    |  834 ++++++++++++
 drivers/net/ehea/ehea_phyp.h    |  479 +++++++
 drivers/net/ehea/ehea_qmr.c     |  634 +++++++++
 drivers/net/ehea/ehea_qmr.h     |  367 +++++
 12 files changed, 5989 insertions(+)

^ permalink raw reply

* [2.6.19 PATCH 1/7] ehea: interface to network stack
From: Jan-Bernd Themann @ 2006-08-22 12:51 UTC (permalink / raw)
  To: netdev
  Cc: Thomas Klein, Jan-Bernd Themann, linux-kernel, linux-ppc,
	Christoph Raisch, Marcus Eder

Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com> 


 drivers/net/ehea/ehea_main.c | 2636 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 2636 insertions(+)



--- linux-2.6.18-rc4-git1-orig/drivers/net/ehea/ehea_main.c	1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_main.c	2006-08-22 06:05:28.526237492 -0700
@@ -0,0 +1,2636 @@
+/*
+ *  linux/drivers/net/ehea/ehea_main.c
+ *
+ *  eHEA ethernet device driver for IBM eServer System p
+ *
+ *  (C) Copyright IBM Corp. 2006
+ *
+ *  Authors:
+ *       Christoph Raisch <raisch@de.ibm.com>
+ *       Jan-Bernd Themann <themann@de.ibm.com>
+ *       Thomas Klein <tklein@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/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/if.h>
+#include <linux/list.h>
+#include <linux/if_ether.h>
+#include <net/ip.h>
+
+#include "ehea.h"
+#include "ehea_qmr.h"
+#include "ehea_phyp.h"
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
+MODULE_DESCRIPTION("IBM eServer HEA Driver");
+MODULE_VERSION(DRV_VERSION);
+
+
+static int msg_level = -1;
+static int rq1_entries = EHEA_DEF_ENTRIES_RQ1;
+static int rq2_entries = EHEA_DEF_ENTRIES_RQ2;
+static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
+static int sq_entries = EHEA_DEF_ENTRIES_SQ;
+
+module_param(msg_level, int, 0);
+module_param(rq1_entries, int, 0);
+module_param(rq2_entries, int, 0);
+module_param(rq3_entries, int, 0);
+module_param(sq_entries, int, 0);
+
+MODULE_PARM_DESC(msg_level, "msg_level");
+MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 "
+		 "[2^x - 1], x = [6..14]. Default = "
+		 __MODULE_STRING(EHEA_DEF_ENTRIES_RQ3) ")");
+MODULE_PARM_DESC(rq2_entries, "Number of entries for Receive Queue 2 "
+		 "[2^x - 1], x = [6..14]. Default = "
+		 __MODULE_STRING(EHEA_DEF_ENTRIES_RQ2) ")");
+MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 "
+		 "[2^x - 1], x = [6..14]. Default = "
+		 __MODULE_STRING(EHEA_DEF_ENTRIES_RQ1) ")");
+MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue  "
+		 "[2^x - 1], x = [6..14]. Default = "
+		 __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")");
+
+void ehea_dump(void *adr, int len, char *msg) {
+	int x;
+	unsigned char *deb = adr;
+	for (x = 0; x < len; x += 16) {
+		printk(DRV_NAME "%s adr=%p ofs=%04x %016lx %016lx\n", msg,
+			  deb, x, *((u64 *)&deb[0]), *((u64 *)&deb[8]));
+		deb += 16;
+	}
+}
+
+static struct net_device_stats *ehea_get_stats(struct net_device *dev)
+{
+	int i;
+	u64 hret;
+	u64 rx_packets = 0;
+	struct ehea_port *port = netdev_priv(dev);
+	struct hcp_ehea_port_cb2 *cb2;
+	struct net_device_stats *stats = &port->stats;
+
+	memset(stats, 0, sizeof(*stats));
+
+	cb2 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb2) {
+		ehea_error("no mem for cb2");
+		goto get_stat_exit;
+	}
+
+	hret = ehea_h_query_ehea_port(port->adapter->handle,
+				      port->logical_port_id,
+				      H_PORT_CB2, H_PORT_CB2_ALL, cb2);
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_port failed");
+		goto get_stat_exit2;
+	}
+
+	if (netif_msg_hw(port))
+		ehea_dump(cb2, sizeof(*cb2), "net_device_stats");
+
+	for (i = 0; i < port->num_def_qps; i++)
+		rx_packets += port->port_res[i].rx_packets;
+
+	stats->tx_packets = cb2->txucp + cb2->txmcp + cb2->txbcp;
+	stats->multicast = cb2->rxmcp;
+	stats->rx_errors = cb2->rxuerr;
+	stats->rx_bytes = cb2->rxo;
+	stats->tx_bytes = cb2->txo;
+	stats->rx_packets = rx_packets;
+get_stat_exit2:
+        kfree(cb2);
+get_stat_exit:
+	return stats;
+}
+
+static inline int ehea_refill_rq1(struct ehea_port_res *pr, int index,
+				  int nr_of_wqes)
+{
+	int ret = 0;
+	struct sk_buff **skb_arr_rq1 = pr->skb_arr_rq1;
+	int max_index_mask = pr->skb_arr_rq1_len - 1;
+	int i;
+
+	if (!nr_of_wqes)
+		return 0;
+
+	for (i = 0; i < nr_of_wqes; i++) {
+		if (!skb_arr_rq1[index]) {
+			skb_arr_rq1[index] = dev_alloc_skb(EHEA_LL_PKT_SIZE);
+
+			if (!skb_arr_rq1[index]) {
+				ehea_error("no mem for skb/%d wqes filled", i);
+				ret = -ENOMEM;
+				break;
+			}
+		}
+		index--;
+		index &= max_index_mask;
+	}
+	/* Ring doorbell */
+	ehea_update_rq1a(pr->qp, i);
+
+	return ret;
+}
+
+static int ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a)
+{
+	int ret = 0;
+	struct sk_buff **skb_arr_rq1 = pr->skb_arr_rq1;
+	int i;
+
+	for (i = 0; i < pr->skb_arr_rq1_len; i++) {
+		skb_arr_rq1[i] = dev_alloc_skb(EHEA_LL_PKT_SIZE);
+		if (!skb_arr_rq1[i]) {
+			ehea_error("no mem for skb/%d skbs filled.", i);
+			ret = -ENOMEM;
+			goto exit0;
+		}
+	}
+	/* Ring doorbell */
+	ehea_update_rq1a(pr->qp, nr_rq1a);
+exit0:
+	return ret;
+}
+
+static int ehea_refill_rq2_def(struct ehea_port_res *pr, int wqes)
+{
+	int i;
+	int ret = 0;
+	struct ehea_qp *qp;
+	struct ehea_rwqe *rwqe;
+	struct sk_buff **skb_arr_rq2 = pr->skb_arr_rq2;
+	int index, max_index_mask, nr_of_wqes;
+
+	nr_of_wqes = pr->os_skbs_rq2 + wqes;
+	if (!nr_of_wqes)
+		return 0;
+
+	qp = pr->qp;
+
+	index = pr->skb_rq2_index;
+	max_index_mask = pr->skb_arr_rq2_len - 1;
+	for (i = 0; i < nr_of_wqes; i++) {
+		struct sk_buff *skb = dev_alloc_skb(EHEA_RQ2_PKT_SIZE
+						    + NET_IP_ALIGN);
+		if (!skb) {
+			ehea_error("no mem for skb/%d wqes filled", i);
+			pr->os_skbs_rq2 = nr_of_wqes - i;
+			ret = -ENOMEM;
+			break;
+		}
+		skb_reserve(skb, NET_IP_ALIGN);
+
+		skb_arr_rq2[index] = skb;
+
+		rwqe = ehea_get_next_rwqe(qp, 2);
+		rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_RWQE2_TYPE)
+		            | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
+		rwqe->sg_list[0].l_key = pr->recv_mr.lkey;
+		rwqe->sg_list[0].vaddr = (u64)skb->data;
+		rwqe->sg_list[0].len = EHEA_RQ2_PKT_SIZE;
+		rwqe->data_segments = 1;
+
+		index++;
+		index &= max_index_mask;
+	}
+	pr->skb_rq2_index = index;
+
+	/* Ring doorbell */
+	iosync();
+	ehea_update_rq2a(qp, i);
+	return ret;
+}
+
+
+static inline int ehea_refill_rq2(struct ehea_port_res *pr, int nr_of_wqes)
+{
+	return ehea_refill_rq2_def(pr, nr_of_wqes);
+}
+
+static int ehea_refill_rq3_def(struct ehea_port_res *pr, int wqes)
+{
+	int ret = 0;
+	struct ehea_qp *qp = pr->qp;
+	struct ehea_rwqe *rwqe;
+	struct sk_buff **skb_arr_rq3 = pr->skb_arr_rq3;
+	int skb_arr_rq3_len = pr->skb_arr_rq3_len;
+	int max_index_mask = skb_arr_rq3_len - 1;
+	int index, nr_of_wqes, i;
+
+	nr_of_wqes = pr->os_skbs_rq3 + wqes;
+	if (nr_of_wqes == 0)
+		return -EINVAL;
+
+	index = pr->skb_rq3_index;
+	for (i = 0; i < nr_of_wqes; i++) {
+		struct sk_buff *skb = dev_alloc_skb(EHEA_MAX_PACKET_SIZE
+						    + NET_IP_ALIGN);
+		if (!skb) {
+			ehea_error("no mem for skb/%d wqes filled", i);
+			pr->os_skbs_rq3 = nr_of_wqes - i;
+			ret = -ENOMEM;
+			break;
+		}
+		skb_reserve(skb, NET_IP_ALIGN);
+
+		rwqe = ehea_get_next_rwqe(qp, 3);
+
+		skb_arr_rq3[index] = skb;
+
+		rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_RWQE3_TYPE)
+			    | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
+		rwqe->sg_list[0].l_key = pr->recv_mr.lkey;
+		rwqe->sg_list[0].vaddr = (u64)skb->data;
+		rwqe->sg_list[0].len = EHEA_MAX_PACKET_SIZE;
+		rwqe->data_segments = 1;
+
+		index++;
+		index &= max_index_mask;
+	}
+	pr->skb_rq3_index = index;
+
+	/* Ring doorbell */
+	iosync();
+	ehea_update_rq3a(qp, i);
+	return ret;
+}
+
+
+static inline int ehea_refill_rq3(struct ehea_port_res *pr, int nr_of_wqes)
+{
+	return ehea_refill_rq3_def(pr, nr_of_wqes);
+}
+
+static inline int ehea_check_cqe(struct ehea_cqe *cqe, int *rq_num)
+{
+	*rq_num = (cqe->type & EHEA_CQE_TYPE_RQ) >> 5;
+	if ((cqe->status & EHEA_CQE_STAT_ERR_MASK) == 0)
+		return 0;
+	if (((cqe->status & EHEA_CQE_STAT_ERR_TCP) != 0)
+	    && (cqe->header_length == 0))
+		return 0;
+	return -EINVAL;
+}
+
+static inline void ehea_fill_skb(struct net_device *dev,
+				 struct sk_buff *skb, struct ehea_cqe *cqe)
+{
+	int length = cqe->num_bytes_transfered - 4;	/*remove CRC */
+
+	skb_put(skb, length);
+	skb->dev = dev;
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	skb->protocol = eth_type_trans(skb, dev);
+}
+
+static inline struct sk_buff *get_skb_by_index(struct sk_buff **skb_array,
+					       int arr_len,
+					       struct ehea_cqe *cqe)
+{
+	int skb_index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
+	struct sk_buff *skb;
+	void *pref;
+	int x;
+
+	x = skb_index + 1;
+	x &= (arr_len - 1);
+
+	pref = (void*)skb_array[x];
+	prefetchw(pref);
+	prefetchw(pref + EHEA_CACHE_LINE);
+
+	pref = (void*)(skb_array[x]->data);
+	prefetch(pref);
+	prefetch(pref + EHEA_CACHE_LINE);
+	prefetch(pref + EHEA_CACHE_LINE * 2);
+	prefetch(pref + EHEA_CACHE_LINE * 3);
+	skb = skb_array[skb_index];
+	skb_array[skb_index] = NULL;
+	return skb;
+}
+
+static inline struct sk_buff *get_skb_by_index_ll(struct sk_buff **skb_array,
+						  int arr_len, int wqe_index)
+{
+	struct sk_buff *skb;
+	void *pref;
+	int x;
+
+	x = wqe_index + 1;
+	x &= (arr_len - 1);
+
+	pref = (void*)skb_array[x];
+	prefetchw(pref);
+	prefetchw(pref + EHEA_CACHE_LINE);
+
+	pref = (void*)(skb_array[x]->data);
+	prefetchw(pref);
+	prefetchw(pref + EHEA_CACHE_LINE);
+
+	skb = skb_array[wqe_index];
+	skb_array[wqe_index] = NULL;
+	return skb;
+}
+
+
+static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
+				 struct ehea_cqe *cqe, int *processed_rq2,
+				 int *processed_rq3)
+{
+	int ret = 0;
+	struct sk_buff *skb;
+
+	if (netif_msg_rx_err(pr->port))
+		ehea_dump(cqe, sizeof(*cqe), "CQE");
+
+	if (rq == 2) {
+		*processed_rq2 += 1;
+		skb = get_skb_by_index(pr->skb_arr_rq2,
+				       pr->skb_arr_rq2_len,
+				       cqe);
+		dev_kfree_skb(skb);
+	}
+
+	if (rq == 3) {
+		*processed_rq3 += 1;
+		skb = get_skb_by_index(pr->skb_arr_rq3,
+				       pr->skb_arr_rq3_len,
+				       cqe);
+		dev_kfree_skb(skb);
+	}
+
+	if (cqe->status & EHEA_CQE_STAT_FAT_ERR_MASK) {
+		ehea_error("Critical error on receive path. Resetting port");
+		queue_work(pr->port->adapter->ehea_wq, &pr->port->reset_task);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+static int ehea_poll(struct net_device *dev, int *budget)
+{
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_port_res *pr = &port->port_res[0];
+	struct ehea_cqe *cqe;
+	struct ehea_qp *qp = pr->qp;
+	int wqe_index, last_wqe_index = 0;
+	int processed = 0;
+	int processed_rq1 = 0;
+	int processed_rq2 = 0;
+	int processed_rq3 = 0;
+	int rq, intreq;
+	int port_reset = 0;
+	struct sk_buff **skb_arr_rq1 = pr->skb_arr_rq1;
+	struct sk_buff **skb_arr_rq2 = pr->skb_arr_rq2;
+	struct sk_buff **skb_arr_rq3 = pr->skb_arr_rq3;
+	int skb_arr_rq1_len = pr->skb_arr_rq1_len;
+	int skb_arr_rq2_len = pr->skb_arr_rq2_len;
+	int skb_arr_rq3_len = pr->skb_arr_rq3_len;
+	int my_quota = min(*budget, dev->quota);
+	struct sk_buff *skb;
+	my_quota = min(my_quota, EHEA_POLL_MAX_RWQE);
+
+	/* rq0 is low latency RQ */
+	cqe = ehea_poll_rq1(qp, &wqe_index);
+	while ((my_quota > 0) && cqe) {
+		ehea_inc_rq1(qp);
+		processed_rq1++;
+		processed++;
+		my_quota--;
+		if (netif_msg_rx_status(port))
+			ehea_dump(cqe, sizeof(*cqe), "CQE");
+
+		last_wqe_index = wqe_index;
+		rmb();
+		if (!ehea_check_cqe(cqe, &rq)) {
+			if (rq == 1) {	/* LL RQ1 */
+				skb = get_skb_by_index_ll(skb_arr_rq1,
+							  skb_arr_rq1_len,
+							  wqe_index);
+				if (unlikely(!skb)) {
+					if (netif_msg_rx_err(port))
+						ehea_error("LL rq1: skb=NULL");
+     					skb = dev_alloc_skb(EHEA_LL_PKT_SIZE);
+					if (!skb)
+						break;
+				}
+				memcpy(skb->data, ((char*)cqe) + 64,
+				       cqe->num_bytes_transfered - 4);
+				ehea_fill_skb(dev, skb, cqe);
+			} else if (rq == 2) {  /* RQ2 */
+				skb = get_skb_by_index(skb_arr_rq2,
+						       skb_arr_rq2_len, cqe);
+				if (unlikely(!skb)) {
+					if (netif_msg_rx_err(port))
+						ehea_error("rq2: skb=NULL");
+					break;
+				}
+				ehea_fill_skb(dev, skb, cqe);
+				processed_rq2++;
+			} else {  /* RQ3 */
+				skb = get_skb_by_index(skb_arr_rq3,
+						       skb_arr_rq3_len, cqe);
+				if (unlikely(!skb)) {
+					if (netif_msg_rx_err(port))
+						ehea_error("rq3: skb=NULL");
+					break;
+				}
+				ehea_fill_skb(dev, skb, cqe);
+				processed_rq3++;
+			}
+
+			if (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
+				vlan_hwaccel_receive_skb(skb, port->vgrp,
+							 cqe->vlan_tag);
+			else
+				netif_receive_skb(skb);
+
+		} else { /* Error occured */
+			pr->p_state.poll_receive_errors++;
+			port_reset = ehea_treat_poll_error(pr, rq, cqe,
+							   &processed_rq2,
+							   &processed_rq3);
+			if (port_reset)
+				break;
+		}
+		cqe = ehea_poll_rq1(qp, &wqe_index);
+	}
+
+	dev->quota -= processed;
+	*budget -= processed;
+
+	pr->p_state.ehea_poll += 1;
+	pr->rx_packets += processed;
+
+	ehea_refill_rq1(pr, last_wqe_index, processed_rq1);
+	ehea_refill_rq2(pr, processed_rq2);
+	ehea_refill_rq3(pr, processed_rq3);
+
+	intreq = ((pr->p_state.ehea_poll & 0xF) == 0xF);
+
+	if (!cqe || intreq) {
+		netif_rx_complete(dev);
+		ehea_reset_cq_ep(pr->recv_cq);
+		ehea_reset_cq_n1(pr->recv_cq);
+		cqe = hw_qeit_get_valid(&qp->hw_rqueue1);
+		if (!cqe || intreq)
+			return 0;
+		if (!netif_rx_reschedule(dev, my_quota))
+			return 0;
+	}
+	return 1;
+}
+
+void free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr)
+{
+	struct sk_buff *skb;
+	int index, max_index_mask;
+	int i;
+
+	index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
+	max_index_mask = pr->skb_arr_sq_len - 1;
+	for (i = 0; i < EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); i++) {
+		skb = pr->skb_arr_sq[index];
+		if (likely(skb)) {
+			dev_kfree_skb(skb);
+			pr->skb_arr_sq[index] = NULL;
+		} else {
+			ehea_error("skb=NULL, wr_id=%lX, loop=%d, index=%d",
+				   cqe->wr_id, i, index);
+		}
+		index--;
+		index &= max_index_mask;
+	}
+}
+
+#define MAX_SENDCOMP_QUOTA 400
+void ehea_send_irq_tasklet(unsigned long data)
+{
+	int quota = MAX_SENDCOMP_QUOTA;
+	int cqe_counter = 0;
+	int swqe_av = 0;
+	unsigned long flags;
+	struct ehea_cqe *cqe;
+	struct ehea_port_res *pr = (struct ehea_port_res*)data;
+	struct ehea_cq *send_cq = pr->send_cq;
+	struct net_device *dev = pr->port->netdev;
+
+	do {
+		cqe = ehea_poll_cq(send_cq);
+		if (!cqe) {
+			ehea_reset_cq_ep(send_cq);
+			ehea_reset_cq_n1(send_cq);
+			cqe = ehea_poll_cq(send_cq);
+			if (!cqe)
+				break;
+		}
+		cqe_counter++;
+		rmb();
+		if (cqe->status & EHEA_CQE_STAT_ERR_MASK) {
+			ehea_error("Send Completion Error: Resetting port");
+			if (netif_msg_tx_err(pr->port))
+				ehea_dump(cqe, sizeof(*cqe), "Send CQE");
+			queue_work(pr->port->adapter->ehea_wq,
+				   &pr->port->reset_task);
+			break;
+		}
+
+		if (netif_msg_tx_done(pr->port))
+			ehea_dump(cqe, sizeof(*cqe), "CQE");
+
+		if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id)
+			   == EHEA_SWQE2_TYPE))
+			free_sent_skbs(cqe, pr);
+
+		swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id);
+		quota--;
+	} while (quota > 0);
+
+	ehea_update_feca(send_cq, cqe_counter);
+	atomic_add(swqe_av, &pr->swqe_avail);
+
+	if (unlikely(netif_queue_stopped(dev))) {
+		spin_lock_irqsave(&pr->netif_queue, flags);
+		if (unlikely((atomic_read(&pr->swqe_avail)
+			      >= EHEA_SWQE_REFILL_TH))) {
+			netif_wake_queue(pr->port->netdev);
+		}
+		spin_unlock_irqrestore(&pr->netif_queue, flags);
+	}
+
+	if (unlikely(cqe))
+		tasklet_hi_schedule(&pr->send_comp_task);
+}
+
+irqreturn_t ehea_send_irq_handler(int irq, void *param, struct pt_regs *regs)
+{
+	struct ehea_port_res *pr = (struct ehea_port_res*)param;
+
+	tasklet_hi_schedule(&pr->send_comp_task);
+
+	return IRQ_HANDLED;
+}
+
+irqreturn_t ehea_recv_irq_handler(int irq, void *param, struct pt_regs * regs)
+{
+	struct ehea_port_res *pr = (struct ehea_port_res*)param;
+	struct ehea_port *port = pr->port;
+	netif_rx_schedule(port->netdev);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param, struct pt_regs * regs)
+{
+	struct ehea_port *port = (struct ehea_port*)param;
+	struct ehea_eqe *eqe;
+	u32 qp_token;
+
+	eqe = ehea_poll_eq(port->qp_eq);
+	ehea_debug("eqe=%p", eqe);
+	while (eqe) {
+		ehea_debug("*eqe=%lx", *(u64*)eqe);
+		eqe = ehea_poll_eq(port->qp_eq);
+		qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry);
+		ehea_debug("next eqe=%p", eqe);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter,
+				       int logical_port)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_ports; i++)
+		if (adapter->port[i]->logical_port_id == logical_port)
+			return adapter->port[i];
+	return NULL;
+}
+
+static int ehea_sense_port_attr(struct ehea_port *port)
+{
+	int ret;
+	u64 hret;
+	struct hcp_ehea_port_cb0 *cb0;
+
+	cb0 = kzalloc(sizeof(*cb0), GFP_KERNEL);
+	if (!cb0) {
+		ehea_error("no mem for cb0");
+		ret = -ENOMEM;
+		goto kzalloc_failed;
+	}
+
+	hret = ehea_h_query_ehea_port(port->adapter->handle,
+				      port->logical_port_id,
+				      H_PORT_CB0,
+				      EHEA_BMASK_SET(H_PORT_CB0_ALL, 0xFFFF),
+				      cb0);
+	if (hret != H_SUCCESS) {
+		ret = -EPERM;
+		goto query_ehea_port_failed;
+	}
+
+	if (netif_msg_probe(port))
+		ehea_dump(cb0, sizeof(*cb0), "ehea_sense_port_attr");
+
+	/* MAC address */
+	port->mac_addr = cb0->port_mac_addr << 16;
+
+	/* Port speed */
+	switch (cb0->port_speed) {
+	case H_PORT_SPEED_10M_H:
+		port->port_speed = EHEA_SPEED_10M;
+		port->full_duplex = 0;
+		break;
+	case H_PORT_SPEED_10M_F:
+		port->port_speed = EHEA_SPEED_10M;
+		port->full_duplex = 1;
+		break;
+	case H_PORT_SPEED_100M_H:
+		port->port_speed = EHEA_SPEED_100M;
+		port->full_duplex = 0;
+		break;
+	case H_PORT_SPEED_100M_F:
+		port->port_speed = EHEA_SPEED_100M;
+		port->full_duplex = 1;
+		break;
+	case H_PORT_SPEED_1G_F:
+		port->port_speed = EHEA_SPEED_1G;
+		port->full_duplex = 1;
+		break;
+	case H_PORT_SPEED_10G_F:
+		port->port_speed = EHEA_SPEED_10G;
+		port->full_duplex = 1;
+		break;
+	default:
+		port->port_speed = 0;
+		port->full_duplex = 0;
+		break;
+	}
+
+	/* Number of default QPs */
+	port->num_def_qps = cb0->num_default_qps;
+	if (port->num_def_qps >= EHEA_NUM_TX_QP)
+		port->num_tx_qps = 0;
+	else
+		port->num_tx_qps = EHEA_NUM_TX_QP - port->num_def_qps;
+
+	ret = 0;
+
+query_ehea_port_failed:
+	kfree(cb0);
+
+kzalloc_failed:
+	return ret;
+}
+
+
+static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
+{
+	int ret;
+	u8 ec;
+	u8 portnum;
+	struct ehea_port *port;
+
+	ec = EHEA_BMASK_GET(NEQE_EVENT_CODE, eqe);
+
+	switch (ec) {
+	case EHEA_EC_PORTSTATE_CHG:	/* port state change */
+		portnum = EHEA_BMASK_GET(NEQE_PORTNUM, eqe);
+		port = ehea_get_port(adapter, portnum);
+
+		if (!port) {
+			ehea_error("unknown portnum %x", portnum);
+			break;
+		}
+
+		if (EHEA_BMASK_GET(NEQE_PORT_UP, eqe)) {
+			if (!netif_carrier_ok(port->netdev)) {
+				ret = ehea_sense_port_attr(
+					adapter->port[portnum]);
+				if (ret) {
+					ehea_error("failed resensing port");
+					break;
+				}
+
+				if (netif_msg_link(port))
+					ehea_info("%s: Logical port up: %dMbps "
+						  "%s Duplex",
+						  port->netdev->name,
+						  port->port_speed,
+						  port->full_duplex ==
+						  1 ? "Full" : "Half");
+
+				netif_carrier_on(port->netdev);
+				netif_wake_queue(port->netdev);
+			}
+		} else
+			if (netif_carrier_ok(port->netdev)) {
+				if (netif_msg_link(port))
+					ehea_info("%s: Logical port down",
+						  port->netdev->name);
+				netif_carrier_off(port->netdev);
+				netif_stop_queue(port->netdev);
+			}
+
+		if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PORT_UP, eqe)) {
+			if (netif_msg_link(port))
+				ehea_info("%s: Physical port up",
+					  port->netdev->name);
+		} else {
+			if (netif_msg_link(port))
+				ehea_info("%s: Physical port down",
+					  port->netdev->name);
+		}
+
+		if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PRIMARY, eqe))
+			ehea_info("Externel switch port is primary port");
+		else
+			ehea_info("Externel switch port is backup port");
+
+		break;
+	case EHEA_EC_ADAPTER_MALFUNC:
+		ehea_error("adapter malfunction");
+		break;
+	case EHEA_EC_PORT_MALFUNC:
+		ehea_info("Port malfunction");
+		break;
+	default:
+		ehea_error("unknown event code %x", ec);
+		break;
+	}
+}
+
+void ehea_neq_tasklet(unsigned long data)
+{
+	struct ehea_adapter *adapter = (struct ehea_adapter*)data;
+	struct ehea_eqe *eqe;
+	u64 event_mask;
+
+	eqe = ehea_poll_eq(adapter->neq);
+	ehea_debug("eqe=%p", eqe);
+
+	while (eqe) {
+		ehea_debug("*eqe=%lx", eqe->entry);
+		ehea_parse_eqe(adapter, eqe->entry);
+		eqe = ehea_poll_eq(adapter->neq);
+		ehea_debug("next eqe=%p", eqe);
+	}
+
+	event_mask = EHEA_BMASK_SET(NELR_PORTSTATE_CHG, 1)
+		   | EHEA_BMASK_SET(NELR_ADAPTER_MALFUNC, 1)
+		   | EHEA_BMASK_SET(NELR_PORT_MALFUNC, 1);
+
+	ehea_h_reset_events(adapter->handle,
+			    adapter->neq->fw_handle, event_mask);
+}
+
+irqreturn_t ehea_interrupt_neq(int irq, void *param, struct pt_regs *regs)
+{
+	struct ehea_adapter *adapter = (struct ehea_adapter*)param;
+	tasklet_hi_schedule(&adapter->neq_tasklet);
+	return IRQ_HANDLED;
+}
+
+
+static int ehea_fill_port_res(struct ehea_port_res *pr)
+{
+	int ret;
+	struct ehea_qp_init_attr *init_attr = &pr->qp->init_attr;
+
+	/* RQ 1 */
+	ret = ehea_init_fill_rq1(pr, init_attr->act_nr_rwqes_rq1
+				     - init_attr->act_nr_rwqes_rq2
+				     - init_attr->act_nr_rwqes_rq3 - 1);
+	/* RQ 2 */
+	ret |= ehea_refill_rq2(pr, init_attr->act_nr_rwqes_rq2);
+
+	/* RQ 3 */
+	ret |= ehea_refill_rq3(pr, init_attr->act_nr_rwqes_rq3);
+
+	return ret;
+}
+
+static int ehea_reg_interrupts(struct net_device *dev)
+{
+	int ret;
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_port_res *pr;
+	int i, k;
+
+	for (i = 0; i < port->num_def_qps; i++) {
+		pr = &port->port_res[i];
+		snprintf(pr->int_recv_name, EHEA_IRQ_NAME_SIZE - 1
+			 , "%s-recv%d", dev->name, i);
+		ret = ibmebus_request_irq(NULL, pr->recv_eq->attr.ist1,
+					  ehea_recv_irq_handler,
+					  SA_INTERRUPT, pr->int_recv_name, pr);
+		if (ret) {
+			ehea_error("failed registering irq for ehea_recv_int:"
+				   "port_res_nr:%d, ist=%X", i,
+				   pr->recv_eq->attr.ist1);
+			for (k = 0; k < i; k++) {
+				u32 ist = port->port_res[k].recv_eq->attr.ist1;
+				ibmebus_free_irq(NULL, ist, &port->port_res[k]);
+			}
+			goto failure;
+		}
+		if (netif_msg_ifup(port))
+			ehea_info("irq_handle 0x%X for funct ehea_recv_int %d "
+				  "registered", pr->recv_eq->attr.ist1, i);
+	}
+
+	snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1,
+		 "%s-aff", dev->name);
+	ret = ibmebus_request_irq(NULL, port->qp_eq->attr.ist1,
+				  ehea_qp_aff_irq_handler,
+				  SA_INTERRUPT, port->int_aff_name, port);
+	if (ret) {
+		ehea_error("failed registering irq for qp_aff_irq_handler:"
+			   " ist=%X", port->qp_eq->attr.ist1);
+		goto failure2;
+	}
+	if (netif_msg_ifup(port))
+		ehea_info("irq_handle 0x%X for function qp_aff_irq_handler "
+			  "registered", port->qp_eq->attr.ist1);
+
+	for (i = 0; i < port->num_def_qps + port->num_tx_qps; i++) {
+		pr = &port->port_res[i];
+		snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1,
+			 "%s-send%d", dev->name, i);
+		ret = ibmebus_request_irq(NULL, pr->send_eq->attr.ist1,
+					  ehea_send_irq_handler,
+					  SA_INTERRUPT, pr->int_send_name,
+					  pr);
+		if (ret) {
+			ehea_error("failed registering irq for ehea_send"
+				   " port_res_nr:%d, ist=%X", i,
+				   pr->send_eq->attr.ist1);
+			for (k = 0; k < i; k++) {
+				u32 ist = port->port_res[k].send_eq->attr.ist1;
+				ibmebus_free_irq(NULL, ist, &port->port_res[i]);
+			}
+			goto failure3;
+		}
+		if (netif_msg_ifup(port))
+			ehea_info("irq_handle 0x%X for function ehea_send_int "
+				  "%d registered", pr->send_eq->attr.ist1, i);
+	}
+	return ret;
+failure3:
+	for (i = 0; i < port->num_def_qps; i++)
+		ibmebus_free_irq(NULL, port->port_res[i].recv_eq->attr.ist1,
+				 &port->port_res[i]);
+failure2:
+	ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port);
+failure:
+	return ret;
+}
+
+static void ehea_free_interrupts(struct net_device *dev)
+{
+	struct ehea_port *port = netdev_priv(dev);
+	int i;
+
+	/* send */
+	for (i = 0; i < port->num_def_qps + port->num_tx_qps; i++) {
+		ibmebus_free_irq(NULL, port->port_res[i].send_eq->attr.ist1,
+				 &port->port_res[i]);
+		if (netif_msg_intr(port))
+			ehea_info("free send irq for res %d with handle 0x%X",
+				  i, port->port_res[i].send_eq->attr.ist1);
+	}
+
+	/* receive */
+	for (i = 0; i < port->num_def_qps; i++) {
+		ibmebus_free_irq(NULL, port->port_res[i].recv_eq->attr.ist1,
+				 &port->port_res[i]);
+		if (netif_msg_intr(port))
+			ehea_info("free recv irq for res %d with handle 0x%X",
+				  i, port->port_res[i].recv_eq->attr.ist1);
+	}
+
+	/* associated events */
+	ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port);
+	if (netif_msg_intr(port))
+		ehea_info("associated event interrupt for handle 0x%X freed",
+			  port->qp_eq->attr.ist1);
+}
+
+static int ehea_configure_port(struct ehea_port *port)
+{
+	int ret;
+	u64 hret;
+	struct hcp_ehea_port_cb0 *cb0;
+	u64 mask = 0;
+	int i;
+
+	cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb0) {
+		ret = -ENOMEM;
+		goto kzalloc_failed;
+	}
+
+	cb0->port_rc = EHEA_BMASK_SET(PXLY_RC_VALID, 1)
+		     | EHEA_BMASK_SET(PXLY_RC_IP_CHKSUM, 1)
+		     | EHEA_BMASK_SET(PXLY_RC_TCP_UDP_CHKSUM, 1)
+                     | EHEA_BMASK_SET(PXLY_RC_VLAN_XTRACT, 1)
+                     | EHEA_BMASK_SET(PXLY_RC_VLAN_TAG_FILTER,
+		                      PXLY_RC_VLAN_FILTER)
+		     | EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1);
+
+	for (i = 0; i < port->num_def_qps; i++) {
+		cb0->default_qpn_array[i] =
+		    port->port_res[i].qp->init_attr.qp_nr;
+	}
+
+	if (netif_msg_ifup(port))
+		ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port");
+
+	mask = EHEA_BMASK_SET(H_PORT_CB0_PRC, 1)
+	     | EHEA_BMASK_SET(H_PORT_CB0_DEFQPNARRAY, 1);
+
+	hret = ehea_h_modify_ehea_port(port->adapter->handle,
+				       port->logical_port_id,
+				       H_PORT_CB0, mask, cb0);
+	if (hret != H_SUCCESS) {
+		ret = -EIO;
+		goto modify_ehea_port_failed;
+	}
+
+	ret = 0;
+
+modify_ehea_port_failed:
+	kfree(cb0);
+
+kzalloc_failed:
+	return ret;
+}
+
+
+static int ehea_gen_smrs(struct ehea_port_res *pr)
+{
+	u64 hret;
+	struct ehea_adapter *adapter = pr->port->adapter;
+
+	hret = ehea_h_register_smr(adapter->handle,
+				   adapter->mr.handle,
+				   adapter->mr.vaddr,
+				   EHEA_MR_ACC_CTRL,
+				   adapter->pd,
+				   &pr->send_mr);
+	if (hret != H_SUCCESS)
+		goto ehea_gen_smrs_err1;
+
+	hret = ehea_h_register_smr(adapter->handle,
+				   adapter->mr.handle,
+				   adapter->mr.vaddr,
+				   EHEA_MR_ACC_CTRL,
+				   adapter->pd,
+				   &pr->recv_mr);
+	if (hret != H_SUCCESS)
+		goto ehea_gen_smrs_err2;
+
+	return 0;
+
+ehea_gen_smrs_err2:
+	hret = ehea_h_free_resource_mr(adapter->handle, pr->send_mr.handle);
+	if (hret != H_SUCCESS)
+		ehea_error("failed freeing SMR");
+ehea_gen_smrs_err1:
+	return -EINVAL;
+}
+
+static int ehea_rem_smrs(struct ehea_port_res *pr)
+{
+	int ret = 0;
+	u64 hret;
+	struct ehea_adapter *adapter = pr->port->adapter;
+
+	hret = ehea_h_free_resource_mr(adapter->handle, pr->send_mr.handle);
+	if (hret != H_SUCCESS) {
+		ret = -EIO;
+		ehea_error("failed freeing send SMR for pr=%p", pr);
+	}
+
+	hret = ehea_h_free_resource_mr(adapter->handle, pr->recv_mr.handle);
+	if (hret != H_SUCCESS) {
+		ret = -EIO;
+		ehea_error("failed freeing recv SMR for pr=%p", pr);
+	}
+
+	return ret;
+}
+
+static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
+			      struct port_res_cfg *pr_cfg, int queue_token)
+{
+	int ret = -EINVAL;
+	int max_rq_entries = 0;
+	enum ehea_eq_type eq_type = EHEA_EQ;
+	struct ehea_qp_init_attr *init_attr = NULL;
+	struct ehea_adapter *adapter = port->adapter;
+
+	memset(pr, 0, sizeof(struct ehea_port_res));
+
+	pr->port = port;
+	spin_lock_init(&pr->send_lock);
+	spin_lock_init(&pr->recv_lock);
+	spin_lock_init(&pr->xmit_lock);
+	spin_lock_init(&pr->netif_queue);
+
+	pr->recv_eq = ehea_create_eq(adapter, eq_type,
+				     EHEA_MAX_ENTRIES_EQ, 0);
+	if (!pr->recv_eq) {
+		ehea_error("create_eq failed (recv_eq)");
+		goto ehea_init_port_res_err;
+	}
+	pr->send_eq = ehea_create_eq(adapter, eq_type,
+				     EHEA_MAX_ENTRIES_EQ, 0);
+	if (!pr->send_eq) {
+		ehea_error("create_eq failed (send_eq)");
+		goto ehea_init_port_res_err;
+	}
+
+	pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq,
+				     pr->recv_eq->fw_handle,
+				     port->logical_port_id);
+	if (!pr->recv_cq) {
+		ehea_error("create_cq failed (cq_recv)");
+		goto ehea_init_port_res_err;
+	}
+
+	pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq,
+				     pr->send_eq->fw_handle,
+				     port->logical_port_id);
+	if (!pr->send_cq) {
+		ehea_error("create_cq failed (cq_send)");
+		goto ehea_init_port_res_err;
+	}
+
+	if (netif_msg_ifup(port))
+		ehea_info("Send CQ: act_nr_cqes=%d, Recv CQ: act_nr_cqes=%d",
+			  pr->send_cq->attr.act_nr_of_cqes,
+			  pr->recv_cq->attr.act_nr_of_cqes);
+
+	init_attr = kzalloc(sizeof(*init_attr), GFP_KERNEL);
+	if (!init_attr) {
+		ret = -ENOMEM;
+		ehea_error("no mem for ehea_qp_init_attr");
+		goto ehea_init_port_res_err;
+	}
+
+	init_attr->low_lat_rq1 = 1;
+	init_attr->signalingtype = 1;	/* generate CQE if specified in WQE */
+	init_attr->rq_count = 3;
+	init_attr->qp_token = queue_token;
+	init_attr->max_nr_send_wqes = pr_cfg->max_entries_sq;
+	init_attr->max_nr_rwqes_rq1 = pr_cfg->max_entries_rq1;
+	init_attr->max_nr_rwqes_rq2 = pr_cfg->max_entries_rq2;
+	init_attr->max_nr_rwqes_rq3 = pr_cfg->max_entries_rq3;
+	init_attr->wqe_size_enc_sq = EHEA_SG_SQ;
+	init_attr->wqe_size_enc_rq1 = EHEA_SG_RQ1;
+	init_attr->wqe_size_enc_rq2 = EHEA_SG_RQ2;
+	init_attr->wqe_size_enc_rq3 = EHEA_SG_RQ3;
+	init_attr->rq2_threshold = EHEA_RQ2_THRESHOLD;
+	init_attr->rq3_threshold = EHEA_RQ3_THRESHOLD;
+	init_attr->port_nr = port->logical_port_id;
+	init_attr->send_cq_handle = pr->send_cq->fw_handle;
+	init_attr->recv_cq_handle = pr->recv_cq->fw_handle;
+	init_attr->aff_eq_handle = port->qp_eq->fw_handle;
+
+	pr->qp = ehea_create_qp(adapter, adapter->pd, init_attr);
+	if (!pr->qp) {
+		ehea_error("create_qp failed");
+		goto ehea_init_port_res_err;
+	}
+
+	if (netif_msg_ifup(port))
+		ehea_info("QP: qp_nr=%d\n act_nr_snd_wqe=%d\n nr_rwqe_rq1=%d\n "
+			  "nr_rwqe_rq2=%d\n nr_rwqe_rq3=%d", init_attr->qp_nr,
+			  init_attr->act_nr_send_wqes,
+			  init_attr->act_nr_rwqes_rq1,
+			  init_attr->act_nr_rwqes_rq2,
+			  init_attr->act_nr_rwqes_rq3);
+
+	/* SQ */
+	max_rq_entries = init_attr->act_nr_send_wqes + 1;
+	pr->skb_arr_sq = vmalloc(sizeof(struct sk_buff*)
+				 * max_rq_entries);
+	if (!pr->skb_arr_sq) {
+		ret = -ENOMEM;
+		goto ehea_init_port_res_err;
+	}
+	memset(pr->skb_arr_sq, 0, sizeof(void*) * max_rq_entries);
+	pr->skb_sq_index = 0;
+	pr->skb_arr_sq_len = max_rq_entries;
+
+	/* RQ 1 */
+	max_rq_entries = init_attr->act_nr_rwqes_rq1 + 1;
+	pr->skb_arr_rq1 = vmalloc(sizeof(struct sk_buff*) * max_rq_entries);
+	if (!pr->skb_arr_rq1) {
+		ret = -ENOMEM;
+		goto ehea_init_port_res_err;
+	}
+	memset(pr->skb_arr_rq1, 0, sizeof(void*) * max_rq_entries);
+	pr->skb_arr_rq1_len = max_rq_entries;
+
+	/* RQ 2 */
+	max_rq_entries = init_attr->act_nr_rwqes_rq2 + 1;
+	pr->skb_arr_rq2 = vmalloc(sizeof(struct sk_buff*)*max_rq_entries);
+	if (!pr->skb_arr_rq2) {
+		ret = -ENOMEM;
+		goto ehea_init_port_res_err;
+	}
+	memset(pr->skb_arr_rq2, 0, sizeof(void*) * max_rq_entries);
+	pr->skb_arr_rq2_len = max_rq_entries;
+	pr->skb_rq2_index = 0;
+
+	/* RQ 3 */
+	max_rq_entries = init_attr->act_nr_rwqes_rq3 + 1;
+	pr->skb_arr_rq3 = vmalloc(sizeof(struct sk_buff*) * max_rq_entries);
+	if (!pr->skb_arr_rq3) {
+		ret = -ENOMEM;
+		goto ehea_init_port_res_err;
+	}
+	memset(pr->skb_arr_rq3, 0, sizeof(void*) * max_rq_entries);
+	pr->skb_arr_rq3_len = max_rq_entries;
+	pr->skb_rq3_index = 0;
+
+	if (ehea_gen_smrs(pr) != 0)
+		goto ehea_init_port_res_err;
+	tasklet_init(&pr->send_comp_task, ehea_send_irq_tasklet,
+		     (unsigned long)pr);
+	atomic_set(&pr->swqe_avail, init_attr->act_nr_send_wqes - 1);
+
+	kfree(init_attr);
+	ret = 0;
+	goto done;
+
+ehea_init_port_res_err:
+	vfree(pr->skb_arr_rq3);
+	vfree(pr->skb_arr_rq2);
+	vfree(pr->skb_arr_rq1);
+	vfree(pr->skb_arr_sq);
+	ehea_destroy_qp(pr->qp);
+	kfree(init_attr);
+	ehea_destroy_cq(pr->send_cq);
+	ehea_destroy_cq(pr->recv_cq);
+	ehea_destroy_eq(pr->send_eq);
+	ehea_destroy_eq(pr->recv_eq);
+done:
+	return ret;
+}
+
+static int ehea_clean_port_res(struct ehea_port *port, struct ehea_port_res *pr)
+{
+	int i;
+	int ret;
+
+	ret = ehea_destroy_qp(pr->qp);
+
+	if (!ret) {
+		ehea_destroy_cq(pr->send_cq);
+		ehea_destroy_cq(pr->recv_cq);
+		ehea_destroy_eq(pr->send_eq);
+		ehea_destroy_eq(pr->recv_eq);
+
+		for (i = 0; i < pr->skb_arr_rq1_len; i++) {
+			if (pr->skb_arr_rq1[i])
+				dev_kfree_skb(pr->skb_arr_rq1[i]);
+		}
+
+		for (i = 0; i < pr->skb_arr_rq2_len; i++)
+			if (pr->skb_arr_rq2[i])
+				dev_kfree_skb(pr->skb_arr_rq2[i]);
+
+		for (i = 0; i < pr->skb_arr_rq3_len; i++)
+			if (pr->skb_arr_rq3[i])
+				dev_kfree_skb(pr->skb_arr_rq3[i]);
+
+		for (i = 0; i < pr->skb_arr_sq_len; i++)
+			if (pr->skb_arr_sq[i])
+				dev_kfree_skb(pr->skb_arr_sq[i]);
+
+		vfree(pr->skb_arr_sq);
+		vfree(pr->skb_arr_rq1);
+		vfree(pr->skb_arr_rq2);
+		vfree(pr->skb_arr_rq3);
+		ret = ehea_rem_smrs(pr);
+	}
+	return ret;
+}
+
+/*
+ * The write_* functions store information in swqe which is used by
+ * the hardware to calculate the ip/tcp/udp checksum
+ */
+
+static inline void write_ip_start_end(struct ehea_swqe *swqe,
+				      const struct sk_buff *skb)
+{
+	swqe->ip_start = (u8)(((u64)skb->nh.iph) - ((u64)skb->data));
+	swqe->ip_end = (u8)(swqe->ip_start + skb->nh.iph->ihl * 4 - 1);
+}
+
+static inline void write_tcp_offset_end(struct ehea_swqe *swqe,
+					const struct sk_buff *skb)
+{
+	swqe->tcp_offset =
+		(u8)(swqe->ip_end + 1 + offsetof(struct tcphdr, check));
+
+	swqe->tcp_end = (u16)skb->len - 1;
+}
+
+static inline void write_udp_offset_end(struct ehea_swqe *swqe,
+					const struct sk_buff *skb)
+{
+	swqe->tcp_offset =
+		(u8)(swqe->ip_end + 1 + offsetof(struct udphdr, check));
+
+	swqe->tcp_end = (u16)skb->len - 1;
+}
+
+
+static inline void write_swqe2_TSO(struct sk_buff *skb,
+				   struct ehea_swqe *swqe, u32 lkey)
+{
+	int skb_data_size = skb->len - skb->data_len;
+	u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
+	struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
+	int headersize;
+	u64 tmp_addr;
+
+	/* Packet is TCP with TSO enabled */
+	swqe->tx_control |= EHEA_SWQE_TSO;
+	swqe->mss = skb_shinfo(skb)->gso_size;
+	/* copy only eth/ip/tcp headers to immediate data and
+	 * the rest of skb->data to sg1entry
+	 */
+	headersize = ETH_HLEN + (skb->nh.iph->ihl * 4)
+			      + (skb->h.th->doff * 4);
+
+	skb_data_size = skb->len - skb->data_len;
+
+	if (skb_data_size >= headersize) {
+		/* copy immediate data */
+		memcpy(imm_data, skb->data, headersize);
+		swqe->immediate_data_length = headersize;
+
+		if (skb_data_size > headersize) {
+			/* set sg1entry data */
+			sg1entry->l_key = lkey;
+			sg1entry->len = skb_data_size - headersize;
+
+			tmp_addr = (u64)(skb->data + headersize);
+			sg1entry->vaddr = tmp_addr;
+			swqe->descriptors++;
+		}
+	} else
+		ehea_error("cannot handle fragmented headers");
+}
+
+static inline void write_swqe2_nonTSO(struct sk_buff *skb,
+				      struct ehea_swqe *swqe, u32 lkey)
+{
+	int skb_data_size = skb->len - skb->data_len;
+	u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
+	struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
+	u64 tmp_addr;
+
+	/* Packet is any nonTSO type
+	 *
+	 * Copy as much as possible skb->data to immediate data and
+	 * the rest to sg1entry
+	 */
+	if (skb_data_size >= SWQE2_MAX_IMM) {
+		/* copy immediate data */
+		memcpy(imm_data, skb->data, SWQE2_MAX_IMM);
+
+		swqe->immediate_data_length = SWQE2_MAX_IMM;
+
+		if (skb_data_size > SWQE2_MAX_IMM) {
+			/* copy sg1entry data */
+			sg1entry->l_key = lkey;
+			sg1entry->len = skb_data_size - SWQE2_MAX_IMM;
+			tmp_addr = (u64)(skb->data + SWQE2_MAX_IMM);
+			sg1entry->vaddr = tmp_addr;
+			swqe->descriptors++;
+		}
+	} else {
+		memcpy(imm_data, skb->data, skb_data_size);
+		swqe->immediate_data_length = skb_data_size;
+	}
+}
+
+static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
+				    struct ehea_swqe *swqe, u32 lkey)
+{
+	int nfrags, sg1entry_contains_frag_data, i;
+	struct ehea_vsgentry *sg_list, *sg1entry, *sgentry;
+	u64 tmp_addr;
+	skb_frag_t *frag;
+
+	nfrags = skb_shinfo(skb)->nr_frags;
+	sg1entry = &swqe->u.immdata_desc.sg_entry;
+	sg_list = (struct ehea_vsgentry*)&swqe->u.immdata_desc.sg_list;
+	swqe->descriptors = 0;
+	sg1entry_contains_frag_data = 0;
+
+	if ((dev->features & NETIF_F_TSO) && skb_shinfo(skb)->gso_size)
+		write_swqe2_TSO(skb, swqe, lkey);
+	else
+		write_swqe2_nonTSO(skb, swqe, lkey);
+
+	/* write descriptors */
+	if (nfrags > 0) {
+		if (swqe->descriptors == 0) {
+			/* sg1entry not yet used */
+			frag = &skb_shinfo(skb)->frags[0];
+
+			/* copy sg1entry data */
+			sg1entry->l_key = lkey;
+			sg1entry->len = frag->size;
+			tmp_addr =  (u64)(page_address(frag->page)
+					  + frag->page_offset);
+			sg1entry->vaddr = tmp_addr;
+			swqe->descriptors++;
+			sg1entry_contains_frag_data = 1;
+		}
+
+		for (i = sg1entry_contains_frag_data; i < nfrags; i++) {
+
+			frag = &skb_shinfo(skb)->frags[i];
+			sgentry = &sg_list[i - sg1entry_contains_frag_data];
+
+			sgentry->l_key = lkey;
+			sgentry->len = frag->size;
+
+			tmp_addr = (u64)(page_address(frag->page)
+					 + frag->page_offset);
+			sgentry->vaddr = tmp_addr;
+		}
+	}
+}
+
+static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid)
+{
+	int ret = 0;
+	u64 hret;
+	u8 reg_type = 0;
+
+	/* De/Register untagged packets */
+	reg_type = EHEA_BCMC_BROADCAST | EHEA_BCMC_UNTAGGED;
+	hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
+				     port->logical_port_id,
+				     reg_type, port->mac_addr, 0, hcallid);
+	if (hret != H_SUCCESS) {
+		ehea_error("reg_dereg_bcmc failed (tagged)");
+		ret = -EOPNOTSUPP;
+		goto hcall_failed;
+	}
+
+	/* De/Register VLAN packets */
+	reg_type = EHEA_BCMC_BROADCAST | EHEA_BCMC_VLANID_ALL;
+	hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
+				     port->logical_port_id,
+				     reg_type, port->mac_addr, 0, hcallid);
+	if (hret != H_SUCCESS) {
+		ehea_error("reg_dereg_bcmc failed (vlan)");
+		ret = -EOPNOTSUPP;
+	}
+hcall_failed:
+	return ret;
+}
+
+static int ehea_set_mac_addr(struct net_device *dev, void *sa)
+{
+	int ret;
+	u64 hret;
+	struct hcp_ehea_port_cb0 *cb0;
+	struct ehea_port *port = netdev_priv(dev);
+	struct sockaddr *mac_addr = (struct sockaddr*)sa;
+
+	if (!is_valid_ether_addr(mac_addr->sa_data)) {
+		ret = -EADDRNOTAVAIL;
+		goto invalid_mac;
+	}
+
+	cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb0) {
+		ehea_error("no mem for cb0");
+		ret = -ENOMEM;
+		goto kzalloc_failed;
+	}
+
+	memcpy(&(cb0->port_mac_addr), &(mac_addr->sa_data[0]), ETH_ALEN);
+
+	cb0->port_mac_addr = cb0->port_mac_addr >> 16;
+
+	hret = ehea_h_modify_ehea_port(port->adapter->handle,
+				       port->logical_port_id,
+				       H_PORT_CB0,
+				       EHEA_BMASK_SET(H_PORT_CB0_MAC, 1),
+				       cb0);
+	if (hret != H_SUCCESS) {
+		ret = -EOPNOTSUPP;
+		goto hcall_failed;
+	}
+
+	memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len);
+
+	/* Deregister old MAC in pHYP */
+	ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+	if (ret)
+		goto hcall_failed;
+
+	port->mac_addr = cb0->port_mac_addr << 16;
+
+	/* Register new MAC in pHYP */
+	ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
+	if (ret)
+		goto hcall_failed;
+
+	ret = 0;
+
+hcall_failed:
+	kfree(cb0);
+
+kzalloc_failed:
+invalid_mac:
+	return ret;
+}
+
+static void ehea_promiscuous(struct net_device *dev, int enable)
+{
+	struct ehea_port *port = netdev_priv(dev);
+
+	if (!port->promisc) {
+		if (enable) {
+			/* Enable promiscuous mode */
+			ehea_error("Enable promiscuous mode: "
+				   "not yet implemented");
+			port->promisc = 1;
+		}
+	} else {
+		if (!enable) {
+			/* Disable promiscuous mode */
+			ehea_error("Disable promiscuous mode: "
+				   "not yet implemented");
+			port->promisc = 0;
+		}
+	}
+}
+
+static u64 ehea_multicast_reg_helper(struct ehea_port *port,
+				     u64 mc_mac_addr,
+				     u32 hcallid)
+{
+	u64 hret;
+	u8 reg_type = 0;
+
+	reg_type = EHEA_BCMC_SCOPE_ALL | EHEA_BCMC_MULTICAST
+		 | EHEA_BCMC_UNTAGGED;
+
+	hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
+				     port->logical_port_id,
+				     reg_type, mc_mac_addr, 0, hcallid);
+	if (hret)
+		goto hcall_failed;
+
+	reg_type = EHEA_BCMC_SCOPE_ALL | EHEA_BCMC_MULTICAST
+		 | EHEA_BCMC_VLANID_ALL;
+
+	hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
+				     port->logical_port_id,
+				     reg_type, mc_mac_addr, 0, hcallid);
+hcall_failed:
+	return hret;
+}
+
+static int ehea_drop_multicast_list(struct net_device *dev)
+{
+	int ret = 0;
+	u64 hret;
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_mc_list *mc_entry = port->mc_list;
+	struct list_head *pos;
+	struct list_head *temp;
+
+	list_for_each_safe(pos, temp, &(port->mc_list->list)) {
+		mc_entry = list_entry(pos, struct ehea_mc_list, list);
+
+		hret = ehea_multicast_reg_helper(port, mc_entry->macaddr,
+						 H_DEREG_BCMC);
+		if (hret) {
+			ehea_error("failed deregistering mcast MAC");
+			ret = -EINVAL;
+		}
+
+		list_del(pos);
+		kfree(mc_entry);
+	}
+	return ret;
+}
+
+static void ehea_allmulti(struct net_device *dev, int enable)
+{
+	u64 hret;
+	struct ehea_port *port = netdev_priv(dev);
+
+	if (!port->allmulti) {
+		if (enable) {
+			/* Enable ALLMULTI */
+			ehea_drop_multicast_list(dev);
+			hret = ehea_multicast_reg_helper(port, 0, H_REG_BCMC);
+			if (!hret)
+				port->allmulti = 1;
+			else
+				ehea_error("failed enabling IFF_ALLMULTI");
+		}
+	} else
+		if (!enable) {
+			/* Disable ALLMULTI */
+			hret = ehea_multicast_reg_helper(port, 0, H_DEREG_BCMC);
+			if (!hret)
+				port->allmulti = 0;
+			else
+				ehea_error("failed disabling IFF_ALLMULTI");
+		}
+}
+
+static void ehea_add_multicast_entry(struct ehea_port* port, u8* mc_mac_addr)
+{
+	u64 hret;
+	struct ehea_mc_list *ehea_mcl_entry;
+
+	ehea_mcl_entry = kzalloc(sizeof(*ehea_mcl_entry), GFP_KERNEL);
+	if (!ehea_mcl_entry) {
+		ehea_error("no mem for mcl_entry");
+		return;
+	}
+
+	INIT_LIST_HEAD(&ehea_mcl_entry->list);
+
+	memcpy(&ehea_mcl_entry->macaddr, mc_mac_addr, ETH_ALEN);
+
+	hret = ehea_multicast_reg_helper(port, ehea_mcl_entry->macaddr,
+					 H_REG_BCMC);
+	if (!hret)
+		list_add(&ehea_mcl_entry->list, &port->mc_list->list);
+	else {
+		ehea_error("failed registering mcast MAC");
+		kfree(ehea_mcl_entry);
+	}
+}
+
+static void ehea_set_multicast_list(struct net_device *dev)
+{
+	int ret;
+	int i;
+	struct ehea_port *port = netdev_priv(dev);
+	struct dev_mc_list *k_mcl_entry;
+
+	if (dev->flags & IFF_PROMISC) {
+		ehea_promiscuous(dev, 1);
+		return;
+	}
+	ehea_promiscuous(dev, 0);
+
+	if (dev->flags & IFF_ALLMULTI) {
+		ehea_allmulti(dev, 1);
+		return;
+	}
+	ehea_allmulti(dev, 0);
+
+	if (dev->mc_count) {
+		ret = ehea_drop_multicast_list(dev);
+		if (ret) {
+			/* Dropping the current multicast list failed.
+			 * Enabling ALL_MULTI is the best we can do.
+			 */
+			ehea_allmulti(dev, 1);
+		}
+
+		if (dev->mc_count > port->adapter->max_mc_mac) {
+			ehea_info("Mcast registration limit reached (0x%lx). "
+				  "Use ALLMULTI!",
+				  port->adapter->max_mc_mac);
+			goto escape;
+		}
+
+		for (i = 0, k_mcl_entry = dev->mc_list;
+		     i < dev->mc_count;
+		     i++, k_mcl_entry = k_mcl_entry->next) {
+			ehea_add_multicast_entry(port,
+						 k_mcl_entry->dmi_addr);
+		}
+	}
+escape:
+	return;
+}
+
+static int ehea_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > EHEA_MAX_PACKET_SIZE))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+static inline void ehea_xmit2(struct sk_buff *skb,
+			      struct net_device *dev, struct ehea_swqe *swqe,
+			      u32 lkey)
+{
+	int nfrags;
+	nfrags = skb_shinfo(skb)->nr_frags;
+
+	if (skb->protocol == htons(ETH_P_IP)) {
+		/* IPv4 */
+		swqe->tx_control |= EHEA_SWQE_CRC
+				 | EHEA_SWQE_IP_CHECKSUM
+				 | EHEA_SWQE_TCP_CHECKSUM
+				 | EHEA_SWQE_IMM_DATA_PRESENT
+				 | EHEA_SWQE_DESCRIPTORS_PRESENT;
+
+		write_ip_start_end(swqe, skb);
+
+		if (skb->nh.iph->protocol == IPPROTO_UDP) {
+			if ((skb->nh.iph->frag_off & IP_MF)
+			    || (skb->nh.iph->frag_off & IP_OFFSET))
+				/* IP fragment, so don't change cs */
+				swqe->tx_control &= ~EHEA_SWQE_TCP_CHECKSUM;
+			else
+				write_udp_offset_end(swqe, skb);
+
+		} else if (skb->nh.iph->protocol == IPPROTO_TCP) {
+			write_tcp_offset_end(swqe, skb);
+		}
+
+		/* icmp (big data) and ip segmentation packets (all other ip
+		   packets) do not require any special handling */
+
+	} else {
+		/* Other Ethernet Protocol */
+		swqe->tx_control |= EHEA_SWQE_CRC
+				 | EHEA_SWQE_IMM_DATA_PRESENT
+				 | EHEA_SWQE_DESCRIPTORS_PRESENT;
+	}
+
+	write_swqe2_data(skb, dev, swqe, lkey);
+}
+
+static inline void ehea_xmit3(struct sk_buff *skb,
+			      struct net_device *dev, struct ehea_swqe *swqe)
+{
+	int i;
+	skb_frag_t *frag;
+	int nfrags = skb_shinfo(skb)->nr_frags;
+	u8 *imm_data = &swqe->u.immdata_nodesc.immediate_data[0];
+
+	if (likely(skb->protocol == htons(ETH_P_IP))) {
+		/* IPv4 */
+		write_ip_start_end(swqe, skb);
+
+		if (skb->nh.iph->protocol == IPPROTO_TCP) {
+			swqe->tx_control |= EHEA_SWQE_CRC
+					 | EHEA_SWQE_IP_CHECKSUM
+					 | EHEA_SWQE_TCP_CHECKSUM
+					 | EHEA_SWQE_IMM_DATA_PRESENT;
+
+			write_tcp_offset_end(swqe, skb);
+
+		} else if (skb->nh.iph->protocol == IPPROTO_UDP) {
+			if ((skb->nh.iph->frag_off & IP_MF)
+			    || (skb->nh.iph->frag_off & IP_OFFSET))
+				/* IP fragment, so don't change cs */
+				swqe->tx_control |= EHEA_SWQE_CRC
+						 | EHEA_SWQE_IMM_DATA_PRESENT;
+			else {
+				swqe->tx_control |= EHEA_SWQE_CRC
+						 | EHEA_SWQE_IP_CHECKSUM
+						 | EHEA_SWQE_TCP_CHECKSUM
+						 | EHEA_SWQE_IMM_DATA_PRESENT;
+
+				write_udp_offset_end(swqe, skb);
+			}
+		} else {
+			/* icmp (big data) and
+			   ip segmentation packets (all other ip packets) */
+			swqe->tx_control |= EHEA_SWQE_CRC
+					 | EHEA_SWQE_IP_CHECKSUM
+					 | EHEA_SWQE_IMM_DATA_PRESENT;
+		}
+	} else {
+		/* Other Ethernet Protocol */
+		swqe->tx_control |= EHEA_SWQE_CRC | EHEA_SWQE_IMM_DATA_PRESENT;
+	}
+	/* copy (immediate) data */
+	if (nfrags == 0) {
+		/* data is in a single piece */
+		memcpy(imm_data, skb->data, skb->len);
+	} else {
+		/* first copy data from the skb->data buffer ... */
+		memcpy(imm_data, skb->data, skb->len - skb->data_len);
+		imm_data += skb->len - skb->data_len;
+
+		/* ... then copy data from the fragments */
+		for (i = 0; i < nfrags; i++) {
+			frag = &skb_shinfo(skb)->frags[i];
+			memcpy(imm_data,
+			       page_address(frag->page) + frag->page_offset,
+			       frag->size);
+			imm_data += frag->size;
+		}
+	}
+	swqe->immediate_data_length = skb->len;
+	dev_kfree_skb(skb);
+}
+
+static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	unsigned long flags;
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_port_res *pr;
+	struct ehea_swqe *swqe;
+	u32 lkey;
+	int swqe_index;
+
+	pr = &port->port_res[0];
+
+	if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
+		spin_lock_irqsave(&pr->netif_queue, flags);
+		if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
+			netif_stop_queue(dev);
+			spin_unlock_irqrestore(&pr->netif_queue, flags);
+			return NETDEV_TX_BUSY;
+		}
+		spin_unlock_irqrestore(&pr->netif_queue, flags);
+	}
+	atomic_dec(&pr->swqe_avail);
+
+	spin_lock(&pr->xmit_lock);
+
+	swqe = ehea_get_swqe(pr->qp, &swqe_index);
+	memset(swqe, 0, SWQE_HEADER_SIZE);
+
+	if (skb->len <= SWQE3_MAX_IMM) {
+		u32 sig_iv = port->sig_comp_iv;
+		u32 swqe_num = pr->swqe_id_counter;
+		ehea_xmit3(skb, dev, swqe);
+		swqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE3_TYPE)
+			| EHEA_BMASK_SET(EHEA_WR_ID_COUNT, swqe_num);
+		if (pr->swqe_ll_count >= (sig_iv - 1)) {
+			swqe->wr_id |= EHEA_BMASK_SET(EHEA_WR_ID_REFILL,
+						      sig_iv);
+			swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
+			pr->swqe_ll_count = 0;
+		} else
+			pr->swqe_ll_count += 1;
+	} else {
+		swqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE2_TYPE)
+		    | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, pr->swqe_id_counter)
+		    | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, pr->skb_sq_index);
+		pr->skb_arr_sq[pr->skb_sq_index] = skb;
+
+		pr->skb_sq_index++;
+		pr->skb_sq_index &= (pr->skb_arr_sq_len - 1);
+
+		lkey = pr->send_mr.lkey;
+		ehea_xmit2(skb, dev, swqe, lkey);
+
+		if (pr->swqe_count >= (EHEA_SIG_IV_LONG - 1)) {
+			swqe->wr_id |= EHEA_BMASK_SET(EHEA_WR_ID_REFILL,
+						      EHEA_SIG_IV_LONG);
+			swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
+			pr->swqe_count = 0;
+		} else
+			pr->swqe_count += 1;
+	}
+	pr->swqe_id_counter += 1;
+
+	if (port->vgrp && vlan_tx_tag_present(skb)) {
+		swqe->tx_control |= EHEA_SWQE_VLAN_INSERT;
+		swqe->vlan_tag = vlan_tx_tag_get(skb);
+	}
+
+	if (netif_msg_tx_queued(port)) {
+		ehea_info("post swqe on QP %d", pr->qp->init_attr.qp_nr);
+		ehea_dump(swqe, sizeof(*swqe), "swqe");
+	}
+
+	ehea_post_swqe(pr->qp, swqe);
+	pr->tx_packets++;
+	spin_unlock(&pr->xmit_lock);
+
+	return NETDEV_TX_OK;
+}
+
+static void ehea_vlan_rx_register(struct net_device *dev,
+				  struct vlan_group *grp)
+{
+	u64 hret;
+	struct hcp_ehea_port_cb1 *cb1;
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_adapter *adapter = port->adapter;
+
+	port->vgrp = grp;
+
+	cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb1) {
+		ehea_error("no mem for cb1");
+		goto vlan_reg_exit;
+	}
+
+	if (grp)
+		memset(cb1->vlan_filter, 0, sizeof(cb1->vlan_filter));
+	else
+		memset(cb1->vlan_filter, 0xFF, sizeof(cb1->vlan_filter));
+
+	hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
+				       H_PORT_CB1, H_PORT_CB1_ALL, cb1);
+	if (hret != H_SUCCESS)
+		ehea_error("modify_ehea_port failed");
+
+	kfree(cb1);
+
+vlan_reg_exit:
+	return;
+}
+
+static void ehea_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+{
+	int index;
+	u64 hret;
+	struct ehea_port *port = netdev_priv(dev);
+	struct hcp_ehea_port_cb1 *cb1;
+	struct ehea_adapter *adapter = port->adapter;
+
+	cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb1) {
+		ehea_error("no mem for cb1");
+		goto vlan_kill_exit;
+	}
+
+	hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
+				      H_PORT_CB1, H_PORT_CB1_ALL, cb1);
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_port failed");
+		goto vlan_kill_exit;
+	}
+
+	index = (vid / 64);
+	cb1->vlan_filter[index] |= ((u64)(1 << (vid & 0x3F)));
+
+	hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
+				       H_PORT_CB1, H_PORT_CB1_ALL, cb1);
+	if (hret != H_SUCCESS)
+		ehea_error("modify_ehea_port failed");
+
+	kfree(cb1);
+
+vlan_kill_exit:
+	return;
+
+}
+
+static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+	int index;
+	u64 hret;
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_adapter *adapter = port->adapter;
+	struct hcp_ehea_port_cb1 *cb1;
+
+	if (port->vgrp)
+		port->vgrp->vlan_devices[vid] = NULL;
+
+	cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb1) {
+		ehea_error("no mem for cb1");
+		goto vlan_kill_exit;
+	}
+
+	hret = ehea_h_query_ehea_port(adapter->handle,
+				       port->logical_port_id,
+				       H_PORT_CB1,
+				       H_PORT_CB1_ALL,
+				       cb1);
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_port failed");
+		goto vlan_kill_exit;
+	}
+
+	index = (vid / 64);
+	cb1->vlan_filter[index] &= ~((u64)(1 << (vid & 0x3F)));
+
+	hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
+				       H_PORT_CB1, H_PORT_CB1_ALL, cb1);
+	if (hret != H_SUCCESS)
+		ehea_error("modify_ehea_port failed");
+
+	kfree(cb1);
+
+vlan_kill_exit:
+	return;
+}
+
+int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
+{
+	int ret = -EIO;
+	u64 hret;
+	u16 dummy16 = 0;
+	u64 dummy64 = 0;
+	struct hcp_modify_qp_cb0* cb0 = NULL;
+
+	cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb0) {
+		ret = -ENOMEM;
+		goto failure;
+	}
+
+	hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				    EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_qp failed (1)");
+		goto failure;
+	}
+
+	cb0->qp_ctl_reg = H_QP_CR_STATE_INITIALIZED;
+	hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				     EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
+				     &dummy64, &dummy64, &dummy16, &dummy16);
+	if (hret != H_SUCCESS) {
+		ehea_error("modify_ehea_qp failed (1)");
+		goto failure;
+	}
+
+	hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				    EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_qp failed (2)");
+		goto failure;
+	}
+
+	cb0->qp_ctl_reg = H_QP_CR_ENABLED | H_QP_CR_STATE_INITIALIZED;
+	hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				     EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
+				     &dummy64, &dummy64, &dummy16, &dummy16);
+	if (hret != H_SUCCESS) {
+		ehea_error("modify_ehea_qp failed (2)");
+		goto failure;
+	}
+
+	hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				    EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_qp failed (3)");
+		goto failure;
+	}
+
+	cb0->qp_ctl_reg = H_QP_CR_ENABLED | H_QP_CR_STATE_RDY2SND;
+	hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				     EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
+				     &dummy64, &dummy64, &dummy16, &dummy16);
+	if (hret != H_SUCCESS) {
+		ehea_error("modify_ehea_qp failed (3)");
+		goto failure;
+	}
+
+	hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				    EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_qp failed (4)");
+		goto failure;
+	}
+
+	ret = 0;
+
+failure:
+	kfree(cb0);
+	return ret;
+}
+
+static int ehea_port_res_setup(struct ehea_port *port, int def_qps,
+			       int add_tx_qps)
+{
+	int ret;
+	struct port_res_cfg pr_cfg, pr_cfg_small_rx;
+	enum ehea_eq_type eq_type = EHEA_EQ;
+	int i, k;
+
+	port->qp_eq = ehea_create_eq(port->adapter, eq_type,
+				   EHEA_MAX_ENTRIES_EQ, 1);
+	if (!port->qp_eq) {
+		ret = -EINVAL;
+		ehea_error("ehea_create_eq failed (qp_eq)");
+		goto port_res_setup_failed2;
+	}
+
+	pr_cfg.max_entries_rcq = rq1_entries + rq2_entries + rq3_entries;
+	pr_cfg.max_entries_scq = sq_entries;
+	pr_cfg.max_entries_sq = sq_entries;
+	pr_cfg.max_entries_rq1 = rq1_entries;
+	pr_cfg.max_entries_rq2 = rq2_entries;
+	pr_cfg.max_entries_rq3 = rq3_entries;
+
+	pr_cfg_small_rx.max_entries_rcq = 1;
+	pr_cfg_small_rx.max_entries_scq = sq_entries;
+	pr_cfg_small_rx.max_entries_sq = sq_entries;
+	pr_cfg_small_rx.max_entries_rq1 = 1;
+	pr_cfg_small_rx.max_entries_rq2 = 1;
+	pr_cfg_small_rx.max_entries_rq3 = 1;
+
+
+	for (i = 0; i < def_qps; i++) {
+		ret = ehea_init_port_res(port, &port->port_res[i], &pr_cfg, i);
+		if (ret)
+			goto port_res_setup_failed;
+	}
+	for (i = def_qps; i < def_qps + add_tx_qps; i++) {
+		ret = ehea_init_port_res(port, &port->port_res[i],
+					 &pr_cfg_small_rx, i);
+		if (ret)
+			goto port_res_setup_failed;
+	}
+	return 0;
+
+port_res_setup_failed:
+	for(k = 0; k < i; k++) {
+		ehea_clean_port_res(port, &port->port_res[k]);
+	}
+port_res_setup_failed2:
+	ehea_destroy_eq(port->qp_eq);
+	return ret;
+}
+
+static int ehea_clean_all_port_res(struct ehea_port *port)
+{
+	int ret = 0;
+	int i;
+
+	for(i = 0; i < port->num_def_qps + port->num_tx_qps; i++)
+		ret |= ehea_clean_port_res(port, &port->port_res[i]);
+
+	ret |= ehea_destroy_eq(port->qp_eq);
+
+	return ret;
+}
+
+int ehea_up(struct net_device *dev)
+{
+	int ret;
+	struct ehea_port *port = netdev_priv(dev);
+	u64 mac_addr = 0;
+	int i;
+
+	if (port->state == EHEA_PORT_UP)
+		return 0;
+
+	ret = ehea_port_res_setup(port, port->num_def_qps, port->num_tx_qps);
+	if (ret)
+		goto port_res_setup_failed;
+
+	/* Set default QP for this port */
+	ret = ehea_configure_port(port);
+	if (ret) {
+		ehea_error("ehea_configure_port failed. ret:%d", ret);
+		goto reg_failed;
+	}
+
+	ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
+	if (ret) {
+		ret = -EIO;
+		goto reg_failed;
+	}
+	mac_addr = (*(u64*)dev->dev_addr) >> 16;
+
+	ret = ehea_reg_interrupts(dev);
+	if (ret)
+		goto irq_reg_failed;
+
+	for(i = 0; i < port->num_def_qps + port->num_tx_qps; i++) {
+		ret = ehea_activate_qp(port->adapter, port->port_res[i].qp);
+		if (ret)
+			goto activate_qp_failed;
+	}
+
+	for(i = 0; i < port->num_def_qps + port->num_tx_qps; i++) {
+		ret = ehea_fill_port_res(&port->port_res[i]);
+		if (ret)
+			goto fill_port_res_failed;
+	}
+
+	ret = 0;
+	port->state = EHEA_PORT_UP;
+	goto done;
+
+fill_port_res_failed:
+activate_qp_failed:
+	ehea_free_interrupts(dev);
+
+irq_reg_failed:
+	ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+
+reg_failed:
+	ehea_clean_all_port_res(port);
+
+port_res_setup_failed:
+done:
+	return ret;
+}
+
+int ehea_open(struct net_device *dev)
+{
+	int ret;
+	struct ehea_port *port = netdev_priv(dev);
+
+	down(&port->port_lock);
+
+	if (netif_msg_ifup(port))
+		ehea_info("enabling port %s", dev->name);
+        ret = ehea_up(dev);
+	if (ret == 0)
+		netif_start_queue(dev);
+	up(&port->port_lock);
+	return ret;
+}
+
+static int ehea_down(struct net_device *dev)
+{
+	int i;
+	int ret;
+	struct ehea_port *port = netdev_priv(dev);
+
+	if (port->state == EHEA_PORT_DOWN)
+		return 0;
+	ehea_drop_multicast_list(dev);
+	ehea_free_interrupts(dev);
+
+	for (i = 0; i < port->num_def_qps + port->num_tx_qps; i++)
+		tasklet_kill(&port->port_res[i].send_comp_task);
+
+	ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+	ret = ehea_clean_all_port_res(port);
+	port->state = EHEA_PORT_DOWN;
+	return ret;
+}
+
+static int ehea_stop(struct net_device *dev)
+{
+	int ret;
+	struct ehea_port *port = netdev_priv(dev);
+
+	if (netif_msg_ifdown(port))
+		ehea_info("disabling port %s", dev->name);
+	flush_workqueue(port->adapter->ehea_wq);
+	down(&port->port_lock);
+	netif_stop_queue(dev);
+	ret = ehea_down(dev);
+	up(&port->port_lock);
+	return ret;
+}
+
+static void ehea_reset_port(unsigned long data)
+{
+	int ret;
+	struct net_device *dev = (struct net_device *)data;
+	struct ehea_port *port = netdev_priv(dev);
+
+	down(&port->port_lock);
+	netif_poll_disable(dev);
+	ret = ehea_down(dev);
+	if (ret)
+		ehea_error("ehea_down failed. not all resources are freed");
+
+	ret = ehea_up(dev);
+	if (ret) {
+		ehea_error("Reset device %s failed: ret=%d", dev->name, ret);
+		goto done;
+	}
+	if (netif_msg_timer(port))
+		ehea_info("Device %s resetted successfully", dev->name);
+	netif_poll_enable(dev);
+	netif_wake_queue(dev);
+done:
+	up(&port->port_lock);
+	return;
+}
+
+static void ehea_tx_watchdog(struct net_device *dev)
+{
+	struct ehea_port *port = netdev_priv(dev);
+
+	if (netif_carrier_ok(dev))
+		queue_work(port->adapter->ehea_wq, &port->reset_task);
+}
+
+int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
+{
+	int ret;
+	u64 hret;
+	struct hcp_query_ehea *cb = NULL;
+
+	cb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb) {
+		ret = -ENOMEM;
+		goto kzalloc_failed;
+	}
+
+	hret = ehea_h_query_ehea(adapter->handle, cb);
+
+	if (hret != H_SUCCESS) {
+		ret = -EIO;
+		goto query_ehea_failed;
+	}
+
+	adapter->num_ports = cb->num_ports;
+	adapter->max_mc_mac = cb->max_mc_mac - 1;
+	ret = 0;
+
+query_ehea_failed:
+	kfree(cb);
+
+kzalloc_failed:
+	return ret;
+}
+
+static int ehea_setup_single_port(struct ehea_port *port,
+				  struct device_node *dn)
+{
+	int ret;
+	u64 hret;
+	struct net_device *dev = port->netdev;
+	struct ehea_adapter *adapter = port->adapter;
+	struct hcp_ehea_port_cb4 *cb4;
+	u32 *dn_log_port_id = NULL;
+
+	if (!dn) {
+		ehea_error("bad device node: dn=%p", dn);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	sema_init(&port->port_lock, 1);
+	port->state = EHEA_PORT_DOWN;
+	port->sig_comp_iv = sq_entries / 10;
+	port->of_dev_node = dn;
+
+	/* Determine logical port id */
+	dn_log_port_id = (u32*)get_property(dn, "ibm,hea-port-no", NULL);
+
+	if (!dn_log_port_id) {
+		ehea_error("bad device node: dn_log_port_id=%p",
+		       dn_log_port_id);
+		ret = -EINVAL;
+		goto done;
+	}
+	port->logical_port_id = *dn_log_port_id;
+
+	port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL);
+	if (!port->mc_list) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	INIT_LIST_HEAD(&port->mc_list->list);
+
+	ret = ehea_sense_port_attr(port);
+	if (ret)
+		goto done;
+
+	/* Enable Jumbo frames */
+	cb4 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb4) {
+		ehea_error("no mem for cb4");
+	} else {
+		cb4->jumbo_frame = 1;
+		hret = ehea_h_modify_ehea_port(adapter->handle,
+					       port->logical_port_id,
+					       H_PORT_CB4, H_PORT_CB4_JUMBO,
+					       cb4);
+		if (hret != H_SUCCESS) {
+			ehea_error("modify_ehea_port failed");
+			ehea_info("Jumbo frames not activated");
+		}
+		kfree(cb4);
+	}
+
+	/* initialize net_device structure */
+	SET_MODULE_OWNER(dev);
+
+	memcpy(dev->dev_addr, &port->mac_addr, ETH_ALEN);
+
+	dev->open = ehea_open;
+	dev->poll = ehea_poll;
+	dev->weight = 64;
+	dev->stop = ehea_stop;
+	dev->hard_start_xmit = ehea_start_xmit;
+	dev->get_stats = ehea_get_stats;
+	dev->set_multicast_list = ehea_set_multicast_list;
+	dev->set_mac_address = ehea_set_mac_addr;
+	dev->change_mtu = ehea_change_mtu;
+	dev->vlan_rx_register = ehea_vlan_rx_register;
+	dev->vlan_rx_add_vid = ehea_vlan_rx_add_vid;
+	dev->vlan_rx_kill_vid = ehea_vlan_rx_kill_vid;
+	dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
+		      | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX
+		      | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER
+		      | NETIF_F_LLTX;
+	dev->tx_timeout = &ehea_tx_watchdog;
+	dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
+
+	INIT_WORK(&port->reset_task,
+		  (void (*)(void *)) ehea_reset_port, dev);
+
+	ehea_set_ethtool_ops(dev);
+
+	ret = register_netdev(dev);
+	if (ret) {
+		ehea_error("register_netdev failed. ret=%d", ret);
+		goto reg_netdev_failed;
+	}
+
+	port->netdev = dev;
+	ret = 0;
+	goto done;
+
+reg_netdev_failed:
+	kfree(port->mc_list);
+done:
+	return ret;
+}
+
+static int ehea_setup_ports(struct ehea_adapter *adapter)
+{
+	int ret;
+	int port_setup_ok = 0;
+	struct ehea_port *port = NULL;
+	struct device_node *dn = NULL;
+	struct net_device *dev;
+	int i;
+
+	/* get port properties for all ports */
+	for (i = 0; i < adapter->num_ports; i++) {
+
+		if (adapter->port[i])
+			continue;	/* port already up and running */
+
+		/* allocate memory for the port structures */
+		dev = alloc_etherdev(sizeof(struct ehea_port));
+
+		if (!dev) {
+			ehea_error("no mem for net_device");
+			break;
+		}
+
+		port = netdev_priv(dev);
+		port->adapter = adapter;
+		port->netdev = dev;
+		adapter->port[i] = port;
+		port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT);
+
+		dn = of_find_node_by_name(dn, "ethernet");
+		ret = ehea_setup_single_port(port, dn);
+		if (ret) {
+			/* Free mem for this port struct. the others will be
+			   processed on rollback */
+			free_netdev(dev);
+			adapter->port[i] = NULL;
+			ehea_error("eHEA port %d setup failed, ret=%d", i, ret);
+		}
+	}
+
+	of_node_put(dn);
+
+	/* Check for succesfully set up ports */
+	for (i = 0; i < adapter->num_ports; i++)
+		if (adapter->port[i])
+			port_setup_ok++;
+
+	if (port_setup_ok)
+		ret = 0;	/* At least some ports are setup correctly */
+	else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static int __devinit ehea_probe(struct ibmebus_dev *dev,
+				const struct of_device_id *id)
+{
+	int ret;
+	struct ehea_adapter *adapter = NULL;
+	u64 *adapter_handle = NULL;
+
+	adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+
+	if (!adapter) {
+		ret = -ENOMEM;
+		dev_err(&dev->ofdev.dev, "no mem for ehea_adapter\n");
+		goto kzalloc_adapter_failed;
+	}
+
+	adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle",
+					    NULL);
+	if (!adapter_handle) {
+		dev_err(&dev->ofdev.dev, "failed getting handle for adapter"
+			" '%s'\n", dev->ofdev.node->full_name);
+		ret = -ENODEV;
+		goto get_property_failed;
+	}
+
+	adapter->handle = *adapter_handle;
+	adapter->pd = EHEA_PD_ID;
+
+	dev->ofdev.dev.driver_data = adapter;
+
+	ret = ehea_reg_mr_adapter(adapter);
+	if (ret) {
+		dev_err(&dev->ofdev.dev, "reg_mr_adapter failed\n");
+		goto register_mr_failed;
+	}
+
+	/* initialize adapter and ports */
+	/* get adapter properties */
+	ret = ehea_sense_adapter_attr(adapter);
+	if (ret) {
+		dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret);
+		goto sense_adapter_failed;
+	}
+	dev_info(&dev->ofdev.dev, "%d eHEA ports found\n", adapter->num_ports);
+
+	adapter->neq = ehea_create_eq(adapter,
+				      EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1);
+	if (!adapter->neq) {
+		dev_err(&dev->ofdev.dev, "NEQ creation failed");
+		goto create_neq_failed;
+	}
+
+	tasklet_init(&adapter->neq_tasklet, ehea_neq_tasklet,
+		     (unsigned long)adapter);
+
+	ret = ibmebus_request_irq(NULL, adapter->neq->attr.ist1,
+				ehea_interrupt_neq, SA_INTERRUPT, "ehea_neq",
+				(void*)adapter);
+	if (ret) {
+		dev_err(&dev->ofdev.dev, "requesting NEQ IRQ failed");
+		goto request_irq_failed;
+	}
+
+	adapter->ehea_wq = create_workqueue("ehea_wq");
+	if (!adapter->ehea_wq)
+		goto create_wq_failed;
+
+	ret = ehea_setup_ports(adapter);
+	if (ret) {
+		dev_err(&dev->ofdev.dev, "setup_ports failed");
+		goto setup_ports_failed;
+	}
+
+	ret = 0;
+	goto done;
+
+setup_ports_failed:
+	destroy_workqueue(adapter->ehea_wq);
+create_wq_failed:
+request_irq_failed:
+	ehea_destroy_eq(adapter->neq);
+create_neq_failed:
+sense_adapter_failed:
+	ehea_dereg_mr_adapter(adapter);
+register_mr_failed:
+get_property_failed:
+	kfree(adapter);
+kzalloc_adapter_failed:
+done:
+	return ret;
+}
+
+static void ehea_shutdown_single_port(struct ehea_port *port)
+{
+	unregister_netdev(port->netdev);
+	kfree(port->mc_list);
+	free_netdev(port->netdev);
+}
+
+static int __devexit ehea_remove(struct ibmebus_dev *dev)
+{
+	int ret;
+	struct ehea_adapter *adapter = dev->ofdev.dev.driver_data;
+	int i;
+
+	for (i = 0; i < adapter->num_ports; i++)
+		if (adapter->port[i]) {
+			ehea_shutdown_single_port(adapter->port[i]);
+			adapter->port[i] = NULL;
+		}
+
+	ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
+
+	ehea_destroy_eq(adapter->neq);
+
+	ret = ehea_dereg_mr_adapter(adapter);
+	if (ret) {
+		dev_err(&dev->ofdev.dev, "dereg_mr_adapter failed");
+		goto deregister_mr_failed;
+	}
+	kfree(adapter);
+	ret = 0;
+
+deregister_mr_failed:
+	return ret;
+}
+
+int check_module_parm(void)
+{
+	int ret = 0;
+
+	if ((rq1_entries < EHEA_MIN_ENTRIES_QP)
+	    || (rq1_entries > EHEA_MAX_ENTRIES_RQ1)) {
+		ehea_info("Bad parameter: rq1_entries");
+		ret = -EINVAL;
+	}
+	if ((rq2_entries < EHEA_MIN_ENTRIES_QP)
+	    || (rq2_entries > EHEA_MAX_ENTRIES_RQ2)) {
+		ehea_info("Bad parameter: rq2_entries");
+		ret = -EINVAL;
+	}
+	if ((rq3_entries < EHEA_MIN_ENTRIES_QP)
+	    || (rq3_entries > EHEA_MAX_ENTRIES_RQ3)) {
+		ehea_info("Bad parameter: rq3_entries");
+		ret = -EINVAL;
+	}
+	if ((sq_entries < EHEA_MIN_ENTRIES_QP)
+	    || (sq_entries > EHEA_MAX_ENTRIES_SQ)) {
+		ehea_info("Bad parameter: sq_entries");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static struct of_device_id ehea_device_table[] = {
+	{
+	 .name = "lhea",
+	 .compatible = "IBM,lhea",
+	 },
+	{},
+};
+
+static struct ibmebus_driver ehea_driver = {
+	.name = "ehea",
+	.id_table = ehea_device_table,
+	.probe = ehea_probe,
+	.remove = ehea_remove,
+};
+
+int __init ehea_module_init(void)
+{
+	int ret;
+
+	printk("IBM eHEA ethernet device driver (Release %s)\n", DRV_VERSION);
+
+	ret = check_module_parm();
+	if (ret)
+		goto done;
+	ret = ibmebus_register_driver(&ehea_driver);
+	if (ret)
+		ehea_error("failed registering eHEA device driver on ebus");
+
+done:
+	return ret;
+}
+
+static void __exit ehea_module_exit(void)
+{
+	ibmebus_unregister_driver(&ehea_driver);
+}
+
+module_init(ehea_module_init);
+module_exit(ehea_module_exit);

^ permalink raw reply

* [2.6.19 PATCH 2/7] ehea: pHYP interface
From: Jan-Bernd Themann @ 2006-08-22 12:52 UTC (permalink / raw)
  To: netdev
  Cc: Thomas Klein, Jan-Bernd Themann, linux-kernel, linux-ppc,
	Christoph Raisch, Marcus Eder

Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com> 


 drivers/net/ehea/ehea_hcall.h |   51 ++
 drivers/net/ehea/ehea_phyp.c  |  834 ++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ehea/ehea_phyp.h  |  479 ++++++++++++++++++++++++
 3 files changed, 1364 insertions(+)



--- linux-2.6.18-rc4-git1-orig/drivers/net/ehea/ehea_phyp.c	1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_phyp.c	2006-08-22 06:05:28.920371128 -0700
@@ -0,0 +1,834 @@
+/*
+ *  linux/drivers/net/ehea/ehea_phyp.c
+ *
+ *  eHEA ethernet device driver for IBM eServer System p
+ *
+ *  (C) Copyright IBM Corp. 2006
+ *
+ *  Authors:
+ *       Christoph Raisch <raisch@de.ibm.com>
+ *       Jan-Bernd Themann <themann@de.ibm.com>
+ *       Thomas Klein <tklein@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 "ehea_phyp.h"
+
+
+static inline u16 get_order_of_qentries(u16 queue_entries)
+{
+	u8 ld = 1;		/*  logarithmus dualis */
+	while (((1U << ld) - 1) < queue_entries)
+		ld++;
+	return ld - 1;
+}
+
+
+/* Defines for H_CALL H_ALLOC_RESOURCE */
+#define H_ALL_RES_TYPE_QP        1
+#define H_ALL_RES_TYPE_CQ        2
+#define H_ALL_RES_TYPE_EQ        3
+#define H_ALL_RES_TYPE_MR        5
+#define H_ALL_RES_TYPE_MW        6
+
+static long ehea_hcall_9arg_9ret(unsigned long opcode,
+         			 unsigned long arg1, unsigned long arg2,
+         			 unsigned long arg3, unsigned long arg4,
+         			 unsigned long arg5, unsigned long arg6,
+         			 unsigned long arg7, unsigned long arg8,
+         			 unsigned long arg9, unsigned long *out1,
+         			 unsigned long *out2,unsigned long *out3,
+         			 unsigned long *out4,unsigned long *out5,
+         			 unsigned long *out6,unsigned long *out7,
+         			 unsigned long *out8,unsigned long *out9)
+{
+	long hret = H_HARDWARE;
+	int i, sleep_msecs;
+
+	for (i = 0; i < 5; i++) {
+		hret = plpar_hcall_9arg_9ret(opcode,arg1, arg2, arg3, arg4,
+					     arg5, arg6, arg7, arg8, arg9, out1,
+					     out2, out3, out4, out5, out6, out7,
+					     out8, out9);
+		if (H_IS_LONG_BUSY(hret)) {
+			sleep_msecs = get_longbusy_msecs(hret);
+			msleep_interruptible(sleep_msecs);
+			continue;
+		}
+
+		if (hret < H_SUCCESS)
+			ehea_error("op=%lx hret=%lx "
+				   "i1=%lx i2=%lx i3=%lx i4=%lx i5=%lx i6=%lx "
+				   "i7=%lx i8=%lx i9=%lx "
+				   "o1=%lx o2=%lx o3=%lx o4=%lx o5=%lx o6=%lx "
+				   "o7=%lx o8=%lx o9=%lx",
+				   opcode, hret, arg1, arg2, arg3, arg4, arg5,
+				   arg6, arg7, arg8, arg9, *out1, *out2, *out3,
+				   *out4, *out5, *out6, *out7, *out8, *out9);
+		return hret;
+	}
+	return H_BUSY;
+}
+
+u64 ehea_h_query_ehea_qp(const u64 hcp_adapter_handle, const u8 qp_category,
+			 const u64 qp_handle, const u64 sel_mask, void *cb_addr)
+{
+	u64 dummy;
+
+	if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0) {
+		ehea_error("not on pageboundary");
+		return H_PARAMETER;
+	}
+
+	return ehea_hcall_9arg_9ret(H_QUERY_HEA_QP,
+				    hcp_adapter_handle,	        /* R4 */
+				    qp_category,	        /* R5 */
+				    qp_handle,	                /* R6 */
+				    sel_mask,	                /* R7 */
+				    virt_to_abs(cb_addr),	/* R8 */
+				    0, 0, 0, 0,	                /* R9-R12 */
+				    &dummy,                     /* R4 */
+				    &dummy,                     /* R5 */
+				    &dummy,	                /* R6 */
+				    &dummy,	                /* R7 */
+				    &dummy,	                /* R8 */
+				    &dummy,	                /* R9 */
+				    &dummy,	                /* R10 */
+				    &dummy,	                /* R11 */
+				    &dummy);	                /* R12 */
+}
+
+/* input param R5 */
+#define H_ALL_RES_QP_EQPO         EHEA_BMASK_IBM(9, 11)
+#define H_ALL_RES_QP_QPP          EHEA_BMASK_IBM(12, 12)
+#define H_ALL_RES_QP_RQR          EHEA_BMASK_IBM(13, 15)
+#define H_ALL_RES_QP_EQEG         EHEA_BMASK_IBM(16, 16)
+#define H_ALL_RES_QP_LL_QP        EHEA_BMASK_IBM(17, 17)
+#define H_ALL_RES_QP_DMA128       EHEA_BMASK_IBM(19, 19)
+#define H_ALL_RES_QP_HSM          EHEA_BMASK_IBM(20, 21)
+#define H_ALL_RES_QP_SIGT         EHEA_BMASK_IBM(22, 23)
+#define H_ALL_RES_QP_TENURE       EHEA_BMASK_IBM(48, 55)
+#define H_ALL_RES_QP_RES_TYP      EHEA_BMASK_IBM(56, 63)
+
+/* input param R9  */
+#define H_ALL_RES_QP_TOKEN        EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_PD           EHEA_BMASK_IBM(32,63)
+
+/* input param R10 */
+#define H_ALL_RES_QP_MAX_SWQE     EHEA_BMASK_IBM(4, 7)
+#define H_ALL_RES_QP_MAX_R1WQE    EHEA_BMASK_IBM(12, 15)
+#define H_ALL_RES_QP_MAX_R2WQE    EHEA_BMASK_IBM(20, 23)
+#define H_ALL_RES_QP_MAX_R3WQE    EHEA_BMASK_IBM(28, 31)
+/* Max Send Scatter Gather Elements */
+#define H_ALL_RES_QP_MAX_SSGE     EHEA_BMASK_IBM(37, 39)
+#define H_ALL_RES_QP_MAX_R1SGE    EHEA_BMASK_IBM(45, 47)
+/* Max Receive SG Elements RQ1 */
+#define H_ALL_RES_QP_MAX_R2SGE    EHEA_BMASK_IBM(53, 55)
+#define H_ALL_RES_QP_MAX_R3SGE    EHEA_BMASK_IBM(61, 63)
+
+/* input param R11 */
+#define H_ALL_RES_QP_SWQE_IDL     EHEA_BMASK_IBM(0, 7)
+/* max swqe immediate data length */
+#define H_ALL_RES_QP_PORT_NUM     EHEA_BMASK_IBM(48, 63)
+
+/* input param R12 */
+#define H_ALL_RES_QP_TH_RQ2       EHEA_BMASK_IBM(0, 15)
+/* Threshold RQ2 */
+#define H_ALL_RES_QP_TH_RQ3       EHEA_BMASK_IBM(16, 31)
+/* Threshold RQ3 */
+
+/* output param R6 */
+#define H_ALL_RES_QP_ACT_SWQE     EHEA_BMASK_IBM(0, 15)
+#define H_ALL_RES_QP_ACT_R1WQE    EHEA_BMASK_IBM(16, 31)
+#define H_ALL_RES_QP_ACT_R2WQE    EHEA_BMASK_IBM(32, 47)
+#define H_ALL_RES_QP_ACT_R3WQE    EHEA_BMASK_IBM(48, 63)
+
+/* output param, R7 */
+#define H_ALL_RES_QP_ACT_SSGE     EHEA_BMASK_IBM(0, 7)
+#define H_ALL_RES_QP_ACT_R1SGE    EHEA_BMASK_IBM(8, 15)
+#define H_ALL_RES_QP_ACT_R2SGE    EHEA_BMASK_IBM(16, 23)
+#define H_ALL_RES_QP_ACT_R3SGE    EHEA_BMASK_IBM(24, 31)
+#define H_ALL_RES_QP_ACT_SWQE_IDL EHEA_BMASK_IBM(32, 39)
+
+/* output param R8,R9 */
+#define H_ALL_RES_QP_SIZE_SQ      EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_SIZE_RQ1     EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_SIZE_RQ2     EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_SIZE_RQ3     EHEA_BMASK_IBM(32, 63)
+
+/* output param R11,R12 */
+#define H_ALL_RES_QP_LIOBN_SQ     EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_LIOBN_RQ1    EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_LIOBN_RQ2    EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_LIOBN_RQ3    EHEA_BMASK_IBM(32, 63)
+
+u64 ehea_h_alloc_resource_qp(const u64 adapter_handle, struct ehea_qp *ehea_qp,
+			     struct ehea_qp_init_attr *init_attr, const u32 pd,
+			     u64 *qp_handle, struct h_epas *h_epas)
+{
+	u64 hret;
+
+	u64 allocate_controls =
+	    EHEA_BMASK_SET(H_ALL_RES_QP_EQPO, init_attr->low_lat_rq1 ? 1 : 0)
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_QPP, 0)
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_RQR, 6)	/* rq1 & rq2 & rq3 */
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_EQEG, 0)	/* EQE gen. disabled */
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_LL_QP, init_attr->low_lat_rq1)
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_DMA128, 0)
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_HSM, 0)
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_SIGT, init_attr->signalingtype)
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_RES_TYP, H_ALL_RES_TYPE_QP);
+
+	u64 r9_reg = EHEA_BMASK_SET(H_ALL_RES_QP_PD, pd)
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_TOKEN, init_attr->qp_token);
+
+	u64 max_r10_reg =
+	    EHEA_BMASK_SET(H_ALL_RES_QP_MAX_SWQE,
+			   get_order_of_qentries(init_attr->max_nr_send_wqes))
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R1WQE,
+			     get_order_of_qentries(init_attr->max_nr_rwqes_rq1))
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R2WQE,
+			     get_order_of_qentries(init_attr->max_nr_rwqes_rq2))
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R3WQE,
+			     get_order_of_qentries(init_attr->max_nr_rwqes_rq3))
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_SSGE, init_attr->wqe_size_enc_sq)
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R1SGE,
+			     init_attr->wqe_size_enc_rq1)
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R2SGE,
+			     init_attr->wqe_size_enc_rq2)
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R3SGE,
+			     init_attr->wqe_size_enc_rq3);
+
+	u64 r11_in =
+	    EHEA_BMASK_SET(H_ALL_RES_QP_SWQE_IDL, init_attr->swqe_imm_data_len)
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_PORT_NUM, init_attr->port_nr);
+	u64 threshold =
+	    EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ2, init_attr->rq2_threshold)
+	    | EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ3, init_attr->rq3_threshold);
+
+	u64 r5_out = 0;
+	u64 r6_out = 0;
+	u64 r7_out = 0;
+	u64 r8_out = 0;
+	u64 r9_out = 0;
+	u64 g_la_user_out = 0;
+	u64 r11_out = 0;
+	u64 r12_out = 0;
+
+	hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE,
+				    adapter_handle,		/* R4 */
+				    allocate_controls,		/* R5 */
+				    init_attr->send_cq_handle,	/* R6 */
+				    init_attr->recv_cq_handle,	/* R7 */
+				    init_attr->aff_eq_handle,	/* R8 */
+				    r9_reg,			/* R9 */
+				    max_r10_reg,		/* R10 */
+				    r11_in,			/* R11 */
+				    threshold,			/* R12 */
+				    qp_handle,			/* R4 */
+				    &r5_out,			/* R5 */
+				    &r6_out,			/* R6 */
+				    &r7_out,			/* R7 */
+				    &r8_out,			/* R8 */
+				    &r9_out,			/* R9 */
+				    &g_la_user_out,		/* R10 */
+				    &r11_out,			/* R11 */
+				    &r12_out);			/* R12 */
+
+	init_attr->qp_nr = (u32)r5_out;
+
+	init_attr->act_nr_send_wqes =
+	    (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_SWQE, r6_out);
+	init_attr->act_nr_rwqes_rq1 =
+	    (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R1WQE, r6_out);
+	init_attr->act_nr_rwqes_rq2 =
+	    (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R2WQE, r6_out);
+	init_attr->act_nr_rwqes_rq3 =
+	    (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R3WQE, r6_out);
+
+	init_attr->act_wqe_size_enc_sq = init_attr->wqe_size_enc_sq;
+	init_attr->act_wqe_size_enc_rq1 = init_attr->wqe_size_enc_rq1;
+	init_attr->act_wqe_size_enc_rq2 = init_attr->wqe_size_enc_rq2;
+	init_attr->act_wqe_size_enc_rq3 = init_attr->wqe_size_enc_rq3;
+
+	init_attr->nr_sq_pages =
+	    (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_SQ, r8_out);
+	init_attr->nr_rq1_pages =
+	    (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ1, r8_out);
+	init_attr->nr_rq2_pages =
+	    (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ2, r9_out);
+	init_attr->nr_rq3_pages =
+	    (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ3, r9_out);
+
+	init_attr->liobn_sq =
+	    (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_SQ, r11_out);
+	init_attr->liobn_rq1 =
+	    (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ1, r11_out);
+	init_attr->liobn_rq2 =
+	    (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ2, r12_out);
+	init_attr->liobn_rq3 =
+	    (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ3, r12_out);
+
+	if (!hret)
+		hcp_epas_ctor(h_epas, g_la_user_out, g_la_user_out);
+
+	return hret;
+}
+
+u64 ehea_h_alloc_resource_cq(const u64 hcp_adapter_handle,
+			     struct ehea_cq *ehea_cq,
+			     struct ehea_cq_attr *cq_attr,
+			     u64 *cq_handle, struct h_epas *epas)
+{
+	u64 hret, dummy, act_nr_of_cqes_out, act_pages_out;
+	u64 g_la_privileged_out, g_la_user_out;
+
+	hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE,
+				    hcp_adapter_handle,		/* R4 */
+				    H_ALL_RES_TYPE_CQ,		/* R5 */
+				    cq_attr->eq_handle,		/* R6 */
+				    cq_attr->cq_token,		/* R7 */
+				    cq_attr->max_nr_of_cqes,	/* R8 */
+				    0, 0, 0, 0,			/* R9-R12 */
+				    cq_handle,			/* R4 */
+				    &dummy,			/* R5 */
+				    &dummy,			/* R6 */
+				    &act_nr_of_cqes_out,	/* R7 */
+				    &act_pages_out,		/* R8 */
+				    &g_la_privileged_out,	/* R9 */
+				    &g_la_user_out,		/* R10 */
+				    &dummy,	                /* R11 */
+				    &dummy);	                /* R12 */
+
+	cq_attr->act_nr_of_cqes = act_nr_of_cqes_out;
+	cq_attr->nr_pages = act_pages_out;
+
+	if (!hret)
+		hcp_epas_ctor(epas, g_la_privileged_out, g_la_user_out);
+
+	return hret;
+}
+
+/* Defines for H_CALL H_ALLOC_RESOURCE */
+#define H_ALL_RES_TYPE_QP        1
+#define H_ALL_RES_TYPE_CQ        2
+#define H_ALL_RES_TYPE_EQ        3
+#define H_ALL_RES_TYPE_MR        5
+#define H_ALL_RES_TYPE_MW        6
+
+/*  input param R5 */
+#define H_ALL_RES_EQ_NEQ             EHEA_BMASK_IBM(0, 0)
+#define H_ALL_RES_EQ_NON_NEQ_ISN     EHEA_BMASK_IBM(6, 7)
+#define H_ALL_RES_EQ_INH_EQE_GEN     EHEA_BMASK_IBM(16, 16)
+#define H_ALL_RES_EQ_RES_TYPE        EHEA_BMASK_IBM(56, 63)
+/*  input param R6 */
+#define H_ALL_RES_EQ_MAX_EQE         EHEA_BMASK_IBM(32, 63)
+
+/*  output param R6 */
+#define H_ALL_RES_EQ_LIOBN           EHEA_BMASK_IBM(32, 63)
+
+/*  output param R7 */
+#define H_ALL_RES_EQ_ACT_EQE         EHEA_BMASK_IBM(32, 63)
+
+/*  output param R8 */
+#define H_ALL_RES_EQ_ACT_PS          EHEA_BMASK_IBM(32, 63)
+
+/*  output param R9 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_C    EHEA_BMASK_IBM(30, 31)
+#define H_ALL_RES_EQ_ACT_EQ_IST_1    EHEA_BMASK_IBM(40, 63)
+
+/*  output param R10 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_2    EHEA_BMASK_IBM(40, 63)
+
+/*  output param R11 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_3    EHEA_BMASK_IBM(40, 63)
+
+/*  output param R12 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_4    EHEA_BMASK_IBM(40, 63)
+
+u64 ehea_h_alloc_resource_eq(const u64 hcp_adapter_handle,
+			     struct ehea_eq *ehea_eq,
+			     struct ehea_eq_attr *eq_attr, u64 *eq_handle)
+{
+	u64 hret, dummy;
+	u64 eq_liobn = 0;
+	u64 allocate_controls = 0;
+	u64 ist1_out = 0;
+	u64 ist2_out = 0;
+	u64 ist3_out = 0;
+	u64 ist4_out = 0;
+	u64 act_nr_of_eqes_out = 0;
+	u64 act_pages_out = 0;
+
+	/* resource type */
+	allocate_controls =
+	    EHEA_BMASK_SET(H_ALL_RES_EQ_RES_TYPE, H_ALL_RES_TYPE_EQ)
+	    | EHEA_BMASK_SET(H_ALL_RES_EQ_NEQ, eq_attr->type ? 1 : 0)
+	    | EHEA_BMASK_SET(H_ALL_RES_EQ_INH_EQE_GEN, !eq_attr->eqe_gen)
+	    | EHEA_BMASK_SET(H_ALL_RES_EQ_NON_NEQ_ISN, 1);
+
+	hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE,
+				    hcp_adapter_handle,		/* R4 */
+				    allocate_controls,		/* R5 */
+				    eq_attr->max_nr_of_eqes,	/* R6 */
+				    0, 0, 0, 0, 0, 0,		/* R7-R10 */
+				    eq_handle,			/* R4 */
+				    &dummy,			/* R5 */
+				    &eq_liobn,			/* R6 */
+				    &act_nr_of_eqes_out,	/* R7 */
+				    &act_pages_out,		/* R8 */
+				    &ist1_out,			/* R9 */
+				    &ist2_out,			/* R10 */
+				    &ist3_out,			/* R11 */
+				    &ist4_out);			/* R12 */
+
+	eq_attr->act_nr_of_eqes = act_nr_of_eqes_out;
+	eq_attr->nr_pages = act_pages_out;
+	eq_attr->ist1 = ist1_out;
+	eq_attr->ist2 = ist2_out;
+	eq_attr->ist3 = ist3_out;
+	eq_attr->ist4 = ist4_out;
+
+	return hret;
+}
+
+u64 ehea_h_modify_ehea_qp(const u64 hcp_adapter_handle, const u8 cat,
+			  const u64 qp_handle, const u64 sel_mask,
+			  void *cb_addr, u64 *inv_attr_id, u64 *proc_mask,
+			  u16 *out_swr, u16 *out_rwr)
+{
+	u64 hret, dummy;
+	u64 act_out_swr = 0;
+	u64 act_out_rwr = 0;
+
+	if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0) {
+		ehea_error("not on page boundary");
+		return H_PARAMETER;
+	}
+
+	hret = ehea_hcall_9arg_9ret(H_MODIFY_HEA_QP,
+				    hcp_adapter_handle,		/* R4 */
+				    (u64) cat,			/* R5 */
+				    qp_handle,			/* R6 */
+				    sel_mask,			/* R7 */
+				    virt_to_abs(cb_addr),	/* R8 */
+				    0, 0, 0, 0,			/* R9-R12 */
+				    inv_attr_id,		/* R4 */
+				    &dummy,			/* R5 */
+				    &dummy,			/* R6 */
+				    &act_out_swr,		/* R7 */
+				    &act_out_rwr,		/* R8 */
+				    proc_mask,			/* R9 */
+				    &dummy,			/* R10 */
+				    &dummy,			/* R11 */
+				    &dummy);			/* R12 */
+	*out_swr = act_out_swr;
+	*out_rwr = act_out_rwr;
+
+	return hret;
+}
+
+u64 ehea_h_register_rpage(const u64 hcp_adapter_handle, const u8 pagesize,
+			  const u8 queue_type, const u64 resource_handle,
+			  const u64 log_pageaddr, u64 count)
+{
+	u64 dummy, reg_control;
+
+	reg_control = EHEA_BMASK_SET(H_REG_RPAGE_PAGE_SIZE, pagesize)
+		    | EHEA_BMASK_SET(H_REG_RPAGE_QT, queue_type);
+
+	return ehea_hcall_9arg_9ret(H_REGISTER_HEA_RPAGES,
+				    hcp_adapter_handle,		/* R4 */
+				    reg_control,		/* R5 */
+				    resource_handle,		/* R6 */
+				    log_pageaddr,		/* R7 */
+				    count,			/* R8 */
+				    0, 0, 0, 0,			/* R9-R12 */
+				    &dummy,			/* R4 */
+				    &dummy,			/* R5 */
+				    &dummy,			/* R6 */
+				    &dummy,			/* R7 */
+				    &dummy,			/* R8 */
+				    &dummy,			/* R9 */
+				    &dummy,			/* R10 */
+				    &dummy,	                /* R11 */
+				    &dummy);	                /* R12 */
+}
+
+u64 ehea_h_register_rpage_eq(const u64 hcp_adapter_handle, const u64 eq_handle,
+			     const u8 pagesize, const u8 queue_type,
+			     const u64 log_pageaddr, const u64 count)
+{
+	if (count != 1)
+		return H_PARAMETER;
+
+	return ehea_h_register_rpage(hcp_adapter_handle, pagesize, queue_type,
+				     eq_handle, log_pageaddr, count);
+}
+
+u64 ehea_h_register_rpage_cq(const u64 hcp_adapter_handle, const u64 cq_handle,
+			     const u8 pagesize, const u8 queue_type,
+			     const u64 log_pageaddr, const u64 count,
+			     const struct h_epa epa)
+{
+	if (count != 1)
+		return H_PARAMETER;
+
+	return ehea_h_register_rpage(hcp_adapter_handle, pagesize, queue_type,
+				     cq_handle, log_pageaddr, count);
+}
+
+u64 ehea_h_register_rpage_qp(const u64 hcp_adapter_handle, const u64 qp_handle,
+			     const u8 pagesize, const u8 queue_type,
+			     const u64 log_pageaddr, const u64 count, 
+			     struct h_epa epa)
+{
+	if (count != 1)
+		return H_PARAMETER;
+
+	return ehea_h_register_rpage(hcp_adapter_handle, pagesize, queue_type,
+				     qp_handle, log_pageaddr, count);
+}
+
+u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle,
+			const u64 vaddr_in, const u32 access_ctrl, const u32 pd,
+			struct ehea_mr *mr)
+{
+	u64 hret, dummy, lkey_out;
+
+	hret = ehea_hcall_9arg_9ret(H_REGISTER_SMR,
+				    adapter_handle       ,          /* R4 */
+				    orig_mr_handle,                 /* R5 */
+				    vaddr_in,                       /* R6 */
+				    (((u64)access_ctrl) << 32ULL),  /* R7 */
+				    pd,                             /* R8 */
+				    0, 0, 0, 0,			    /* R9-R12 */
+				    &mr->handle,                    /* R4 */
+				    &dummy,                         /* R5 */
+				    &lkey_out,                      /* R6 */
+				    &dummy,                         /* R7 */
+				    &dummy,                         /* R8 */
+				    &dummy,                         /* R9 */
+				    &dummy,                         /* R10 */
+				    &dummy,                         /* R11 */
+				    &dummy);                        /* R12 */
+	mr->lkey = (u32)lkey_out;
+
+	return hret;
+}
+
+u64 ehea_h_destroy_qp(const u64 hcp_adapter_handle, struct ehea_qp *qp,
+		      u64 qp_handle, struct h_epas *epas)
+{
+	u64 hret, dummy, ladr_next_sq_wqe_out;
+	u64 ladr_next_rq1_wqe_out, ladr_next_rq2_wqe_out, ladr_next_rq3_wqe_out;
+
+	hcp_epas_dtor(epas);
+
+	hret = ehea_hcall_9arg_9ret(H_DISABLE_AND_GET_HEA,
+				    hcp_adapter_handle,		/* R4 */
+				    H_DISABLE_GET_EHEA_WQE_P,	/* R5 */
+				    qp_handle,			/* R6 */
+				    0, 0, 0, 0, 0, 0,		/* R7-R12 */
+				    &ladr_next_sq_wqe_out,	/* R4 */
+				    &ladr_next_rq1_wqe_out,	/* R5 */
+				    &ladr_next_rq2_wqe_out,	/* R6 */
+				    &ladr_next_rq3_wqe_out,	/* R7 */
+				    &dummy,			/* R8 */
+				    &dummy,			/* R9 */
+				    &dummy,			/* R10 */
+				    &dummy,                     /* R11 */
+				    &dummy);                    /* R12 */
+	if (hret == H_HARDWARE) {
+		ehea_error("QP not disabled, hret=%lx", hret);
+		return hret;
+	}
+
+	hret = ehea_hcall_9arg_9ret(H_FREE_RESOURCE,
+				    hcp_adapter_handle,		/* R4 */
+				    qp_handle,			/* R5 */
+				    0, 0, 0, 0, 0, 0, 0,	/* R6-R12 */
+				    &dummy,			/* R4 */
+				    &dummy,			/* R5 */
+				    &dummy,			/* R6 */
+				    &dummy,			/* R7 */
+				    &dummy,			/* R8 */
+				    &dummy,			/* R9 */
+				    &dummy,			/* R10 */
+				    &dummy,                     /* R11 */
+				    &dummy);                    /* R12 */
+	if (hret == H_RESOURCE)
+		ehea_error("resource in use");
+
+	return hret;
+}
+
+u64 ehea_h_destroy_cq(const u64 hcp_adapter_handle, struct ehea_cq *cq,
+		      u64 cq_handle, struct h_epas *epas)
+{
+	u64 hret, dummy;
+
+	hcp_epas_dtor(epas);
+
+	hret = ehea_hcall_9arg_9ret(H_FREE_RESOURCE,
+				    hcp_adapter_handle,		/* R4 */
+				    cq_handle,			/* R5 */
+				    0, 0, 0, 0, 0, 0, 0,	/* R6-R12 */
+				    &dummy,			/* R4 */
+				    &dummy,			/* R5 */
+				    &dummy,			/* R6 */
+				    &dummy,			/* R7 */
+				    &dummy,			/* R8 */
+				    &dummy,			/* R9 */
+				    &dummy,			/* R10 */
+				    &dummy,                     /* R11 */
+				    &dummy);                    /* R12 */
+	if (hret == H_RESOURCE)
+		ehea_error("resource in use");
+
+	return hret;
+}
+
+u64 ehea_h_destroy_eq(const u64 hcp_adapter_handle, struct ehea_eq * eq,
+		      u64 eq_handle, struct h_epas * epas)
+{
+	u64 hret, dummy;
+
+	hcp_epas_dtor(epas);
+
+	hret = ehea_hcall_9arg_9ret(H_FREE_RESOURCE,
+				    hcp_adapter_handle,		/* R4 */
+				    eq_handle,			/* R5 */
+				    0, 0, 0, 0, 0, 0, 0,	/* R6-R12 */
+				    &dummy,			/* R4 */
+				    &dummy,			/* R5 */
+				    &dummy,			/* R6 */
+				    &dummy,			/* R7 */
+				    &dummy,			/* R8 */
+				    &dummy,			/* R9 */
+				    &dummy,			/* R10 */
+				    &dummy,                     /* R11 */
+				    &dummy);                    /* R12 */
+	if (hret == H_RESOURCE)
+		ehea_error("resource in use");
+
+	return hret;
+}
+
+u64 ehea_h_free_resource_mr(const u64 hcp_adapter_handle, const u64 mr_handle)
+{
+	u64 dummy;
+
+	return ehea_hcall_9arg_9ret(H_FREE_RESOURCE,
+				    hcp_adapter_handle,    /* R4 */
+				    mr_handle,             /* R5 */
+				    0, 0, 0, 0, 0, 0, 0,   /* R6-R12 */
+				    &dummy,                /* R4 */
+				    &dummy,                /* R5 */
+				    &dummy,                /* R6 */
+				    &dummy,                /* R7 */
+				    &dummy,                /* R8 */
+				    &dummy,                /* R9 */
+				    &dummy,		   /* R10 */
+				    &dummy,                /* R11 */
+				    &dummy);               /* R12 */
+}
+
+u64 ehea_h_alloc_resource_mr(const u64 hcp_adapter_handle, const u64 vaddr,
+			     const u64 length, const u32 access_ctrl,
+			     const u32 pd, u64 *mr_handle, u32 *lkey)
+{
+	u64 hret, dummy, lkey_out;
+
+	hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE,
+				    hcp_adapter_handle,		   /* R4 */
+				    5,				   /* R5 */
+				    vaddr,			   /* R6 */
+				    length,			   /* R7 */
+				    (((u64) access_ctrl) << 32ULL),/* R8 */
+				    pd,				   /* R9 */
+				    0, 0, 0,			   /* R10-R12 */
+				    mr_handle,			   /* R4 */
+				    &dummy,			   /* R5 */
+				    &lkey_out,			   /* R6 */
+				    &dummy,			   /* R7 */
+				    &dummy,			   /* R8 */
+				    &dummy,			   /* R9 */
+				    &dummy,			   /* R10 */
+				    &dummy,                        /* R11 */
+				    &dummy);                       /* R12 */
+	*lkey = (u32) lkey_out;
+
+	return hret;
+}
+
+u64 ehea_h_register_rpage_mr(const u64 hcp_adapter_handle, const u64 mr_handle,
+			     const u8 pagesize, const u8 queue_type,
+			     const u64 log_pageaddr, const u64 count)
+{
+	if ((count > 1) && (log_pageaddr & 0xfff)) {
+		ehea_error("not on pageboundary");
+		return H_PARAMETER;
+	}
+
+	return ehea_h_register_rpage(hcp_adapter_handle, pagesize,
+				     queue_type, mr_handle, 
+				     log_pageaddr, count);
+}
+
+u64 ehea_h_query_ehea(const u64 hcp_adapter_handle, void *cb_addr)
+{
+	u64 hret, dummy, cb_logaddr;
+
+	cb_logaddr = virt_to_abs(cb_addr);
+
+	hret = ehea_hcall_9arg_9ret(H_QUERY_HEA,
+				    hcp_adapter_handle,		/* R4 */
+				    cb_logaddr,			/* R5 */
+				    0, 0, 0, 0, 0, 0, 0,	/* R6-R12 */
+				    &dummy,			/* R4 */
+				    &dummy,			/* R5 */
+				    &dummy,			/* R6 */
+				    &dummy,			/* R7 */
+				    &dummy,			/* R8 */
+				    &dummy,			/* R9 */
+				    &dummy,			/* R10 */
+				    &dummy,             	/* R11 */
+				    &dummy);            	/* R12 */
+#ifdef DEBUG
+	ehea_dmp(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea");
+#endif
+	return hret;
+}
+
+u64 ehea_h_query_ehea_port(const u64 hcp_adapter_handle, const u16 port_num,
+			   const u8 cb_cat, const u64 select_mask,
+			   void *cb_addr)
+{
+	u64 port_info = 0;
+	u64 arr_index = 0;
+	u64 cb_logaddr = virt_to_abs(cb_addr);
+	u64 dummy;
+
+	port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
+		  | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num);
+
+	return ehea_hcall_9arg_9ret(H_QUERY_HEA_PORT,
+				    hcp_adapter_handle,		/* R4 */
+				    port_info,			/* R5 */
+				    select_mask,		/* R6 */
+				    arr_index,			/* R7 */
+				    cb_logaddr,			/* R8 */
+				    0, 0, 0, 0,			/* R9-R12 */
+				    &dummy,			/* R4 */
+				    &dummy,			/* R5 */
+				    &dummy,			/* R6 */
+				    &dummy,			/* R7 */
+				    &dummy,			/* R8 */
+				    &dummy,			/* R9 */
+				    &dummy,			/* R10 */
+				    &dummy,                     /* R11 */
+				    &dummy);                    /* R12 */
+}
+
+u64 ehea_h_modify_ehea_port(const u64 hcp_adapter_handle, const u16 port_num,
+			    const u8 cb_cat, const u64 select_mask, 
+			    void *cb_addr)
+{
+	u64 port_info = 0;
+	u64 arr_index = 0;
+	u64 cb_logaddr = virt_to_abs(cb_addr);
+	u64 dummy;
+
+	port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
+		  | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num);
+#ifdef DEBUG
+	ehea_dump(cb_addr, sizeof(struct hcp_ehea_port_cb0), "Before HCALL");
+#endif
+	return ehea_hcall_9arg_9ret(H_MODIFY_HEA_PORT,
+				    hcp_adapter_handle,		/* R4 */
+				    port_info,			/* R5 */
+				    select_mask,		/* R6 */
+				    arr_index,			/* R7 */
+				    cb_logaddr,			/* R8 */
+				    0, 0, 0, 0,			/* R9-R12 */
+				    &dummy,			/* R4 */
+				    &dummy,			/* R5 */
+				    &dummy,			/* R6 */
+				    &dummy,			/* R7 */
+				    &dummy,			/* R8 */
+				    &dummy,			/* R9 */
+				    &dummy,			/* R10 */
+				    &dummy,                     /* R11 */
+				    &dummy);                    /* R12 */
+}
+
+u64 ehea_h_reg_dereg_bcmc(const u64 hcp_adapter_handle, const u16 port_num,
+			  const u8 reg_type, const u64 mc_mac_addr,
+			  const u16 vlan_id, const u32 hcall_id)
+{
+	u64 r5_port_num = 0;
+	u64 r6_reg_type = 0;
+	u64 r7_mc_mac_addr = 0;
+	u64 r8_vlan_id = 0;
+	u64 dummy;
+
+	u64 mac_addr = mc_mac_addr >> 16;
+
+	r5_port_num = EHEA_BMASK_SET(H_REGBCMC_PN, port_num);
+	r6_reg_type = EHEA_BMASK_SET(H_REGBCMC_REGTYPE, reg_type);
+	r7_mc_mac_addr = EHEA_BMASK_SET(H_REGBCMC_MACADDR, mac_addr);
+	r8_vlan_id = EHEA_BMASK_SET(H_REGBCMC_VLANID, vlan_id);
+
+	return ehea_hcall_9arg_9ret(hcall_id,
+				    hcp_adapter_handle,		/* R4 */
+				    r5_port_num,		/* R5 */
+				    r6_reg_type,		/* R6 */
+				    r7_mc_mac_addr,		/* R7 */
+				    r8_vlan_id,			/* R8 */
+				    0, 0, 0, 0,			/* R9-R12 */
+				    &dummy,			/* R4 */
+				    &dummy,			/* R5 */
+				    &dummy,			/* R6 */
+				    &dummy,			/* R7 */
+				    &dummy,			/* R8 */
+				    &dummy,			/* R9 */
+				    &dummy,			/* R10 */
+				    &dummy,                     /* R11 */
+				    &dummy);                    /* R12 */
+}
+
+u64 ehea_h_reset_events(const u64 hcp_adapter_handle, const u64 neq_handle, 
+			const u64 event_mask)
+{
+	u64 dummy;
+
+	return ehea_hcall_9arg_9ret(H_RESET_EVENTS,
+				    hcp_adapter_handle,		/* R4 */
+				    neq_handle,			/* R5 */
+				    event_mask,			/* R6 */
+				    0, 0, 0, 0, 0, 0,		/* R7-R12 */
+				    &dummy,			/* R4 */
+				    &dummy,			/* R5 */
+				    &dummy,			/* R6 */
+				    &dummy,			/* R7 */
+				    &dummy,			/* R8 */
+				    &dummy,			/* R9 */
+				    &dummy,			/* R10 */
+				    &dummy,                     /* R11 */
+				    &dummy);                    /* R12 */
+}
--- linux-2.6.18-rc4-git1-orig/drivers/net/ehea/ehea_phyp.h	1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_phyp.h	2006-08-22 06:05:28.738369480 -0700
@@ -0,0 +1,479 @@
+/*
+ *  linux/drivers/net/ehea/ehea_phyp.h
+ *
+ *  eHEA ethernet device driver for IBM eServer System p
+ *
+ *  (C) Copyright IBM Corp. 2006
+ *
+ *  Authors:
+ *       Christoph Raisch <raisch@de.ibm.com>
+ *       Jan-Bernd Themann <themann@de.ibm.com>
+ *       Thomas Klein <tklein@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 __EHEA_PHYP_H__
+#define __EHEA_PHYP_H__
+
+#include <linux/delay.h>
+#include <asm/hvcall.h>
+#include "ehea.h"
+#include "ehea_hw.h"
+#include "ehea_hcall.h"
+
+
+
+/* Some abbreviations used here:
+ *
+ * hcp_*  - structures, variables and functions releated to Hypervisor Calls
+ */
+
+
+static inline u32 get_longbusy_msecs(int long_busy_ret_code)
+{
+	switch (long_busy_ret_code) {
+	case H_LONG_BUSY_ORDER_1_MSEC:
+		return 1;
+	case H_LONG_BUSY_ORDER_10_MSEC:
+		return 10;
+	case H_LONG_BUSY_ORDER_100_MSEC:
+		return 100;
+	case H_LONG_BUSY_ORDER_1_SEC:
+		return 1000;
+	case H_LONG_BUSY_ORDER_10_SEC:
+		return 10000;
+	case H_LONG_BUSY_ORDER_100_SEC:
+		return 100000;
+	default:
+		return 1;
+	}
+}
+
+/* Notification Event Queue (NEQ) Entry bit masks */
+#define NEQE_EVENT_CODE		EHEA_BMASK_IBM(2, 7)
+#define NEQE_PORTNUM  		EHEA_BMASK_IBM(32, 47)
+#define NEQE_PORT_UP		EHEA_BMASK_IBM(16, 16)
+#define NEQE_EXTSWITCH_PORT_UP	EHEA_BMASK_IBM(17, 17)
+#define NEQE_EXTSWITCH_PRIMARY	EHEA_BMASK_IBM(18, 18)
+#define NEQE_PLID		EHEA_BMASK_IBM(16, 47)
+
+/* Notification Event Codes */
+#define EHEA_EC_PORTSTATE_CHG	0x30
+#define EHEA_EC_ADAPTER_MALFUNC	0x32
+#define EHEA_EC_PORT_MALFUNC	0x33
+
+/* Notification Event Log Register (NELR) bit masks */
+#define NELR_PORT_MALFUNC	EHEA_BMASK_IBM(61, 61)
+#define NELR_ADAPTER_MALFUNC	EHEA_BMASK_IBM(62, 62)
+#define NELR_PORTSTATE_CHG	EHEA_BMASK_IBM(63, 63)
+
+static inline void hcp_epas_ctor(struct h_epas *epas, u64 paddr_kernel,
+				 u64 paddr_user)
+{
+	epas->kernel.fw_handle = (u64)ioremap(paddr_kernel, PAGE_SIZE);
+	epas->user.fw_handle = paddr_user;
+}
+
+static inline void hcp_epas_dtor(struct h_epas *epas)
+{
+	if (epas->kernel.fw_handle)
+		iounmap((void *)epas->kernel.fw_handle);
+
+	epas->user.fw_handle = epas->kernel.fw_handle = 0;
+}
+
+struct hcp_modify_qp_cb0 {
+	u64 qp_ctl_reg;		/* 00 */
+	u32 max_swqe;		/* 02 */
+	u32 max_rwqe;		/* 03 */
+	u32 port_nb;		/* 04 */
+	u32 reserved0;		/* 05 */
+	u64 qp_aer;		/* 06 */
+	u64 qp_tenure;		/* 08 */
+};
+
+/* Hcall Query/Modify Queue Pair Control Block 0 Selection Mask Bits */
+#define H_QPCB0_ALL             EHEA_BMASK_IBM(0, 5)
+#define H_QPCB0_QP_CTL_REG      EHEA_BMASK_IBM(0, 0)
+#define H_QPCB0_MAX_SWQE        EHEA_BMASK_IBM(1, 1)
+#define H_QPCB0_MAX_RWQE        EHEA_BMASK_IBM(2, 2)
+#define H_QPCB0_PORT_NB         EHEA_BMASK_IBM(3, 3)
+#define H_QPCB0_QP_AER          EHEA_BMASK_IBM(4, 4)
+#define H_QPCB0_QP_TENURE       EHEA_BMASK_IBM(5, 5)
+
+/* Queue Pair Control Register Status Bits */
+#define H_QP_CR_ENABLED		    0x8000000000000000ULL /* QP enabled */
+							  /* QP States: */
+#define H_QP_CR_STATE_RESET	    0x0000010000000000ULL /*  Reset */
+#define H_QP_CR_STATE_INITIALIZED   0x0000020000000000ULL /*  Initialized */
+#define H_QP_CR_STATE_RDY2RCV	    0x0000030000000000ULL /*  Ready to recv */
+#define H_QP_CR_STATE_RDY2SND	    0x0000050000000000ULL /*  Ready to send */
+#define H_QP_CR_STATE_ERROR	    0x0000800000000000ULL /*  Error */
+
+struct hcp_modify_qp_cb1 {
+	u32 qpn;		/* 00 */
+	u32 qp_asyn_ev_eq_nb;	/* 01 */
+	u64 sq_cq_handle;	/* 02 */
+	u64 rq_cq_handle;	/* 04 */
+	/* sgel = scatter gather element */
+	u32 sgel_nb_sq;		/* 06 */
+	u32 sgel_nb_rq1;	/* 07 */
+	u32 sgel_nb_rq2;	/* 08 */
+	u32 sgel_nb_rq3;	/* 09 */
+};
+
+/* Hcall Query/Modify Queue Pair Control Block 1 Selection Mask Bits */
+#define H_QPCB1_ALL             EHEA_BMASK_IBM(0, 7)
+#define H_QPCB1_QPN             EHEA_BMASK_IBM(0, 0)
+#define H_QPCB1_ASYN_EV_EQ_NB   EHEA_BMASK_IBM(1, 1)
+#define H_QPCB1_SQ_CQ_HANDLE    EHEA_BMASK_IBM(2, 2)
+#define H_QPCB1_RQ_CQ_HANDLE    EHEA_BMASK_IBM(3, 3)
+#define H_QPCB1_SGEL_NB_SQ      EHEA_BMASK_IBM(4, 4)
+#define H_QPCB1_SGEL_NB_RQ1     EHEA_BMASK_IBM(5, 5)
+#define H_QPCB1_SGEL_NB_RQ2     EHEA_BMASK_IBM(6, 6)
+#define H_QPCB1_SGEL_NB_RQ3     EHEA_BMASK_IBM(7, 7)
+
+struct hcp_query_ehea {
+	u32 cur_num_qps;		/* 00 */
+	u32 cur_num_cqs;		/* 01 */
+	u32 cur_num_eqs;		/* 02 */
+	u32 cur_num_mrs;		/* 03 */
+	u32 auth_level;			/* 04 */
+	u32 max_num_qps;		/* 05 */
+	u32 max_num_cqs;		/* 06 */
+	u32 max_num_eqs;		/* 07 */
+	u32 max_num_mrs;		/* 08 */
+	u32 reserved0;			/* 09 */
+	u32 int_clock_freq;		/* 10 */
+	u32 max_num_pds;		/* 11 */
+	u32 max_num_addr_handles;	/* 12 */
+	u32 max_num_cqes;		/* 13 */
+	u32 max_num_wqes;		/* 14 */
+	u32 max_num_sgel_rq1wqe;	/* 15 */
+	u32 max_num_sgel_rq2wqe;	/* 16 */
+	u32 max_num_sgel_rq3wqe;	/* 17 */
+	u32 mr_page_size;		/*define */
+	u32 reserved1;			/* 19 */
+	u64 max_mr_size;		/* 20 */
+	u64 reserved2;			/* 22 */
+	u32 num_ports;			/* 24 */
+	u32 reserved3;			/* 25 */
+	u32 reserved4;			/* 26 */
+	u32 reserved5;			/* 27 */
+	u64 max_mc_mac;			/* 28 */
+	u64 ehea_cap;			/* 30 */
+	u32 max_isn_per_eq;		/* 32 */
+	u32 max_num_neq;		/* 33 */
+	u64 max_num_vlan_ids;		/* 34 */
+	u32 max_num_port_group;		/* 36 */
+	u32 max_num_phys_port;		/* 37 */
+
+};
+
+/* Hcall Query/Modify Port Control Block defines */
+#define H_PORT_CB0	 0
+#define H_PORT_CB1	 1
+#define H_PORT_CB2	 2
+#define H_PORT_CB3	 3
+#define H_PORT_CB4	 4
+#define H_PORT_CB5	 5
+#define H_PORT_CB6	 6
+#define H_PORT_CB7	 7
+
+struct hcp_ehea_port_cb0 {
+	u64 port_mac_addr;
+	u64 port_rc;
+	u64 reserved0;
+	u32 port_op_state;
+	u32 port_speed;
+	u32 ext_swport_op_state;
+	u32 neg_tpf_prpf;
+	u32 num_default_qps;
+	u32 reserved1;
+	u64 default_qpn_array[16];
+};
+
+/* Hcall Query/Modify Port Control Block 0 Selection Mask Bits */
+#define H_PORT_CB0_ALL		EHEA_BMASK_IBM(0, 7)    /* Set all bits */
+#define H_PORT_CB0_MAC		EHEA_BMASK_IBM(0, 0)    /* MAC address */
+#define H_PORT_CB0_PRC		EHEA_BMASK_IBM(1, 1)    /* Port Recv Control */
+#define H_PORT_CB0_DEFQPNARRAY	EHEA_BMASK_IBM(7, 7)    /* Default QPN Array */
+
+/*  Hcall Query Port: Returned port speed values */
+#define H_PORT_SPEED_10M_H	1	/*  10 Mbps, Half Duplex */
+#define H_PORT_SPEED_10M_F	2	/*  10 Mbps, Full Duplex */
+#define H_PORT_SPEED_100M_H	3	/* 100 Mbps, Half Duplex */
+#define H_PORT_SPEED_100M_F	4	/* 100 Mbps, Full Duplex */
+#define H_PORT_SPEED_1G_F	6	/*   1 Gbps, Full Duplex */
+#define H_PORT_SPEED_10G_F	8	/*  10 Gbps, Full Duplex */
+
+/* Port Receive Control Status Bits */
+#define PXLY_RC_VALID           EHEA_BMASK_IBM(49, 49)
+#define PXLY_RC_VLAN_XTRACT     EHEA_BMASK_IBM(50, 50)
+#define PXLY_RC_TCP_6_TUPLE     EHEA_BMASK_IBM(51, 51)
+#define PXLY_RC_UDP_6_TUPLE     EHEA_BMASK_IBM(52, 52)
+#define PXLY_RC_TCP_3_TUPLE     EHEA_BMASK_IBM(53, 53)
+#define PXLY_RC_TCP_2_TUPLE     EHEA_BMASK_IBM(54, 54)
+#define PXLY_RC_LLC_SNAP        EHEA_BMASK_IBM(55, 55)
+#define PXLY_RC_JUMBO_FRAME     EHEA_BMASK_IBM(56, 56)
+#define PXLY_RC_FRAG_IP_PKT     EHEA_BMASK_IBM(57, 57)
+#define PXLY_RC_TCP_UDP_CHKSUM  EHEA_BMASK_IBM(58, 58)
+#define PXLY_RC_IP_CHKSUM       EHEA_BMASK_IBM(59, 59)
+#define PXLY_RC_MAC_FILTER      EHEA_BMASK_IBM(60, 60)
+#define PXLY_RC_UNTAG_FILTER    EHEA_BMASK_IBM(61, 61)
+#define PXLY_RC_VLAN_TAG_FILTER EHEA_BMASK_IBM(62, 63)
+
+#define PXLY_RC_VLAN_FILTER     2
+#define PXLY_RC_VLAN_PERM       0
+
+
+#define H_PORT_CB1_ALL          0x8000000000000000ULL
+
+struct hcp_ehea_port_cb1 {
+	u64 vlan_filter[64];
+};
+
+#define H_PORT_CB2_ALL          0xFFE0000000000000ULL
+
+struct hcp_ehea_port_cb2 {
+	u64 rxo;
+	u64 rxucp;
+	u64 rxufd;
+	u64 rxuerr;
+	u64 rxftl;
+	u64 rxmcp;
+	u64 rxbcp;
+	u64 txo;
+	u64 txucp;
+	u64 txmcp;
+	u64 txbcp;
+};
+
+struct hcp_ehea_port_cb3 {
+	u64 vlan_bc_filter[64];
+	u64 vlan_mc_filter[64];
+	u64 vlan_un_filter[64];
+	u64 port_mac_hash_array[64];
+};
+
+#define H_PORT_CB4_ALL          0xF000000000000000ULL
+#define H_PORT_CB4_JUMBO        0x1000000000000000ULL
+
+struct hcp_ehea_port_cb4 {
+	u32 port_speed;
+	u32 pause_frame;
+	u32 ens_port_op_state;
+	u32 jumbo_frame;
+	u32 ens_port_wrap;
+};
+
+struct hcp_ehea_port_cb5 {
+	u64 prc;	        /* 00 */
+	u64 uaa;		/* 01 */
+	u64 macvc;		/* 02 */
+	u64 xpcsc;		/* 03 */
+	u64 xpcsp;		/* 04 */
+	u64 pcsid;		/* 05 */
+	u64 xpcsst;		/* 06 */
+	u64 pthlb;		/* 07 */
+	u64 pthrb;		/* 08 */
+	u64 pqu;		/* 09 */
+	u64 pqd;		/* 10 */
+	u64 prt;		/* 11 */
+	u64 wsth;		/* 12 */
+	u64 rcb;		/* 13 */
+	u64 rcm;		/* 14 */
+	u64 rcu;		/* 15 */
+	u64 macc;		/* 16 */
+	u64 pc;			/* 17 */
+	u64 pst;		/* 18 */
+	u64 ducqpn;		/* 19 */
+	u64 mcqpn;		/* 20 */
+	u64 mma;		/* 21 */
+	u64 pmc0h;		/* 22 */
+	u64 pmc0l;		/* 23 */
+	u64 lbc;		/* 24 */
+};
+
+#define H_PORT_CB6_ALL  0xFFFFFE7FFFFF8000ULL
+
+struct hcp_ehea_port_cb6 {
+	u64 rxo;		/* 00 */
+	u64 rx64;		/* 01 */
+	u64 rx65;		/* 02 */
+	u64 rx128;		/* 03 */
+	u64 rx256;		/* 04 */
+	u64 rx512;		/* 05 */
+	u64 rx1024;		/* 06 */
+	u64 rxbfcs;		/* 07 */
+	u64 rxime;		/* 08 */
+	u64 rxrle;		/* 09 */
+	u64 rxorle;		/* 10 */
+	u64 rxftl;		/* 11 */
+	u64 rxjab;		/* 12 */
+	u64 rxse;		/* 13 */
+	u64 rxce;		/* 14 */
+	u64 rxrf;		/* 15 */
+	u64 rxfrag;		/* 16 */
+	u64 rxuoc;		/* 17 */
+	u64 rxcpf;		/* 18 */
+	u64 rxsb;		/* 19 */
+	u64 rxfd;		/* 20 */
+	u64 rxoerr;		/* 21 */
+	u64 rxaln;		/* 22 */
+	u64 ducqpn;		/* 23 */
+	u64 reserved0;		/* 24 */
+	u64 rxmcp;		/* 25 */
+	u64 rxbcp;		/* 26 */
+	u64 txmcp;		/* 27 */
+	u64 txbcp;		/* 28 */
+	u64 txo;		/* 29 */
+	u64 tx64;		/* 30 */
+	u64 tx65;		/* 31 */
+	u64 tx128;		/* 32 */
+	u64 tx256;		/* 33 */
+	u64 tx512;		/* 34 */
+	u64 tx1024;		/* 35 */
+	u64 txbfcs;		/* 36 */
+	u64 txcpf;		/* 37 */
+	u64 txlf;		/* 38 */
+	u64 txrf;		/* 39 */
+	u64 txime;		/* 40 */
+	u64 txsc;		/* 41 */
+	u64 txmc;		/* 42 */
+	u64 txsqe;		/* 43 */
+	u64 txdef;		/* 44 */
+	u64 txlcol;		/* 45 */
+	u64 txexcol;		/* 46 */
+	u64 txcse;		/* 47 */
+	u64 txbor;		/* 48 */
+};
+
+struct hcp_ehea_port_cb7 {
+	u64 def_uc_qpn;
+};
+
+u64 ehea_h_query_ehea_qp(const u64 hcp_adapter_handle,
+			 const u8 qp_category,
+			 const u64 qp_handle, const u64 sel_mask,
+			 void *cb_addr);
+
+u64 ehea_h_modify_ehea_qp(const u64 hcp_adapter_handle,
+			  const u8 cat,
+			  const u64 qp_handle,
+			  const u64 sel_mask,
+			  void *cb_addr,
+			  u64 * inv_attr_id,
+			  u64 * proc_mask, u16 * out_swr, u16 * out_rwr);
+
+u64 ehea_h_alloc_resource_eq(const u64 hcp_adapter_handle,
+			     struct ehea_eq *ehea_eq,
+			     struct ehea_eq_attr *eq_attr, u64 * eq_handle);
+
+u64 ehea_h_alloc_resource_cq(const u64 hcp_adapter_handle,
+			     struct ehea_cq *ehea_cq,
+			     struct ehea_cq_attr *cq_attr,
+			     u64 * cq_handle, struct h_epas *epas);
+
+u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
+			     struct ehea_qp *ehea_qp,
+			     struct ehea_qp_init_attr *init_attr,
+			     const u32 pd,
+			     u64 * qp_handle, struct h_epas *h_epas);
+
+#define H_REG_RPAGE_PAGE_SIZE          EHEA_BMASK_IBM(48,55)
+#define H_REG_RPAGE_QT                 EHEA_BMASK_IBM(62,63)
+
+u64 ehea_h_register_rpage(const u64 hcp_adapter_handle,
+			  const u8 pagesize,
+			  const u8 queue_type,
+			  const u64 resource_handle,
+			  const u64 log_pageaddr, u64 count);
+
+u64 ehea_h_register_rpage_eq(const u64 hcp_adapter_handle,
+			     const u64 eq_handle,
+			     const u8 pagesize,
+			     const u8 queue_type,
+			     const u64 log_pageaddr, const u64 count);
+
+u64 ehea_h_register_rpage_cq(const u64 hcp_adapter_handle,
+			     const u64 cq_handle,
+			     const u8 pagesize,
+			     const u8 queue_type,
+			     const u64 log_pageaddr,
+			     const u64 count, const struct h_epa epa);
+
+u64 ehea_h_register_rpage_qp(const u64 hcp_adapter_handle,
+			     const u64 qp_handle,
+			     const u8 pagesize,
+			     const u8 queue_type,
+			     const u64 log_pageaddr,
+			     const u64 count, struct h_epa epa);
+
+#define H_DISABLE_GET_EHEA_WQE_P  1
+#define H_DISABLE_GET_SQ_WQE_P    2
+#define H_DISABLE_GET_RQC         3
+
+u64 ehea_h_destroy_qp(const u64 hcp_adapter_handle, struct ehea_qp *qp,
+		      u64 qp_handle, struct h_epas *epas);
+
+u64 ehea_h_destroy_cq(const u64 hcp_adapter_handle, struct ehea_cq *cq,
+		      u64 cq_handle, struct h_epas *epas);
+
+u64 ehea_h_destroy_eq(const u64 hcp_adapter_handle, struct ehea_eq *eq,
+		      u64 eq_handle, struct h_epas *epas);
+
+u64 ehea_h_free_resource_mr(const u64 hcp_adapter_handle, const u64 mr_handle);
+
+u64 ehea_h_alloc_resource_mr(const u64 hcp_adapter_handle, const u64 vaddr,
+			     const u64 length, const u32 access_ctrl,
+			     const u32 pd, u64 * mr_handle, u32 * lkey);
+
+u64 ehea_h_register_rpage_mr(const u64 hcp_adapter_handle, const u64 mr_handle,
+			     const u8 pagesize, const u8 queue_type,
+			     const u64 log_pageaddr, const u64 count);
+u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle,
+			const u64 vaddr_in, const u32 access_ctrl, const u32 pd,
+			struct ehea_mr *mr);
+
+u64 ehea_h_query_ehea(const u64 hcp_adapter_handle, void *cb_addr);
+
+/* output param R5 */
+#define H_MEHEAPORT_CAT		EHEA_BMASK_IBM(40,47)
+#define H_MEHEAPORT_PN		EHEA_BMASK_IBM(48,63)
+
+u64 ehea_h_query_ehea_port(const u64 hcp_adapter_handle, const u16 port_num,
+			   const u8 cb_cat, const u64 select_mask,
+			   void *cb_addr);
+
+u64 ehea_h_modify_ehea_port(const u64 hcp_adapter_handle, const u16 port_num,
+			    const u8 cb_cat, const u64 select_mask,
+			    void *cb_addr);
+
+#define H_REGBCMC_PN            EHEA_BMASK_IBM(48, 63)
+#define H_REGBCMC_REGTYPE       EHEA_BMASK_IBM(61, 63)
+#define H_REGBCMC_MACADDR       EHEA_BMASK_IBM(16, 63)
+#define H_REGBCMC_VLANID        EHEA_BMASK_IBM(52, 63)
+
+u64 ehea_h_reg_dereg_bcmc(const u64 hcp_adapter_handle, const u16 port_num,
+			  const u8 reg_type, const u64 mc_mac_addr,
+			  const u16 vlan_id, const u32 hcall_id);
+
+u64 ehea_h_reset_events(const u64 hcp_adapter_handle, const u64 neq_handle,
+			const u64 event_mask);
+
+#endif	/* __EHEA_PHYP_H__ */
--- linux-2.6.18-rc4-git1-orig/drivers/net/ehea/ehea_hcall.h	1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_hcall.h	2006-08-22 06:05:26.992093525 -0700
@@ -0,0 +1,51 @@
+/*
+ *  linux/drivers/net/ehea/ehea_hcall.h
+ *
+ *  eHEA ethernet device driver for IBM eServer System p
+ *
+ *  (C) Copyright IBM Corp. 2006
+ *
+ *  Authors:
+ *       Christoph Raisch <raisch@de.ibm.com>
+ *       Jan-Bernd Themann <themann@de.ibm.com>
+ *       Thomas Klein <tklein@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 __EHEA_HCALL_H__
+#define __EHEA_HCALL_H__
+
+/**
+ * This file contains HCALL defines that are to be included in the appropriate
+ * kernel files later
+ */
+
+#define H_ALLOC_HEA_RESOURCE   0x278
+#define H_MODIFY_HEA_QP        0x250
+#define H_QUERY_HEA_QP         0x254
+#define H_QUERY_HEA            0x258
+#define H_QUERY_HEA_PORT       0x25C
+#define H_MODIFY_HEA_PORT      0x260
+#define H_REG_BCMC             0x264
+#define H_DEREG_BCMC           0x268
+#define H_REGISTER_HEA_RPAGES  0x26C
+#define H_DISABLE_AND_GET_HEA  0x270
+#define H_GET_HEA_INFO         0x274
+#define H_ADD_CONN             0x284
+#define H_DEL_CONN             0x288
+
+#endif	/* __EHEA_HCALL_H__ */

^ permalink raw reply

* [2.6.19 PATCH 3/7] ehea: queue management
From: Jan-Bernd Themann @ 2006-08-22 12:53 UTC (permalink / raw)
  To: netdev
  Cc: Thomas Klein, Jan-Bernd Themann, linux-kernel, linux-ppc,
	Christoph Raisch, Marcus Eder

Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com> 


 drivers/net/ehea/ehea_qmr.c |  634 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ehea/ehea_qmr.h |  367 +++++++++++++++++++++++++
 2 files changed, 1001 insertions(+)



--- linux-2.6.18-rc4-git1-orig/drivers/net/ehea/ehea_qmr.c	1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_qmr.c	2006-08-22 06:05:29.120372939 -0700
@@ -0,0 +1,634 @@
+/*
+ *  linux/drivers/net/ehea/ehea_qmr.c
+ *
+ *  eHEA ethernet device driver for IBM eServer System p
+ *
+ *  (C) Copyright IBM Corp. 2006
+ *
+ *  Authors:
+ *       Christoph Raisch <raisch@de.ibm.com>
+ *       Jan-Bernd Themann <themann@de.ibm.com>
+ *       Thomas Klein <tklein@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 "ehea.h"
+#include "ehea_phyp.h"
+#include "ehea_qmr.h"
+
+static void *hw_qpageit_get_inc(struct hw_queue *queue)
+{
+	void *retvalue = hw_qeit_get(queue);
+
+	queue->current_q_offset += queue->pagesize;
+	if (queue->current_q_offset > queue->queue_length) {
+		queue->current_q_offset -= queue->pagesize;
+		retvalue = NULL;
+	} else if (((u64) retvalue) & (EHEA_PAGESIZE-1)) {
+		ehea_error("not on pageboundary");
+		retvalue = NULL;
+	}
+	return retvalue;
+}
+
+static int hw_queue_ctor(struct hw_queue *queue, const u32 nr_of_pages,
+			  const u32 pagesize, const u32 qe_size)
+{
+	int pages_per_kpage = PAGE_SIZE / pagesize;
+	int i;
+
+	if ((pagesize > PAGE_SIZE) || (!pages_per_kpage)) {
+		ehea_error("pagesize conflict! kernel pagesize=%d, "
+			   "ehea pagesize=%d", (int)PAGE_SIZE, (int)pagesize);
+		return -EINVAL;
+	}
+
+	queue->queue_length = nr_of_pages * pagesize;
+	queue->queue_pages = kmalloc(nr_of_pages * sizeof(void*), GFP_KERNEL);
+	if (!queue->queue_pages) {
+		ehea_error("no mem for queue_pages");
+		return -ENOMEM;
+	}
+
+	/*
+	 * allocate pages for queue:
+	 * outer loop allocates whole kernel pages (page aligned) and
+	 * inner loop divides a kernel page into smaller hea queue pages
+	 */
+	i = 0;
+	while (i < nr_of_pages) {
+		int k;
+		u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL);
+		if (!kpage)
+			goto hw_queue_ctor_exit0;
+		for (k = 0; k < pages_per_kpage && i < nr_of_pages; k++) {
+			(queue->queue_pages)[i] = (struct ehea_page *)kpage;
+			kpage += pagesize;
+			i++;
+		}
+	}
+
+	queue->current_q_offset = 0;
+	queue->qe_size = qe_size;
+	queue->pagesize = pagesize;
+	queue->toggle_state = 1;
+
+	return 0;
+
+hw_queue_ctor_exit0:
+	for (i = 0; i < nr_of_pages; i += pages_per_kpage) {
+		if (!(queue->queue_pages)[i])
+			break;
+		free_page((unsigned long)(queue->queue_pages)[i]);
+	}
+	return -ENOMEM;
+}
+
+static void hw_queue_dtor(struct hw_queue *queue)
+{
+	int pages_per_kpage = PAGE_SIZE / queue->pagesize;
+	int i;
+	int nr_pages;
+
+	if (!queue || !queue->queue_pages)
+		return;
+
+	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]);
+
+	kfree(queue->queue_pages);
+}
+
+struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
+			       int nr_of_cqe, u64 eq_handle, u32 cq_token)
+{
+	struct ehea_cq *cq = NULL;
+	struct h_epa epa;
+
+	u64 *cq_handle_ref;
+	u32 act_nr_of_entries;
+	u32 act_pages;
+	u64 hret;
+	int ret;
+	u32 counter;
+	void *vpage = NULL;
+	u64 rpage = 0;
+
+	cq = kzalloc(sizeof(*cq), GFP_KERNEL);
+	if (!cq) {
+		ehea_error("no mem for cq");
+		goto create_cq_exit0;
+	}
+
+	cq->attr.max_nr_of_cqes = nr_of_cqe;
+	cq->attr.cq_token = cq_token;
+	cq->attr.eq_handle = eq_handle;
+
+	cq->adapter = adapter;
+
+	cq_handle_ref = &cq->fw_handle;
+	act_nr_of_entries = 0;
+	act_pages = 0;
+
+	hret = ehea_h_alloc_resource_cq(adapter->handle, cq, &cq->attr,
+					&cq->fw_handle, &cq->epas);
+	if (hret != H_SUCCESS) {
+		ehea_error("alloc_resource_cq failed");
+		goto create_cq_exit1;
+	}
+
+	ret = hw_queue_ctor(&cq->hw_queue, cq->attr.nr_pages,
+			    EHEA_PAGESIZE, sizeof(struct ehea_cqe));
+	if (ret)
+		goto create_cq_exit2;
+
+	for (counter = 0; counter < cq->attr.nr_pages; counter++) {
+		vpage = hw_qpageit_get_inc(&cq->hw_queue);
+		if (!vpage) {
+			ehea_error("hw_qpageit_get_inc failed");
+			goto create_cq_exit3;
+		}
+
+		rpage = virt_to_abs(vpage);
+
+		hret = ehea_h_register_rpage_cq(adapter->handle, cq->fw_handle,
+						0, EHEA_CQ_REGISTER_ORIG, rpage,
+						1, cq->epas.kernel);
+		if (hret < H_SUCCESS) {
+			ehea_error("register_rpage_cq failed ehea_cq=%p "
+				   "hret=%lx counter=%i act_pages=%i",
+				   cq, hret, counter, cq->attr.nr_pages);
+			goto create_cq_exit3;
+		}
+
+		if (counter == (cq->attr.nr_pages - 1)) {
+			vpage = hw_qpageit_get_inc(&cq->hw_queue);
+
+			if ((hret != H_SUCCESS) || (vpage)) {
+				ehea_error("registration of pages not "
+					   "complete hret=%lx\n", hret);
+				goto create_cq_exit3;
+			}
+		} else {
+			if ((hret != H_PAGE_REGISTERED) || (!vpage)) {
+				ehea_error("CQ: registration of page failed "
+					   "hret=%lx\n", hret);
+				goto create_cq_exit3;
+			}
+		}
+	}
+
+	hw_qeit_reset(&cq->hw_queue);
+	epa = cq->epas.kernel;
+	ehea_reset_cq_ep(cq);
+	ehea_reset_cq_n1(cq);
+
+	return cq;
+
+create_cq_exit3:
+	hw_queue_dtor(&cq->hw_queue);
+
+create_cq_exit2:
+	ehea_h_destroy_cq(adapter->handle, cq, cq->fw_handle, &cq->epas);
+
+create_cq_exit1:
+	kfree(cq);
+
+create_cq_exit0:
+	return NULL;
+}
+
+int ehea_destroy_cq(struct ehea_cq *cq)
+{
+	u64 adapter_handle;
+	u64 hret;
+
+	adapter_handle = cq->adapter->handle;
+
+	if (!cq)
+		return 0;
+
+	/* deregister all previous registered pages */
+	hret = ehea_h_destroy_cq(adapter_handle, cq, cq->fw_handle, &cq->epas);
+	if (hret != H_SUCCESS) {
+		ehea_error("destroy CQ failed");
+		return -EINVAL;
+	}
+
+	hw_queue_dtor(&cq->hw_queue);
+	kfree(cq);
+
+	return 0;
+}
+
+struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
+			       const enum ehea_eq_type type,
+			       const u32 max_nr_of_eqes, const u8 eqe_gen)
+{
+	u64 hret;
+	int ret;
+	u32 i;
+	void *vpage = NULL;
+	u64 rpage = 0;
+	struct ehea_eq *eq;
+
+	eq = kzalloc(sizeof(*eq), GFP_KERNEL);
+	if (!eq) {
+		ehea_error("no mem for eq");
+		return NULL;
+	}
+
+	eq->adapter = adapter;
+	eq->attr.type = type;
+	eq->attr.max_nr_of_eqes = max_nr_of_eqes;
+	eq->attr.eqe_gen = eqe_gen;
+	spin_lock_init(&eq->spinlock);
+
+	hret = ehea_h_alloc_resource_eq(adapter->handle,
+					eq, &eq->attr, &eq->fw_handle);
+	if (hret != H_SUCCESS) {
+		ehea_error("alloc_resource_eq failed");
+		goto free_eq_mem;
+	}
+
+	ret = hw_queue_ctor(&eq->hw_queue, eq->attr.nr_pages, 
+			    EHEA_PAGESIZE, sizeof(struct ehea_eqe));
+	if (ret) {
+		ehea_error("can't allocate eq pages");
+		goto alloc_pages_failed;
+	}
+
+	for (i = 0; i < eq->attr.nr_pages; i++) {
+		vpage = hw_qpageit_get_inc(&eq->hw_queue);
+		if (!vpage) {
+			ehea_error("hw_qpageit_get_inc failed");
+			hret = H_RESOURCE;
+			goto register_page_failed;
+		}
+
+		rpage = virt_to_abs(vpage);
+
+		hret = ehea_h_register_rpage_eq(adapter->handle, eq->fw_handle,
+						0, EHEA_EQ_REGISTER_ORIG, rpage,
+						1);
+
+		if (i == (eq->attr.nr_pages - 1)) {
+			/* last page */
+			vpage = hw_qpageit_get_inc(&eq->hw_queue);
+			if ((hret != H_SUCCESS) || (vpage)) {
+				goto register_page_failed;
+			}
+		} else {
+			if ((hret != H_PAGE_REGISTERED) || (!vpage)) {
+				goto register_page_failed;
+			}
+		}
+	}
+
+	hw_qeit_reset(&eq->hw_queue);
+	return eq;
+
+register_page_failed:
+	hw_queue_dtor(&eq->hw_queue);
+
+alloc_pages_failed:
+	ehea_h_destroy_eq(adapter->handle, eq, eq->fw_handle, &eq->epas);
+free_eq_mem:
+	kfree(eq);
+	return NULL;
+}
+
+struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq)
+{
+	struct ehea_eqe *eqe = NULL;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&eq->spinlock, flags);
+	eqe = (struct ehea_eqe*)hw_eqit_eq_get_inc_valid(&eq->hw_queue);
+	spin_unlock_irqrestore(&eq->spinlock, flags);
+
+	return eqe;
+}
+
+int ehea_destroy_eq(struct ehea_eq *eq)
+{
+	u64 hret;
+	unsigned long flags = 0;
+
+	if (!eq)
+		return 0;
+
+	spin_lock_irqsave(&eq->spinlock, flags);
+
+	hret = ehea_h_destroy_eq(eq->adapter->handle, eq, eq->fw_handle,
+				 &eq->epas);
+	spin_unlock_irqrestore(&eq->spinlock, flags);
+
+	if (hret != H_SUCCESS) {
+		ehea_error("destroy_eq failed");
+		return -EINVAL;
+	}
+
+	hw_queue_dtor(&eq->hw_queue);
+	kfree(eq);
+
+	return 0;
+}
+
+/**
+ * allocates memory for a queue and registers pages in phyp
+ */
+int ehea_qp_alloc_register(struct ehea_qp *qp, struct hw_queue *hw_queue,
+			   int nr_pages, int wqe_size, int act_nr_sges,
+			   struct ehea_adapter *adapter, int h_call_q_selector)
+{
+	u64 hret;
+	u64 rpage = 0;
+	int ret;
+	int cnt = 0;
+	void *vpage = NULL;
+
+	ret = hw_queue_ctor(hw_queue, nr_pages, EHEA_PAGESIZE, wqe_size);
+	if (ret)
+		return ret;
+
+	for (cnt = 0; cnt < nr_pages; cnt++) {
+		vpage = hw_qpageit_get_inc(hw_queue);
+		if (!vpage) {
+			ehea_error("hw_qpageit_get_inc failed");
+			goto qp_alloc_register_exit0;
+		}
+		rpage = virt_to_abs(vpage);
+
+		hret = ehea_h_register_rpage_qp(adapter->handle, qp->fw_handle,
+						0, h_call_q_selector, rpage, 1,
+						qp->epas.kernel);
+		if (hret < H_SUCCESS) {
+			ehea_error("register_rpage_qp failed");
+			goto qp_alloc_register_exit0;
+		}
+	}
+	hw_qeit_reset(hw_queue);
+	return 0;
+
+qp_alloc_register_exit0:
+	hw_queue_dtor(hw_queue);
+	return -EINVAL;
+}
+
+static inline u32 map_wqe_size(u8 wqe_enc_size)
+{
+	return 128 << wqe_enc_size;
+}
+
+struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
+			       u32 pd, struct ehea_qp_init_attr *init_attr)
+{
+	int ret;
+	u64 hret;
+	struct ehea_qp *qp;
+	u32 wqe_size_in_bytes_sq = 0;
+	u32 wqe_size_in_bytes_rq1 = 0;
+	u32 wqe_size_in_bytes_rq2 = 0;
+	u32 wqe_size_in_bytes_rq3 = 0;
+
+
+	qp = kzalloc(sizeof(*qp), GFP_KERNEL);
+	if (!qp) {
+		ehea_error("no mem for qp");
+		return NULL;
+	}
+
+	qp->adapter = adapter;
+
+	hret = ehea_h_alloc_resource_qp(adapter->handle, qp, init_attr, pd,
+					&qp->fw_handle, &qp->epas);
+	if (hret != H_SUCCESS) {
+		ehea_error("ehea_h_alloc_resource_qp failed");
+		goto create_qp_exit1;
+	}
+
+	wqe_size_in_bytes_sq = map_wqe_size(init_attr->act_wqe_size_enc_sq);
+	wqe_size_in_bytes_rq1 = map_wqe_size(init_attr->act_wqe_size_enc_rq1);
+	wqe_size_in_bytes_rq2 = map_wqe_size(init_attr->act_wqe_size_enc_rq2);
+	wqe_size_in_bytes_rq3 = map_wqe_size(init_attr->act_wqe_size_enc_rq3);
+
+	ret = ehea_qp_alloc_register(qp, &qp->hw_squeue, init_attr->nr_sq_pages,
+				     wqe_size_in_bytes_sq,
+				     init_attr->act_wqe_size_enc_sq, adapter,
+				     0);
+	if (ret) {
+		ehea_error("can't register for sq ret=%x", ret);
+		goto create_qp_exit2;
+	}
+
+	ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue1,
+				     init_attr->nr_rq1_pages,
+				     wqe_size_in_bytes_rq1,
+				     init_attr->act_wqe_size_enc_rq1,
+				     adapter, 1);
+	if (ret) {
+		ehea_error("can't register for rq1 ret=%x", ret);
+		goto create_qp_exit3;
+	}
+
+	if (init_attr->rq_count > 1) {
+		ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue2,
+					     init_attr->nr_rq2_pages,
+					     wqe_size_in_bytes_rq2,
+					     init_attr->act_wqe_size_enc_rq2,
+					     adapter, 2);
+		if (ret) {
+			ehea_error("can't register for rq2 ret=%x", ret);
+			goto create_qp_exit4;
+		}
+	}
+
+	if (init_attr->rq_count > 2) {
+		ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue3,
+					     init_attr->nr_rq3_pages,
+					     wqe_size_in_bytes_rq3,
+					     init_attr->act_wqe_size_enc_rq3,
+					     adapter, 3);
+		if (ret) {
+			ehea_error("can't register for rq3 ret=%x", ret);
+			goto create_qp_exit5;
+		}
+	}
+
+	qp->init_attr = *init_attr;
+
+	return qp;
+
+create_qp_exit5:
+	hw_queue_dtor(&qp->hw_rqueue2);
+
+create_qp_exit4:
+	hw_queue_dtor(&qp->hw_rqueue1);
+
+create_qp_exit3:
+	hw_queue_dtor(&qp->hw_squeue);
+
+create_qp_exit2:
+	hret = ehea_h_destroy_qp(adapter->handle, qp, qp->fw_handle, &qp->epas);
+
+create_qp_exit1:
+	kfree(qp);
+	return NULL;
+}
+
+int ehea_destroy_qp(struct ehea_qp *qp)
+{
+	u64 hret;
+	struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
+
+	if (!qp)
+		return 0;
+
+	hret = ehea_h_destroy_qp(qp->adapter->handle, qp, qp->fw_handle,
+				 &qp->epas);
+	if (hret != H_SUCCESS) {
+		ehea_error("destroy_qp failed");
+		return -EINVAL;
+	}
+
+	hw_queue_dtor(&qp->hw_squeue);
+	hw_queue_dtor(&qp->hw_rqueue1);
+
+   	if (qp_attr->rq_count > 1)
+		hw_queue_dtor(&qp->hw_rqueue2);
+   	if (qp_attr->rq_count > 2)
+		hw_queue_dtor(&qp->hw_rqueue3);
+	kfree(qp);
+
+	return 0;
+}
+
+int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
+{
+	int i = 0;
+	int k = 0;
+	u64 hret;
+	u64 start = KERNELBASE;
+	u64 end = (u64) high_memory;
+	u64 nr_pages = (end - start) / PAGE_SIZE;
+	u32 acc_ctrl = EHEA_MR_ACC_CTRL;
+	u64 pt_abs = 0;
+	u64 *pt;
+
+	pt =  kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!pt) {
+		ehea_error("no mem");
+		return -ENOMEM;
+	}
+	pt_abs = virt_to_abs(pt);
+
+	hret = ehea_h_alloc_resource_mr(adapter->handle, start, end - start,
+					acc_ctrl, adapter->pd,
+					&adapter->mr.handle, &adapter->mr.lkey);
+	if (hret != H_SUCCESS) {
+		ehea_error("alloc_mr failed");
+		return -EINVAL;
+	}
+
+	adapter->mr.vaddr = KERNELBASE;
+
+	while (nr_pages > 0) {
+		if (nr_pages > 1) {
+			u64 num_pages = min(nr_pages, (u64)512);
+			for (i = 0; i < num_pages; i++)
+				pt[i] = virt_to_abs((void*)(((u64)start)
+							     + ((k++) *
+								PAGE_SIZE)));
+
+			hret = ehea_h_register_rpage_mr(adapter->handle,
+							adapter->mr.handle, 0,
+							0, (u64)pt_abs,
+							num_pages);
+			nr_pages -= num_pages;
+		} else {
+			u64 abs_adr = virt_to_abs((void *)(((u64)start)
+							   + (k * PAGE_SIZE)));
+			hret = ehea_h_register_rpage_mr(adapter->handle,
+							adapter->mr.handle, 0,
+							0, abs_adr,1);
+			nr_pages--;
+		}
+
+		if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) {
+			ehea_h_free_resource_mr(adapter->handle,
+						adapter->mr.handle);
+			ehea_error("free_resource_mr failed");
+			return -EINVAL;
+		}
+	}
+
+	if (hret != H_SUCCESS) {
+		ehea_h_free_resource_mr(adapter->handle, adapter->mr.handle);
+		ehea_error("free_resource_mr failed for last page");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int ehea_reg_mr_pages(struct ehea_adapter *adapter,
+		      struct ehea_mr *mr,
+		      u64 start, u64 *pt, int nr_pages)
+{
+	u64 hret;
+	u32 acc_ctrl = EHEA_MR_ACC_CTRL;
+
+	u64 pt_abs = virt_to_abs(pt);
+	u64 first_page = pt[0];
+
+	hret = ehea_h_alloc_resource_mr(adapter->handle, start,
+					PAGE_SIZE * nr_pages, acc_ctrl,
+					adapter->pd, &mr->handle, &mr->lkey);
+	if (hret != H_SUCCESS) {
+		ehea_error("alloc_resource_mr failed");
+		return -EINVAL;
+	}
+
+	if (nr_pages > 1)
+		hret = ehea_h_register_rpage_mr(adapter->handle, mr->handle,
+						0, 0, (u64)pt_abs, nr_pages);
+	else
+		hret = ehea_h_register_rpage_mr(adapter->handle, mr->handle,
+						0, 0, first_page, 1);
+
+	if (hret != H_SUCCESS) {
+		ehea_h_free_resource_mr(adapter->handle, mr->handle);
+		ehea_error("free_resource_mr failed for last page");
+		return -EINVAL;
+	}
+	mr->vaddr = start;
+	return 0;
+}
+
+int ehea_dereg_mr_adapter(struct ehea_adapter *adapter)
+{
+	u64 hret;
+
+	hret = ehea_h_free_resource_mr(adapter->handle, adapter->mr.handle);
+	if (hret != H_SUCCESS) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
--- linux-2.6.18-rc4-git1-orig/drivers/net/ehea/ehea_qmr.h	1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_qmr.h	2006-08-22 06:05:29.003371879 -0700
@@ -0,0 +1,367 @@
+/*
+ *  linux/drivers/net/ehea/ehea_qmr.h
+ *
+ *  eHEA ethernet device driver for IBM eServer System p
+ *
+ *  (C) Copyright IBM Corp. 2006
+ *
+ *  Authors:
+ *       Christoph Raisch <raisch@de.ibm.com>
+ *       Jan-Bernd Themann <themann@de.ibm.com>
+ *       Thomas Klein <tklein@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 __EHEA_QMR_H__
+#define __EHEA_QMR_H__
+
+#include "ehea.h"
+#include "ehea_hw.h"
+
+/*
+ * page size of ehea hardware queues
+ */
+
+#define EHEA_PAGESHIFT  12
+#define EHEA_PAGESIZE   4096UL
+
+/* Some abbreviations used here:
+ *
+ * WQE  - Work Queue Entry
+ * SWQE - Send Work Queue Entry
+ * RWQE - Receive Work Queue Entry
+ * CQE  - Completion Queue Entry
+ * EQE  - Event Queue Entry
+ * MR   - Memory Region
+ */
+
+/* Use of WR_ID field for EHEA */
+#define EHEA_WR_ID_COUNT   EHEA_BMASK_IBM(0, 19)
+#define EHEA_WR_ID_TYPE    EHEA_BMASK_IBM(20, 23)
+#define EHEA_SWQE2_TYPE    0x1
+#define EHEA_SWQE3_TYPE    0x2
+#define EHEA_RWQE2_TYPE    0x3
+#define EHEA_RWQE3_TYPE    0x4
+#define EHEA_WR_ID_INDEX   EHEA_BMASK_IBM(24, 47)
+#define EHEA_WR_ID_REFILL  EHEA_BMASK_IBM(48, 63)
+
+struct ehea_vsgentry {
+	u64 vaddr;
+	u32 l_key;
+	u32 len;
+};
+
+/* maximum number of sg entries allowed in a WQE */
+#define EHEA_MAX_WQE_SG_ENTRIES  	252
+#define SWQE2_MAX_IMM            	(0xD0 - 0x30)
+#define SWQE3_MAX_IMM            	224
+
+/* tx control flags for swqe */
+#define EHEA_SWQE_CRC                   0x8000
+#define EHEA_SWQE_IP_CHECKSUM           0x4000
+#define EHEA_SWQE_TCP_CHECKSUM          0x2000
+#define EHEA_SWQE_TSO                   0x1000
+#define EHEA_SWQE_SIGNALLED_COMPLETION  0x0800
+#define EHEA_SWQE_VLAN_INSERT           0x0400
+#define EHEA_SWQE_IMM_DATA_PRESENT      0x0200
+#define EHEA_SWQE_DESCRIPTORS_PRESENT   0x0100
+#define EHEA_SWQE_WRAP_CTL_REC          0x0080
+#define EHEA_SWQE_WRAP_CTL_FORCE        0x0040
+#define EHEA_SWQE_BIND                  0x0020
+#define EHEA_SWQE_PURGE                 0x0010
+
+/* sizeof(struct ehea_swqe) less the union */
+#define SWQE_HEADER_SIZE		32
+
+struct ehea_swqe {
+	u64 wr_id;
+	u16 tx_control;
+	u16 vlan_tag;
+	u8 reserved1;
+	u8 ip_start;
+	u8 ip_end;
+	u8 immediate_data_length;
+	u8 tcp_offset;
+	u8 reserved2;
+	u16 tcp_end;
+	u8 wrap_tag;
+	u8 descriptors;		/* number of valid descriptors in WQE */
+	u16 reserved3;
+	u16 reserved4;
+	u16 mss;
+	u32 reserved5;
+	union {
+		/*  Send WQE Format 1 */
+		struct {
+			struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES];
+		} no_immediate_data;
+
+		/*  Send WQE Format 2 */
+		struct {
+			struct ehea_vsgentry sg_entry;
+			/* 0x30 */
+			u8 immediate_data[SWQE2_MAX_IMM];
+			/* 0xd0 */
+			struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES-1];
+		} immdata_desc __attribute__ ((packed));
+
+		/*  Send WQE Format 3 */
+		struct {
+			u8 immediate_data[SWQE3_MAX_IMM];
+		} immdata_nodesc;
+	} u;
+};
+
+struct ehea_rwqe {
+	u64 wr_id;		/* work request ID */
+	u8 reserved1[5];
+	u8 data_segments;
+	u16 reserved2;
+	u64 reserved3;
+	u64 reserved4;
+	struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES];
+};
+
+#define EHEA_CQE_VLAN_TAG_XTRACT   0x0400
+
+#define EHEA_CQE_TYPE_RQ           0x60
+#define EHEA_CQE_STAT_ERR_MASK     0x721F
+#define EHEA_CQE_STAT_FAT_ERR_MASK 0x1F
+#define EHEA_CQE_STAT_ERR_TCP      0x4000
+
+struct ehea_cqe {
+	u64 wr_id;		/* work request ID from WQE */
+	u8 type;
+	u8 valid;
+	u16 status;
+	u16 reserved1;
+	u16 num_bytes_transfered;
+	u16 vlan_tag;
+	u16 inet_checksum_value;
+	u8 reserved2;
+	u8 header_length;
+	u16 reserved3;
+	u16 page_offset;
+	u16 wqe_count;
+	u32 qp_token;
+	u32 timestamp;
+	u32 reserved4;
+	u64 reserved5[3];
+};
+
+#define EHEA_EQE_VALID           EHEA_BMASK_IBM(0, 0)
+#define EHEA_EQE_IS_CQE          EHEA_BMASK_IBM(1, 1)
+#define EHEA_EQE_IDENTIFIER      EHEA_BMASK_IBM(2, 7)
+#define EHEA_EQE_QP_CQ_NUMBER    EHEA_BMASK_IBM(8, 31)
+#define EHEA_EQE_QP_TOKEN        EHEA_BMASK_IBM(32, 63)
+#define EHEA_EQE_CQ_TOKEN        EHEA_BMASK_IBM(32, 63)
+#define EHEA_EQE_KEY             EHEA_BMASK_IBM(32, 63)
+#define EHEA_EQE_PORT_NUMBER     EHEA_BMASK_IBM(56, 63)
+#define EHEA_EQE_EQ_NUMBER       EHEA_BMASK_IBM(48, 63)
+#define EHEA_EQE_SM_ID           EHEA_BMASK_IBM(48, 63)
+#define EHEA_EQE_SM_MECH_NUMBER  EHEA_BMASK_IBM(48, 55)
+#define EHEA_EQE_SM_PORT_NUMBER  EHEA_BMASK_IBM(56, 63)
+
+struct ehea_eqe {
+	u64 entry;
+};
+
+static inline void *hw_qeit_calc(struct hw_queue *queue, u64 q_offset)
+{
+	struct ehea_page *current_page;
+
+	if (q_offset >= queue->queue_length)
+		q_offset -= queue->queue_length;
+	current_page = (queue->queue_pages)[q_offset >> EHEA_PAGESHIFT];
+	return &current_page->entries[q_offset & (EHEA_PAGESIZE - 1)];
+}
+
+static inline void *hw_qeit_get(struct hw_queue *queue)
+{
+	return hw_qeit_calc(queue, queue->current_q_offset);
+}
+
+static inline void hw_qeit_inc(struct hw_queue *queue)
+{
+	queue->current_q_offset += queue->qe_size;
+	if (queue->current_q_offset >= queue->queue_length) {
+		queue->current_q_offset = 0;
+		/* toggle the valid flag */
+		queue->toggle_state = (~queue->toggle_state) & 1;
+	}
+}
+
+static inline void *hw_qeit_get_inc(struct hw_queue *queue)
+{
+	void *retvalue = hw_qeit_get(queue);
+	hw_qeit_inc(queue);
+	return retvalue;
+}
+
+static inline void *hw_qeit_get_inc_valid(struct hw_queue *queue)
+{
+	struct ehea_cqe *retvalue = hw_qeit_get(queue);
+	u8 valid = retvalue->valid;
+	void *pref;
+
+	if ((valid >> 7) == (queue->toggle_state & 1)) {
+		/* this is a good one */
+		hw_qeit_inc(queue);
+		pref = hw_qeit_calc(queue, queue->current_q_offset);
+		prefetch(pref);
+		prefetch(pref + 128);
+	} else
+		retvalue = NULL;
+	return retvalue;
+}
+
+static inline void *hw_qeit_get_valid(struct hw_queue *queue)
+{
+	struct ehea_cqe *retvalue = hw_qeit_get(queue);
+	void *pref;
+	u8 valid;
+
+	pref = hw_qeit_calc(queue, queue->current_q_offset);
+	prefetch(pref);
+	prefetch(pref + 128);
+	prefetch(pref + 256);
+	valid = retvalue->valid;
+	if (!((valid >> 7) == (queue->toggle_state & 1)))
+		retvalue = NULL;
+	return retvalue;
+}
+
+static inline void *hw_qeit_reset(struct hw_queue *queue)
+{
+	queue->current_q_offset = 0;
+	return hw_qeit_get(queue);
+}
+
+static inline void *hw_qeit_eq_get_inc(struct hw_queue *queue)
+{
+	u64 last_entry_in_q = queue->queue_length - queue->qe_size;
+	void *retvalue;
+
+
+	retvalue = hw_qeit_get(queue);
+	queue->current_q_offset += queue->qe_size;
+	if (queue->current_q_offset > last_entry_in_q) {
+		queue->current_q_offset = 0;
+		queue->toggle_state = (~queue->toggle_state) & 1;
+	}
+	return retvalue;
+}
+
+static inline void *hw_eqit_eq_get_inc_valid(struct hw_queue *queue)
+{
+	void *retvalue = hw_qeit_get(queue);
+	u32 qe = *(u8 *) retvalue;
+	if ((qe >> 7) == (queue->toggle_state & 1))
+		hw_qeit_eq_get_inc(queue);
+	else
+		retvalue = NULL;
+	return retvalue;
+}
+
+static inline struct ehea_rwqe *ehea_get_next_rwqe(struct ehea_qp *qp,
+						   int rq_nr)
+{
+	struct hw_queue *queue = NULL;
+
+	if (rq_nr == 1)
+		queue = &qp->hw_rqueue1;
+	else if (rq_nr == 2)
+		queue = &qp->hw_rqueue2;
+	else
+		queue = &qp->hw_rqueue3;
+
+	return (struct ehea_rwqe *)hw_qeit_get_inc(queue);
+}
+
+static inline struct ehea_swqe *ehea_get_swqe(struct ehea_qp *my_qp,
+					      int *wqe_index)
+{
+	struct hw_queue *queue = &my_qp->hw_squeue;
+	struct ehea_swqe *wqe_p = NULL;
+	*wqe_index = (queue->current_q_offset) >> (7 + EHEA_SG_SQ);
+	wqe_p = (struct ehea_swqe *)hw_qeit_get_inc(&my_qp->hw_squeue);
+	return wqe_p;
+}
+
+static inline void ehea_post_swqe(struct ehea_qp *my_qp, struct ehea_swqe *swqe)
+{
+	iosync();
+	ehea_update_sqa(my_qp, 1);
+}
+
+static inline struct ehea_cqe *ehea_poll_rq1(struct ehea_qp *qp, int *wqe_index)
+{
+	struct hw_queue *queue = &qp->hw_rqueue1;
+	struct ehea_cqe *cqe = NULL;
+
+	*wqe_index = (queue->current_q_offset) >> (7 + EHEA_SG_RQ1);
+	cqe = (struct ehea_cqe *)hw_qeit_get_valid(queue);
+	return cqe;
+}
+
+static inline void ehea_inc_rq1(struct ehea_qp *qp)
+{
+	struct hw_queue *queue = &qp->hw_rqueue1;
+	hw_qeit_inc(queue);
+}
+
+static inline struct ehea_cqe *ehea_poll_cq(struct ehea_cq *my_cq)
+{
+	struct ehea_cqe *wqe_p = NULL;
+	wqe_p = (struct ehea_cqe *)hw_qeit_get_inc_valid(&my_cq->hw_queue);
+	return wqe_p;
+};
+
+#define EHEA_CQ_REGISTER_ORIG 0
+#define EHEA_EQ_REGISTER_ORIG 0
+
+enum ehea_eq_type {
+	EHEA_EQ = 0,		/* event queue              */
+	EHEA_NEQ		/* notification event queue */
+};
+
+struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
+			       enum ehea_eq_type type,
+			       const u32 length, const u8 eqe_gen);
+
+int ehea_destroy_eq(struct ehea_eq *eq);
+
+struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq);
+
+struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, int cqe,
+			       u64 eq_handle, u32 cq_token);
+
+int ehea_destroy_cq(struct ehea_cq *cq);
+
+struct ehea_qp *ehea_create_qp(struct ehea_adapter * adapter, u32 pd,
+			       struct ehea_qp_init_attr *init_attr);
+
+int ehea_destroy_qp(struct ehea_qp *qp);
+
+int ehea_reg_mr_adapter(struct ehea_adapter *adapter);
+int ehea_dereg_mr_adapter(struct ehea_adapter *adapter);
+
+int ehea_reg_mr_pages(struct ehea_adapter *adapter,
+		      struct ehea_mr *mr,
+		      u64 start, u64 *pt, int nr_pages);
+
+#endif	/* __EHEA_QMR_H__ */

^ permalink raw reply

* [2.6.19 PATCH 4/7] ehea: ethtool interface
From: Jan-Bernd Themann @ 2006-08-22 12:54 UTC (permalink / raw)
  To: netdev
  Cc: Thomas Klein, Jan-Bernd Themann, linux-kernel, linux-ppc,
	Christoph Raisch, Marcus Eder

Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com> 


 drivers/net/ehea/ehea_ethtool.c |  244 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 244 insertions(+)



--- linux-2.6.18-rc4-git1-orig/drivers/net/ehea/ehea_ethtool.c	1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_ethtool.c	2006-08-22 06:05:29.197373636 -0700
@@ -0,0 +1,244 @@
+/*
+ *  linux/drivers/net/ehea/ehea_ethtool.c
+ *
+ *  eHEA ethernet device driver for IBM eServer System p
+ *
+ *  (C) Copyright IBM Corp. 2006
+ *
+ *  Authors:
+ *       Christoph Raisch <raisch@de.ibm.com>
+ *       Jan-Bernd Themann <themann@de.ibm.com>
+ *       Thomas Klein <tklein@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 "ehea.h"
+#include "ehea_phyp.h"
+
+
+static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	u64 hret;
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_adapter *adapter = port->adapter;
+	struct hcp_ehea_port_cb4 *cb4;
+
+	cb4 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb4) {
+		ehea_error("no mem for cb4");
+		return -ENOMEM;
+	}
+
+	hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
+				      H_PORT_CB4, H_PORT_CB4_ALL, cb4);
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_port failed");
+		kfree(cb4);
+		return -EIO;
+	}
+
+	if (netif_msg_hw(port))
+		ehea_dump(cb4, sizeof(*cb4), "netdev_get_settings");
+
+	if (netif_carrier_ok(dev)) {
+		switch(cb4->port_speed){
+		case H_PORT_SPEED_10M_H:
+			cmd->speed = SPEED_10;
+			cmd->duplex = DUPLEX_HALF;
+			break;
+		case H_PORT_SPEED_10M_F:
+			cmd->speed = SPEED_10;
+			cmd->duplex = DUPLEX_FULL;
+			break;
+		case H_PORT_SPEED_100M_H:
+			cmd->speed = SPEED_100;
+			cmd->duplex = DUPLEX_HALF;
+			break;
+		case H_PORT_SPEED_100M_F:
+			cmd->speed = SPEED_100;
+			cmd->duplex = DUPLEX_FULL;
+			break;
+		case H_PORT_SPEED_1G_F:
+			cmd->speed = SPEED_1000;
+			cmd->duplex = DUPLEX_FULL;
+			break;
+		case H_PORT_SPEED_10G_F:
+			cmd->speed = SPEED_10000;
+			cmd->duplex = DUPLEX_FULL;
+			break;
+		}
+	} else {
+		cmd->speed = -1;
+		cmd->duplex = -1;
+	}
+
+	cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_1000baseT_Full
+		       | SUPPORTED_100baseT_Full |  SUPPORTED_100baseT_Half
+		       | SUPPORTED_10baseT_Full | SUPPORTED_10baseT_Half
+		       | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
+
+	cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_Autoneg
+			 | ADVERTISED_FIBRE);
+
+	cmd->port = PORT_FIBRE;
+	cmd->autoneg = AUTONEG_ENABLE;
+
+	kfree(cb4);
+	return 0;
+}
+
+static void netdev_get_drvinfo(struct net_device *dev,
+			       struct ethtool_drvinfo *info)
+{
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
+}
+
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+	struct ehea_port *port = netdev_priv(dev);
+	return port->msg_enable;
+}
+
+static void netdev_set_msglevel(struct net_device *dev, u32 value)
+{
+	struct ehea_port *port = netdev_priv(dev);
+	port->msg_enable = value;
+}
+
+static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
+	{"poll_max_processed"},
+	{"queue_stopped"},
+	{"min_swqe_avail"},
+	{"poll_receive_err"},
+	{"pkt_send"},
+	{"pkt_xmit"},
+	{"send_tasklet"},
+	{"ehea_poll"},
+	{"nwqe"},
+	{"swqe_available_0"},
+	{"sig_comp_iv"},
+	{"rxo"},
+	{"rx64"},
+	{"rx65"},
+	{"rx128"},
+	{"rx256"},
+	{"rx512"},
+	{"rx1024"},
+	{"txo"},
+	{"tx64"},
+	{"tx65"},
+	{"tx128"},
+	{"tx256"},
+	{"tx512"},
+	{"tx1024"},
+};
+
+static void netdev_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	if (stringset == ETH_SS_STATS) {
+		memcpy(data, &ehea_ethtool_stats_keys,
+		       sizeof(ehea_ethtool_stats_keys));
+	}
+}
+
+static int netdev_get_stats_count(struct net_device *dev)
+{
+	return ARRAY_SIZE(ehea_ethtool_stats_keys);
+}
+
+static void netdev_get_ethtool_stats(struct net_device *dev,
+				     struct ethtool_stats *stats, u64 *data)
+{
+	u64 hret;
+	int i;
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_adapter *adapter = port->adapter;
+	struct ehea_port_res *pr = &port->port_res[0];
+	struct port_state *p_state = &pr->p_state;
+	struct hcp_ehea_port_cb6 *cb6;
+
+	for (i = 0; i < netdev_get_stats_count(dev); i++) 
+		data[i] = 0;
+
+	i = 0;
+
+	data[i++] = p_state->poll_max_processed;
+	data[i++] = p_state->queue_stopped;
+	data[i++] = p_state->min_swqe_avail;
+	data[i++] = p_state->poll_receive_errors;
+	data[i++] = p_state->pkt_send;
+	data[i++] = p_state->pkt_xmit;
+	data[i++] = p_state->send_tasklet;
+	data[i++] = p_state->ehea_poll;
+	data[i++] = p_state->nwqe;
+	data[i++] = atomic_read(&port->port_res[0].swqe_avail);
+	data[i++] = port->sig_comp_iv;
+
+	cb6 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb6) {
+		ehea_error("no mem for cb6");
+		return;
+	}
+
+	hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
+				      H_PORT_CB6, H_PORT_CB6_ALL, cb6);
+	if (netif_msg_hw(port))
+		ehea_dump(cb6, sizeof(*cb6), "netdev_get_ethtool_stats");
+
+	if (hret == H_SUCCESS) {
+		data[i++] = cb6->rxo;
+		data[i++] = cb6->rx64;
+		data[i++] = cb6->rx65;
+		data[i++] = cb6->rx128;
+		data[i++] = cb6->rx256;
+		data[i++] = cb6->rx512;
+		data[i++] = cb6->rx1024;
+		data[i++] = cb6->txo;
+		data[i++] = cb6->tx64;
+		data[i++] = cb6->tx65;
+		data[i++] = cb6->tx128;
+		data[i++] = cb6->tx256;
+		data[i++] = cb6->tx512;
+		data[i++] = cb6->tx1024;
+	} else
+		ehea_error("query_ehea_port failed");
+
+	kfree(cb6);
+}
+
+struct ethtool_ops ehea_ethtool_ops = {
+	.get_settings = netdev_get_settings,
+	.get_drvinfo = netdev_get_drvinfo,
+	.get_msglevel = netdev_get_msglevel,
+	.set_msglevel = netdev_set_msglevel,
+	.get_link = ethtool_op_get_link,
+	.get_tx_csum = ethtool_op_get_tx_csum,
+	.set_tx_csum = ethtool_op_set_tx_csum,
+	.get_sg = ethtool_op_get_sg,
+	.set_sg = ethtool_op_set_sg,
+	.get_tso = ethtool_op_get_tso,
+	.set_tso = ethtool_op_set_tso,
+	.get_strings = netdev_get_strings,
+	.get_stats_count = netdev_get_stats_count,
+	.get_ethtool_stats = netdev_get_ethtool_stats,
+};
+
+void ehea_set_ethtool_ops(struct net_device *netdev)
+{
+	SET_ETHTOOL_OPS(netdev, &ehea_ethtool_ops);
+}

^ permalink raw reply

* [2.6.19 PATCH 5/7] ehea: main header files
From: Jan-Bernd Themann @ 2006-08-22 12:55 UTC (permalink / raw)
  To: netdev
  Cc: Thomas Klein, Jan-Bernd Themann, linux-kernel, linux-ppc,
	Christoph Raisch, Marcus Eder

Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com> 


 drivers/net/ehea/ehea.h    |  437 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ehea/ehea_hw.h |  290 +++++++++++++++++++++++++++++
 2 files changed, 727 insertions(+)



--- linux-2.6.18-rc4-git1-orig/drivers/net/ehea/ehea.h	1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea.h	2006-08-22 06:05:29.284374423 -0700
@@ -0,0 +1,437 @@
+/*
+ *  linux/drivers/net/ehea/ehea.h
+ *
+ *  eHEA ethernet device driver for IBM eServer System p
+ *
+ *  (C) Copyright IBM Corp. 2006
+ *
+ *  Authors:
+ *       Christoph Raisch <raisch@de.ibm.com>
+ *       Jan-Bernd Themann <themann@de.ibm.com>
+ *       Thomas Klein <tklein@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 __EHEA_H__
+#define __EHEA_H__
+
+#include <linux/module.h>
+#include <linux/ethtool.h>
+#include <linux/vmalloc.h>
+#include <linux/if_vlan.h>
+
+#include <asm/ibmebus.h>
+#include <asm/abs_addr.h>
+#include <asm/io.h>
+
+#define DRV_NAME	"ehea"
+#define DRV_VERSION	"EHEA_0019"
+
+#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER)
+
+#define EHEA_MAX_ENTRIES_RQ1 32767
+#define EHEA_MAX_ENTRIES_RQ2 16383
+#define EHEA_MAX_ENTRIES_RQ3 16383
+#define EHEA_MAX_ENTRIES_SQ  32767
+#define EHEA_MIN_ENTRIES_QP  127
+
+#define EHEA_NUM_TX_QP 1
+
+#ifdef EHEA_SMALL_QUEUES
+#define EHEA_MAX_CQE_COUNT      1023
+#define EHEA_DEF_ENTRIES_SQ     1023
+#define EHEA_DEF_ENTRIES_RQ1    4095
+#define EHEA_DEF_ENTRIES_RQ2    1023
+#define EHEA_DEF_ENTRIES_RQ3    1023
+#define EHEA_SWQE_REFILL_TH      100
+#else
+#define EHEA_MAX_CQE_COUNT     32000
+#define EHEA_DEF_ENTRIES_SQ    16000
+#define EHEA_DEF_ENTRIES_RQ1   32080
+#define EHEA_DEF_ENTRIES_RQ2    4020
+#define EHEA_DEF_ENTRIES_RQ3    4020
+#define EHEA_SWQE_REFILL_TH     1000
+#endif
+
+#define EHEA_MAX_ENTRIES_EQ 20
+
+#define EHEA_SG_SQ  2
+#define EHEA_SG_RQ1 1
+#define EHEA_SG_RQ2 0
+#define EHEA_SG_RQ3 0
+
+#define EHEA_MAX_PACKET_SIZE    9022	/* for jumbo frames */
+#define EHEA_RQ2_PKT_SIZE       1522
+#define EHEA_LL_PKT_SIZE         256	/* low latency */
+
+#define EHEA_POLL_MAX_RWQE      1000
+
+/* Send completion signaling */
+#define EHEA_SIG_IV_LONG           4
+
+/* Protection Domain Identifier */
+#define EHEA_PD_ID        0xaabcdeff
+
+#define EHEA_RQ2_THRESHOLD 	   1
+#define EHEA_RQ3_THRESHOLD 	   9	/* use RQ3 threshold of 1522 bytes */
+
+#define EHEA_SPEED_10G         10000
+#define EHEA_SPEED_1G           1000
+#define EHEA_SPEED_100M          100
+#define EHEA_SPEED_10M            10
+
+/* Broadcast/Multicast registration types */
+#define EHEA_BCMC_SCOPE_ALL	0x08
+#define EHEA_BCMC_SCOPE_SINGLE	0x00
+#define EHEA_BCMC_MULTICAST	0x04
+#define EHEA_BCMC_BROADCAST	0x00
+#define EHEA_BCMC_UNTAGGED	0x02
+#define EHEA_BCMC_TAGGED	0x00
+#define EHEA_BCMC_VLANID_ALL	0x01
+#define EHEA_BCMC_VLANID_SINGLE	0x00
+
+/* Use this define to kmallocate pHYP control blocks */
+#define H_CB_ALIGNMENT		4096
+
+#define EHEA_CACHE_LINE          128
+
+/* Memory Regions */
+#define EHEA_MR_MAX_TX_PAGES   20
+#define EHEA_MR_TX_DATA_PN      3
+#define EHEA_MR_ACC_CTRL       0x00800000
+#define EHEA_RWQES_PER_MR_RQ2  10
+#define EHEA_RWQES_PER_MR_RQ3  10
+
+#define EHEA_WATCH_DOG_TIMEOUT 10*HZ
+
+
+void ehea_set_ethtool_ops(struct net_device *netdev);
+
+/* utility functions */
+
+#define ehea_info(fmt, args...) \
+	printk(KERN_INFO DRV_NAME ": " fmt "\n", ## args)
+
+#define ehea_error(fmt, args...) \
+	printk(KERN_ERR DRV_NAME ": Error in %s: " fmt "\n", __func__, ## args)
+
+#ifdef DEBUG
+#define ehea_debug(fmt, args...) \
+	printk(KERN_DEBUG DRV_NAME ": " fmt, ## args)
+#else
+#define ehea_debug(fmt, args...) do {} while (0)
+#endif
+
+void ehea_dump(void *adr, int len, char *msg);
+
+#define EHEA_BMASK(pos, length) (((pos) << 16) + (length))
+
+#define EHEA_BMASK_IBM(from, to) (((63 - to) << 16) + ((to) - (from) + 1))
+
+#define EHEA_BMASK_SHIFTPOS(mask) (((mask) >> 16) & 0xffff)
+
+#define EHEA_BMASK_MASK(mask) \
+	(0xffffffffffffffffULL >> ((64 - (mask)) & 0xffff))
+
+#define EHEA_BMASK_SET(mask, value) \
+        ((EHEA_BMASK_MASK(mask) & ((u64)(value))) << EHEA_BMASK_SHIFTPOS(mask))
+
+#define EHEA_BMASK_GET(mask, value) \
+        (EHEA_BMASK_MASK(mask) & (((u64)(value)) >> EHEA_BMASK_SHIFTPOS(mask)))
+
+/*
+ * Generic ehea page
+ */
+struct ehea_page {
+	u8 entries[PAGE_SIZE];
+};
+
+/*
+ * Generic queue in linux kernel virtual memory
+ */
+struct hw_queue {
+	u64 current_q_offset;		/* current queue entry */
+	struct ehea_page **queue_pages;	/* array of pages belonging to queue */
+	u32 qe_size;			/* queue entry size */
+	u32 queue_length;      		/* queue length allocated in bytes */
+	u32 pagesize;
+	u32 toggle_state;		/* toggle flag - per page */
+	u32 reserved;			/* 64 bit alignment */
+};
+
+/*
+ * For pSeries this is a 64bit memory address where
+ * I/O memory is mapped into CPU address space
+ */
+struct h_epa {
+	u64 fw_handle;
+};
+
+struct h_epas {
+	struct h_epa kernel;	/* kernel space accessible resource,
+				   set to 0 if unused */
+	struct h_epa user;	/* user space accessible resource
+				   set to 0 if unused */
+	u32 pid;		/* PID of userspace epa checking */
+};
+
+struct ehea_qp;
+struct ehea_cq;
+struct ehea_eq;
+struct ehea_port;
+struct ehea_av;
+
+/*
+ * Queue attributes passed to ehea_create_qp()
+ */
+struct ehea_qp_init_attr {
+        /* input parameter */
+	u32 qp_token;           /* queue token */
+	u8 low_lat_rq1;
+	u8 signalingtype;       /* cqe generation flag */
+	u8 rq_count;            /* num of receive queues */
+	u8 eqe_gen;             /* eqe generation flag */
+	u16 max_nr_send_wqes;   /* max number of send wqes */
+	u16 max_nr_rwqes_rq1;   /* max number of receive wqes */
+	u16 max_nr_rwqes_rq2;
+	u16 max_nr_rwqes_rq3;
+	u8 wqe_size_enc_sq;
+	u8 wqe_size_enc_rq1;
+	u8 wqe_size_enc_rq2;
+	u8 wqe_size_enc_rq3;
+	u8 swqe_imm_data_len;   /* immediate data length for swqes */
+	u16 port_nr;
+	u16 rq2_threshold;
+	u16 rq3_threshold;
+	u64 send_cq_handle;
+	u64 recv_cq_handle;
+	u64 aff_eq_handle;
+
+        /* output parameter */
+	u32 qp_nr;
+	u16 act_nr_send_wqes;
+	u16 act_nr_rwqes_rq1;
+	u16 act_nr_rwqes_rq2;
+	u16 act_nr_rwqes_rq3;
+	u8 act_wqe_size_enc_sq;
+	u8 act_wqe_size_enc_rq1;
+	u8 act_wqe_size_enc_rq2;
+	u8 act_wqe_size_enc_rq3;
+	u32 nr_sq_pages;
+	u32 nr_rq1_pages;
+	u32 nr_rq2_pages;
+	u32 nr_rq3_pages;
+	u32 liobn_sq;
+	u32 liobn_rq1;
+	u32 liobn_rq2;
+	u32 liobn_rq3;
+};
+
+/*
+ * Event Queue attributes, passed as paramter
+ */
+struct ehea_eq_attr {
+	u32 type;
+	u32 max_nr_of_eqes;
+	u8 eqe_gen;        /* generate eqe flag */
+	u64 eq_handle;
+	u32 act_nr_of_eqes;
+	u32 nr_pages;
+	u32 ist1;          /* Interrupt service token */
+	u32 ist2;
+	u32 ist3;
+	u32 ist4;
+};
+
+
+/*
+ * Event Queue
+ */
+struct ehea_eq {
+	struct ehea_adapter *adapter;
+	struct hw_queue hw_queue;
+	u64 fw_handle;
+	struct h_epas epas;
+	spinlock_t spinlock;
+	struct ehea_eq_attr attr;
+};
+
+/*
+ * HEA Queues
+ */
+struct ehea_qp {
+	struct ehea_adapter *adapter;
+	u64 fw_handle;			/* QP handle for firmware calls */
+	struct hw_queue hw_squeue;
+	struct hw_queue hw_rqueue1;
+	struct hw_queue hw_rqueue2;
+	struct hw_queue hw_rqueue3;
+	struct h_epas epas;
+	struct ehea_qp_init_attr init_attr;
+};
+
+/*
+ * Completion Queue attributes
+ */
+struct ehea_cq_attr {
+        /* input parameter */
+	u32 max_nr_of_cqes;
+	u32 cq_token;
+	u64 eq_handle;
+
+        /* output parameter */
+	u32 act_nr_of_cqes;
+	u32 nr_pages;
+};
+
+/*
+ * Completion Queue
+ */
+struct ehea_cq {
+	struct ehea_adapter *adapter;
+	u64 fw_handle;
+	struct hw_queue hw_queue;
+	struct h_epas epas;
+	struct ehea_cq_attr attr;
+};
+
+/*
+ * Memory Region
+ */
+struct ehea_mr {
+	u64 handle;
+	u64 vaddr;
+	u32 lkey;
+};
+
+/*
+ * Port state information
+ */
+struct port_state {
+	int poll_max_processed;
+	int poll_receive_errors;
+	int ehea_poll;
+	int queue_stopped;
+	int min_swqe_avail;
+	u64 sqc_stop_sum;
+	int pkt_send;
+	int pkt_xmit;
+	int send_tasklet;
+	int nwqe;
+};
+
+#define EHEA_IRQ_NAME_SIZE 20
+
+/*
+ * Port resources
+ */
+struct ehea_port_res {
+	struct ehea_mr send_mr;       /* send memory region */
+	struct ehea_mr recv_mr;       /* receive memory region */
+	spinlock_t xmit_lock;
+	struct ehea_port *port;
+	char int_recv_name[EHEA_IRQ_NAME_SIZE];
+	char int_send_name[EHEA_IRQ_NAME_SIZE];
+	struct ehea_qp *qp;
+	struct ehea_cq *send_cq;
+	struct ehea_cq *recv_cq;
+	struct ehea_eq *send_eq;
+	struct ehea_eq *recv_eq;
+	spinlock_t send_lock;
+	struct sk_buff **skb_arr_rq1; /* skb array for rq1 */
+	struct sk_buff **skb_arr_rq2;
+	struct sk_buff **skb_arr_rq3;
+	struct sk_buff **skb_arr_sq;
+	int skb_arr_rq1_len;
+	int skb_arr_rq2_len;
+	int skb_arr_rq3_len;
+	int skb_arr_sq_len;
+	int skb_rq2_index;
+	int skb_rq3_index;
+	int skb_sq_index;
+	int os_skbs_rq2;              /* outstanding skbs for rq2 */
+	int os_skbs_rq3;
+	spinlock_t netif_queue;
+	atomic_t swqe_avail;
+	int swqe_ll_count;
+	int swqe_count;
+	u32 swqe_id_counter;
+	u64 tx_packets;
+	struct tasklet_struct send_comp_task;
+	spinlock_t recv_lock;
+	struct port_state p_state;
+	u64 rx_packets;
+	u32 poll_counter;
+};
+
+
+struct ehea_adapter {
+	u64 handle;
+	u8 num_ports;
+	struct ehea_port *port[16];
+	struct ehea_eq *neq;       /* notification event queue */
+	struct workqueue_struct *ehea_wq;
+	struct tasklet_struct neq_tasklet;
+	struct ehea_mr mr;
+	u32 pd;                    /* protection domain */
+	u64 max_mc_mac;            /* max number of multicast mac addresses */
+};
+
+
+struct ehea_mc_list {
+	struct list_head list;
+	u64 macaddr;
+};
+
+#define EHEA_PORT_UP 1
+#define EHEA_PORT_DOWN 0
+#define EHEA_MAX_PORT_RES 16
+struct ehea_port {
+	struct ehea_adapter *adapter;	 /* adapter that owns this port */
+	struct net_device *netdev;
+	struct net_device_stats stats;
+	struct ehea_port_res port_res[EHEA_MAX_PORT_RES];
+	struct device_node *of_dev_node; /* Open Firmware Device Node */
+	struct ehea_mc_list *mc_list;	 /* Multicast MAC addresses */
+	struct vlan_group *vgrp;
+	struct ehea_eq *qp_eq;
+	struct work_struct reset_task;
+	struct semaphore port_lock;
+	char int_aff_name[EHEA_IRQ_NAME_SIZE];
+	int allmulti;			 /* Indicates IFF_ALLMULTI state */
+	int promisc;		 	 /* Indicates IFF_PROMISC state */
+	int num_tx_qps;
+	u64 mac_addr;
+	u32 logical_port_id;
+	u32 port_speed;
+	u32 msg_enable;
+	u32 sig_comp_iv;
+	u32 state;
+	u8 full_duplex;
+	u8 num_def_qps;
+};
+
+struct port_res_cfg {
+	int max_entries_rcq;
+	int max_entries_scq;
+	int max_entries_sq;
+	int max_entries_rq1;
+	int max_entries_rq2;
+	int max_entries_rq3;
+};
+
+#endif	/* __EHEA_H__ */
--- linux-2.6.18-rc4-git1-orig/drivers/net/ehea/ehea_hw.h	1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_hw.h	2006-08-22 06:05:29.271374306 -0700
@@ -0,0 +1,290 @@
+/*
+ *  linux/drivers/net/ehea/ehea_hw.h
+ *
+ *  eHEA ethernet device driver for IBM eServer System p
+ *
+ *  (C) Copyright IBM Corp. 2006
+ *
+ *  Authors:
+ *       Christoph Raisch <raisch@de.ibm.com>
+ *       Jan-Bernd Themann <themann@de.ibm.com>
+ *       Thomas Klein <tklein@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 __EHEA_HW_H__
+#define __EHEA_HW_H__
+
+#define QPX_SQA_VALUE   EHEA_BMASK_IBM(48,63)
+#define QPX_RQ1A_VALUE  EHEA_BMASK_IBM(48,63)
+#define QPX_RQ2A_VALUE  EHEA_BMASK_IBM(48,63)
+#define QPX_RQ3A_VALUE  EHEA_BMASK_IBM(48,63)
+
+#define QPTEMM_OFFSET(x) offsetof(struct ehea_qptemm, x)
+
+struct ehea_qptemm {
+	u64 qpx_hcr;
+	u64 qpx_c;
+	u64 qpx_herr;
+	u64 qpx_aer;
+	u64 qpx_sqa;
+	u64 qpx_sqc;
+	u64 qpx_rq1a;
+	u64 qpx_rq1c;
+	u64 qpx_st;
+	u64 qpx_aerr;
+	u64 qpx_tenure;
+	u64 qpx_reserved1[(0x098 - 0x058) / 8];
+	u64 qpx_portp;
+	u64 qpx_reserved2[(0x100 - 0x0A0) / 8];
+	u64 qpx_t;
+	u64 qpx_sqhp;
+	u64 qpx_sqptp;
+	u64 qpx_reserved3[(0x140 - 0x118) / 8];
+	u64 qpx_sqwsize;
+	u64 qpx_reserved4[(0x170 - 0x148) / 8];
+	u64 qpx_sqsize;
+	u64 qpx_reserved5[(0x1B0 - 0x178) / 8];
+	u64 qpx_sigt;
+	u64 qpx_wqecnt;
+	u64 qpx_rq1hp;
+	u64 qpx_rq1ptp;
+	u64 qpx_rq1size;
+	u64 qpx_reserved6[(0x220 - 0x1D8) / 8];
+	u64 qpx_rq1wsize;
+	u64 qpx_reserved7[(0x240 - 0x228) / 8];
+	u64 qpx_pd;
+	u64 qpx_scqn;
+	u64 qpx_rcqn;
+	u64 qpx_aeqn;
+	u64 reserved49;
+	u64 qpx_ram;
+	u64 qpx_reserved8[(0x300 - 0x270) / 8];
+	u64 qpx_rq2a;
+	u64 qpx_rq2c;
+	u64 qpx_rq2hp;
+	u64 qpx_rq2ptp;
+	u64 qpx_rq2size;
+	u64 qpx_rq2wsize;
+	u64 qpx_rq2th;
+	u64 qpx_rq3a;
+	u64 qpx_rq3c;
+	u64 qpx_rq3hp;
+	u64 qpx_rq3ptp;
+	u64 qpx_rq3size;
+	u64 qpx_rq3wsize;
+	u64 qpx_rq3th;
+	u64 qpx_lpn;
+	u64 qpx_reserved9[(0x400 - 0x378) / 8];
+	u64 reserved_ext[(0x500 - 0x400) / 8];
+	u64 reserved2[(0x1000 - 0x500) / 8];
+};
+
+#define MRx_HCR_LPARID_VALID EHEA_BMASK_IBM(0, 0)
+
+#define MRMWMM_OFFSET(x) offsetof(struct ehea_mrmwmm, x)
+
+struct ehea_mrmwmm {
+	u64 mrx_hcr;
+	u64 mrx_c;
+	u64 mrx_herr;
+	u64 mrx_aer;
+	u64 mrx_pp;
+	u64 reserved1;
+	u64 reserved2;
+	u64 reserved3;
+	u64 reserved4[(0x200 - 0x40) / 8];
+	u64 mrx_ctl[64];
+};
+
+#define QPEDMM_OFFSET(x) offsetof(struct ehea_qpedmm, x)
+
+struct ehea_qpedmm {
+
+	u64 reserved0[(0x400) / 8];
+	u64 qpedx_phh;
+	u64 qpedx_ppsgp;
+	u64 qpedx_ppsgu;
+	u64 qpedx_ppdgp;
+	u64 qpedx_ppdgu;
+	u64 qpedx_aph;
+	u64 qpedx_apsgp;
+	u64 qpedx_apsgu;
+	u64 qpedx_apdgp;
+	u64 qpedx_apdgu;
+	u64 qpedx_apav;
+	u64 qpedx_apsav;
+	u64 qpedx_hcr;
+	u64 reserved1[4];
+	u64 qpedx_rrl0;
+	u64 qpedx_rrrkey0;
+	u64 qpedx_rrva0;
+	u64 reserved2;
+	u64 qpedx_rrl1;
+	u64 qpedx_rrrkey1;
+	u64 qpedx_rrva1;
+	u64 reserved3;
+	u64 qpedx_rrl2;
+	u64 qpedx_rrrkey2;
+	u64 qpedx_rrva2;
+	u64 reserved4;
+	u64 qpedx_rrl3;
+	u64 qpedx_rrrkey3;
+	u64 qpedx_rrva3;
+};
+
+#define CQX_FECADDER EHEA_BMASK_IBM(32, 63)
+#define CQX_FEC_CQE_CNT EHEA_BMASK_IBM(32, 63)
+#define CQX_N1_GENERATE_COMP_EVENT EHEA_BMASK_IBM(0, 0)
+#define CQX_EP_EVENT_PENDING EHEA_BMASK_IBM(0, 0)
+
+#define CQTEMM_OFFSET(x) offsetof(struct ehea_cqtemm, x)
+
+struct ehea_cqtemm {
+	u64 cqx_hcr;
+	u64 cqx_c;
+	u64 cqx_herr;
+	u64 cqx_aer;
+	u64 cqx_ptp;
+	u64 cqx_tp;
+	u64 cqx_fec;
+	u64 cqx_feca;
+	u64 cqx_ep;
+	u64 cqx_eq;
+	u64 reserved1;
+	u64 cqx_n0;
+	u64 cqx_n1;
+	u64 reserved2[(0x1000 - 0x60) / 8];
+};
+
+#define EQTEMM_OFFSET(x) offsetof(struct ehea_eqtemm, x)
+
+struct ehea_eqtemm {
+	u64 EQx_HCR;
+	u64 EQx_C;
+	u64 EQx_HERR;
+	u64 EQx_AER;
+	u64 EQx_PTP;
+	u64 EQx_TP;
+	u64 EQx_SSBA;
+	u64 EQx_PSBA;
+	u64 EQx_CEC;
+	u64 EQx_MEQL;
+	u64 EQx_XISBI;
+	u64 EQx_XISC;
+	u64 EQx_IT;
+};
+
+static inline u64 epa_load(struct h_epa epa, u32 offset)
+{
+	u64 addr = epa.fw_handle + offset;
+	return *(volatile u64*)addr;
+}
+
+static inline void epa_store(struct h_epa epa, u32 offset, u64 value)
+{
+	u64 addr = epa.fw_handle + offset;
+	*(u64*)addr = value;
+	epa_load(epa, offset);	/* synchronize explicitly to eHEA */
+}
+
+static inline void epa_store_acc(struct h_epa epa, u32 offset, u64 value)
+{
+	u64 addr = epa.fw_handle + offset;
+	*(u64*)addr = value;
+}
+
+#define epa_store_eq(epa, offset, value)\
+        epa_store(epa, EQTEMM_OFFSET(offset), value)
+#define epa_load_eq(epa, offset)\
+        epa_load(epa, EQTEMM_OFFSET(offset))
+
+#define epa_store_cq(epa, offset, value)\
+        epa_store(epa, CQTEMM_OFFSET(offset), value)
+#define epa_load_cq(epa, offset)\
+        epa_load(epa, CQTEMM_OFFSET(offset))
+
+#define epa_store_qp(epa, offset, value)\
+        epa_store(epa, QPTEMM_OFFSET(offset), value)
+#define epa_load_qp(epa, offset)\
+        epa_load(epa, QPTEMM_OFFSET(offset))
+
+#define epa_store_qped(epa, offset, value)\
+        epa_store(epa, QPEDMM_OFFSET(offset), value)
+#define epa_load_qped(epa, offset)\
+        epa_load(epa, QPEDMM_OFFSET(offset))
+
+#define epa_store_mrmw(epa, offset, value)\
+        epa_store(epa, MRMWMM_OFFSET(offset), value)
+#define epa_load_mrmw(epa, offset)\
+        epa_load(epa, MRMWMM_OFFSET(offset))
+
+#define epa_store_base(epa, offset, value)\
+        epa_store(epa, HCAGR_OFFSET(offset), value)
+#define epa_load_base(epa, offset)\
+        epa_load(epa, HCAGR_OFFSET(offset))
+
+static inline void ehea_update_sqa(struct ehea_qp *qp, u16 nr_wqes)
+{
+	struct h_epa epa = qp->epas.kernel;
+	epa_store_acc(epa, QPTEMM_OFFSET(qpx_sqa),
+		      EHEA_BMASK_SET(QPX_SQA_VALUE, nr_wqes));
+}
+
+static inline void ehea_update_rq3a(struct ehea_qp *qp, u16 nr_wqes)
+{
+	struct h_epa epa = qp->epas.kernel;
+	epa_store_acc(epa, QPTEMM_OFFSET(qpx_rq3a),
+		      EHEA_BMASK_SET(QPX_RQ1A_VALUE, nr_wqes));
+}
+
+static inline void ehea_update_rq2a(struct ehea_qp *qp, u16 nr_wqes)
+{
+	struct h_epa epa = qp->epas.kernel;
+	epa_store_acc(epa, QPTEMM_OFFSET(qpx_rq2a),
+		      EHEA_BMASK_SET(QPX_RQ1A_VALUE, nr_wqes));
+}
+
+static inline void ehea_update_rq1a(struct ehea_qp *qp, u16 nr_wqes)
+{
+	struct h_epa epa = qp->epas.kernel;
+	epa_store_acc(epa, QPTEMM_OFFSET(qpx_rq1a),
+		      EHEA_BMASK_SET(QPX_RQ1A_VALUE, nr_wqes));
+}
+
+static inline void ehea_update_feca(struct ehea_cq *cq, u32 nr_cqes)
+{
+	struct h_epa epa = cq->epas.kernel;
+	epa_store_acc(epa, CQTEMM_OFFSET(cqx_feca),
+		      EHEA_BMASK_SET(CQX_FECADDER, nr_cqes));
+}
+
+static inline void ehea_reset_cq_n1(struct ehea_cq *cq)
+{
+	struct h_epa epa = cq->epas.kernel;
+	epa_store_cq(epa, cqx_n1,
+		     EHEA_BMASK_SET(CQX_N1_GENERATE_COMP_EVENT, 1));
+}
+
+static inline void ehea_reset_cq_ep(struct ehea_cq *my_cq)
+{
+	struct h_epa epa = my_cq->epas.kernel;
+	epa_store_acc(epa, CQTEMM_OFFSET(cqx_ep),
+		      EHEA_BMASK_SET(CQX_EP_EVENT_PENDING, 0));
+}
+
+#endif	/* __EHEA_HW_H__ */

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox