LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* 83xx immap_qe.h -> SIR type def error?
From: Russell McGuire @ 2008-02-01 11:47 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <mailman.3.1201827605.31777.linuxppc-embedded@ozlabs.org>

All Freescale,

Not sure if this is the place to post this, but I have run across what I
consider to be a possible type error in the immap_qe.h file, for the
asm/powerpc branch.

In the file immap_qe.h

/* SI Routing Tables */
struct sir {
	u8  tx[0x400];
	u8  rx[0x400];
	u8  res0[0x800];
}

Shouldn't these types be defined as __be16 ?

According to the Freescale manual this is a 16 bit field, not an 8-bit
field.

Spent an hour trying to figure out why I couldn't fill this field out with
upper 8 bits last night.

Thoughts?

Russell McGuire

^ permalink raw reply

* arch/powerpc 440GX external IRQ
From: Neil Wilson @ 2008-02-01 10:19 UTC (permalink / raw)
  To: linuxppc-embedded

Hi,

Does anyone have these working and/or is able to talk me through the DTS
structure for them please ?
I have a 440GX board that works fine under arch/ppc with external
IRQ4,5,6 however I cannot get it correct in the DTS, I think I am not
correctly specifying the cascade of the UIC ?  I started off using the
Taishan DTS as a template as that seems to be the only 440GX in
powerpc/platforms and can get the board to boot, mount NFS etc.

Thanks.

Neil

--
Neil Wilson
Principal Engineer, Embedded Software
Airspan Communications Ltd
Cambridge House, Oxford Road
Uxbridge, Middlesex, UB8 1UN, UK.
+44(0)1895-467265
nwilson@airspan.com=20

^ permalink raw reply

* Re: [PATCH 1/2] pci: Fix bus resource assignment on 32 bits with 64b resources
From: Stefan Roese @ 2008-02-01 10:18 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: linuxppc-dev, linux-pci, linux-kernel, Greg Kroah-Hartman
In-Reply-To: <20071210063216.89DBBDDE1E@ozlabs.org>

On Monday 10 December 2007, Benjamin Herrenschmidt wrote:
> The current pci_assign_unassigned_resources() code doesn't work properly
> on 32 bits platforms with 64 bits resources. The main reason is the use
> of unsigned long in various places instead of resource_size_t.
>
> This fixes it, along with some tricks to avoid casting to 64 bits on
> platforms that don't need it in every printk around.
>
> This is a pre-requisite for making powerpc use the generic code instead of
> its own half-useful implementation.
>
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Checking Linus's latest git repository, it seems this patch (and the 2nd from 
this series) hasn't been applied till now. This is just a reminder, that it 
gets in in this merge-window.

Thanks.

Best regards,
Stefan

^ permalink raw reply

* Re: ndfc ecc byte order
From: Stefan Roese @ 2008-02-01  8:34 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Sean MacLennan
In-Reply-To: <200802010912.22571.sr@denx.de>

On Friday 01 February 2008, Stefan Roese wrote:
> > So the SMC byte ordering is selected and it should match the version used
> > in U-Boot. In Linux the swapping is done in nand_ecc.c.
>
> Seems that I was incorrect here. Tests showed that writing from Linux and
> then reading back from U-Boot results in ECC errors. My comment above is
> bogus, since nand_calculate_ecc() from nand_ecc.c is not used with HW-ECC
> generation enabled.

And after another coffee I noticed that the current Linux implementation is 
correct. The U-Boot implementation needs to get fixed. Brown paper bag time 
for me.

Best regards,
Stefan

^ permalink raw reply

* External Interrupt
From: Marco Stornelli @ 2008-02-01  8:11 UTC (permalink / raw)
  To: Linuxppc Embedded Mailing List

Hi,

I used the linux kernel 2.6.10 with a processor MPC8548E. I wrote a
driver for a device connected with the local bus. This device has an
external interrupt. In the local bus driver I have used the macro
MPC85xx_IRQ_EXT<X> to get the interrupt number and pass it to the
driver and after that register the ISR. Now with a kernel 2.6.21 this
macro isn't available because in the header file irq.h there is the
option CONFIG_PPC_MERGE that disable those options. I think this
problem is related to the migration of ppc code towards powerpc. I
know that now there is the new device tree source file where I can add
a device and its interrupt number  but I think in this file I should
describe only the platform device, and this device is not a platform
device. Then, how can I get now this  value? Is there some function to
call? How can I perform this operation?

Thanks in advance.

Marco

^ permalink raw reply

* Re: ndfc ecc byte order
From: Stefan Roese @ 2008-02-01  8:12 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Sean MacLennan
In-Reply-To: <200801302201.04552.sr@denx.de>

On Wednesday 30 January 2008, Stefan Roese wrote:
> On Wednesday 30 January 2008, Sean MacLennan wrote:
> > There seems to be a byte order conflict between the u-boot and Linux
> > ndfc drivers.
> >
> > u-boot has the following:
> >
> >     /* The NDFC uses Smart Media (SMC) bytes order*/
> >     ecc_code[0] = p[2];
> >     ecc_code[1] = p[1];
> >     ecc_code[2] = p[3];
> >
> > the kernel has:
> >
> >     ecc_code[0] = p[1];
> >     ecc_code[1] = p[2];
> >     ecc_code[2] = p[3];
> >
> > I think u-boot has it right since u-boot and kernel software calculated
> > ECCs agree. Anybody know a reason *not* to switch to the SMC byte order?
>
> Please take a look at Kconfig
>
> config MTD_NAND_NDFC
> 	tristate "NDFC NanD Flash Controller"
> 	depends on 4xx && !PPC_MERGE
> 	select MTD_NAND_ECC_SMC
>
> So the SMC byte ordering is selected and it should match the version used
> in U-Boot. In Linux the swapping is done in nand_ecc.c.

Seems that I was incorrect here. Tests showed that writing from Linux and then 
reading back from U-Boot results in ECC errors. My comment above is bogus, 
since nand_calculate_ecc() from nand_ecc.c is not used with HW-ECC generation 
enabled.

I'll send a patch to fix this in a short while.

Best regards,
Stefan

^ permalink raw reply

* Re: [PATCH] [POWERPC] pasemi: Fix thinko in dma_direct_ops setup
From: Michael Ellerman @ 2008-02-01  7:56 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev, torvalds, Paul Mackerras
In-Reply-To: <20080131235002.GA16753@lixom.net>

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

On Thu, 2008-01-31 at 17:50 -0600, Olof Johansson wrote:
> [POWERPC] pasemi: Fix thinko in dma_direct_ops setup
> 
> The first patch will just fall through and still set dma_data to a bad
> value, make it return directly instead.
> 
> Signed-off-by: Olof Johansson <olof@lixom.net>

OK I get it now, sorry for the breakage.

Acked-by: Michael Ellerman <michael@ellerman.id.au>

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH 2/10] sbc8560: Add v1 device tree source for Wind River SBC8560 board
From: David Gibson @ 2008-02-01  7:54 UTC (permalink / raw)
  To: Paul Gortmaker; +Cc: linuxppc-dev
In-Reply-To: <7107e511a0f989ad55335855fa0f241f09eff52f.1201217172.git.paul.gortmaker@windriver.com>

On Thu, Jan 24, 2008 at 06:41:24PM -0500, Paul Gortmaker wrote:
> This adds a v1 device tree source for the Wind River SBC8560 board.  The
> biggest difference between this and the MPC8560ADS reference platform
> dts is the use of an external 16550 compatible UART instead of the CPM2.
> 
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>

[snip]
> +/dts-v1/;
> +
> +/ {
> +	model = "SBC8560";
> +	compatible = "SBC8560";

This is not the conventional format for board-level compatible
entries, which should generally be "vendor,model" and all in lower
case.

[snip]
> +		enet0: ethernet@24000 {
> +			cell-index = <0>;
> +			device_type = "network";
> +			model = "TSEC";
> +			compatible = "gianfar";

This looks like the old dodgy gianfar binding, and needs updating
(mdio node will probably also need changes).

[snip]
> +	localbus@ff705000 {
> +		compatible = "fsl,mpc8560-localbus";
> +		#address-cells = <2>;
> +		#size-cells = <1>;
> +		reg = <0xff705000 0x100>;	// BRx, ORx, etc.
> +
> +		ranges = <
> +			0x0 0x0 0xff800000 0x0800000	// 8MB boot flash
> +			0x1 0x0 0xe4000000 0x4000000	// 64MB flash
> +			0x3 0x0 0x20000000 0x4000000	// 64MB SDRAM
> +			0x4 0x0 0x24000000 0x4000000	// 64MB SDRAM
> +			0x5 0x0 0xfc000000 0x0c00000	// EPLD
> +			0x6 0x0 0xe0000000 0x4000000	// 64MB flash
> +			0x7 0x0 0x80000000 0x0200000	// ATM1,2
> +		>;
> +
> +		epld@5,0 {

I'm not entirely convinced on this two-level representation.  I think
the FSL people need to get together and define a binding (or set of
bindings) for their various chipselect style external bus bridges.

> +			compatible = "wrs,epld-localbus";
> +			#address-cells = <2>;
> +			#size-cells = <1>;
> +			reg = <0x5 0x0 0xc00000>;
> +			ranges = <
> +				0x0 0x0 0x5 0x000000 0x1fff	// LED disp.
> +				0x1 0x0 0x5 0x100000 0x1fff	// switches
> +				0x2 0x0 0x5 0x200000 0x1fff	// ID reg.
> +				0x3 0x0 0x5 0x300000 0x1fff	// status reg.
> +				0x4 0x0 0x5 0x400000 0x1fff	// reset reg.
> +				0x5 0x0 0x5 0x500000 0x1fff	// Wind port
> +				0x7 0x0 0x5 0x700000 0x1fff	// UART #1
> +				0x8 0x0 0x5 0x800000 0x1fff	// UART #2
> +				0x9 0x0 0x5 0x900000 0x1fff	// RTC
> +				0xb 0x0 0x5 0xb00000 0x1fff	// EEPROM
> +			>;

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* Re: [PATCH 2/4 v4] POWERPC: Add StorCenter DTS first draft.
From: David Gibson @ 2008-02-01  7:50 UTC (permalink / raw)
  To: Jon Loeliger; +Cc: linuxppc-dev
In-Reply-To: <E1JHkYP-00010b-At@jdl.com>

On Wed, Jan 23, 2008 at 12:42:29PM -0600, Jon Loeliger wrote:
> 
> Based on the Kurobox DTS files.

[snip]
> +/ {
> +	model = "StorCenter";
> +	compatible = "storcenter";

This really needs a vendor prefix.

> +	chosen {
> +		linux,stdout-path = "/soc/serial@4500";

You can now use a path reference here.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* Re: [PATCH 3/3] Add device tree compatible aliases to i2c drivers
From: David Gibson @ 2008-02-01  7:32 UTC (permalink / raw)
  To: Matt Sealey; +Cc: linuxppc-dev, i2c
In-Reply-To: <4797A127.8070401@genesi-usa.com>

On Wed, Jan 23, 2008 at 08:18:47PM +0000, Matt Sealey wrote:
> 
> 
> Jon Smirl wrote:
> > --- a/drivers/i2c/chips/tps65010.c
> > +++ b/drivers/i2c/chips/tps65010.c
> > @@ -571,6 +571,10 @@ static const struct i2c_device_id tps65010_id[] = {
> >  	{ "tps65011", TPS65011 },
> >  	{ "tps65012", TPS65012 },
> >  	{ "tps65013", TPS65013 },
> > +	OF_ID("ti,tps65010", TPS65010)
> > +	OF_ID("ti,tps65011", TPS65011)
> > +	OF_ID("ti,tps65012", TPS65012)
> > +	OF_ID("ri,tps65013", TPS65013)
> >  	{ },
> 
> ti, ti, ti, ri?
> 
> > --- a/drivers/rtc/rtc-ds1307.c
> > +++ b/drivers/rtc/rtc-ds1307.c
> > @@ -129,6 +129,12 @@ static const struct i2c_device_id ds1307_id[] = {
> >  	{ "ds1339", ds_1339 },
> >  	{ "ds1340", ds_1340 },
> >  	{ "m41t00", m41t00 },
> > +	OF_ID("dallas,ds1307", ds_1307)
> > +	OF_ID("dallas,ds1337", ds_1337)
> > +	OF_ID("dallas,ds1338", ds_1338)
> > +	OF_ID("dallas,ds1339", ds_1339)
> > +	OF_ID("dallas,ds1340", ds_1340)
> > +	OF_ID("stm,m41t00", m41t00)
> >  	{},
> >  };
> 
> The convention is to use the stock ticker, capitalized, if a company
> has one, I guess dallas is MXIM these days, but dallas is a good
> substitute based on the fact that most people still remember Dallas
> clock chips and so on from the Ancient Days. STMicroelectronics is STM.
> I couldn't care less about case sensitivity, but the stock ticker
> thing was always a good idea.. it gives a sort of grounding in reality
> for the manufacturer names.

The stock ticker is a recent convention.  "dallas," has been used in
existing IEEE1275 bindings, which to my mind trumps newer conventions.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* Re: [PATCH] [POWERPC] Xilinx: hwicap driver
From: Nathan Lynch @ 2008-02-01  5:56 UTC (permalink / raw)
  To: Stephen Neuendorffer; +Cc: linuxppc-dev
In-Reply-To: <20080201050228.7A6E117C0053@mail145-dub.bigfish.com>

Stephen Neuendorffer wrote:
>
> +static ssize_t
> +hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos)
> +{
> +	struct hwicap_drvdata *drvdata = file->private_data;
> +	ssize_t bytes_to_read = 0;
> +	u32 *kbuf;
> +	u32 words;
> +	u32 bytes_remaining;
> +	int status;
> +
> +        spin_lock(&hwicap_spinlock);
> +	if (drvdata->is_accessing)
> +		return -EBUSY;

Need to unlock before returning (several places in this patch).

^ permalink raw reply

* Re: [PATCH] [POWERPC] Xilinx: hwicap driver
From: Grant Likely @ 2008-02-01  5:21 UTC (permalink / raw)
  To: Stephen Neuendorffer; +Cc: linuxppc-dev
In-Reply-To: <20080201010256.22BCCBE006A@mail38-sin.bigfish.com>

On 1/31/08, Stephen Neuendorffer <stephen.neuendorffer@xilinx.com> wrote:
> This includes code for new fifo-based xps_hwicap in addition to the
> older opb_hwicap, which has a significantly different interface.  The
> common code between the two drivers is largely shared.
>
> Significant differences exists between this driver and what is
> supported in the EDK drivers.  In particular, most of the
> architecture-specific code for reconfiguring individual FPGA resources
> has been removed.  This functionality is likely better provided in a
> user-space support library.  In addition, read and write access is
> supported.  In addition, although the xps_hwicap cores support
> interrupt-driver mode, this driver only supports polled operation, in
> order to make the code simpler, and since the interrupt processing
> overhead is likely to slow down the throughput under Linux.
>
> Signed-off-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com>
>
> Fixed to add spinlocks, and a few style issues.

You're probably better off using a semaphore, or more specifically a
MUTEX, to protect the whole fop instead of a spin lock and the flags.
The semantics are simpler if do it with a mutex and the function can
sleep while holding it.

Cheers,
g.

^ permalink raw reply

* Re: Kernel oops in MPC8568MDS BSP
From: Kumar Gala @ 2008-02-01  5:19 UTC (permalink / raw)
  To: mike zheng; +Cc: linuxppc-dev
In-Reply-To: <5c9cd53b0801311128s1801c720pdeda8ee1bdd518e@mail.gmail.com>


On Jan 31, 2008, at 1:28 PM, mike zheng wrote:

> Hello,
>
> I am using MPC8568MDS BSP on my board, which has same memory map with
> MPC8568MDS board. However I have kernel Ooop at
> free_bootmem_with_active_regions() within do_init_bootmem(). Any idea
> on this issue?

such questions should be asked of the BSP provider.

- k

^ permalink raw reply

* Re: [PATCH 0/5] ehea checkpatch fixups
From: Doug Maxey @ 2008-02-01  4:35 UTC (permalink / raw)
  To: Nathan Lynch
  Cc: Jan-Bernd Themann, netdev, Jeff Garzik, Linux PowerPC List,
	Paul Mackerras
In-Reply-To: <20080201030542.GX14201@localdomain>


On Thu, 31 Jan 2008 21:05:42 CST, Nathan Lynch wrote:
> Doug Maxey wrote:
> > 
> > A small set of fixups for checkpatch.
> > 
> > Based on upstream pull from a few hours ago.
> 
> Er, ehea doesn't even build right now[1], maybe that could get fixed
> first?  :-)
> 
> [1] http://lkml.org/lkml/2008/1/28/337

For sure these won't break it any worse.  ;)  Think of these more as a 
janitorial thing vs. structural.

Doesn't gregkh's patch work?  At least for the interim?

Jan-Bernd,
What tools are looking in sysfs? distro scripts?  I don't see any link 
between ethtool and the driver (other than the driver internal bits).
Am I missing something obvious?

++doug

^ permalink raw reply

* RE: [PATCH] [POWERPC] Xilinx: hwicap driver
From: Stephen Neuendorffer @ 2008-02-01  5:01 UTC (permalink / raw)
  To: Stephen Neuendorffer, linuxppc-dev, grant.likely, jacmet
In-Reply-To: <1201827769-7439-1-git-send-email-stephen.neuendorffer@xilinx.com>

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


Nevermind... I posted this too fast and screwed up the spinlocks.

-----Original Message-----
From: Stephen Neuendorffer [mailto:stephen.neuendorffer@xilinx.com]
Sent: Thu 1/31/2008 5:02 PM
To: linuxppc-dev@ozlabs.org; grant.likely@secretlab.ca; jacmet@sunsite.dk
Cc: Stephen Neuendorffer
Subject: [PATCH] [POWERPC] Xilinx: hwicap driver
 
This includes code for new fifo-based xps_hwicap in addition to the
older opb_hwicap, which has a significantly different interface.  The
common code between the two drivers is largely shared.

Significant differences exists between this driver and what is
supported in the EDK drivers.  In particular, most of the
architecture-specific code for reconfiguring individual FPGA resources
has been removed.  This functionality is likely better provided in a
user-space support library.  In addition, read and write access is
supported.  In addition, although the xps_hwicap cores support
interrupt-driver mode, this driver only supports polled operation, in
order to make the code simpler, and since the interrupt processing
overhead is likely to slow down the throughput under Linux.

Signed-off-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com>

Fixed to add spinlocks, and a few style issues.
---
 drivers/char/Kconfig                       |    7 +
 drivers/char/Makefile                      |    1 +
 drivers/char/xilinx_hwicap/Makefile        |    7 +
 drivers/char/xilinx_hwicap/buffer_icap.c   |  380 ++++++++++++
 drivers/char/xilinx_hwicap/buffer_icap.h   |   57 ++
 drivers/char/xilinx_hwicap/fifo_icap.c     |  381 ++++++++++++
 drivers/char/xilinx_hwicap/fifo_icap.h     |   62 ++
 drivers/char/xilinx_hwicap/xilinx_hwicap.c |  912 ++++++++++++++++++++++++++++
 drivers/char/xilinx_hwicap/xilinx_hwicap.h |  193 ++++++
 9 files changed, 2000 insertions(+), 0 deletions(-)
 create mode 100644 drivers/char/xilinx_hwicap/Makefile
 create mode 100644 drivers/char/xilinx_hwicap/buffer_icap.c
 create mode 100644 drivers/char/xilinx_hwicap/buffer_icap.h
 create mode 100644 drivers/char/xilinx_hwicap/fifo_icap.c
 create mode 100644 drivers/char/xilinx_hwicap/fifo_icap.h
 create mode 100644 drivers/char/xilinx_hwicap/xilinx_hwicap.c
 create mode 100644 drivers/char/xilinx_hwicap/xilinx_hwicap.h

diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index ef1ed5d..157ae2a 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -831,6 +831,13 @@ config DTLK
 	  To compile this driver as a module, choose M here: the
 	  module will be called dtlk.
 
+config XILINX_HWICAP
+	tristate "Xilinx HWICAP Support"
+	depends on XILINX_VIRTEX
+	help
+	  This option enables support for Xilinx Internal Configuration
+	  Access Port (ICAP) driver.
+
 config R3964
 	tristate "Siemens R3964 line discipline"
 	---help---
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 07304d5..3a278a0 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_EFI_RTC)		+= efirtc.o
 obj-$(CONFIG_SGI_DS1286)	+= ds1286.o
 obj-$(CONFIG_SGI_IP27_RTC)	+= ip27-rtc.o
 obj-$(CONFIG_DS1302)		+= ds1302.o
+obj-$(CONFIG_XILINX_HWICAP)    += xilinx_hwicap/
 ifeq ($(CONFIG_GENERIC_NVRAM),y)
   obj-$(CONFIG_NVRAM)	+= generic_nvram.o
 else
diff --git a/drivers/char/xilinx_hwicap/Makefile b/drivers/char/xilinx_hwicap/Makefile
new file mode 100644
index 0000000..5491cbc
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Xilinx OPB hwicap driver
+#
+
+obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap_m.o 
+ 
+xilinx_hwicap_m-y := xilinx_hwicap.o fifo_icap.o buffer_icap.o
diff --git a/drivers/char/xilinx_hwicap/buffer_icap.c b/drivers/char/xilinx_hwicap/buffer_icap.c
new file mode 100644
index 0000000..dfea2bd
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/buffer_icap.c
@@ -0,0 +1,380 @@
+/*****************************************************************************
+ *
+ *     Author: Xilinx, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ *     AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ *     SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
+ *     OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ *     APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ *     THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ *     AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ *     FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
+ *     WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ *     IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ *     REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ *     INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE.
+ *
+ *     Xilinx products are not intended for use in life support appliances,
+ *     devices, or systems. Use in such applications is expressly prohibited.
+ *
+ *     (c) Copyright 2003-2008 Xilinx Inc.
+ *     All rights reserved.
+ *
+ *     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 "buffer_icap.h"
+
+/* Indicates how many bytes will fit in a buffer. (1 BRAM) */
+#define XHI_MAX_BUFFER_BYTES        2048
+#define XHI_MAX_BUFFER_INTS         (XHI_MAX_BUFFER_BYTES >> 2)
+
+/* File access and error constants */
+#define XHI_DEVICE_READ_ERROR       -1
+#define XHI_DEVICE_WRITE_ERROR      -2
+#define XHI_BUFFER_OVERFLOW_ERROR   -3
+
+#define XHI_DEVICE_READ             0x1
+#define XHI_DEVICE_WRITE            0x0
+
+/* Constants for checking transfer status */
+#define XHI_CYCLE_DONE              0
+#define XHI_CYCLE_EXECUTING         1
+
+/* buffer_icap register offsets */
+
+/* Size of transfer, read & write */
+#define XHI_SIZE_REG_OFFSET        0x800L
+/* offset into bram, read & write */
+#define XHI_BRAM_OFFSET_REG_OFFSET 0x804L
+/* Read not Configure, direction of transfer.  Write only */
+#define XHI_RNC_REG_OFFSET         0x808L
+/* Indicates transfer complete. Read only */
+#define XHI_STATUS_REG_OFFSET      0x80CL
+
+/* Constants for setting the RNC register */
+#define XHI_CONFIGURE              0x0UL
+#define XHI_READBACK               0x1UL
+
+/* Constants for the Done register */
+#define XHI_NOT_FINISHED           0x0UL
+#define XHI_FINISHED               0x1UL
+
+#define XHI_BUFFER_START 0
+
+/**
+ * buffer_icap_get_status: Get the contents of the status register.
+ * @parameter base_address: is the base address of the device
+ *
+ * The status register contains the ICAP status and the done bit.
+ *
+ * D8 - cfgerr
+ * D7 - dalign
+ * D6 - rip
+ * D5 - in_abort_l
+ * D4 - Always 1
+ * D3 - Always 1
+ * D2 - Always 1
+ * D1 - Always 1
+ * D0 - Done bit
+ **/
+static inline u32 buffer_icap_get_status(void __iomem *base_address)
+{
+	return in_be32(base_address + XHI_STATUS_REG_OFFSET);
+}
+
+/**
+ * buffer_icap_get_bram: Reads data from the storage buffer bram.
+ * @parameter base_address: contains the base address of the component.
+ * @parameter offset: The word offset from which the data should be read.
+ *
+ * A bram is used as a configuration memory cache.  One frame of data can
+ * be stored in this "storage buffer".
+ **/
+static inline u32 buffer_icap_get_bram(void __iomem *base_address,
+		u32 offset)
+{
+	return in_be32(base_address + (offset << 2));
+}
+
+/**
+ * buffer_icap_busy: Return true if the icap device is busy
+ * @parameter base_address: is the base address of the device
+ *
+ * The queries the low order bit of the status register, which
+ * indicates whether the current configuration or readback operation
+ * has completed.
+ **/
+static inline bool buffer_icap_busy(void __iomem *base_address)
+{
+	return (buffer_icap_get_status(base_address) & 1) == XHI_NOT_FINISHED;
+}
+
+/**
+ * buffer_icap_busy: Return true if the icap device is not busy
+ * @parameter base_address: is the base address of the device
+ *
+ * The queries the low order bit of the status register, which
+ * indicates whether the current configuration or readback operation
+ * has completed.
+ **/
+static inline bool buffer_icap_done(void __iomem *base_address)
+{
+	return (buffer_icap_get_status(base_address) & 1) == XHI_FINISHED;
+}
+
+/**
+ * buffer_icap_set_size: Set the size register.
+ * @parameter base_address: is the base address of the device
+ * @parameter data: The size in bytes.
+ *
+ * The size register holds the number of 8 bit bytes to transfer between
+ * bram and the icap (or icap to bram).
+ **/
+static inline void buffer_icap_set_size(void __iomem *base_address,
+		u32 data)
+{
+	out_be32(base_address + XHI_SIZE_REG_OFFSET, data);
+}
+
+/**
+ * buffer_icap_mSetoffsetReg: Set the bram offset register.
+ * @parameter base_address: contains the base address of the device.
+ * @parameter data: is the value to be written to the data register.
+ *
+ * The bram offset register holds the starting bram address to transfer
+ * data from during configuration or write data to during readback.
+ **/
+static inline void buffer_icap_set_offset(void __iomem *base_address,
+		u32 data)
+{
+	out_be32(base_address + XHI_BRAM_OFFSET_REG_OFFSET, data);
+}
+
+/**
+ * buffer_icap_set_rnc: Set the RNC (Readback not Configure) register.
+ * @parameter base_address: contains the base address of the device.
+ * @parameter data: is the value to be written to the data register.
+ *
+ * The RNC register determines the direction of the data transfer.  It
+ * controls whether a configuration or readback take place.  Writing to
+ * this register initiates the transfer.  A value of 1 initiates a
+ * readback while writing a value of 0 initiates a configuration.
+ **/
+static inline void buffer_icap_set_rnc(void __iomem *base_address,
+		u32 data)
+{
+	out_be32(base_address + XHI_RNC_REG_OFFSET, data);
+}
+
+/**
+ * buffer_icap_set_bram: Write data to the storage buffer bram.
+ * @parameter base_address: contains the base address of the component.
+ * @parameter offset: The word offset at which the data should be written.
+ * @parameter data: The value to be written to the bram offset.
+ *
+ * A bram is used as a configuration memory cache.  One frame of data can
+ * be stored in this "storage buffer".
+ **/
+static inline void buffer_icap_set_bram(void __iomem *base_address,
+		u32 offset, u32 data)
+{
+	out_be32(base_address + (offset << 2), data);
+}
+
+/**
+ * buffer_icap_device_read: Transfer bytes from ICAP to the storage buffer.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter offset: The storage buffer start address.
+ * @parameter count: The number of words (32 bit) to read from the
+ *           device (ICAP).
+ **/
+static int buffer_icap_device_read(struct hwicap_drvdata *drvdata,
+		u32 offset, u32 count)
+{
+
+	s32 retries = 0;
+	void __iomem *base_address = drvdata->base_address;
+
+	if (buffer_icap_busy(base_address))
+		return -EBUSY;
+
+	if ((offset + count) > XHI_MAX_BUFFER_INTS)
+		return -EINVAL;
+
+	/* setSize count*4 to get bytes. */
+	buffer_icap_set_size(base_address, (count << 2));
+	buffer_icap_set_offset(base_address, offset);
+	buffer_icap_set_rnc(base_address, XHI_READBACK);
+
+	while (buffer_icap_busy(base_address)) {
+		retries++;
+		if (retries > XHI_MAX_RETRIES)
+			return -EBUSY;
+	}
+	return 0;
+
+};
+
+/**
+ * buffer_icap_device_write: Transfer bytes from ICAP to the storage buffer.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter offset: The storage buffer start address.
+ * @parameter count: The number of words (32 bit) to read from the
+ *           device (ICAP).
+ **/
+static int buffer_icap_device_write(struct hwicap_drvdata *drvdata,
+		u32 offset, u32 count)
+{
+
+	s32 retries = 0;
+	void __iomem *base_address = drvdata->base_address;
+
+	if (buffer_icap_busy(base_address))
+		return -EBUSY;
+
+	if ((offset + count) > XHI_MAX_BUFFER_INTS)
+		return -EINVAL;
+
+	/* setSize count*4 to get bytes. */
+	buffer_icap_set_size(base_address, count << 2);
+	buffer_icap_set_offset(base_address, offset);
+	buffer_icap_set_rnc(base_address, XHI_CONFIGURE);
+
+	while (buffer_icap_busy(base_address)) {
+		retries++;
+		if (retries > XHI_MAX_RETRIES)
+			return -EBUSY;
+	}
+	return 0;
+
+};
+
+/**
+ * buffer_icap_reset: Reset the logic of the icap device.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * Writing to the status register resets the ICAP logic in an internal
+ * version of the core.  For the version of the core published in EDK,
+ * this is a noop.
+ **/
+void buffer_icap_reset(struct hwicap_drvdata *drvdata)
+{
+    out_be32(drvdata->base_address + XHI_STATUS_REG_OFFSET, 0xFEFE);
+}
+
+/**
+ * buffer_icap_set_configuration: Load a partial bitstream from system memory.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: Kernel address of the partial bitstream.
+ * @parameter size: the size of the partial bitstream in 32 bit words.
+ **/
+int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
+			     u32 size)
+{
+	int status;
+	s32 buffer_count = 0;
+	s32 num_writes = 0;
+	bool dirty = 0;
+	u32 i;
+	void __iomem *base_address = drvdata->base_address;
+
+	/* Loop through all the data */
+	for (i = 0, buffer_count = 0; i < size; i++) {
+
+		/* Copy data to bram */
+		buffer_icap_set_bram(base_address, buffer_count, data[i]);
+		dirty = 1;
+
+		if (buffer_count < XHI_MAX_BUFFER_INTS - 1) {
+			buffer_count++;
+			continue;
+		}
+
+		/* Write data to ICAP */
+		status = buffer_icap_device_write(
+				drvdata,
+				XHI_BUFFER_START,
+				XHI_MAX_BUFFER_INTS);
+		if (status != 0) {
+			/* abort. */
+			buffer_icap_reset(drvdata);
+			return status;
+		}
+
+		buffer_count = 0;
+		num_writes++;
+		dirty = 0;
+	}
+
+	/* Write unwritten data to ICAP */
+	if (dirty) {
+		/* Write data to ICAP */
+		status = buffer_icap_device_write(drvdata, XHI_BUFFER_START,
+					     buffer_count);
+		if (status != 0) {
+			/* abort. */
+			buffer_icap_reset(drvdata);
+		}
+		return status;
+	}
+
+	return 0;
+};
+
+/**
+ * buffer_icap_get_configuration: Read configuration data from the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: Address of the data representing the partial bitstream
+ * @parameter size: the size of the partial bitstream in 32 bit words.
+ **/
+int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data,
+			     u32 size)
+{
+	int status;
+	s32 buffer_count = 0;
+	s32 read_count = 0;
+	u32 i;
+	void __iomem *base_address = drvdata->base_address;
+
+	/* Loop through all the data */
+	for (i = 0, buffer_count = XHI_MAX_BUFFER_INTS; i < size; i++) {
+		if (buffer_count == XHI_MAX_BUFFER_INTS) {
+			u32 words_remaining = size - i;
+			u32 words_to_read =
+				words_remaining <
+				XHI_MAX_BUFFER_INTS ? words_remaining :
+				XHI_MAX_BUFFER_INTS;
+
+			/* Read data from ICAP */
+			status = buffer_icap_device_read(
+					drvdata,
+					XHI_BUFFER_START,
+					words_to_read);
+			if (status != 0) {
+				/* abort. */
+				buffer_icap_reset(drvdata);
+				return status;
+			}
+
+			buffer_count = 0;
+			read_count++;
+		}
+
+		/* Copy data from bram */
+		data[i] = buffer_icap_get_bram(base_address, buffer_count);
+		buffer_count++;
+	}
+
+	return 0;
+};
diff --git a/drivers/char/xilinx_hwicap/buffer_icap.h b/drivers/char/xilinx_hwicap/buffer_icap.h
new file mode 100644
index 0000000..0318495
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/buffer_icap.h
@@ -0,0 +1,57 @@
+/*****************************************************************************
+ *
+ *     Author: Xilinx, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ *     AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ *     SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
+ *     OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ *     APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ *     THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ *     AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ *     FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
+ *     WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ *     IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ *     REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ *     INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE.
+ *
+ *     Xilinx products are not intended for use in life support appliances,
+ *     devices, or systems. Use in such applications is expressly prohibited.
+ *
+ *     (c) Copyright 2003-2008 Xilinx Inc.
+ *     All rights reserved.
+ *
+ *     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 XILINX_BUFFER_ICAP_H_	/* prevent circular inclusions */
+#define XILINX_BUFFER_ICAP_H_	/* by using protection macros */
+
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include "xilinx_hwicap.h"
+
+void buffer_icap_reset(struct hwicap_drvdata *drvdata);
+
+/* Loads a partial bitstream from system memory. */
+int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
+			     u32 Size);
+
+/* Loads a partial bitstream from system memory. */
+int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data,
+			     u32 Size);
+
+#endif
diff --git a/drivers/char/xilinx_hwicap/fifo_icap.c b/drivers/char/xilinx_hwicap/fifo_icap.c
new file mode 100644
index 0000000..0988314
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/fifo_icap.c
@@ -0,0 +1,381 @@
+/*****************************************************************************
+ *
+ *     Author: Xilinx, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ *     AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ *     SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
+ *     OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ *     APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ *     THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ *     AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ *     FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
+ *     WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ *     IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ *     REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ *     INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE.
+ *
+ *     Xilinx products are not intended for use in life support appliances,
+ *     devices, or systems. Use in such applications is expressly prohibited.
+ *
+ *     (c) Copyright 2007-2008 Xilinx Inc.
+ *     All rights reserved.
+ *
+ *     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 "fifo_icap.h"
+
+/* Register offsets for the XHwIcap device. */
+#define XHI_GIER_OFFSET	0x1C  /* Device Global Interrupt Enable Reg */
+#define XHI_IPISR_OFFSET 0x20  /* Interrupt Status Register */
+#define XHI_IPIER_OFFSET 0x28  /* Interrupt Enable Register */
+#define XHI_WF_OFFSET 0x100 /* Write FIFO */
+#define XHI_RF_OFFSET 0x104 /* Read FIFO */
+#define XHI_SZ_OFFSET 0x108 /* Size Register */
+#define XHI_CR_OFFSET 0x10C /* Control Register */
+#define XHI_SR_OFFSET 0x110 /* Status Register */
+#define XHI_WFV_OFFSET 0x114 /* Write FIFO Vacancy Register */
+#define XHI_RFO_OFFSET 0x118 /* Read FIFO Occupancy Register */
+
+/* Device Global Interrupt Enable Register (GIER) bit definitions */
+
+#define XHI_GIER_GIE_MASK 0x80000000 /* Global Interrupt enable Mask */
+
+/**
+ * HwIcap Device Interrupt Status/Enable Registers
+ *
+ * Interrupt Status Register (IPISR) : This register holds the
+ * interrupt status flags for the device. These bits are toggle on
+ * write.
+ *
+ * Interrupt Enable Register (IPIER) : This register is used to enable
+ * interrupt sources for the device.
+ * Writing a '1' to a bit enables the corresponding interrupt.
+ * Writing a '0' to a bit disables the corresponding interrupt.
+ *
+ * IPISR/IPIER registers have the same bit definitions and are only defined
+ * once.
+ */
+#define XHI_IPIXR_RFULL_MASK 0x00000008 /* Read FIFO Full */
+#define XHI_IPIXR_WEMPTY_MASK 0x00000004 /* Write FIFO Empty */
+#define XHI_IPIXR_RDP_MASK 0x00000002 /* Read FIFO half full */
+#define XHI_IPIXR_WRP_MASK 0x00000001 /* Write FIFO half full */
+#define XHI_IPIXR_ALL_MASK 0x0000000F /* Mask of all interrupts */
+
+/* Control Register (CR) */
+#define XHI_CR_SW_RESET_MASK 0x00000008 /* SW Reset Mask */
+#define XHI_CR_FIFO_CLR_MASK 0x00000004 /* FIFO Clear Mask */
+#define XHI_CR_READ_MASK 0x00000002 /* Read from ICAP to FIFO */
+#define XHI_CR_WRITE_MASK 0x00000001 /* Write from FIFO to ICAP */
+
+/* Status Register (SR) */
+#define XHI_SR_CFGERR_N_MASK 0x00000100 /* Config Error Mask */
+#define XHI_SR_DALIGN_MASK 0x00000080 /* Data Alignment Mask */
+#define XHI_SR_RIP_MASK 0x00000040 /* Read back Mask */
+#define XHI_SR_IN_ABORT_N_MASK 0x00000020 /* Select Map Abort Mask */
+#define XHI_SR_DONE_MASK 0x00000001 /* Done bit Mask  */
+
+
+#define XHI_WFO_MAX_VACANCY 1024 /* Max Write FIFO Vacancy, in words */
+#define XHI_RFO_MAX_OCCUPANCY 256 /* Max Read FIFO Occupancy, in words */
+/* The maximum amount we can request from fifo_icap_get_configuration
+   at once, in bytes. */
+#define XHI_MAX_READ_TRANSACTION_WORDS 0xFFF
+
+
+/**
+ * fifo_icap_fifo_write: Write data to the write FIFO.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: the 32-bit value to be written to the FIFO.
+ *
+ * This function will silently fail if the fifo is full.
+ **/
+static inline void fifo_icap_fifo_write(struct hwicap_drvdata *drvdata,
+		u32 data)
+{
+	dev_dbg(drvdata->dev, "fifo_write: %x\n", data);
+	out_be32(drvdata->base_address + XHI_WF_OFFSET, data);
+}
+
+/**
+ * fifo_icap_fifo_read: Read data from the Read FIFO.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * This function will silently fail if the fifo is empty.
+ **/
+static inline u32 fifo_icap_fifo_read(struct hwicap_drvdata *drvdata)
+{
+	u32 data = in_be32(drvdata->base_address + XHI_RF_OFFSET);
+	dev_dbg(drvdata->dev, "fifo_read: %x\n", data);
+	return data;
+}
+
+/**
+ * fifo_icap_set_read_size: Set the the size register.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: the size of the following read transaction, in words.
+ **/
+static inline void fifo_icap_set_read_size(struct hwicap_drvdata *drvdata,
+		u32 data)
+{
+	out_be32(drvdata->base_address + XHI_SZ_OFFSET, data);
+}
+
+/**
+ * fifo_icap_start_config: Initiate a configuration (write) to the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ **/
+static inline void fifo_icap_start_config(struct hwicap_drvdata *drvdata)
+{
+	out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_WRITE_MASK);
+	dev_dbg(drvdata->dev, "configuration started\n");
+}
+
+/**
+ * fifo_icap_start_readback: Initiate a readback from the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ **/
+static inline void fifo_icap_start_readback(struct hwicap_drvdata *drvdata)
+{
+	out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_READ_MASK);
+	dev_dbg(drvdata->dev, "readback started\n");
+}
+
+/**
+ * fifo_icap_busy: Return true if the ICAP is still processing a transaction.
+ * @parameter drvdata: a pointer to the drvdata.
+ **/
+static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata)
+{
+	u32 status = in_be32(drvdata->base_address + XHI_SR_OFFSET);
+	dev_dbg(drvdata->dev, "Getting status = %x\n", status);
+	return (status & XHI_SR_DONE_MASK) ? 0 : 1;
+}
+
+/**
+ * fifo_icap_write_fifo_vacancy: Query the write fifo available space.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * Return the number of words that can be safely pushed into the write fifo.
+ **/
+static inline u32 fifo_icap_write_fifo_vacancy(
+		struct hwicap_drvdata *drvdata)
+{
+	return in_be32(drvdata->base_address + XHI_WFV_OFFSET);
+}
+
+/**
+ * fifo_icap_read_fifo_occupancy: Query the read fifo available data.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * Return the number of words that can be safely read from the read fifo.
+ **/
+static inline u32 fifo_icap_read_fifo_occupancy(
+		struct hwicap_drvdata *drvdata)
+{
+	return in_be32(drvdata->base_address + XHI_RFO_OFFSET);
+}
+
+/**
+ * fifo_icap_set_configuration: Send configuration data to the ICAP.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter frame_buffer: a pointer to the data to be written to the
+ *		ICAP device.
+ * @parameter num_words: the number of words (32 bit) to write to the ICAP
+ *		device.
+
+ * This function writes the given user data to the Write FIFO in
+ * polled mode and starts the transfer of the data to
+ * the ICAP device.
+ **/
+int fifo_icap_set_configuration(struct hwicap_drvdata *drvdata,
+		u32 *frame_buffer, u32 num_words)
+{
+
+	u32 write_fifo_vacancy = 0;
+	u32 retries = 0;
+	u32 remaining_words;
+
+	dev_dbg(drvdata->dev, "fifo_set_configuration\n");
+
+	/*
+	 * Check if the ICAP device is Busy with the last Read/Write
+	 */
+	if (fifo_icap_busy(drvdata))
+		return -EBUSY;
+
+	/*
+	 * Set up the buffer pointer and the words to be transferred.
+	 */
+	remaining_words = num_words;
+
+	while (remaining_words > 0) {
+		/*
+		 * Wait until we have some data in the fifo.
+		 */
+		while (write_fifo_vacancy == 0) {
+			write_fifo_vacancy =
+				fifo_icap_write_fifo_vacancy(drvdata);
+			retries++;
+			if (retries > XHI_MAX_RETRIES)
+				return -EIO;
+		}
+
+		/*
+		 * Write data into the Write FIFO.
+		 */
+		while ((write_fifo_vacancy != 0) &&
+				(remaining_words > 0)) {
+			fifo_icap_fifo_write(drvdata, *frame_buffer);
+
+			remaining_words--;
+			write_fifo_vacancy--;
+			frame_buffer++;
+		}
+		/* Start pushing whatever is in the FIFO into the ICAP. */
+		fifo_icap_start_config(drvdata);
+	}
+
+	/* Wait until the write has finished. */
+	while (fifo_icap_busy(drvdata)) {
+		retries++;
+		if (retries > XHI_MAX_RETRIES)
+			break;
+	}
+
+	dev_dbg(drvdata->dev, "done fifo_set_configuration\n");
+
+	/*
+	 * If the requested number of words have not been read from
+	 * the device then indicate failure.
+	 */
+	if (remaining_words != 0)
+		return -EIO;
+
+	return 0;
+}
+
+/**
+ * fifo_icap_get_configuration: Read configuration data from the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter data: Address of the data representing the partial bitstream
+ * @parameter size: the size of the partial bitstream in 32 bit words.
+ *
+ * This function reads the specified number of words from the ICAP device in
+ * the polled mode.
+ */
+int fifo_icap_get_configuration(struct hwicap_drvdata *drvdata,
+		u32 *frame_buffer, u32 num_words)
+{
+
+	u32 read_fifo_occupancy = 0;
+	u32 retries = 0;
+	u32 *data = frame_buffer;
+	u32 remaining_words;
+	u32 words_to_read;
+
+	dev_dbg(drvdata->dev, "fifo_get_configuration\n");
+
+	/*
+	 * Check if the ICAP device is Busy with the last Write/Read
+	 */
+	if (fifo_icap_busy(drvdata))
+		return -EBUSY;
+
+	remaining_words = num_words;
+
+	while (remaining_words > 0) {
+		words_to_read = remaining_words;
+		/* The hardware has a limit on the number of words
+		   that can be read at one time.  */
+		if (words_to_read > XHI_MAX_READ_TRANSACTION_WORDS)
+			words_to_read = XHI_MAX_READ_TRANSACTION_WORDS;
+
+		remaining_words -= words_to_read;
+
+		fifo_icap_set_read_size(drvdata, words_to_read);
+		fifo_icap_start_readback(drvdata);
+
+		while (words_to_read > 0) {
+			/* Wait until we have some data in the fifo. */
+			while (read_fifo_occupancy == 0) {
+				read_fifo_occupancy =
+					fifo_icap_read_fifo_occupancy(drvdata);
+				retries++;
+				if (retries > XHI_MAX_RETRIES)
+					return -EIO;
+			}
+
+			if (read_fifo_occupancy > words_to_read)
+				read_fifo_occupancy = words_to_read;
+
+			words_to_read -= read_fifo_occupancy;
+
+			/* Read the data from the Read FIFO. */
+			while (read_fifo_occupancy != 0) {
+				*data++ = fifo_icap_fifo_read(drvdata);
+				read_fifo_occupancy--;
+			}
+		}
+	}
+
+	dev_dbg(drvdata->dev, "done fifo_get_configuration\n");
+
+	return 0;
+}
+
+/**
+ * buffer_icap_reset: Reset the logic of the icap device.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * This function forces the software reset of the complete HWICAP device.
+ * All the registers will return to the default value and the FIFO is also
+ * flushed as a part of this software reset.
+ */
+void fifo_icap_reset(struct hwicap_drvdata *drvdata)
+{
+	u32 reg_data;
+	/*
+	 * Reset the device by setting/clearing the RESET bit in the
+	 * Control Register.
+	 */
+	reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET);
+
+	out_be32(drvdata->base_address + XHI_CR_OFFSET,
+				reg_data | XHI_CR_SW_RESET_MASK);
+
+	out_be32(drvdata->base_address + XHI_CR_OFFSET,
+				reg_data & (~XHI_CR_SW_RESET_MASK));
+
+}
+
+/**
+ * fifo_icap_flush_fifo: This function flushes the FIFOs in the device.
+ * @parameter drvdata: a pointer to the drvdata.
+ */
+void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata)
+{
+	u32 reg_data;
+	/*
+	 * Flush the FIFO by setting/clearing the FIFO Clear bit in the
+	 * Control Register.
+	 */
+	reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET);
+
+	out_be32(drvdata->base_address + XHI_CR_OFFSET,
+				reg_data | XHI_CR_FIFO_CLR_MASK);
+
+	out_be32(drvdata->base_address + XHI_CR_OFFSET,
+				reg_data & (~XHI_CR_FIFO_CLR_MASK));
+}
+
diff --git a/drivers/char/xilinx_hwicap/fifo_icap.h b/drivers/char/xilinx_hwicap/fifo_icap.h
new file mode 100644
index 0000000..4d3068d
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/fifo_icap.h
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ *
+ *     Author: Xilinx, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ *     AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ *     SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
+ *     OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ *     APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ *     THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ *     AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ *     FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
+ *     WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ *     IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ *     REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ *     INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE.
+ *
+ *     Xilinx products are not intended for use in life support appliances,
+ *     devices, or systems. Use in such applications is expressly prohibited.
+ *
+ *     (c) Copyright 2007-2008 Xilinx Inc.
+ *     All rights reserved.
+ *
+ *     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 XILINX_FIFO_ICAP_H_	/* prevent circular inclusions */
+#define XILINX_FIFO_ICAP_H_	/* by using protection macros */
+
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include "xilinx_hwicap.h"
+
+/* Reads integers from the device into the storage buffer. */
+int fifo_icap_get_configuration(
+		struct hwicap_drvdata *drvdata,
+		u32 *FrameBuffer,
+		u32 NumWords);
+
+/* Writes integers to the device from the storage buffer. */
+int fifo_icap_set_configuration(
+		struct hwicap_drvdata *drvdata,
+		u32 *FrameBuffer,
+		u32 NumWords);
+
+void fifo_icap_reset(struct hwicap_drvdata *drvdata);
+void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata);
+
+#endif
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
new file mode 100644
index 0000000..a55e6e1
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -0,0 +1,912 @@
+/*****************************************************************************
+ *
+ *     Author: Xilinx, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ *     AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ *     SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
+ *     OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ *     APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ *     THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ *     AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ *     FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
+ *     WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ *     IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ *     REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ *     INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE.
+ *
+ *     Xilinx products are not intended for use in life support appliances,
+ *     devices, or systems. Use in such applications is expressly prohibited.
+ *
+ *     (c) Copyright 2002 Xilinx Inc., Systems Engineering Group
+ *     (c) Copyright 2004 Xilinx Inc., Systems Engineering Group
+ *     (c) Copyright 2007-2008 Xilinx Inc.
+ *     All rights reserved.
+ *
+ *     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.
+ *
+ *****************************************************************************/
+
+/*
+ * This is the code behind /dev/xilinx_icap -- it allows a user-space
+ * application to use the Xilinx ICAP subsystem.
+ *
+ * The following operations are possible:
+ *
+ * open		open the port and initialize for access.
+ * release	release port
+ * write        Write a bitstream to the configuration processor.
+ * read         Read a data stream from the configuration processor.
+ *
+ * After being opened, the port is initialized and accessed to avoid a
+ * corrupted first read which may occur with some hardware.  The port
+ * is left in a desynched state, requiring that a synch sequence be
+ * transmitted before any valid configuration data.  A user will have
+ * exclusive access to the device while it remains open, and the state
+ * of the ICAP cannot be guaranteed after the device is closed.  Note
+ * that a complete reset of the core and the state of the ICAP cannot
+ * be performed on many versions of the cores, hence users of this
+ * device should avoid making inconsistent accesses to the device.  In
+ * particular, accessing the read interface, without first generating
+ * a write containing a readback packet can leave the ICAP in an
+ * inaccessible state.
+ *
+ * Note that in order to use the read interface, it is first necessary
+ * to write a request packet to the write interface.  i.e., it is not
+ * possible to simply readback the bitstream (or any configuration
+ * bits) from a device without specifically requesting them first.
+ * The code to craft such packets is intended to be part of the
+ * user-space application code that uses this device.  The simplest
+ * way to use this interface is simply:
+ *
+ * cp foo.bit /dev/xilinx_icap
+ *
+ * Note that unless foo.bit is an appropriately constructed partial
+ * bitstream, this has a high likelyhood of overwriting the design
+ * currently programmed in the FPGA.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/sysctl.h>
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_OF
+/* For open firmware. */
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#endif
+
+#include "xilinx_hwicap.h"
+#include "buffer_icap.h"
+#include "fifo_icap.h"
+
+#define DRIVER_NAME "xilinx_icap"
+
+#define HWICAP_REGS   (0x10000)
+
+/* dynamically allocate device number */
+static int xhwicap_major;
+static int xhwicap_minor;
+#define HWICAP_DEVICES 1
+
+module_param(xhwicap_major, int, S_IRUGO);
+module_param(xhwicap_minor, int, S_IRUGO);
+
+/* An array, which is set to true when the device is registered. */
+static bool probed_devices[HWICAP_DEVICES];
+
+static spinlock_t hwicap_spinlock = SPIN_LOCK_UNLOCKED;
+
+static struct class *icap_class;
+
+#define UNIMPLEMENTED 0xFFFF
+
+static const struct config_registers v2_config_registers = {
+	.CRC = 0,
+	.FAR = 1,
+	.FDRI = 2,
+	.FDRO = 3,
+	.CMD = 4,
+	.CTL = 5,
+	.MASK = 6,
+	.STAT = 7,
+	.LOUT = 8,
+	.COR = 9,
+	.MFWR = 10,
+	.FLR = 11,
+	.KEY = 12,
+	.CBC = 13,
+	.IDCODE = 14,
+	.AXSS = UNIMPLEMENTED,
+	.C0R_1 = UNIMPLEMENTED,
+	.CSOB = UNIMPLEMENTED,
+	.WBSTAR = UNIMPLEMENTED,
+	.TIMER = UNIMPLEMENTED,
+	.BOOTSTS = UNIMPLEMENTED,
+	.CTL_1 = UNIMPLEMENTED,
+};
+
+static const struct config_registers v4_config_registers = {
+	.CRC = 0,
+	.FAR = 1,
+	.FDRI = 2,
+	.FDRO = 3,
+	.CMD = 4,
+	.CTL = 5,
+	.MASK = 6,
+	.STAT = 7,
+	.LOUT = 8,
+	.COR = 9,
+	.MFWR = 10,
+	.FLR = UNIMPLEMENTED,
+	.KEY = UNIMPLEMENTED,
+	.CBC = 11,
+	.IDCODE = 12,
+	.AXSS = 13,
+	.C0R_1 = UNIMPLEMENTED,
+	.CSOB = UNIMPLEMENTED,
+	.WBSTAR = UNIMPLEMENTED,
+	.TIMER = UNIMPLEMENTED,
+	.BOOTSTS = UNIMPLEMENTED,
+	.CTL_1 = UNIMPLEMENTED,
+};
+static const struct config_registers v5_config_registers = {
+	.CRC = 0,
+	.FAR = 1,
+	.FDRI = 2,
+	.FDRO = 3,
+	.CMD = 4,
+	.CTL = 5,
+	.MASK = 6,
+	.STAT = 7,
+	.LOUT = 8,
+	.COR = 9,
+	.MFWR = 10,
+	.FLR = UNIMPLEMENTED,
+	.KEY = UNIMPLEMENTED,
+	.CBC = 11,
+	.IDCODE = 12,
+	.AXSS = 13,
+	.C0R_1 = 14,
+	.CSOB = 15,
+	.WBSTAR = 16,
+	.TIMER = 17,
+	.BOOTSTS = 18,
+	.CTL_1 = 19,
+};
+
+/**
+ * hwicap_command_desync: Send a DESYNC command to the ICAP port.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * This command desynchronizes the ICAP After this command, a
+ * bitstream containing a NULL packet, followed by a SYNCH packet is
+ * required before the ICAP will recognize commands.
+ */
+int hwicap_command_desync(struct hwicap_drvdata *drvdata)
+{
+	u32 buffer[4];
+	u32 index = 0;
+
+	/*
+	 * Create the data to be written to the ICAP.
+	 */
+	buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1;
+	buffer[index++] = XHI_CMD_DESYNCH;
+	buffer[index++] = XHI_NOOP_PACKET;
+	buffer[index++] = XHI_NOOP_PACKET;
+
+	/*
+	 * Write the data to the FIFO and intiate the transfer of data present
+	 * in the FIFO to the ICAP device.
+	 */
+	return drvdata->config->set_configuration(drvdata,
+			&buffer[0], index);
+}
+
+/**
+ * hwicap_command_capture: Send a CAPTURE command to the ICAP port.
+ * @parameter drvdata: a pointer to the drvdata.
+ *
+ * This command captures all of the flip flop states so they will be
+ * available during readback.  One can use this command instead of
+ * enabling the CAPTURE block in the design.
+ */
+int hwicap_command_capture(struct hwicap_drvdata *drvdata)
+{
+	u32 buffer[7];
+	u32 index = 0;
+
+	/*
+	 * Create the data to be written to the ICAP.
+	 */
+	buffer[index++] = XHI_DUMMY_PACKET;
+	buffer[index++] = XHI_SYNC_PACKET;
+	buffer[index++] = XHI_NOOP_PACKET;
+	buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1;
+	buffer[index++] = XHI_CMD_GCAPTURE;
+	buffer[index++] = XHI_DUMMY_PACKET;
+	buffer[index++] = XHI_DUMMY_PACKET;
+
+	/*
+	 * Write the data to the FIFO and intiate the transfer of data
+	 * present in the FIFO to the ICAP device.
+	 */
+	return drvdata->config->set_configuration(drvdata,
+			&buffer[0], index);
+
+}
+
+/**
+ * hwicap_get_configuration_register: Query a configuration register.
+ * @parameter drvdata: a pointer to the drvdata.
+ * @parameter reg: a constant which represents the configuration
+ *		register value to be returned.
+ * 		Examples:  XHI_IDCODE, XHI_FLR.
+ * @parameter RegData: returns the value of the register.
+ *
+ * Sends a query packet to the ICAP and then receives the response.
+ * The icap is left in Synched state.
+ */
+int hwicap_get_configuration_register(struct hwicap_drvdata *drvdata,
+		u32 reg, u32 *RegData)
+{
+	int status;
+	u32 buffer[6];
+	u32 index = 0;
+
+	/*
+	 * Create the data to be written to the ICAP.
+	 */
+	buffer[index++] = XHI_DUMMY_PACKET;
+	buffer[index++] = XHI_SYNC_PACKET;
+	buffer[index++] = XHI_NOOP_PACKET;
+	buffer[index++] = hwicap_type_1_read(reg) | 1;
+	buffer[index++] = XHI_NOOP_PACKET;
+	buffer[index++] = XHI_NOOP_PACKET;
+
+	/*
+	 * Write the data to the FIFO and intiate the transfer of data present
+	 * in the FIFO to the ICAP device.
+	 */
+	status = drvdata->config->set_configuration(drvdata,
+			&buffer[0], index);
+	if (status)
+		return status;
+
+	/*
+	 * Read the configuration register
+	 */
+	status = drvdata->config->get_configuration(drvdata, RegData, 1);
+	if (status)
+		return status;
+
+	return 0;
+}
+
+int hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata)
+{
+	int status;
+	u32 idcode;
+
+	dev_dbg(drvdata->dev, "initializing\n");
+
+	/* Abort any current transaction, to make sure we have the
+	 * ICAP in a good state. */
+	dev_dbg(drvdata->dev, "Reset...\n");
+	drvdata->config->reset(drvdata);
+
+	dev_dbg(drvdata->dev, "Desync...\n");
+	status = hwicap_command_desync(drvdata);
+	if (status)
+		return status;
+
+	/* Attempt to read the IDCODE from ICAP.  This
+	 * may not be returned correctly, due to the design of the
+	 * hardware.
+	 */
+	dev_dbg(drvdata->dev, "Reading IDCODE...\n");
+	status = hwicap_get_configuration_register(
+			drvdata, drvdata->config_regs->IDCODE, &idcode);
+	dev_dbg(drvdata->dev, "IDCODE = %x\n", idcode);
+	if (status)
+		return status;
+
+	dev_dbg(drvdata->dev, "Desync...\n");
+	status = hwicap_command_desync(drvdata);
+	if (status)
+		return status;
+
+	return 0;
+}
+
+static ssize_t
+hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	struct hwicap_drvdata *drvdata = file->private_data;
+	ssize_t bytes_to_read = 0;
+	u32 *kbuf;
+	u32 words;
+	u32 bytes_remaining;
+	int status;
+
+        spin_lock(&hwicap_spinlock);
+	if (drvdata->is_accessing)
+		return -EBUSY;
+	drvdata->is_accessing = 1;
+        spin_unlock(&hwicap_spinlock);
+
+	if (drvdata->read_buffer_in_use) {
+		/* If there are leftover bytes in the buffer, just */
+		/* return them and don't try to read more from the */
+		/* ICAP device. */
+		bytes_to_read =
+			(count < drvdata->read_buffer_in_use) ? count :
+			drvdata->read_buffer_in_use;
+
+		/* Return the data currently in the read buffer. */
+		if (copy_to_user(buf, drvdata->read_buffer, bytes_to_read)) {
+			status = -EFAULT;
+			goto error;
+		}
+		drvdata->read_buffer_in_use -= bytes_to_read;
+		memcpy(drvdata->read_buffer + bytes_to_read,
+				drvdata->read_buffer, 4 - bytes_to_read);
+	} else {
+		/* Get new data from the ICAP, and return was was requested. */
+		kbuf = (u32 *) get_zeroed_page(GFP_KERNEL);
+		if (!kbuf) {
+			status = -ENOMEM;
+			goto error;
+		}
+
+		/* The ICAP device is only able to read complete */
+		/* words.  If a number of bytes that do not correspond */
+		/* to complete words is requested, then we read enough */
+		/* words to get the required number of bytes, and then */
+		/* save the remaining bytes for the next read. */
+
+		/* Determine the number of words to read, rounding up */
+		/* if necessary. */
+		words = ((count + 3) >> 2);
+		bytes_to_read = words << 2;
+
+		if (bytes_to_read > PAGE_SIZE)
+			bytes_to_read = PAGE_SIZE;
+
+		/* Ensure we only read a complete number of words. */
+		bytes_remaining = bytes_to_read & 3;
+		bytes_to_read &= ~3;
+		words = bytes_to_read >> 2;
+
+		status = drvdata->config->get_configuration(drvdata,
+				kbuf, words);
+
+		/* If we didn't read correctly, then bail out. */
+		if (status) {
+			free_page((unsigned long)kbuf);
+			goto error;
+		}
+
+		/* If we fail to return the data to the user, then bail out. */
+		if (copy_to_user(buf, kbuf, bytes_to_read)) {
+			free_page((unsigned long)kbuf);
+			status = -EFAULT;
+			goto error;
+		}
+		memcpy(kbuf, drvdata->read_buffer, bytes_remaining);
+		drvdata->read_buffer_in_use = bytes_remaining;
+		free_page((unsigned long)kbuf);
+	}
+	status = bytes_to_read;
+ error:
+        spin_lock(&hwicap_spinlock);
+	drvdata->is_accessing = 0;
+        spin_unlock(&hwicap_spinlock);
+	return status;
+}
+
+static ssize_t
+hwicap_write(struct file *file, const char *buf,
+		size_t count, loff_t *ppos)
+{
+	struct hwicap_drvdata *drvdata = file->private_data;
+	ssize_t written = 0;
+	ssize_t left = count;
+	u32 *kbuf;
+	ssize_t len;
+	ssize_t status;
+
+        spin_lock(&hwicap_spinlock);
+	if (drvdata->is_accessing)
+		return -EBUSY;
+	drvdata->is_accessing = 1;
+        spin_unlock(&hwicap_spinlock);
+
+	left += drvdata->write_buffer_in_use;
+
+	/* Only write multiples of 4 bytes. */
+	if (left < 4) {
+		status = 0;
+		goto error;
+	}
+
+	kbuf = (u32 *) __get_free_page(GFP_KERNEL);
+	if (!kbuf) {
+		status = -ENOMEM;
+		goto error;
+	}
+
+	while (left > 3) {
+		/* only write multiples of 4 bytes, so there might */
+		/* be as many as 3 bytes left (at the end). */
+		len = left;
+
+		if (len > PAGE_SIZE)
+			len = PAGE_SIZE;
+		len &= ~3;
+
+		if (drvdata->write_buffer_in_use) {
+			memcpy(kbuf, drvdata->write_buffer,
+					drvdata->write_buffer_in_use);
+			if (copy_from_user(
+			    (((char *)kbuf) + (drvdata->write_buffer_in_use)),
+			    buf + written,
+			    len - (drvdata->write_buffer_in_use))) {
+				free_page((unsigned long)kbuf);
+				status = -EFAULT;
+				goto error;
+			}
+		} else {
+			if (copy_from_user(kbuf, buf + written, len)) {
+				free_page((unsigned long)kbuf);
+				status = -EFAULT;
+				goto error;
+			}
+		}
+
+		status = drvdata->config->set_configuration(drvdata,
+				kbuf, len >> 2);
+
+		if (status) {
+			free_page((unsigned long)kbuf);
+			status = -EFAULT;
+			goto error;
+		}
+		if (drvdata->write_buffer_in_use) {
+			len -= drvdata->write_buffer_in_use;
+			left -= drvdata->write_buffer_in_use;
+			drvdata->write_buffer_in_use = 0;
+		}
+		written += len;
+		left -= len;
+	}
+	if ((left > 0) && (left < 4)) {
+		if (!copy_from_user(drvdata->write_buffer,
+						buf + written, left)) {
+			drvdata->write_buffer_in_use = left;
+			written += left;
+			left = 0;
+		}
+	}
+
+	free_page((unsigned long)kbuf);
+	status = written;
+ error:
+        spin_lock(&hwicap_spinlock);
+	drvdata->is_accessing = 0;
+        spin_unlock(&hwicap_spinlock);
+	return status;
+}
+
+static int hwicap_open(struct inode *inode, struct file *file)
+{
+	struct hwicap_drvdata *drvdata;
+	int status;
+
+	drvdata = container_of(inode->i_cdev, struct hwicap_drvdata, cdev);
+
+        spin_lock(&hwicap_spinlock);
+	if (drvdata->is_open)
+		return -EBUSY;
+	drvdata->is_open = 1;
+	drvdata->is_accessing = 0;
+        spin_unlock(&hwicap_spinlock);
+
+	status = hwicap_initialize_hwicap(drvdata);
+	if (status) {
+		dev_err(drvdata->dev, "Failed to open file");
+		return status;
+	}
+
+	file->private_data = drvdata;
+	drvdata->write_buffer_in_use = 0;
+	drvdata->read_buffer_in_use = 0;
+
+	return 0;
+}
+
+static int hwicap_release(struct inode *inode, struct file *file)
+{
+	struct hwicap_drvdata *drvdata = file->private_data;
+	int i;
+	int status = 0;
+
+	if (drvdata->write_buffer_in_use) {
+		/* Flush write buffer. */
+		for (i = drvdata->write_buffer_in_use; i < 4; i++)
+			drvdata->write_buffer[i] = 0;
+
+		status = drvdata->config->set_configuration(drvdata,
+				(u32 *) drvdata->write_buffer, 1);
+		if (status)
+			goto error;
+	}
+
+	status = hwicap_command_desync(drvdata);
+	if (status)
+		goto error;
+
+ error:
+        spin_lock(&hwicap_spinlock);
+	drvdata->is_open = 0;
+        spin_unlock(&hwicap_spinlock);
+	return status;
+}
+
+static struct file_operations hwicap_fops = {
+	.owner = THIS_MODULE,
+	.write = hwicap_write,
+	.read = hwicap_read,
+	.open = hwicap_open,
+	.release = hwicap_release,
+};
+
+static int __devinit hwicap_setup(struct device *dev, int id,
+		const struct resource *regs_res,
+		const struct hwicap_driver_config *config,
+		const struct config_registers *config_regs)
+{
+	dev_t devt;
+	struct hwicap_drvdata *drvdata = NULL;
+	int retval = 0;
+
+	dev_info(dev, "Xilinx icap port driver\n");
+
+	if (id < 0) {
+		for (id = 0; id < HWICAP_DEVICES; id++)
+			if (!probed_devices[id])
+				break;
+	}
+	if (id < 0 || id >= HWICAP_DEVICES) {
+		dev_err(dev, "%s%i too large\n", DRIVER_NAME, id);
+		return -EINVAL;
+	}
+	if (probed_devices[id]) {
+		dev_err(dev, "cannot assign to %s%i; it is already in use\n",
+			DRIVER_NAME, id);
+		return -EBUSY;
+	}
+
+	probed_devices[id] = 1;
+
+	devt = MKDEV(xhwicap_major, xhwicap_minor + id);
+
+	drvdata = kmalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL);
+	if (!drvdata) {
+		dev_err(dev, "Couldn't allocate device private record\n");
+		return -ENOMEM;
+	}
+	memset((void *)drvdata, 0, sizeof(struct hwicap_drvdata));
+	dev_set_drvdata(dev, (void *)drvdata);
+
+	if (!regs_res) {
+		dev_err(dev, "Couldn't get registers resource\n");
+		retval = -EFAULT;
+		goto failed1;
+	}
+
+	drvdata->mem_start = regs_res->start;
+	drvdata->mem_end = regs_res->end;
+	drvdata->mem_size = regs_res->end - regs_res->start + 1;
+
+	if (!request_mem_region(drvdata->mem_start,
+					drvdata->mem_size, DRIVER_NAME)) {
+		dev_err(dev, "Couldn't lock memory region at %p\n",
+			(void *)regs_res->start);
+		retval = -EBUSY;
+		goto failed1;
+	}
+
+	drvdata->devt = devt;
+	drvdata->dev = dev;
+	drvdata->base_address = ioremap(drvdata->mem_start, drvdata->mem_size);
+	if (!drvdata->base_address) {
+		dev_err(dev, "ioremap() failed\n");
+		goto failed2;
+	}
+
+	drvdata->config = config;
+	drvdata->config_regs = config_regs;
+
+        spin_lock(&hwicap_spinlock);
+	drvdata->is_open = 0;
+	drvdata->is_accessing = 0;
+        spin_unlock(&hwicap_spinlock);
+
+	dev_info(dev, "ioremap %lx to %p with size %x\n",
+		 (unsigned long int)drvdata->mem_start,
+			drvdata->base_address, drvdata->mem_size);
+
+	cdev_init(&drvdata->cdev, &hwicap_fops);
+	drvdata->cdev.owner = THIS_MODULE;
+	retval = cdev_add(&drvdata->cdev, devt, 1);
+	if (retval) {
+		dev_err(dev, "cdev_add() failed\n");
+		goto failed3;
+	}
+	/*  devfs_mk_cdev(devt, S_IFCHR|S_IRUGO|S_IWUGO, DRIVER_NAME); */
+	class_device_create(icap_class, NULL, devt, NULL, DRIVER_NAME);
+	return 0;		/* success */
+
+ failed3:
+	iounmap(drvdata->base_address);
+
+ failed2:
+	release_mem_region(regs_res->start, drvdata->mem_size);
+
+ failed1:
+	kfree(drvdata);
+
+	return retval;
+}
+
+static struct hwicap_driver_config buffer_icap_config = {
+	.get_configuration = buffer_icap_get_configuration,
+	.set_configuration = buffer_icap_set_configuration,
+	.reset = buffer_icap_reset,
+};
+
+static struct hwicap_driver_config fifo_icap_config = {
+	.get_configuration = fifo_icap_get_configuration,
+	.set_configuration = fifo_icap_set_configuration,
+	.reset = fifo_icap_reset,
+};
+
+static int __devexit hwicap_remove(struct device *dev)
+{
+	struct hwicap_drvdata *drvdata;
+
+	drvdata = (struct hwicap_drvdata *)dev_get_drvdata(dev);
+
+	if (!drvdata)
+            return 0;
+        
+        class_device_destroy(icap_class, drvdata->devt);
+        cdev_del(&drvdata->cdev);
+        iounmap(drvdata->base_address);
+        release_mem_region(drvdata->mem_start, drvdata->mem_size);
+        kfree(drvdata);
+        dev_set_drvdata(dev, NULL);
+        probed_devices[MINOR(dev->devt)-xhwicap_minor] = 0;
+	
+	return 0;		/* success */
+}
+
+static int __devinit hwicap_drv_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	const struct config_registers *regs;
+	const char *family;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	/* It's most likely that we're using V4, if the family is not
+	   specified */
+	regs = &v4_config_registers;
+	family = pdev->dev.platform_data;
+
+	if (family) {
+		if (!strcmp(family, "virtex2p")) {
+			regs = &v2_config_registers;
+		} else if (!strcmp(family, "virtex4")) {
+			regs = &v4_config_registers;
+		} else if (!strcmp(family, "virtex5")) {
+			regs = &v5_config_registers;
+		}
+	}
+
+	return hwicap_setup(&pdev->dev, pdev->id, res,
+			&buffer_icap_config, regs);
+}
+
+static int __devexit hwicap_drv_remove(struct platform_device *pdev)
+{
+	return hwicap_remove(&pdev->dev);
+}
+
+static struct platform_driver hwicap_platform_driver = {
+	.probe = hwicap_drv_probe,
+	.remove = hwicap_drv_remove,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = DRIVER_NAME,
+	},
+};
+
+/* ---------------------------------------------------------------------
+ * OF bus binding
+ */
+
+#if defined(CONFIG_OF)
+static int __devinit
+hwicap_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+	struct resource res;
+	const unsigned int *id;
+	const char *family;
+	int rc;
+	const struct hwicap_driver_config *config = match->data;
+	const struct config_registers *regs;
+
+	dev_dbg(&op->dev, "hwicap_of_probe(%p, %p)\n", op, match);
+
+	rc = of_address_to_resource(op->node, 0, &res);
+	if (rc) {
+		dev_err(&op->dev, "invalid address\n");
+		return rc;
+	}
+
+	id = of_get_property(op->node, "port-number", NULL);
+
+	/* It's most likely that we're using V4, if the family is not
+	   specified */
+	regs = &v4_config_registers;
+	family = of_get_property(op->node, "xlnx,family", NULL);
+
+	if (family) {
+		if (!strcmp(family, "virtex2p")) {
+			regs = &v2_config_registers;
+		} else if (!strcmp(family, "virtex4")) {
+			regs = &v4_config_registers;
+		} else if (!strcmp(family, "virtex5")) {
+			regs = &v5_config_registers;
+		}
+	}
+	return hwicap_setup(&op->dev, id ? *id : -1, &res, config,
+			regs);
+}
+
+static int __devexit hwicap_of_remove(struct of_device *op)
+{
+	return hwicap_remove(&op->dev);
+}
+
+/* Match table for of_platform binding */
+static const struct of_device_id __devinit hwicap_of_match[] = {
+	{ .compatible = "xlnx,opb-hwicap-1.00.b", .data = &buffer_icap_config},
+	{ .compatible = "xlnx,xps-hwicap-1.00.a", .data = &fifo_icap_config},
+	{},
+};
+MODULE_DEVICE_TABLE(of, hwicap_of_match);
+
+static struct of_platform_driver hwicap_of_driver = {
+	.owner = THIS_MODULE,
+	.name = DRIVER_NAME,
+	.match_table = hwicap_of_match,
+	.probe = hwicap_of_probe,
+	.remove = __devexit_p(hwicap_of_remove),
+	.driver = {
+		.name = DRIVER_NAME,
+	},
+};
+
+/* Registration helpers to keep the number of #ifdefs to a minimum */
+static inline int __devinit hwicap_of_register(void)
+{
+	pr_debug("hwicap: calling of_register_platform_driver()\n");
+	return of_register_platform_driver(&hwicap_of_driver);
+}
+
+static inline void __devexit hwicap_of_unregister(void)
+{
+	of_unregister_platform_driver(&hwicap_of_driver);
+}
+#else /* CONFIG_OF */
+/* CONFIG_OF not enabled; do nothing helpers */
+static inline int __devinit hwicap_of_register(void) { return 0; }
+static inline void __devexit hwicap_of_unregister(void) { }
+#endif /* CONFIG_OF */
+
+static int __devinit hwicap_module_init(void)
+{
+	dev_t devt;
+	int retval;
+
+	icap_class = class_create(THIS_MODULE, "xilinx_config");
+
+	if (xhwicap_major) {
+		devt = MKDEV(xhwicap_major, xhwicap_minor);
+		retval = register_chrdev_region(
+				devt,
+				HWICAP_DEVICES,
+				DRIVER_NAME);
+		if (retval < 0)
+			return retval;
+	} else {
+		retval = alloc_chrdev_region(&devt,
+				xhwicap_minor,
+				HWICAP_DEVICES,
+				DRIVER_NAME);
+		if (retval < 0)
+			return retval;
+		xhwicap_major = MAJOR(devt);
+	}
+
+	retval = platform_driver_register(&hwicap_platform_driver);
+
+	if (retval)
+		goto failed1;
+
+	retval = hwicap_of_register();
+
+	if (retval)
+		goto failed2;
+
+	return retval;
+
+ failed2:
+	platform_driver_unregister(&hwicap_platform_driver);
+
+ failed1:
+	unregister_chrdev_region(devt, HWICAP_DEVICES);
+
+	return retval;
+}
+
+static void __devexit hwicap_module_cleanup(void)
+{
+	dev_t devt = MKDEV(xhwicap_major, xhwicap_minor);
+
+	class_destroy(icap_class);
+
+	platform_driver_unregister(&hwicap_platform_driver);
+
+	hwicap_of_unregister();
+
+	unregister_chrdev_region(devt, HWICAP_DEVICES);
+}
+
+module_init(hwicap_module_init);
+module_exit(hwicap_module_cleanup);
+
+MODULE_AUTHOR("Xilinx, Inc; Xilinx Research Labs Group");
+MODULE_DESCRIPTION("Xilinx ICAP Port Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.h b/drivers/char/xilinx_hwicap/xilinx_hwicap.h
new file mode 100644
index 0000000..b6b47d0
--- /dev/null
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.h
@@ -0,0 +1,193 @@
+/*****************************************************************************
+ *
+ *     Author: Xilinx, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation; either version 2 of the License, or (at your
+ *     option) any later version.
+ *
+ *     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
+ *     AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
+ *     SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
+ *     OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
+ *     APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
+ *     THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
+ *     AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
+ *     FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
+ *     WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
+ *     IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
+ *     REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
+ *     INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *     FOR A PARTICULAR PURPOSE.
+ *
+ *     Xilinx products are not intended for use in life support appliances,
+ *     devices, or systems. Use in such applications is expressly prohibited.
+ *
+ *     (c) Copyright 2003-2007 Xilinx Inc.
+ *     All rights reserved.
+ *
+ *     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 XILINX_HWICAP_H_	/* prevent circular inclusions */
+#define XILINX_HWICAP_H_	/* by using protection macros */
+
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+struct hwicap_drvdata {
+	u32 write_buffer_in_use;  /* Always in [0,3] */
+	u8 write_buffer[4];
+	u32 read_buffer_in_use;	  /* Always in [0,3] */
+	u8 read_buffer[4];
+	u32 mem_start;		  /* phys. address of the control registers */
+	u32 mem_end;		  /* phys. address of the control registers */
+	u32 mem_size;
+	void __iomem *base_address;/* virt. address of the control registers */
+
+	struct device *dev;
+	struct cdev cdev;	/* Char device structure */
+	dev_t devt;
+
+	const struct hwicap_driver_config *config;
+	const struct config_registers *config_regs;
+	void *private_data;
+	bool is_open;
+	bool is_accessing;
+};
+
+struct hwicap_driver_config {
+	int (*get_configuration)(struct hwicap_drvdata *drvdata, u32 *data,
+			u32 size);
+	int (*set_configuration)(struct hwicap_drvdata *drvdata, u32 *data,
+			u32 size);
+	void (*reset)(struct hwicap_drvdata *drvdata);
+};
+
+/* Number of times to poll the done regsiter */
+#define XHI_MAX_RETRIES     10
+
+/************ Constant Definitions *************/
+
+#define XHI_PAD_FRAMES              0x1
+
+/* Mask for calculating configuration packet headers */
+#define XHI_WORD_COUNT_MASK_TYPE_1  0x7FFUL
+#define XHI_WORD_COUNT_MASK_TYPE_2  0x1FFFFFUL
+#define XHI_TYPE_MASK               0x7
+#define XHI_REGISTER_MASK           0xF
+#define XHI_OP_MASK                 0x3
+
+#define XHI_TYPE_SHIFT              29
+#define XHI_REGISTER_SHIFT          13
+#define XHI_OP_SHIFT                27
+
+#define XHI_TYPE_1                  1
+#define XHI_TYPE_2                  2
+#define XHI_OP_WRITE                2
+#define XHI_OP_READ                 1
+
+/* Address Block Types */
+#define XHI_FAR_CLB_BLOCK           0
+#define XHI_FAR_BRAM_BLOCK          1
+#define XHI_FAR_BRAM_INT_BLOCK      2
+
+struct config_registers {
+	u32 CRC;
+	u32 FAR;
+	u32 FDRI;
+	u32 FDRO;
+	u32 CMD;
+	u32 CTL;
+	u32 MASK;
+	u32 STAT;
+	u32 LOUT;
+	u32 COR;
+	u32 MFWR;
+	u32 FLR;
+	u32 KEY;
+	u32 CBC;
+	u32 IDCODE;
+	u32 AXSS;
+	u32 C0R_1;
+	u32 CSOB;
+	u32 WBSTAR;
+	u32 TIMER;
+	u32 BOOTSTS;
+	u32 CTL_1;
+};
+
+/* Configuration Commands */
+#define XHI_CMD_NULL                0
+#define XHI_CMD_WCFG                1
+#define XHI_CMD_MFW                 2
+#define XHI_CMD_DGHIGH              3
+#define XHI_CMD_RCFG                4
+#define XHI_CMD_START               5
+#define XHI_CMD_RCAP                6
+#define XHI_CMD_RCRC                7
+#define XHI_CMD_AGHIGH              8
+#define XHI_CMD_SWITCH              9
+#define XHI_CMD_GRESTORE            10
+#define XHI_CMD_SHUTDOWN            11
+#define XHI_CMD_GCAPTURE            12
+#define XHI_CMD_DESYNCH             13
+#define XHI_CMD_IPROG               15 /* Only in Virtex5 */
+#define XHI_CMD_CRCC                16 /* Only in Virtex5 */
+#define XHI_CMD_LTIMER              17 /* Only in Virtex5 */
+
+/* Packet constants */
+#define XHI_SYNC_PACKET             0xAA995566UL
+#define XHI_DUMMY_PACKET            0xFFFFFFFFUL
+#define XHI_NOOP_PACKET             (XHI_TYPE_1 << XHI_TYPE_SHIFT)
+#define XHI_TYPE_2_READ ((XHI_TYPE_2 << XHI_TYPE_SHIFT) | \
+			(XHI_OP_READ << XHI_OP_SHIFT))
+
+#define XHI_TYPE_2_WRITE ((XHI_TYPE_2 << XHI_TYPE_SHIFT) | \
+			(XHI_OP_WRITE << XHI_OP_SHIFT))
+
+#define XHI_TYPE2_CNT_MASK          0x07FFFFFF
+
+#define XHI_TYPE_1_PACKET_MAX_WORDS 2047UL
+#define XHI_TYPE_1_HEADER_BYTES     4
+#define XHI_TYPE_2_HEADER_BYTES     8
+
+/* Constant to use for CRC check when CRC has been disabled */
+#define XHI_DISABLED_AUTO_CRC       0x0000DEFCUL
+
+/**
+ * hwicap_type_1_read: Generates a Type 1 read packet header.
+ * @parameter: Register is the address of the register to be read back.
+ *
+ * Generates a Type 1 read packet header, which is used to indirectly
+ * read registers in the configuration logic.  This packet must then
+ * be sent through the icap device, and a return packet received with
+ * the information.
+ **/
+static inline u32 hwicap_type_1_read(u32 Register)
+{
+	return (XHI_TYPE_1 << XHI_TYPE_SHIFT) |
+		(Register << XHI_REGISTER_SHIFT) |
+		(XHI_OP_READ << XHI_OP_SHIFT);
+}
+
+/**
+ * hwicap_type_1_write: Generates a Type 1 write packet header
+ * @parameter: Register is the address of the register to be read back.
+ **/
+static inline u32 hwicap_type_1_write(u32 Register)
+{
+	return (XHI_TYPE_1 << XHI_TYPE_SHIFT) |
+		(Register << XHI_REGISTER_SHIFT) |
+		(XHI_OP_WRITE << XHI_OP_SHIFT);
+}
+
+#endif
-- 
1.5.3.4-dirty




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

^ permalink raw reply related

* [PATCH powerpc] Fake NUMA emulation for PowerPC (Take 4)
From: Balbir Singh @ 2008-02-01  4:57 UTC (permalink / raw)
  To: Michael Ellerman, Paul Mackerras; +Cc: linuxppc-dev, LKML
In-Reply-To: <1201611898.26410.7.camel@concordia>

* Michael Ellerman <michael@ellerman.id.au> [2008-01-30 00:04:58]:

> Why do you check !p after assigning to nid? I assume it's because we
> might have reached the end of the command line, ie. p == NULL, but we're
> still adding memory to the last node? If so it's a it's a little subtle
> and deserves a comment I think.
> 
> Otherwise this looks pretty good.
> 
> cheers
> 

Hi, Paul,

Could you please consider version 4 for inclusion?


Changelong v4

1. Add more comments around the checks for command line arguments.

Changelog v3
1. Remove the side-effect of not setting nodes online if they end
   up having no memory in them because of the memory limit.

Changelog v2

1. Get rid of the constant 5 (based on comments from
                                Geert.Uytterhoeven@sonycom.com)
2. Implement suggestions from Olof Johannson
3. Check if cmdline is NULL in fake_numa_create_new_node()

Tested with additional parameters from Olof

numa=debug,fake=
numa=foo,fake=bar


Here's a dumb simple implementation of fake NUMA nodes for PowerPC. Fake
NUMA nodes can be specified using the following command line option

numa=fake=<node range>

node range is of the format <range1>,<range2>,...<rangeN>

Each of the rangeX parameters is passed using memparse(). I find the patch
useful for fake NUMA emulation on my simple PowerPC machine. I've tested it
on a numa box with the following arguments

numa=fake=512M
numa=fake=512M,768M
numa=fake=256M,512M mem=512M
numa=fake=1G mem=768M
numa=fake=
without any numa= argument

The other side-effect introduced by this patch is that; in the case where we
don't have NUMA information, we now set a node online after adding each LMB.
This node could very well be node 0, but in the case that we enable fake
NUMA nodes, when we cross node boundaries, we need to set the new node online.


Signed-off-by: Balbir Singh <balbir@linux.vnet.ibm.com>
---

 arch/powerpc/mm/numa.c |   66 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 63 insertions(+), 3 deletions(-)

diff -puN arch/powerpc/mm/numa.c~fakenumappc arch/powerpc/mm/numa.c
--- linux-2.6.24-rc8/arch/powerpc/mm/numa.c~fakenumappc	2008-01-28 17:05:34.000000000 +0530
+++ linux-2.6.24-rc8-balbir/arch/powerpc/mm/numa.c	2008-02-01 10:24:57.000000000 +0530
@@ -24,6 +24,8 @@
 
 static int numa_enabled = 1;
 
+static char *cmdline __initdata;
+
 static int numa_debug;
 #define dbg(args...) if (numa_debug) { printk(KERN_INFO args); }
 
@@ -39,6 +41,53 @@ static bootmem_data_t __initdata plat_no
 static int min_common_depth;
 static int n_mem_addr_cells, n_mem_size_cells;
 
+static int __cpuinit fake_numa_create_new_node(unsigned long end_pfn,
+						unsigned int *nid)
+{
+	unsigned long long mem;
+	char *p = cmdline;
+	static unsigned int fake_nid;
+	static unsigned long long curr_boundary;
+
+	/*
+	 * Modify node id, iff we started creating NUMA nodes
+	 * We want to continue from where we left of the last time
+	 */
+	if (fake_nid)
+		*nid = fake_nid;
+	/*
+	 * In case there are no more arguments to parse, the
+	 * node_id should be the same as the last fake node id
+	 * (we've handled this above).
+	 */
+	if (!p)
+		return 0;
+
+	mem = memparse(p, &p);
+	if (!mem)
+		return 0;
+
+	if (mem < curr_boundary)
+		return 0;
+
+	curr_boundary = mem;
+
+	if ((end_pfn << PAGE_SHIFT) > mem) {
+		/*
+		 * Skip commas and spaces
+		 */
+		while (*p == ',' || *p == ' ' || *p == '\t')
+			p++;
+
+		cmdline = p;
+		fake_nid++;
+		*nid = fake_nid;
+		dbg("created new fake_node with id %d\n", fake_nid);
+		return 1;
+	}
+	return 0;
+}
+
 static void __cpuinit map_cpu_to_node(int cpu, int node)
 {
 	numa_cpu_lookup_table[cpu] = node;
@@ -344,6 +393,9 @@ static void __init parse_drconf_memory(s
 			if (nid == 0xffff || nid >= MAX_NUMNODES)
 				nid = default_nid;
 		}
+
+		fake_numa_create_new_node(((start + lmb_size) >> PAGE_SHIFT),
+						&nid);
 		node_set_online(nid);
 
 		size = numa_enforce_memory_limit(start, lmb_size);
@@ -429,6 +481,8 @@ new_range:
 		nid = of_node_to_nid_single(memory);
 		if (nid < 0)
 			nid = default_nid;
+
+		fake_numa_create_new_node(((start + size) >> PAGE_SHIFT), &nid);
 		node_set_online(nid);
 
 		if (!(size = numa_enforce_memory_limit(start, size))) {
@@ -461,7 +515,7 @@ static void __init setup_nonnuma(void)
 	unsigned long top_of_ram = lmb_end_of_DRAM();
 	unsigned long total_ram = lmb_phys_mem_size();
 	unsigned long start_pfn, end_pfn;
-	unsigned int i;
+	unsigned int i, nid = 0;
 
 	printk(KERN_DEBUG "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
 	       top_of_ram, total_ram);
@@ -471,9 +525,11 @@ static void __init setup_nonnuma(void)
 	for (i = 0; i < lmb.memory.cnt; ++i) {
 		start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT;
 		end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i);
-		add_active_range(0, start_pfn, end_pfn);
+
+		fake_numa_create_new_node(end_pfn, &nid);
+		add_active_range(nid, start_pfn, end_pfn);
+		node_set_online(nid);
 	}
-	node_set_online(0);
 }
 
 void __init dump_numa_cpu_topology(void)
@@ -702,6 +758,10 @@ static int __init early_numa(char *p)
 	if (strstr(p, "debug"))
 		numa_debug = 1;
 
+	p = strstr(p, "fake=");
+	if (p)
+		cmdline = p + strlen("fake=");
+
 	return 0;
 }
 early_param("numa", early_numa);
_

-- 
	Warm Regards,
	Balbir Singh
	Linux Technology Center
	IBM, ISTL

^ permalink raw reply

* RE: [PATCH 1/2] Add RapidIO node into MPC8641HPCN dts file
From: Zhang Wei @ 2008-02-01  4:51 UTC (permalink / raw)
  To: Loeliger Jon; +Cc: linuxppc-dev
In-Reply-To: <47A1F73E.3090600@freescale.com>

Hi, Jon,=20

> -----Original Message-----
> From: Loeliger Jon=20
>=20
> Zhang Wei wrote:
> > Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
> > ---
> >  arch/powerpc/boot/dts/mpc8641_hpcn.dts |   13 +++++++++++++
> >  1 files changed, 13 insertions(+), 0 deletions(-)
> >=20
> > diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts=20
> b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
> > index 556a9ca..1a0fce5 100644
> > --- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
> > +++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
> > @@ -25,6 +25,7 @@
> >  		serial1 =3D &serial1;
> >  		pci0 =3D &pci0;
> >  		pci1 =3D &pci1;
> > +		rapidio0 =3D &rapidio0;
> >  	};
> > =20
> >  	cpus {
> > @@ -499,4 +500,16 @@
> >  				  0 00100000>;
> >  		};
> >  	};
> > +
> > +	rapidio0: rapidio@f80c0000 {
> > +		#address-cells =3D <2>;
> > +		#size-cells =3D <2>;
> > +		compatible =3D "fsl,rapidio-delta";
> > +		reg =3D <f80c0000 20000>;
> > +		ranges =3D <0 0 c0000000 0 20000000>;
> > +		interrupt-parent =3D <&mpic>;
> > +		/* err_irq bell_outb_irq bell_inb_irq
> > +			msg1_tx_irq msg1_rx_irq	msg2_tx_irq=20
> msg2_rx_irq */
> > +		interrupts =3D <30 2 31 2 32 2 35 2 36 2 37 2 38 2>;
> > +	};
> >  };
>=20
> The 8641 DTS file has been converted to /dts-v1/ format now.
> Please rewrite this patch with explicit hex numbers for
> addresses, even if 0x0, and decimal for IRQs.
>=20
I have seen other nodes in mpc8641_hpcn.dts still use old style.
 Is it better to create an another new patch for correcting the style =
all?

Cheers!
Wei

^ permalink raw reply

* RE: [PATCH 4/6] Add multi mport support.
From: Zhang Wei @ 2008-02-01  4:06 UTC (permalink / raw)
  To: pterry; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <1201804525.14266.45.camel@pterry-fc6.micromemory.com>

Hi, Phil,

> -----Original Message-----
> From: Phil Terry [mailto:pterry@micromemory.com]=20
>=20
> On Thu, 2008-01-31 at 14:30 +0800, Zhang Wei wrote:
> > =20
> > > >
> > I consider each RIO controller will has its own network,=20
> the device IDs
> > should be
> > unique only in its port network.
> Hmmm, I see two cases:

Good questions! They are very important and also my concern now.

>=20
> 1. I have two mport to two controllers each connected to different
> physical fabrics. This system can act as an application bridge between
> the two fabrics.
>=20

The current driver just looks two mport as two independent fabrics.
We can add bridge driver to implement your idea.

> 2. I have two mports to two controllers each connected directly or
> indirectly to the same fabric. I want to use the extra bandwidth and
> load balance and/or have a fall back redundant connection via an
> alternate physical connection to the fabric etc.
>=20

That's a terrible thing in the current driver. Two mports get the same
 ID in one fabric. About the port bound, it's a good idea, I also need
 a new driver to support it.

In fact, our first mission is to make the RapidIO driver ported from ppc
to powerpc can
 be compiled and run. Fortunately, there is no more than one port in
processor now,
 we have time to implement it.

> What should be the rules for allocating the initial IDs to the two
> mports to allow system wide enumeration to work in both of the above
> cases?=20
>=20

A choice is add ID option into dts node. I have some ideas about RapidIO
 driver in u-boot. U-boot can assign ID in dts and tell kernel.

> What do you expect the semantics of higher level addressing to be:
>  a pair <mport,id>, where <x,n> is a different device from <y,n>,
>  a pair <mport,id>, where <x,n> is the same device as <y,n>,or
>  a singleton n, where n is unique and identifies the first=20
> routing step
> of which controller, x or y, to use.

It seems the address pair is a must-be selection as pci bus.
But now, no connection between ports. Every operations in only
 in its own port view.

> I smell a can of worms.... :-)

A good nose! Thanks! :)

Cheers!
Wei

^ permalink raw reply

* Re: Reminder: removal of arch/ppc
From: Kumar Gala @ 2008-02-01  3:33 UTC (permalink / raw)
  To: Mark A. Greer; +Cc: linuxppc-dev list, linuxppc-embedded
In-Reply-To: <20080131225446.GA9633@mag.az.mvista.com>


On Jan 31, 2008, at 4:54 PM, Mark A. Greer wrote:

> On Fri, Jan 25, 2008 at 10:55:25AM -0600, Kumar Gala wrote:
>> Just a reminder that the plan is to remove arch/ppc this summer (June
>> 2008).  The following boards still existing over in arch/ppc.  Some  
>> of
>> them have been ported over to arch/powerpc.  If you care about one of
>> these boards and its not ported speak up (it helps if you have access
>> to the board).  Also, if you know a given board is free to die of
>> bitrot let us know so we know not to worry about it:
>
> I guess I'm just not a nice guy but I say let them die.  No need
> to worry.  The code really isn't going anywhere -- git-checkout
> v2.6.<pick your favorite version> and its back.
>
> /me's $0.02.

this is where I poke you about the sandpoint port ;)

- k

^ permalink raw reply

* Re: [PATCH 1/2] Add RapidIO node into MPC8641HPCN dts file
From: Kumar Gala @ 2008-02-01  3:32 UTC (permalink / raw)
  To: Zhang Wei; +Cc: linuxppc-dev
In-Reply-To: <ABF87B0B6A38C0458E319AC973ED68AEBD089C@zch01exm26.fsl.freescale.net>


On Jan 31, 2008, at 9:21 PM, Zhang Wei wrote:

>
>
>> -----Original Message-----
>> From: Loeliger Jon
>>
>> Zhang Wei wrote:
>>> Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
>>> ---
>>> arch/powerpc/boot/dts/mpc8641_hpcn.dts |   13 +++++++++++++
>>> 1 files changed, 13 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
>> b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
>>> index 556a9ca..1a0fce5 100644
>>> --- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
>>> +++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
>>
>>> @@ -499,4 +500,16 @@
>>> 				  0 00100000>;
>>> 		};
>>> 	};
>>> +
>>> +	rapidio0: rapidio@f80c0000 {
>>> +		#address-cells = <2>;
>>> +		#size-cells = <2>;
>>> +		compatible = "fsl,rapidio-delta";
>>> +		reg = <f80c0000 20000>;
>>> +		ranges = <0 0 c0000000 0 20000000>;
>>> +		interrupt-parent = <&mpic>;
>>> +		/* err_irq bell_outb_irq bell_inb_irq
>>> +			msg1_tx_irq msg1_rx_irq	msg2_tx_irq
>> msg2_rx_irq */
>>> +		interrupts = <30 2 31 2 32 2 35 2 36 2 37 2 38 2>;
>>> +	};
>>> };
>>
>> Have updates to the booting-without-of.txt file for
>> been made or proposed for the RapidIO node definition?
>>
> I remember Kumar has a patch for RapidIO node of booting-without- 
> of.txt, is it?

I do.. I'll post it and update the .dts patch once I sort through all  
the patches.

- k

^ permalink raw reply

* RE: [PATCH 1/2] Add RapidIO node into MPC8641HPCN dts file
From: Zhang Wei @ 2008-02-01  3:21 UTC (permalink / raw)
  To: Loeliger Jon; +Cc: linuxppc-dev
In-Reply-To: <47A1FEB4.1040806@freescale.com>

=20

> -----Original Message-----
> From: Loeliger Jon=20
>=20
> Zhang Wei wrote:
> > Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
> > ---
> >  arch/powerpc/boot/dts/mpc8641_hpcn.dts |   13 +++++++++++++
> >  1 files changed, 13 insertions(+), 0 deletions(-)
> >=20
> > diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts=20
> b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
> > index 556a9ca..1a0fce5 100644
> > --- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
> > +++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
>=20
> > @@ -499,4 +500,16 @@
> >  				  0 00100000>;
> >  		};
> >  	};
> > +
> > +	rapidio0: rapidio@f80c0000 {
> > +		#address-cells =3D <2>;
> > +		#size-cells =3D <2>;
> > +		compatible =3D "fsl,rapidio-delta";
> > +		reg =3D <f80c0000 20000>;
> > +		ranges =3D <0 0 c0000000 0 20000000>;
> > +		interrupt-parent =3D <&mpic>;
> > +		/* err_irq bell_outb_irq bell_inb_irq
> > +			msg1_tx_irq msg1_rx_irq	msg2_tx_irq=20
> msg2_rx_irq */
> > +		interrupts =3D <30 2 31 2 32 2 35 2 36 2 37 2 38 2>;
> > +	};
> >  };
>=20
> Have updates to the booting-without-of.txt file for
> been made or proposed for the RapidIO node definition?
>=20
I remember Kumar has a patch for RapidIO node of booting-without-of.txt, =
is it?

Cheers!
Wei.

^ permalink raw reply

* RE: [PATCH 1/2] Add RapidIO node into MPC8641HPCN dts file
From: Zhang Wei @ 2008-02-01  3:19 UTC (permalink / raw)
  To: Loeliger Jon; +Cc: linuxppc-dev
In-Reply-To: <47A1F73E.3090600@freescale.com>

Hi, Jon,=20

> -----Original Message-----
> From: Loeliger Jon=20
>=20
> Zhang Wei wrote:
> > Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
> > ---
> >  arch/powerpc/boot/dts/mpc8641_hpcn.dts |   13 +++++++++++++
> >  1 files changed, 13 insertions(+), 0 deletions(-)
> >=20
> > diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts=20
> b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
> > index 556a9ca..1a0fce5 100644
> > --- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
> > +++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
> > @@ -25,6 +25,7 @@
> >  		serial1 =3D &serial1;
> >  		pci0 =3D &pci0;
> >  		pci1 =3D &pci1;
> > +		rapidio0 =3D &rapidio0;
> >  	};
> > =20
> >  	cpus {
> > @@ -499,4 +500,16 @@
> >  				  0 00100000>;
> >  		};
> >  	};
> > +
> > +	rapidio0: rapidio@f80c0000 {
> > +		#address-cells =3D <2>;
> > +		#size-cells =3D <2>;
> > +		compatible =3D "fsl,rapidio-delta";
> > +		reg =3D <f80c0000 20000>;
> > +		ranges =3D <0 0 c0000000 0 20000000>;
> > +		interrupt-parent =3D <&mpic>;
> > +		/* err_irq bell_outb_irq bell_inb_irq
> > +			msg1_tx_irq msg1_rx_irq	msg2_tx_irq=20
> msg2_rx_irq */
> > +		interrupts =3D <30 2 31 2 32 2 35 2 36 2 37 2 38 2>;
> > +	};
> >  };
>=20
> The 8641 DTS file has been converted to /dts-v1/ format now.
> Please rewrite this patch with explicit hex numbers for
> addresses, even if 0x0, and decimal for IRQs.
>=20

Thanks! I'm dropped by fashion. :) I'll re-do them.

Cheers!
Wei.

^ permalink raw reply

* Re: [PATCH 0/5] ehea checkpatch fixups
From: Nathan Lynch @ 2008-02-01  3:05 UTC (permalink / raw)
  To: Doug Maxey
  Cc: Linux PowerPC List, Jan-Bernd Themann, Jeff Garzik,
	Paul Mackerras, netdev
In-Reply-To: <1201832451-23634-1-git-send-email-dwm@austin.ibm.com>

Doug Maxey wrote:
> 
> A small set of fixups for checkpatch.
> 
> Based on upstream pull from a few hours ago.

Er, ehea doesn't even build right now[1], maybe that could get fixed
first?  :-)

[1] http://lkml.org/lkml/2008/1/28/337

^ permalink raw reply

* [PATCH 1/5] ehea: fix ehea.h checkpatch complaints
From: Doug Maxey @ 2008-02-01  2:20 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Linux PowerPC List, netdev, Paul Mackerras, Jan-Bernd Themann
In-Reply-To: <1201832451-23634-1-git-send-email-dwm@austin.ibm.com>

Cc: Jan-Bernd Themann <themann@de.ibm.com>
Signed-off-by: Doug Maxey <dwm@austin.ibm.com>
---
 drivers/net/ehea/ehea.h    |    3 +++
 drivers/net/ehea/ehea_hw.h |    8 ++++----
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 5f82a46..88fb53e 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -458,4 +458,7 @@ void ehea_set_ethtool_ops(struct net_device *netdev);
 int ehea_sense_port_attr(struct ehea_port *port);
 int ehea_set_portspeed(struct ehea_port *port, u32 port_speed);
 
+extern u64 ehea_driver_flags;
+extern struct work_struct ehea_rereg_mr_task;
+
 #endif	/* __EHEA_H__ */
diff --git a/drivers/net/ehea/ehea_hw.h b/drivers/net/ehea/ehea_hw.h
index 1af7ca4..567981b 100644
--- a/drivers/net/ehea/ehea_hw.h
+++ b/drivers/net/ehea/ehea_hw.h
@@ -29,10 +29,10 @@
 #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 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)
 
-- 
1.5.3.8

^ permalink raw reply related

* [PATCH 3/5] ehea: fix main checkpatch complaints
From: Doug Maxey @ 2008-02-01  2:20 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Linux PowerPC List, netdev, Paul Mackerras, Jan-Bernd Themann
In-Reply-To: <1201832451-23634-1-git-send-email-dwm@austin.ibm.com>

Cc: Jan-Bernd Themann <themann@de.ibm.com>
Signed-off-by: Doug Maxey <dwm@austin.ibm.com>
---
 drivers/net/ehea/ehea_main.c |   87 ++++++++++++++++++++++--------------------
 1 files changed, 46 insertions(+), 41 deletions(-)

diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 869e160..99ea46a 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -6,9 +6,9 @@
  *  (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>
+ *	 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
@@ -54,11 +54,11 @@ 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;
-static int use_mcs = 0;
-static int use_lro = 0;
+static int use_mcs;
+static int use_lro;
 static int lro_max_aggr = EHEA_LRO_MAX_AGGR;
 static int num_tx_qps = EHEA_NUM_TX_QP;
-static int prop_carrier_state = 0;
+static int prop_carrier_state;
 
 module_param(msg_level, int, 0);
 module_param(rq1_entries, int, 0);
@@ -94,9 +94,9 @@ MODULE_PARM_DESC(lro_max_aggr, " LRO: Max packets to be aggregated. Default = "
 MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, "
 		 "Default = 0");
 
-static int port_name_cnt = 0;
+static int port_name_cnt;
 static LIST_HEAD(adapter_list);
-u64 ehea_driver_flags = 0;
+u64 ehea_driver_flags;
 struct work_struct ehea_rereg_mr_task;
 
 struct semaphore dlpar_mem_lock;
@@ -121,12 +121,13 @@ static struct of_platform_driver ehea_driver = {
 	.remove = ehea_remove,
 };
 
-void ehea_dump(void *adr, int len, char *msg) {
+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, x, *((u64 *)&deb[0]), *((u64 *)&deb[8]));
 		deb += 16;
 	}
 }
@@ -518,7 +519,8 @@ static int ehea_proc_rwqes(struct net_device *dev,
 		last_wqe_index = wqe_index;
 		rmb();
 		if (!ehea_check_cqe(cqe, &rq)) {
-			if (rq == 1) {	/* LL RQ1 */
+			if (rq == 1) {
+				/* LL RQ1 */
 				skb = get_skb_by_index_ll(skb_arr_rq1,
 							  skb_arr_rq1_len,
 							  wqe_index);
@@ -531,10 +533,11 @@ static int ehea_proc_rwqes(struct net_device *dev,
 					if (!skb)
 						break;
 				}
-				skb_copy_to_linear_data(skb, ((char*)cqe) + 64,
+				skb_copy_to_linear_data(skb, ((char *)cqe) + 64,
 						 cqe->num_bytes_transfered - 4);
 				ehea_fill_skb(dev, skb, cqe);
-			} else if (rq == 2) {  /* RQ2 */
+			} else if (rq == 2) {
+				/* RQ2 */
 				skb = get_skb_by_index(skb_arr_rq2,
 						       skb_arr_rq2_len, cqe);
 				if (unlikely(!skb)) {
@@ -544,7 +547,8 @@ static int ehea_proc_rwqes(struct net_device *dev,
 				}
 				ehea_fill_skb(dev, skb, cqe);
 				processed_rq2++;
-			} else {  /* RQ3 */
+			} else {
+				/* RQ3 */
 				skb = get_skb_by_index(skb_arr_rq3,
 						       skb_arr_rq3_len, cqe);
 				if (unlikely(!skb)) {
@@ -592,7 +596,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
 	unsigned long flags;
 
 	cqe = ehea_poll_cq(send_cq);
-	while(cqe && (quota > 0)) {
+	while (cqe && (quota > 0)) {
 		ehea_inc_cq(send_cq);
 
 		cqe_counter++;
@@ -643,7 +647,8 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
 
 static int ehea_poll(struct napi_struct *napi, int budget)
 {
-	struct ehea_port_res *pr = container_of(napi, struct ehea_port_res, napi);
+	struct ehea_port_res *pr = container_of(napi, struct ehea_port_res,
+						napi);
 	struct net_device *dev = pr->port->netdev;
 	struct ehea_cqe *cqe;
 	struct ehea_cqe *cqe_skb = NULL;
@@ -743,8 +748,9 @@ int ehea_sense_port_attr(struct ehea_port *port)
 	u64 hret;
 	struct hcp_ehea_port_cb0 *cb0;
 
-	cb0 = kzalloc(PAGE_SIZE, GFP_ATOMIC);   /* May be called via */
-	if (!cb0) {                             /* ehea_neq_tasklet() */
+	/* may be called via ehea_neq_tasklet() */
+	cb0 = kzalloc(PAGE_SIZE, GFP_ATOMIC);
+	if (!cb0) {
 		ehea_error("no mem for cb0");
 		ret = -ENOMEM;
 		goto out;
@@ -762,7 +768,7 @@ int ehea_sense_port_attr(struct ehea_port *port)
 	/* MAC address */
 	port->mac_addr = cb0->port_mac_addr << 16;
 
-	if (!is_valid_ether_addr((u8*)&port->mac_addr)) {
+	if (!is_valid_ether_addr((u8 *)&port->mac_addr)) {
 		ret = -EADDRNOTAVAIL;
 		goto out_free;
 	}
@@ -994,7 +1000,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
 
 static void ehea_neq_tasklet(unsigned long data)
 {
-	struct ehea_adapter *adapter = (struct ehea_adapter*)data;
+	struct ehea_adapter *adapter = (struct ehea_adapter *)data;
 	struct ehea_eqe *eqe;
 	u64 event_mask;
 
@@ -1204,7 +1210,7 @@ int ehea_rem_smrs(struct ehea_port_res *pr)
 
 static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries)
 {
-	int arr_size = sizeof(void*) * max_q_entries;
+	int arr_size = sizeof(void *) * max_q_entries;
 
 	q_skba->arr = vmalloc(arr_size);
 	if (!q_skba->arr)
@@ -1489,7 +1495,7 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
 
 	nfrags = skb_shinfo(skb)->nr_frags;
 	sg1entry = &swqe->u.immdata_desc.sg_entry;
-	sg_list = (struct ehea_vsgentry*)&swqe->u.immdata_desc.sg_list;
+	sg_list = (struct ehea_vsgentry *)&swqe->u.immdata_desc.sg_list;
 	swqe->descriptors = 0;
 	sg1entry_contains_frag_data = 0;
 
@@ -1542,7 +1548,7 @@ static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid)
 				     reg_type, port->mac_addr, 0, hcallid);
 	if (hret != H_SUCCESS) {
 		ehea_error("%sregistering bc address failed (tagged)",
-                           hcallid == H_REG_BCMC ? "" : "de");
+			   hcallid == H_REG_BCMC ? "" : "de");
 		ret = -EIO;
 		goto out_herr;
 	}
@@ -1732,7 +1738,7 @@ static void ehea_allmulti(struct net_device *dev, int enable)
 		}
 }
 
-static void ehea_add_multicast_entry(struct ehea_port* port, u8* mc_mac_addr)
+static void ehea_add_multicast_entry(struct ehea_port *port, u8 *mc_mac_addr)
 {
 	struct ehea_mc_list *ehea_mcl_entry;
 	u64 hret;
@@ -1791,11 +1797,10 @@ static void ehea_set_multicast_list(struct net_device *dev)
 			goto out;
 		}
 
-		for (i = 0, k_mcl_entry = dev->mc_list;
-		     i < dev->mc_count;
-		     i++, k_mcl_entry = k_mcl_entry->next) {
+		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);
-		}
+
 	}
 out:
 	return;
@@ -1925,12 +1930,12 @@ static inline int ehea_hash_skb(struct sk_buff *skb, int num_qps)
 
 	if ((skb->protocol == htons(ETH_P_IP)) &&
 	    (ip_hdr(skb)->protocol == IPPROTO_TCP)) {
-		tcp = (struct tcphdr*)(skb_network_header(skb) + (ip_hdr(skb)->ihl * 4));
+		tcp = (struct tcphdr *)(skb_network_header(skb) +
+					(ip_hdr(skb)->ihl * 4));
 		tmp = (tcp->source + (tcp->dest << 16)) % 31;
 		tmp += ip_hdr(skb)->daddr % 31;
 		return tmp % num_qps;
-	}
-	else
+	} else
 		return 0;
 }
 
@@ -2122,7 +2127,7 @@ int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
 	u64 hret;
 	u16 dummy16 = 0;
 	u64 dummy64 = 0;
-	struct hcp_modify_qp_cb0* cb0;
+	struct hcp_modify_qp_cb0 *cb0;
 
 	cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
 	if (!cb0) {
@@ -2248,7 +2253,7 @@ static int ehea_clean_all_portres(struct ehea_port *port)
 	int ret = 0;
 	int i;
 
-	for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
+	for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
 		ret |= ehea_clean_portres(port, &port->port_res[i]);
 
 	ret |= ehea_destroy_eq(port->qp_eq);
@@ -2300,7 +2305,7 @@ static int ehea_up(struct net_device *dev)
 		goto out_clean_pr;
 	}
 
-	for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+	for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
 		ret = ehea_activate_qp(port->adapter, port->port_res[i].qp);
 		if (ret) {
 			ehea_error("activate_qp failed");
@@ -2308,7 +2313,7 @@ static int ehea_up(struct net_device *dev)
 		}
 	}
 
-	for(i = 0; i < port->num_def_qps; i++) {
+	for (i = 0; i < port->num_def_qps; i++) {
 		ret = ehea_fill_port_res(&port->port_res[i]);
 		if (ret) {
 			ehea_error("out_free_irqs");
@@ -2425,7 +2430,7 @@ int ehea_stop_qps(struct net_device *dev)
 {
 	struct ehea_port *port = netdev_priv(dev);
 	struct ehea_adapter *adapter = port->adapter;
-	struct hcp_modify_qp_cb0* cb0;
+	struct hcp_modify_qp_cb0 *cb0;
 	int ret = -EIO;
 	int dret;
 	int i;
@@ -2490,7 +2495,7 @@ out:
 	return ret;
 }
 
-void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res * pr)
+void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res *pr)
 {
 	struct ehea_qp qp = *orig_qp;
 	struct ehea_qp_init_attr *init_attr = &qp.init_attr;
@@ -2530,7 +2535,7 @@ int ehea_restart_qps(struct net_device *dev)
 	int ret = 0;
 	int i;
 
-	struct hcp_modify_qp_cb0* cb0;
+	struct hcp_modify_qp_cb0 *cb0;
 	u64 hret;
 	u64 dummy64 = 0;
 	u16 dummy16 = 0;
@@ -3109,7 +3114,7 @@ static ssize_t ehea_probe_port(struct device *dev,
 	of_node_put(eth_dn);
 
 	if (port) {
-		for (i=0; i < EHEA_MAX_PORTS; i++)
+		for (i = 0; i < EHEA_MAX_PORTS; i++)
 			if (!adapter->port[i]) {
 				adapter->port[i] = port;
 				break;
@@ -3144,7 +3149,7 @@ static ssize_t ehea_remove_port(struct device *dev,
 
 		ehea_shutdown_single_port(port);
 
-		for (i=0; i < EHEA_MAX_PORTS; i++)
+		for (i = 0; i < EHEA_MAX_PORTS; i++)
 			if (adapter->port[i] == port) {
 				adapter->port[i] = NULL;
 				break;
@@ -3313,7 +3318,7 @@ static int ehea_reboot_notifier(struct notifier_block *nb,
 }
 
 static struct notifier_block ehea_reboot_nb = {
-        .notifier_call = ehea_reboot_notifier,
+	.notifier_call = ehea_reboot_notifier,
 };
 
 static int check_module_parm(void)
-- 
1.5.3.8

^ permalink raw reply related


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