Netdev List
 help / color / mirror / Atom feed
* pull-request: bpf 2018-08-29
From: Daniel Borkmann @ 2018-08-29 19:07 UTC (permalink / raw)
  To: davem; +Cc: daniel, ast, netdev

Hi David,

The following pull-request contains BPF updates for your *net* tree.

The main changes are:

1) Fix a build error in sk_reuseport_convert_ctx_access() when
   compiling with clang which cannot resolve hweight_long() at
   build time inside the BUILD_BUG_ON() assertion, from Stefan.

2) Several fixes for BPF sockmap, four of them in getting the
   bpf_msg_pull_data() helper to work, one use after free case
   in bpf_tcp_close() and one refcount leak in bpf_tcp_recvmsg(),
   from Daniel.

3) Another fix for BPF sockmap where we misaccount sk_mem_uncharge()
   in the socket redirect error case from unwinding scatterlist
   twice, from John.

Please consider pulling these changes from:

  git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git

Thanks a lot!

----------------------------------------------------------------

The following changes since commit 53ae914d898e5dd5984d352d5fa0b23410f966a0:

  net/rds: Use rdma_read_gids to get connection SGID/DGID in IPv6 (2018-08-27 15:26:01 -0700)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf.git 

for you to fetch changes up to d65e6c80c6bb72ced46ce90dea4016d913a8ddd4:

  Merge branch 'bpf_msg_pull_data-fixes' (2018-08-29 10:47:18 -0700)

----------------------------------------------------------------
Alexei Starovoitov (1):
      Merge branch 'bpf_msg_pull_data-fixes'

Daniel Borkmann (6):
      bpf, sockmap: fix potential use after free in bpf_tcp_close
      bpf, sockmap: fix psock refcount leak in bpf_tcp_recvmsg
      bpf: fix several offset tests in bpf_msg_pull_data
      bpf: fix msg->data/data_end after sg shift repair in bpf_msg_pull_data
      bpf: fix shift upon scatterlist ring wrap-around in bpf_msg_pull_data
      bpf: fix sg shift repair start offset in bpf_msg_pull_data

John Fastabend (1):
      bpf: sockmap, decrement copied count correctly in redirect error case

Stefan Agner (1):
      bpf: fix build error with clang

 kernel/bpf/sockmap.c | 52 +++++++++++++++++++++++++---------------------------
 net/core/filter.c    | 52 +++++++++++++++++++++++++++++-----------------------
 2 files changed, 54 insertions(+), 50 deletions(-)

^ permalink raw reply

* Re: [PATCH bpf-next 08/11] i40e: add AF_XDP zero-copy Rx support
From: Jakub Kicinski @ 2018-08-29 19:14 UTC (permalink / raw)
  To: Björn Töpel
  Cc: magnus.karlsson, magnus.karlsson, alexander.h.duyck,
	alexander.duyck, ast, brouer, daniel, netdev, jesse.brandeburg,
	anjali.singhai, peter.waskiewicz.jr, Björn Töpel,
	michael.lundkvist, willemdebruijn.kernel, john.fastabend,
	neerav.parikh, mykyta.iziumtsev, francois.ozog, ilias.apalodimas,
	brian.brooks, u9012063, pavel, qi.z.zhang
In-Reply-To: <20180828124435.30578-9-bjorn.topel@gmail.com>

On Tue, 28 Aug 2018 14:44:32 +0200, Björn Töpel wrote:
> From: Björn Töpel <bjorn.topel@intel.com>
> 
> This patch adds zero-copy Rx support for AF_XDP sockets. Instead of
> allocating buffers of type MEM_TYPE_PAGE_SHARED, the Rx frames are
> allocated as MEM_TYPE_ZERO_COPY when AF_XDP is enabled for a certain
> queue.
> 
> All AF_XDP specific functions are added to a new file, i40e_xsk.c.
> 
> Note that when AF_XDP zero-copy is enabled, the XDP action XDP_PASS
> will allocate a new buffer and copy the zero-copy frame prior passing
> it to the kernel stack.
> 
> Signed-off-by: Björn Töpel <bjorn.topel@intel.com>

Mm.. I'm surprised you don't run into buffer reuse issues that I had
when playing with AF_XDP.  What happens in i40e if someone downs the
interface?  Will UMEMs get destroyed?  Will the RX buffers get freed?

I'll shortly send an RFC with my quick and dirty RX buffer reuse queue,
FWIW.

^ permalink raw reply

* [RFC] net: xsk: add a simple buffer reuse queue
From: Jakub Kicinski @ 2018-08-29 19:19 UTC (permalink / raw)
  To: Björn Töpel
  Cc: magnus.karlsson, magnus.karlsson, alexander.h.duyck,
	alexander.duyck, ast, brouer, daniel, netdev, jesse.brandeburg,
	anjali.singhai, peter.waskiewicz.jr, Björn Töpel,
	michael.lundkvist, willemdebruijn.kernel, john.fastabend,
	neerav.parikh, mykyta.iziumtsev, francois.ozog, ilias.apalodimas,
	brian.brooks, u9012063, pavel, qi.z.zhang
In-Reply-To: <20180828124435.30578-1-bjorn.topel@gmail.com>

XSK UMEM is strongly single producer single consumer so reuse of
frames is challenging.  Add a simple "stash" of FILL packets to
reuse for drivers to optionally make use of.  This is useful
when driver has to free (ndo_stop) or resize a ring with an active
AF_XDP ZC socket.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 include/net/xdp_sock.h | 44 +++++++++++++++++++++++++++++++++
 net/xdp/xdp_umem.c     |  2 ++
 net/xdp/xsk_queue.c    | 56 ++++++++++++++++++++++++++++++++++++++++++
 net/xdp/xsk_queue.h    |  3 +++
 4 files changed, 105 insertions(+)

diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h
index 6871e4755975..108c1c100de4 100644
--- a/include/net/xdp_sock.h
+++ b/include/net/xdp_sock.h
@@ -14,6 +14,7 @@
 #include <net/sock.h>
 
 struct net_device;
+struct xdp_umem_fq_reuse;
 struct xsk_queue;
 
 struct xdp_umem_props {
@@ -41,6 +42,7 @@ struct xdp_umem {
 	struct page **pgs;
 	u32 npgs;
 	struct net_device *dev;
+	struct xdp_umem_fq_reuse *fq_reuse;
 	u16 queue_id;
 	bool zc;
 	spinlock_t xsk_list_lock;
@@ -110,4 +112,46 @@ static inline dma_addr_t xdp_umem_get_dma(struct xdp_umem *umem, u64 addr)
 	return umem->pages[addr >> PAGE_SHIFT].dma + (addr & (PAGE_SIZE - 1));
 }
 
+struct xdp_umem_fq_reuse {
+	u32 nentries;
+	u32 length;
+	u64 handles[];
+};
+
+/* Following functions are not thread-safe in any way */
+struct xdp_umem_fq_reuse *xsk_reuseq_prepare(u32 nentries);
+struct xdp_umem_fq_reuse *xsk_reuseq_swap(struct xdp_umem *umem,
+					  struct xdp_umem_fq_reuse *newq);
+void xsk_reuseq_free(struct xdp_umem_fq_reuse *rq);
+
+/* Reuse-queue aware version of FILL queue helpers */
+static inline u64 *xsk_umem_peek_addr_rq(struct xdp_umem *umem, u64 *addr)
+{
+	struct xdp_umem_fq_reuse *rq = umem->fq_reuse;
+
+	if (!rq->length) {
+		return xsk_umem_peek_addr(umem, addr);
+	} else {
+		*addr = rq->handles[rq->length - 1];
+		return addr;
+	}
+}
+
+static inline void xsk_umem_discard_addr_rq(struct xdp_umem *umem)
+{
+	struct xdp_umem_fq_reuse *rq = umem->fq_reuse;
+
+	if (!rq->length)
+		xsk_umem_discard_addr(umem);
+	else
+		rq->length--;
+}
+
+static inline void xsk_umem_fq_reuse(struct xdp_umem *umem, u64 addr)
+{
+	struct xdp_umem_fq_reuse *rq = umem->fq_reuse;
+
+	rq->handles[rq->length++] = addr;
+}
+
 #endif /* _LINUX_XDP_SOCK_H */
diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c
index e762310c9bee..40303e24c954 100644
--- a/net/xdp/xdp_umem.c
+++ b/net/xdp/xdp_umem.c
@@ -170,6 +170,8 @@ static void xdp_umem_release(struct xdp_umem *umem)
 		umem->cq = NULL;
 	}
 
+	xsk_reuseq_destroy(umem);
+
 	xdp_umem_unpin_pages(umem);
 
 	task = get_pid_task(umem->pid, PIDTYPE_PID);
diff --git a/net/xdp/xsk_queue.c b/net/xdp/xsk_queue.c
index 6c32e92e98fc..f9ee40a13a9a 100644
--- a/net/xdp/xsk_queue.c
+++ b/net/xdp/xsk_queue.c
@@ -3,7 +3,9 @@
  * Copyright(c) 2018 Intel Corporation.
  */
 
+#include <linux/log2.h>
 #include <linux/slab.h>
+#include <linux/overflow.h>
 
 #include "xsk_queue.h"
 
@@ -61,3 +63,57 @@ void xskq_destroy(struct xsk_queue *q)
 	page_frag_free(q->ring);
 	kfree(q);
 }
+
+struct xdp_umem_fq_reuse *xsk_reuseq_prepare(u32 nentries)
+{
+	struct xdp_umem_fq_reuse *newq;
+
+	/* Check for overflow */
+	if (nentries > (u32)roundup_pow_of_two(nentries))
+		return NULL;
+	nentries = roundup_pow_of_two(nentries);
+
+	newq = kvmalloc(struct_size(newq, handles, nentries), GFP_KERNEL);
+	if (!newq)
+		return NULL;
+	memset(newq, 0, offsetof(typeof(*newq), handles));
+
+	newq->nentries = nentries;
+	return newq;
+}
+EXPORT_SYMBOL_GPL(xsk_reuseq_prepare);
+
+struct xdp_umem_fq_reuse *xsk_reuseq_swap(struct xdp_umem *umem,
+					  struct xdp_umem_fq_reuse *newq)
+{
+	struct xdp_umem_fq_reuse *oldq = umem->fq_reuse;
+
+	if (!oldq) {
+		umem->fq_reuse = newq;
+		return NULL;
+	}
+
+	if (newq->nentries < oldq->length)
+		return newq;
+
+
+	memcpy(newq->handles, oldq->handles,
+	       array_size(oldq->length, sizeof(u64)));
+	newq->length = oldq->length;
+
+	umem->fq_reuse = newq;
+	return oldq;
+}
+EXPORT_SYMBOL_GPL(xsk_reuseq_swap);
+
+void xsk_reuseq_free(struct xdp_umem_fq_reuse *rq)
+{
+	kvfree(rq);
+}
+EXPORT_SYMBOL_GPL(xsk_reuseq_free);
+
+void xsk_reuseq_destroy(struct xdp_umem *umem)
+{
+	xsk_reuseq_free(umem->fq_reuse);
+	umem->fq_reuse = NULL;
+}
diff --git a/net/xdp/xsk_queue.h b/net/xdp/xsk_queue.h
index 8a64b150be54..7a480e3eb35d 100644
--- a/net/xdp/xsk_queue.h
+++ b/net/xdp/xsk_queue.h
@@ -257,4 +257,7 @@ void xskq_set_umem(struct xsk_queue *q, struct xdp_umem_props *umem_props);
 struct xsk_queue *xskq_create(u32 nentries, bool umem_queue);
 void xskq_destroy(struct xsk_queue *q_ops);
 
+/* Executed by the core when the entire UMEM gets freed */
+void xsk_reuseq_destroy(struct xdp_umem *umem);
+
 #endif /* _LINUX_XSK_QUEUE_H */
-- 
2.17.1

^ permalink raw reply related

* Re: [PATCH bpf-next 08/11] i40e: add AF_XDP zero-copy Rx support
From: Alexei Starovoitov @ 2018-08-29 19:22 UTC (permalink / raw)
  To: Björn Töpel
  Cc: magnus.karlsson, magnus.karlsson, alexander.h.duyck,
	alexander.duyck, ast, brouer, daniel, netdev, jesse.brandeburg,
	anjali.singhai, peter.waskiewicz.jr, Björn Töpel,
	michael.lundkvist, willemdebruijn.kernel, john.fastabend,
	jakub.kicinski, neerav.parikh, mykyta.iziumtsev, francois.ozog,
	ilias.apalodimas, brian.brooks, u9012063, pavel, qi.z.zhang
In-Reply-To: <20180828124435.30578-9-bjorn.topel@gmail.com>

On Tue, Aug 28, 2018 at 02:44:32PM +0200, Björn Töpel wrote:
> From: Björn Töpel <bjorn.topel@intel.com>
> 
> This patch adds zero-copy Rx support for AF_XDP sockets. Instead of
> allocating buffers of type MEM_TYPE_PAGE_SHARED, the Rx frames are
> allocated as MEM_TYPE_ZERO_COPY when AF_XDP is enabled for a certain
> queue.
> 
> All AF_XDP specific functions are added to a new file, i40e_xsk.c.
> 
> Note that when AF_XDP zero-copy is enabled, the XDP action XDP_PASS
> will allocate a new buffer and copy the zero-copy frame prior passing
> it to the kernel stack.
> 
> Signed-off-by: Björn Töpel <bjorn.topel@intel.com>
...
> +/**
> + * i40e_construct_skb_zc - Create skbufff from zero-copy Rx buffer

typo sk_buff

overall the set looks great to me. The driver side changes look
particularly clean and independent from skb path of the driver.
I think the issues brought up by other reviews are not blockers
for the set, but certainly should be addressed in the follow up patches.

^ permalink raw reply

* Re: Kernel warnings from tcp.c
From: Stephen Hemminger @ 2018-08-29 19:35 UTC (permalink / raw)
  To: Adam Mitchell; +Cc: netdev
In-Reply-To: <CAEXp4ork9mZ9pY_o5LnG87tL5aRPLfpr1ZZ=p7qpZMJCKi-enA@mail.gmail.com>

On Wed, 29 Aug 2018 14:38:38 -0400
Adam Mitchell <adamhmitchell@gmail.com> wrote:

> Anyone with experience in tcp.c have an idea what's causing this on
> our busy database server?  Comes from this macro at line 2278:
>      WARN_ON(sock_owned_by_user(sk));
> 
> 
> [726780.788201] WARNING: CPU: 15 PID: 52245 at net/ipv4/tcp.c:2278
> tcp_close+0x40f/0x430
> 
> [726780.794947] Modules linked in: binfmt_misc nf_conntrack_netlink
> nfnetlink_queue tcp_diag inet_diag isofs ip6table_mangle ip6table_raw
> ip6table_nat nf_nat_ipv6 iptable_security xt_CT iptable_raw
> iptable_nat nf_nat_ipv4 nf_nat iptable_mangle xt_pkttype xt_NFLOG
> nfnetlink_log xt_u32 xt_multiport xt_set xt_conntrack
> ip_set_hash_netport ip_set_hash_ipport ip_set_hash_net ip_set_hash_ip
> ip_set nfnetlink nf_conntrack_proto_gre nf_conntrack_ipv6
> nf_defrag_ipv6 ip6table_filter ip6_tables xt_LOG nf_conntrack_tftp
> nf_conntrack_ftp nf_conntrack_ipv4 nf_defrag_ipv4 nf_conntrack
> iptable_filter zfs(PO) zunicode(PO) zavl(PO) icp(PO) sb_edac
> intel_powerclamp crct10dif_pclmul crc32_pclmul ghash_clmulni_intel
> pcbc aesni_intel crypto_simd glue_helper cryptd cirrus snd_seq
> zcommon(PO) ttm intel_rapl_perf snd_seq_device
> [726780.848696]  drm_kms_helper znvpair(PO) snd_pcm snd_timer spl(O)
> drm snd soundcore syscopyarea sysfillrect pcspkr sysimgblt input_leds
> fb_sys_fops i2c_piix4 ip_tables xfs libcrc32c ata_generic pata_acpi
> ata_piix xen_blkfront crc32c_intel libata ena(O) serio_raw floppy
> sunrpc
> [726780.863916] CPU: 15 PID: 52245 Comm: mysqld Tainted: P        W  O
>     4.16.13-1.el7.elrepo.x86_64 #1
>

Sorry, you have a tainted kernel with modules that are not upstream
therefore don't expect any support from kernel community

^ permalink raw reply

* Re: [PATCH bpf-next 00/11] AF_XDP zero-copy support for i40e
From: Alexei Starovoitov @ 2018-08-29 19:39 UTC (permalink / raw)
  To: Björn Töpel
  Cc: magnus.karlsson, magnus.karlsson, alexander.h.duyck,
	alexander.duyck, ast, brouer, daniel, netdev, jesse.brandeburg,
	anjali.singhai, peter.waskiewicz.jr, Björn Töpel,
	michael.lundkvist, willemdebruijn.kernel, john.fastabend,
	jakub.kicinski, neerav.parikh, mykyta.iziumtsev, francois.ozog,
	ilias.apalodimas, brian.brooks, u9012063, pavel, qi.z.zhang
In-Reply-To: <20180828124435.30578-1-bjorn.topel@gmail.com>

On Tue, Aug 28, 2018 at 02:44:24PM +0200, Björn Töpel wrote:
> From: Björn Töpel <bjorn.topel@intel.com>
> 
> This patch set introduces zero-copy AF_XDP support for Intel's i40e
> driver. In the first preparatory patch we also add support for
> XDP_REDIRECT for zero-copy allocated frames so that XDP programs can
> redirect them. This was a ToDo from the first AF_XDP zero-copy patch
> set from early June. Special thanks to Alex Duyck and Jesper Dangaard
> Brouer for reviewing earlier versions of this patch set.
> 
> The i40e zero-copy code is located in its own file i40e_xsk.[ch]. Note
> that in the interest of time, to get an AF_XDP zero-copy implementation
> out there for people to try, some code paths have been copied from the
> XDP path to the zero-copy path. It is out goal to merge the two paths
> in later patch sets.
> 
> In contrast to the implementation from beginning of June, this patch
> set does not require any extra HW queues for AF_XDP zero-copy
> TX. Instead, the XDP TX HW queue is used for both XDP_REDIRECT and
> AF_XDP zero-copy TX.
> 
> Jeff, given that most of changes are in i40e, it is up to you how you
> would like to route these patches. The set is tagged bpf-next, but
> if taking it via the Intel driver tree is easier, let us know.
> 
> We have run some benchmarks on a dual socket system with two Broadwell
> E5 2660 @ 2.0 GHz with hyperthreading turned off. Each socket has 14
> cores which gives a total of 28, but only two cores are used in these
> experiments. One for TR/RX and one for the user space application. The
> memory is DDR4 @ 2133 MT/s (1067 MHz) and the size of each DIMM is
> 8192MB and with 8 of those DIMMs in the system we have 64 GB of total
> memory. The compiler used is gcc (Ubuntu 7.3.0-16ubuntu3) 7.3.0. The
> NIC is Intel I40E 40Gbit/s using the i40e driver.
> 
> Below are the results in Mpps of the I40E NIC benchmark runs for 64
> and 1500 byte packets, generated by a commercial packet generator HW
> outputing packets at full 40 Gbit/s line rate. The results are with
> retpoline and all other spectre and meltdown fixes, so these results
> are not comparable to the ones from the zero-copy patch set in June.
> 
> AF_XDP performance 64 byte packets.
> Benchmark   XDP_SKB    XDP_DRV    XDP_DRV with zerocopy
> rxdrop       2.6        8.2         15.0
> txpush       2.2        -           21.9
> l2fwd        1.7        2.3         11.3
> 
> AF_XDP performance 1500 byte packets:
> Benchmark   XDP_SKB   XDP_DRV     XDP_DRV with zerocopy
> rxdrop       2.0        3.3         3.3
> l2fwd        1.3        1.7         3.1
> 
> XDP performance on our system as a base line:
> 
> 64 byte packets:
> XDP stats       CPU     pps         issue-pps
> XDP-RX CPU      16      18.4M  0
> 
> 1500 byte packets:
> XDP stats       CPU     pps         issue-pps
> XDP-RX CPU      16      3.3M    0
> 
> The structure of the patch set is as follows:
> 
> Patch 1: Add support for XDP_REDIRECT of zero-copy allocated frames
> Patches 2-4: Preparatory patches to common xsk and net code
> Patches 5-7: Preparatory patches to i40e driver code for RX
> Patch 8: i40e zero-copy support for RX
> Patch 9: Preparatory patch to i40e driver code for TX
> Patch 10: i40e zero-copy support for TX
> Patch 11: Add flags to sample application to force zero-copy/copy mode
> 
> We based this patch set on bpf-next commit 050cdc6c9501 ("Merge
> git://git.kernel.org/pub/scm/linux/kernel/git/davem/net")
> 
> 
> Magnus & Björn
> 
> Björn Töpel (8):
>   xdp: implement convert_to_xdp_frame for MEM_TYPE_ZERO_COPY
>   xdp: export xdp_rxq_info_unreg_mem_model
>   xsk: expose xdp_umem_get_{data,dma} to drivers
>   i40e: added queue pair disable/enable functions
>   i40e: refactor Rx path for re-use
>   i40e: move common Rx functions to i40e_txrx_common.h
>   i40e: add AF_XDP zero-copy Rx support
>   samples/bpf: add -c/--copy -z/--zero-copy flags to xdpsock
> 
> Magnus Karlsson (3):
>   net: add napi_if_scheduled_mark_missed
>   i40e: move common Tx functions to i40e_txrx_common.h
>   i40e: add AF_XDP zero-copy Tx support

Applied to bpf-next.
Thanks a lot to the authors, code reviewers and testers.

I hope all the issues brought up during code review can be quickly
addressed in the follow up patches and zerocopy feature in i40e
and other drivers will be mainline ready for the next merge window.

^ permalink raw reply

* [PATCH net] nfp: wait for posted reconfigs when disabling the device
From: Jakub Kicinski @ 2018-08-29 19:46 UTC (permalink / raw)
  To: davem; +Cc: netdev, oss-drivers, Jakub Kicinski

To avoid leaking a running timer we need to wait for the
posted reconfigs after netdev is unregistered.  In common
case the process of deinitializing the device will perform
synchronous reconfigs which wait for posted requests, but
especially with VXLAN ports being actively added and removed
there can be a race condition leaving a timer running after
adapter structure is freed leading to a crash.

Add an explicit flush after deregistering and for a good
measure a warning to check if timer is running just before
structures are freed.

Fixes: 3d780b926a12 ("nfp: add async reconfiguration mechanism")
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Dirk van der Merwe <dirk.vandermerwe@netronome.com>
---
 .../ethernet/netronome/nfp/nfp_net_common.c   | 48 +++++++++++++------
 1 file changed, 33 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index a8b9fbab5f73..253bdaef1505 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -229,29 +229,16 @@ static void nfp_net_reconfig_post(struct nfp_net *nn, u32 update)
 	spin_unlock_bh(&nn->reconfig_lock);
 }
 
-/**
- * nfp_net_reconfig() - Reconfigure the firmware
- * @nn:      NFP Net device to reconfigure
- * @update:  The value for the update field in the BAR config
- *
- * Write the update word to the BAR and ping the reconfig queue.  The
- * poll until the firmware has acknowledged the update by zeroing the
- * update word.
- *
- * Return: Negative errno on error, 0 on success
- */
-int nfp_net_reconfig(struct nfp_net *nn, u32 update)
+static void nfp_net_reconfig_sync_enter(struct nfp_net *nn)
 {
 	bool cancelled_timer = false;
 	u32 pre_posted_requests;
-	int ret;
 
 	spin_lock_bh(&nn->reconfig_lock);
 
 	nn->reconfig_sync_present = true;
 
 	if (nn->reconfig_timer_active) {
-		del_timer(&nn->reconfig_timer);
 		nn->reconfig_timer_active = false;
 		cancelled_timer = true;
 	}
@@ -260,14 +247,43 @@ int nfp_net_reconfig(struct nfp_net *nn, u32 update)
 
 	spin_unlock_bh(&nn->reconfig_lock);
 
-	if (cancelled_timer)
+	if (cancelled_timer) {
+		del_timer_sync(&nn->reconfig_timer);
 		nfp_net_reconfig_wait(nn, nn->reconfig_timer.expires);
+	}
 
 	/* Run the posted reconfigs which were issued before we started */
 	if (pre_posted_requests) {
 		nfp_net_reconfig_start(nn, pre_posted_requests);
 		nfp_net_reconfig_wait(nn, jiffies + HZ * NFP_NET_POLL_TIMEOUT);
 	}
+}
+
+static void nfp_net_reconfig_wait_posted(struct nfp_net *nn)
+{
+	nfp_net_reconfig_sync_enter(nn);
+
+	spin_lock_bh(&nn->reconfig_lock);
+	nn->reconfig_sync_present = false;
+	spin_unlock_bh(&nn->reconfig_lock);
+}
+
+/**
+ * nfp_net_reconfig() - Reconfigure the firmware
+ * @nn:      NFP Net device to reconfigure
+ * @update:  The value for the update field in the BAR config
+ *
+ * Write the update word to the BAR and ping the reconfig queue.  The
+ * poll until the firmware has acknowledged the update by zeroing the
+ * update word.
+ *
+ * Return: Negative errno on error, 0 on success
+ */
+int nfp_net_reconfig(struct nfp_net *nn, u32 update)
+{
+	int ret;
+
+	nfp_net_reconfig_sync_enter(nn);
 
 	nfp_net_reconfig_start(nn, update);
 	ret = nfp_net_reconfig_wait(nn, jiffies + HZ * NFP_NET_POLL_TIMEOUT);
@@ -3633,6 +3649,7 @@ struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, bool needs_netdev,
  */
 void nfp_net_free(struct nfp_net *nn)
 {
+	WARN_ON(timer_pending(&nn->reconfig_timer) || nn->reconfig_posted);
 	if (nn->dp.netdev)
 		free_netdev(nn->dp.netdev);
 	else
@@ -3920,4 +3937,5 @@ void nfp_net_clean(struct nfp_net *nn)
 		return;
 
 	unregister_netdev(nn->dp.netdev);
+	nfp_net_reconfig_wait_posted(nn);
 }
-- 
2.17.1

^ permalink raw reply related

* Re: Fw: [Bug 200943] New: Repeating tcp_mark_head_lost in dmesg
From: Yuchung Cheng @ 2018-08-29 19:57 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20180829080257.2ef072c6@xeon-e3>

On Wed, Aug 29, 2018 at 8:02 AM, Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
>
>
> Begin forwarded message:
>
> Date: Sun, 26 Aug 2018 22:24:12 +0000
> From: bugzilla-daemon@bugzilla.kernel.org
> To: stephen@networkplumber.org
> Subject: [Bug 200943] New: Repeating tcp_mark_head_lost in dmesg
>
>
> https://bugzilla.kernel.org/show_bug.cgi?id=200943
>
>             Bug ID: 200943
>            Summary: Repeating tcp_mark_head_lost in dmesg
>            Product: Networking
>            Version: 2.5
>     Kernel Version: 4.14.66
>           Hardware: All
>                 OS: Linux
>               Tree: Mainline
>             Status: NEW
>           Severity: normal
>           Priority: P1
>          Component: IPV4
>           Assignee: stephen@networkplumber.org
>           Reporter: rm+bko@romanrm.net
>         Regression: No
>
> Getting a bunch of these now every hour during continuous ~100 Mbit of network
> traffic.
> What's up with that? Seems harmless, as in the kernel doesn't crash and the
> network connection is not interrupted. (Maybe the particular TCP session is?)
> If there are no ill-effects from this condition, is such spammy WARN_ON really
> necessary?
This warning is likely triggered by buggy remote SACK behaviors, and
is pretty harmless - in my opinion the warning tcp_verify_left_out()
is still worthy to detect other inflight states inconsistencies.

The good news the particular loss recovery code path is disabled by
default on 4.18+ kernels by this patch

commit b38a51fec1c1f693f03b1aa19d0622123634d4b7
Author: Yuchung Cheng <ycheng@google.com>
Date:   Wed May 16 16:40:11 2018 -0700

    tcp: disable RFC6675 loss detection


>
> [Mon Aug 27 02:16:11 2018] ------------[ cut here ]------------
> [Mon Aug 27 02:16:11 2018] WARNING: CPU: 5 PID: 0 at net/ipv4/tcp_input.c:2263
> tcp_mark_head_lost+0x247/0x260
> [Mon Aug 27 02:16:11 2018] Modules linked in: dm_snapshot loop vhost_net vhost
> tap tun ip6t_MASQUERADE nf_nat_masquerade_ipv6 ipt_MASQUERADE
> nf_nat_masquerade_ipv4 xt_DSCP xt_mark ip6t_REJECT nf_reject_ipv6 ipt_REJECT
> nf_reject_ipv4 xt_owner xt_tcpudp xt_set ip_set_hash_net ip_set nfnetlink
> xt_limit xt_length xt_multiport xt_conntrack ip6t_rpfilter ipt_rpfilter
> ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_raw
> wireguard ip6_udp_tunnel udp_tunnel ip6table_mangle iptable_nat
> nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_raw
> iptable_mangle ip6table_filter ip6_tables matroxfb_base matroxfb_g450
> matroxfb_Ti3026 matroxfb_accel matroxfb_DAC1064 g450_pll matroxfb_misc
> iptable_filter ip_tables x_tables cpufreq_powersave cpufreq_userspace
> cpufreq_conservative 8021q garp mrp
> [Mon Aug 27 02:16:11 2018]  bridge stp llc bonding tcp_bbr sch_fq tcp_illinois
> fuse radeon ttm drm_kms_helper drm i2c_algo_bit it87 hwmon_vid eeepc_wmi
> asus_wmi sparse_keymap rfkill video wmi_bmof mxm_wmi edac_mce_amd kvm_amd kvm
> snd_pcm snd_timer snd soundcore joydev evdev pcspkr k10temp fam15h_power
> sp5100_tco sg shpchp wmi pcc_cpufreq acpi_cpufreq button ext4 crc16 mbcache
> jbd2 fscrypto btrfs zstd_decompress zstd_compress xxhash algif_skcipher af_alg
> dm_crypt dm_thin_pool dm_persistent_data dm_bio_prison dm_bufio dm_mod
> hid_generic usbhid hid raid10 raid456 async_raid6_recov async_memcpy async_pq
> async_xor async_tx xor sd_mod raid6_pq libcrc32c crc32c_generic raid1 raid0
> multipath linear md_mod vfio_pci irqbypass vfio_virqfd vfio_iommu_type1 vfio
> ohci_pci crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel
> [Mon Aug 27 02:16:11 2018]  pcbc aesni_intel aes_x86_64 crypto_simd glue_helper
> cryptd r8169 ahci xhci_pci libahci ohci_hcd ehci_pci mii xhci_hcd ehci_hcd
> i2c_piix4 libata usbcore scsi_mod bnx2
> [Mon Aug 27 02:16:11 2018] CPU: 5 PID: 0 Comm: swapper/5 Tainted: G        W
>    4.14.66-rm1+ #132
> [Mon Aug 27 02:16:11 2018] Hardware name: To be filled by O.E.M. To be filled
> by O.E.M./SABERTOOTH 990FX R2.0, BIOS 2901 05/04/2016
> [Mon Aug 27 02:16:11 2018] task: ffff8ba79c679dc0 task.stack: ffffb4d741928000
> [Mon Aug 27 02:16:11 2018] RIP: 0010:tcp_mark_head_lost+0x247/0x260
> [Mon Aug 27 02:16:11 2018] RSP: 0018:ffff8ba7aed437d8 EFLAGS: 00010202
> [Mon Aug 27 02:16:11 2018] RAX: 0000000000000018 RBX: ffff8ba3901a0800 RCX:
> 0000000000000000
> [Mon Aug 27 02:16:11 2018] RDX: 0000000000000017 RSI: 0000000000000001 RDI:
> ffff8ba4d47e9000
> [Mon Aug 27 02:16:11 2018] RBP: ffff8ba4d47e9000 R08: 000000000000000d R09:
> 0000000000000000
> [Mon Aug 27 02:16:11 2018] R10: 000000000000100c R11: 0000000000000000 R12:
> 0000000000000001
> [Mon Aug 27 02:16:11 2018] R13: ffff8ba4d47e9158 R14: 0000000000000001 R15:
> 000000009d0b6708
> [Mon Aug 27 02:16:11 2018] FS:  0000000000000000(0000)
> GS:ffff8ba7aed40000(0000) knlGS:0000000000000000
> [Mon Aug 27 02:16:11 2018] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [Mon Aug 27 02:16:11 2018] CR2: 0000000001fbdff0 CR3: 000000040c8d6000 CR4:
> 00000000000406e0
> [Mon Aug 27 02:16:11 2018] Call Trace:
> [Mon Aug 27 02:16:11 2018]  <IRQ>
> [Mon Aug 27 02:16:11 2018]  tcp_fastretrans_alert+0x5c3/0xa20
> [Mon Aug 27 02:16:11 2018]  tcp_ack+0x95a/0x1170
> [Mon Aug 27 02:16:11 2018]  ? __slab_free.isra.70+0x79/0x200
> [Mon Aug 27 02:16:11 2018]  tcp_rcv_established+0x16a/0x5a0
> [Mon Aug 27 02:16:11 2018]  ? tcp_v4_inbound_md5_hash+0x76/0x1e0
> [Mon Aug 27 02:16:11 2018]  tcp_v4_do_rcv+0x130/0x1f0
> [Mon Aug 27 02:16:11 2018]  tcp_v4_rcv+0x9ac/0xaa0
> [Mon Aug 27 02:16:11 2018]  ip_local_deliver_finish+0x9a/0x1c0
> [Mon Aug 27 02:16:11 2018]  ip_local_deliver+0x6b/0xe0
> [Mon Aug 27 02:16:11 2018]  ? ip_rcv_finish+0x440/0x440
> [Mon Aug 27 02:16:11 2018]  ip_rcv+0x2b0/0x3c0
> [Mon Aug 27 02:16:11 2018]  ? inet_del_offload+0x50/0x50
> [Mon Aug 27 02:16:11 2018]  __netif_receive_skb_core+0x85f/0xb50
> [Mon Aug 27 02:16:11 2018]  ? br_allowed_egress+0x2d/0x50 [bridge]
> [Mon Aug 27 02:16:11 2018]  ? br_forward+0x49/0xe0 [bridge]
> [Mon Aug 27 02:16:11 2018]  ? br_vlan_lookup+0xdd/0x150 [bridge]
> [Mon Aug 27 02:16:11 2018]  netif_receive_skb_internal+0x34/0xe0
> [Mon Aug 27 02:16:11 2018]  ? br_handle_vlan+0x4b/0xf0 [bridge]
> [Mon Aug 27 02:16:11 2018]  br_pass_frame_up+0xd4/0x180 [bridge]
> [Mon Aug 27 02:16:11 2018]  ? br_allowed_ingress+0x1ea/0x2e0 [bridge]
> [Mon Aug 27 02:16:11 2018]  br_handle_frame_finish+0x23f/0x530 [bridge]
> [Mon Aug 27 02:16:11 2018]  ? get_partial_node.isra.69+0x13c/0x1d0
> [Mon Aug 27 02:16:11 2018]  br_handle_frame+0x1b7/0x320 [bridge]
> [Mon Aug 27 02:16:11 2018]  __netif_receive_skb_core+0x367/0xb50
> [Mon Aug 27 02:16:11 2018]  ? inet_gro_receive+0x203/0x2b0
> [Mon Aug 27 02:16:11 2018]  netif_receive_skb_internal+0x34/0xe0
> [Mon Aug 27 02:16:11 2018]  napi_gro_receive+0xb8/0xe0
> [Mon Aug 27 02:16:11 2018]  bnx2_poll_work+0x71a/0x12e0 [bnx2]
> [Mon Aug 27 02:16:11 2018]  bnx2_poll_msix+0x41/0xf0 [bnx2]
> [Mon Aug 27 02:16:11 2018]  net_rx_action+0x28c/0x3f0
> [Mon Aug 27 02:16:11 2018]  __do_softirq+0x10a/0x2a2
> [Mon Aug 27 02:16:11 2018]  irq_exit+0xbe/0xd0
> [Mon Aug 27 02:16:11 2018]  do_IRQ+0x66/0x100
> [Mon Aug 27 02:16:11 2018]  common_interrupt+0x7d/0x7d
> [Mon Aug 27 02:16:11 2018]  </IRQ>
> [Mon Aug 27 02:16:11 2018] RIP: 0010:cpuidle_enter_state+0xa4/0x2d0
> [Mon Aug 27 02:16:11 2018] RSP: 0018:ffffb4d74192bea0 EFLAGS: 00000246
> ORIG_RAX: ffffffffffffff1a
> [Mon Aug 27 02:16:11 2018] RAX: ffff8ba7aed61800 RBX: 0000f8f2a31961cb RCX:
> 000000000000001f
> [Mon Aug 27 02:16:11 2018] RDX: 0000f8f2a31961cb RSI: fffffff1cd4e0887 RDI:
> 0000000000000000
> [Mon Aug 27 02:16:11 2018] RBP: 0000000000000002 R08: 000000000000000a R09:
> 000000000000000a
> [Mon Aug 27 02:16:11 2018] R10: 0000000000000364 R11: 00000000000002a6 R12:
> ffff8ba7961b3200
> [Mon Aug 27 02:16:11 2018] R13: ffffffff90cb2c58 R14: 0000f8f2a3139a63 R15:
> ffffffff90cb2b80
> [Mon Aug 27 02:16:11 2018]  do_idle+0x19d/0x200
> [Mon Aug 27 02:16:11 2018]  cpu_startup_entry+0x6f/0x80
> [Mon Aug 27 02:16:11 2018]  start_secondary+0x1ae/0x200
> [Mon Aug 27 02:16:11 2018]  secondary_startup_64+0xa5/0xb0
> [Mon Aug 27 02:16:11 2018] Code: e8 df aa 00 00 85 c0 78 0c 0f b6 43 39 44 89
> e6 e9 16 ff ff ff 8b 95 ec 05 00 00 8b 85 80 06 00 00 03 85 84 06 00 00 39 d0
> 76 a7 <0f> 0b eb a3 31 f6 e9 12 fe ff ff 66 66 2e 0f 1f 84 00 00 00 00
> [Mon Aug 27 02:16:11 2018] ---[ end trace 3d7c0b943ef03b6a ]---
>
> --
> You are receiving this mail because:
> You are the assignee for the bug.

^ permalink raw reply

* Re: GPL compliance issue with liquidio/lio_23xx_vsw.bin firmware
From: Ben Hutchings @ 2018-08-29 20:26 UTC (permalink / raw)
  To: Felix Manlunas, Florian Weimer
  Cc: linux-firmware, netdev@vger.kernel.org, Derek Chickles,
	Satanand Burla, Felix Manlunas, Raghu Vatsavayi, Manish Awasthi,
	Manojkumar.Panicker
In-Reply-To: <20180828000445.GA7039@felix-thinkpad.cavium.com>

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

On Mon, 2018-08-27 at 17:04 -0700, Felix Manlunas wrote:
> On Mon, Aug 27, 2018 at 05:01:10PM +0200, Florian Weimer wrote:
> > liquidio/lio_23xx_vsw.bin contains a compiled MIPS Linux kernel:
> > 
> > $ tail --bytes=+1313 liquidio/lio_23xx_vsw.bin > elf
> > $ readelf -aW elf
> > […]
> >   [ 6] __ksymtab         PROGBITS        ffffffff80e495f8 64a5f8 00d130
> > 00   A  0   0  8
> >   [ 7] __ksymtab_gpl     PROGBITS        ffffffff80e56728 657728 008400
> > 00   A  0   0  8
> >   [ 8] __ksymtab_strings PROGBITS        ffffffff80e5eb28 65fb28 018868
> > 00   A  0   0  1
> > […]
> > Symbol table '.symtab' contains 1349 entries:
> >    Num:    Value          Size Type    Bind   Vis      Ndx Name
> >      0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
> >      1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS
> > arch/mips/kernel/head.o
> >      2: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS init/main.c
> >      3: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS
> > include/linux/types.h
> > […]
> > 
> > Yet there is no corresponding source provided, and LICENCE.cavium lacks
> > the required notices.
> > 
> > Thanks,
> > Florian
> 
> Cavium apologizes for the oversight.  Cavium has been advertising the
> appropriate license terms including the existence of GPL in the firmware
> in our outbox releases. We will update the license terms in LICENCE.cavium
> in our upstream contribution in collaboration with our legal team.

Everything added to linux-firmware.git needs to be safe for Linux
distributions to redistribute.  (There are some ancient firmware images
with unclear licensing, but we don't want to add any more.)

My understanding is that GPL v2 requires that commercial distributors
either provide the complete and corresponding source alongside the
binaries, or include a written offer to provide it later.  They
*cannot* simply point to your offer to do this (only non-commercial
distributors can do that).  So the source needs to be published too.

Adding the complete Linux kernel source code to linux-firmware.git
doesn't seem like a sensible step, so maybe this particular firmware
needs to live elsewhere.

Ben.

-- 
Ben Hutchings
For every complex problem
there is a solution that is simple, neat, and wrong.



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

^ permalink raw reply

* Wine Enthusiasts List
From: Julie Wider @ 2018-08-29 19:41 UTC (permalink / raw)
  To: netdev


Hi,

Greeting of the day!

Would you be interested in reaching out to "Wine Enthusiasts list" from USA?

Our Databases:-     1.Beer Enthusiasts List        2.Alcohol Enthusiasts List
                     3.Beverage Consumers           4.Liquor Enthusiasts List
                     5.Chocolate Enthusiasts List   6.Students List
                     7.Luxury Brand Buyers List     8.Food Lovers List
                     9.Spa and Resort Visitors      10.Sports Enthusiasts List and many more.

Each record in the list contains Contact Name (First and Last Name), Mailing Address, List type and Opt-in email address.

All the contacts are opt-in verified, complete permission based and can be used for unlimited multi-channel marketing.

Let me know if you'd be interested in hearing more about it.

Waiting for your valuable and sincere reply.

Best Regards,
Julie Wider
Research Analyst

^ permalink raw reply

* [PATCH net-next 0/3] nixge: fixed-link support
From: Moritz Fischer @ 2018-08-30  0:40 UTC (permalink / raw)
  To: davem
  Cc: keescook, f.fainelli, linux-kernel, netdev, alex.williams,
	Moritz Fischer

Hi,

this series adds support for using nixge with fixed-link nodes,
as well as an early attempt to support nixge as a subdevice of
another device.

This series goes on top of: https://lkml.org/lkml/2018/8/28/1011

Patch 1: Adds of based fixed-link support, and hopefully isn't too
         controversial barring grave mistakes.

Patch 2: Is an attempt at making sure that nixge works as a subdevice
         of another (pci) device without a PHY. Note that same as Patch
         3 the actual platform data might still change since the parent
         device driver is still under development. So this is more of an
         RFC, too.

Patch 3: Is more of an RFC at this point since the PCI parent device is
         still under development, but required to run with IOMMU
         support. Feedback on this one would be appreciated.

Thanks for your input,

Moritz

Moritz Fischer (3):
  net: nixge: Add support for fixed-link subnodes
  net: nixge: Add support for having nixge as subdevice
  net: nixge: Use sysdev instead of ndev->dev.parent for DMA

 drivers/net/ethernet/ni/nixge.c     | 187 ++++++++++++++++++++++------
 include/linux/platform_data/nixge.h |  19 +++
 2 files changed, 165 insertions(+), 41 deletions(-)
 create mode 100644 include/linux/platform_data/nixge.h

-- 
2.18.0

^ permalink raw reply

* [PATCH net-next 1/3] net: nixge: Add support for fixed-link subnodes
From: Moritz Fischer @ 2018-08-30  0:40 UTC (permalink / raw)
  To: davem
  Cc: keescook, f.fainelli, linux-kernel, netdev, alex.williams,
	Moritz Fischer
In-Reply-To: <20180830004046.9417-1-mdf@kernel.org>

Add support for fixed-link cases where no MDIO is
actually required to run the device.
In that case no MDIO bus is instantiated since the
actual registers are not available in hardware.

Signed-off-by: Moritz Fischer <mdf@kernel.org>
---
 drivers/net/ethernet/ni/nixge.c | 72 ++++++++++++++++++++++++---------
 1 file changed, 53 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c
index 74cf52e3fb09..670249313ff0 100644
--- a/drivers/net/ethernet/ni/nixge.c
+++ b/drivers/net/ethernet/ni/nixge.c
@@ -1189,9 +1189,36 @@ static int nixge_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
 	return err;
 }
 
+static int nixge_of_get_phy(struct nixge_priv *priv, struct device_node *np)
+{
+	priv->phy_mode = of_get_phy_mode(np);
+	if (priv->phy_mode < 0) {
+		dev_err(priv->dev, "not find \"phy-mode\" property\n");
+		return -EINVAL;
+	}
+
+	if (of_phy_is_fixed_link(np)) {
+		if (of_phy_register_fixed_link(np) < 0) {
+			dev_err(priv->dev, "broken fixed link spec\n");
+			return -EINVAL;
+		}
+
+		priv->phy_node = of_node_get(np);
+	} else {
+		priv->phy_node = of_parse_phandle(np, "phy-handle", 0);
+		if (!priv->phy_node) {
+			dev_err(priv->dev, "not find \"phy-handle\" property\n");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int nixge_mdio_setup(struct nixge_priv *priv, struct device_node *np)
 {
 	struct mii_bus *bus;
+	int err;
 
 	bus = devm_mdiobus_alloc(priv->dev);
 	if (!bus)
@@ -1230,6 +1257,7 @@ static int nixge_probe(struct platform_device *pdev)
 	struct nixge_priv *priv;
 	struct net_device *ndev;
 	struct resource *dmares;
+	struct device_node *np;
 	const u8 *mac_addr;
 	int err;
 
@@ -1237,6 +1265,8 @@ static int nixge_probe(struct platform_device *pdev)
 	if (!ndev)
 		return -ENOMEM;
 
+	np = pdev->dev.of_node;
+
 	platform_set_drvdata(pdev, ndev);
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 
@@ -1286,24 +1316,19 @@ static int nixge_probe(struct platform_device *pdev)
 	priv->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD;
 	priv->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD;
 
-	err = nixge_mdio_setup(priv, pdev->dev.of_node);
-	if (err) {
-		netdev_err(ndev, "error registering mdio bus");
-		goto free_netdev;
-	}
-
-	priv->phy_mode = of_get_phy_mode(pdev->dev.of_node);
-	if (priv->phy_mode < 0) {
-		netdev_err(ndev, "not find \"phy-mode\" property\n");
-		err = -EINVAL;
-		goto unregister_mdio;
+	if (np) {
+		err = nixge_of_get_phy(priv, np);
+		if (err)
+			goto free_netdev;
 	}
 
-	priv->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
-	if (!priv->phy_node) {
-		netdev_err(ndev, "not find \"phy-handle\" property\n");
-		err = -EINVAL;
-		goto unregister_mdio;
+	/* only if it's not a fixed link, do we care about MDIO at all */
+	if (priv->phy_node && !of_phy_is_fixed_link(np)) {
+		err = nixge_mdio_setup(priv, np);
+		if (err) {
+			dev_err(&pdev->dev, "error registering mdio bus");
+			goto free_phy;
+		}
 	}
 
 	err = register_netdev(priv->ndev);
@@ -1315,8 +1340,13 @@ static int nixge_probe(struct platform_device *pdev)
 	return 0;
 
 unregister_mdio:
-	mdiobus_unregister(priv->mii_bus);
-
+	if (priv->mii_bus)
+		mdiobus_unregister(priv->mii_bus);
+free_phy:
+	if (np && of_phy_is_fixed_link(np)) {
+		of_phy_deregister_fixed_link(np);
+		of_node_put(np);
+	}
 free_netdev:
 	free_netdev(ndev);
 
@@ -1330,7 +1360,11 @@ static int nixge_remove(struct platform_device *pdev)
 
 	unregister_netdev(ndev);
 
-	mdiobus_unregister(priv->mii_bus);
+	if (priv->mii_bus)
+		mdiobus_unregister(priv->mii_bus);
+
+	if (np && of_phy_is_fixed_link(np))
+		of_phy_deregister_fixed_link(np);
 
 	free_netdev(ndev);
 
-- 
2.18.0

^ permalink raw reply related

* [PATCH net-next 2/3] net: nixge: Add support for having nixge as subdevice
From: Moritz Fischer @ 2018-08-30  0:40 UTC (permalink / raw)
  To: davem
  Cc: keescook, f.fainelli, linux-kernel, netdev, alex.williams,
	Moritz Fischer
In-Reply-To: <20180830004046.9417-1-mdf@kernel.org>

Add support for instantiating nixge as subdevice using
fixed-link and platform data to configure it.

Signed-off-by: Moritz Fischer <mdf@kernel.org>
---

Hi,

not this patch is still in the early stages,
and as the rest of this series goes on top of [1].

The actual platform data might still change since
the parent device driver is still under development.

Thanks for your time,

Moritz


[1] https://lkml.org/lkml/2018/8/28/1011

---
 drivers/net/ethernet/ni/nixge.c     | 71 ++++++++++++++++++++++++++---
 include/linux/platform_data/nixge.h | 19 ++++++++
 2 files changed, 83 insertions(+), 7 deletions(-)
 create mode 100644 include/linux/platform_data/nixge.h

diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c
index 670249313ff0..fd8e5b02c459 100644
--- a/drivers/net/ethernet/ni/nixge.c
+++ b/drivers/net/ethernet/ni/nixge.c
@@ -7,6 +7,8 @@
 #include <linux/etherdevice.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
+#include <linux/phy_fixed.h>
+#include <linux/platform_data/nixge.h>
 #include <linux/of_address.h>
 #include <linux/of_mdio.h>
 #include <linux/of_net.h>
@@ -167,6 +169,7 @@ struct nixge_priv {
 	/* Connection to PHY device */
 	struct device_node *phy_node;
 	phy_interface_t		phy_mode;
+	struct phy_device *phydev;
 
 	int link;
 	unsigned int speed;
@@ -859,15 +862,25 @@ static void nixge_dma_err_handler(unsigned long data)
 static int nixge_open(struct net_device *ndev)
 {
 	struct nixge_priv *priv = netdev_priv(ndev);
-	struct phy_device *phy;
+	struct phy_device *phy = NULL;
 	int ret;
 
 	nixge_device_reset(ndev);
 
-	phy = of_phy_connect(ndev, priv->phy_node,
-			     &nixge_handle_link_change, 0, priv->phy_mode);
-	if (!phy)
-		return -ENODEV;
+	if (priv->dev->of_node) {
+		phy = of_phy_connect(ndev, priv->phy_node,
+				     &nixge_handle_link_change, 0,
+				     priv->phy_mode);
+		if (!phy)
+			return -ENODEV;
+	} else if (priv->phydev) {
+		ret = phy_connect_direct(ndev, priv->phydev,
+					 &nixge_handle_link_change,
+					 priv->phy_mode);
+		if (ret)
+			return ret;
+		phy = priv->phydev;
+	}
 
 	phy_start(phy);
 
@@ -1215,10 +1228,41 @@ static int nixge_of_get_phy(struct nixge_priv *priv, struct device_node *np)
 	return 0;
 }
 
+static int nixge_pdata_get_phy(struct nixge_priv *priv,
+			       struct nixge_platform_data *pdata)
+{
+	struct phy_device *phy = NULL;
+
+	if (!pdata)
+		return -EINVAL;
+
+	if (pdata && pdata->phy_interface == PHY_INTERFACE_MODE_NA) {
+		struct fixed_phy_status fphy_status = {
+			.link = 1,
+			.duplex = pdata->phy_duplex,
+			.speed = pdata->phy_speed,
+			.pause = 0,
+			.asym_pause = 0,
+		};
+
+		/* TODO: Pull out GPIO from pdata */
+		phy = fixed_phy_register(PHY_POLL, &fphy_status, -1,
+					 NULL);
+		if (IS_ERR_OR_NULL(phy)) {
+			dev_err(priv->dev,
+				"failed to register fixed PHY device\n");
+			return -ENODEV;
+		}
+	}
+	priv->phy_mode = pdata->phy_interface;
+	priv->phydev = phy;
+
+	return 0;
+}
+
 static int nixge_mdio_setup(struct nixge_priv *priv, struct device_node *np)
 {
 	struct mii_bus *bus;
-	int err;
 
 	bus = devm_mdiobus_alloc(priv->dev);
 	if (!bus)
@@ -1254,6 +1298,7 @@ static void *nixge_get_nvmem_address(struct device *dev)
 
 static int nixge_probe(struct platform_device *pdev)
 {
+	struct nixge_platform_data *pdata = NULL;
 	struct nixge_priv *priv;
 	struct net_device *ndev;
 	struct resource *dmares;
@@ -1320,10 +1365,16 @@ static int nixge_probe(struct platform_device *pdev)
 		err = nixge_of_get_phy(priv, np);
 		if (err)
 			goto free_netdev;
+	} else {
+		pdata = dev_get_platdata(&pdev->dev);
+		err = nixge_pdata_get_phy(priv, pdata);
+		if (err)
+			goto free_netdev;
 	}
 
 	/* only if it's not a fixed link, do we care about MDIO at all */
-	if (priv->phy_node && !of_phy_is_fixed_link(np)) {
+	if ((priv->phy_node && !of_phy_is_fixed_link(np)) ||
+	    (pdata && pdata->phy_interface != PHY_INTERFACE_MODE_NA)) {
 		err = nixge_mdio_setup(priv, np);
 		if (err) {
 			dev_err(&pdev->dev, "error registering mdio bus");
@@ -1347,6 +1398,9 @@ static int nixge_probe(struct platform_device *pdev)
 		of_phy_deregister_fixed_link(np);
 		of_node_put(np);
 	}
+
+	if (priv->phydev && phy_is_pseudo_fixed_link(priv->phydev))
+		fixed_phy_unregister(priv->phydev);
 free_netdev:
 	free_netdev(ndev);
 
@@ -1357,6 +1411,7 @@ static int nixge_remove(struct platform_device *pdev)
 {
 	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct nixge_priv *priv = netdev_priv(ndev);
+	struct device_node *np = pdev->dev.of_node;
 
 	unregister_netdev(ndev);
 
@@ -1365,6 +1420,8 @@ static int nixge_remove(struct platform_device *pdev)
 
 	if (np && of_phy_is_fixed_link(np))
 		of_phy_deregister_fixed_link(np);
+	else if (priv->phydev && phy_is_pseudo_fixed_link(priv->phydev))
+		fixed_phy_unregister(priv->phydev);
 
 	free_netdev(ndev);
 
diff --git a/include/linux/platform_data/nixge.h b/include/linux/platform_data/nixge.h
new file mode 100644
index 000000000000..aa5dd5760074
--- /dev/null
+++ b/include/linux/platform_data/nixge.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018 National Instruments Corp.
+ *
+ * Author: Moritz Fischer <mdf@kernel.org>
+ */
+
+#ifndef __NIXGE_PDATA_H__
+#define __NIXGE_PDATA_H__
+
+#include <linux/phy.h>
+
+struct nixge_platform_data {
+	phy_interface_t phy_interface;
+	int phy_speed;
+	int phy_duplex;
+};
+
+#endif /* __NIXGE_PDATA_H__ */
+
-- 
2.18.0

^ permalink raw reply related

* [PATCH net-next 3/3] net: nixge: Use sysdev instead of ndev->dev.parent for DMA
From: Moritz Fischer @ 2018-08-30  0:40 UTC (permalink / raw)
  To: davem
  Cc: keescook, f.fainelli, linux-kernel, netdev, alex.williams,
	Moritz Fischer
In-Reply-To: <20180830004046.9417-1-mdf@kernel.org>

Use sysdev instead of ndev->dev.parent for DMA in order to
enable usecases where an IOMMU might get in the way otherwise.
In the PCIe wrapper case on x86 the IOMMU group is not inherited
by the platform device that is created as a subdevice of the
PCI wrapper driver.

Signed-off-by: Moritz Fischer <mdf@kernel.org>
---

Hi,

not this patch is still in the early stages,
and as the rest of this series goes on top of [1].

The actual parent device might still change since
the parent device driver is still under development.

If there are clever suggestions on how to generalize
the assignment of sysdev, I'm all ears.

Thanks for your time,

Moritz


[1] https://lkml.org/lkml/2018/8/28/1011

---
 drivers/net/ethernet/ni/nixge.c | 50 +++++++++++++++++++++------------
 1 file changed, 32 insertions(+), 18 deletions(-)

diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c
index fd8e5b02c459..25fb1642d558 100644
--- a/drivers/net/ethernet/ni/nixge.c
+++ b/drivers/net/ethernet/ni/nixge.c
@@ -16,6 +16,7 @@
 #include <linux/of_irq.h>
 #include <linux/skbuff.h>
 #include <linux/phy.h>
+#include <linux/pci.h>
 #include <linux/mii.h>
 #include <linux/nvmem-consumer.h>
 #include <linux/ethtool.h>
@@ -165,6 +166,7 @@ struct nixge_priv {
 	struct net_device *ndev;
 	struct napi_struct napi;
 	struct device *dev;
+	struct device *sysdev;
 
 	/* Connection to PHY device */
 	struct device_node *phy_node;
@@ -250,7 +252,7 @@ static void nixge_hw_dma_bd_release(struct net_device *ndev)
 		phys_addr = nixge_hw_dma_bd_get_addr(&priv->rx_bd_v[i],
 						     phys);
 
-		dma_unmap_single(ndev->dev.parent, phys_addr,
+		dma_unmap_single(priv->sysdev, phys_addr,
 				 NIXGE_MAX_JUMBO_FRAME_SIZE,
 				 DMA_FROM_DEVICE);
 
@@ -261,16 +263,16 @@ static void nixge_hw_dma_bd_release(struct net_device *ndev)
 	}
 
 	if (priv->rx_bd_v)
-		dma_free_coherent(ndev->dev.parent,
+		dma_free_coherent(priv->sysdev,
 				  sizeof(*priv->rx_bd_v) * RX_BD_NUM,
 				  priv->rx_bd_v,
 				  priv->rx_bd_p);
 
 	if (priv->tx_skb)
-		devm_kfree(ndev->dev.parent, priv->tx_skb);
+		devm_kfree(priv->sysdev, priv->tx_skb);
 
 	if (priv->tx_bd_v)
-		dma_free_coherent(ndev->dev.parent,
+		dma_free_coherent(priv->sysdev,
 				  sizeof(*priv->tx_bd_v) * TX_BD_NUM,
 				  priv->tx_bd_v,
 				  priv->tx_bd_p);
@@ -290,19 +292,19 @@ static int nixge_hw_dma_bd_init(struct net_device *ndev)
 	priv->rx_bd_ci = 0;
 
 	/* Allocate the Tx and Rx buffer descriptors. */
-	priv->tx_bd_v = dma_zalloc_coherent(ndev->dev.parent,
+	priv->tx_bd_v = dma_zalloc_coherent(priv->sysdev,
 					    sizeof(*priv->tx_bd_v) * TX_BD_NUM,
 					    &priv->tx_bd_p, GFP_KERNEL);
 	if (!priv->tx_bd_v)
 		goto out;
 
-	priv->tx_skb = devm_kcalloc(ndev->dev.parent,
+	priv->tx_skb = devm_kcalloc(priv->sysdev,
 				    TX_BD_NUM, sizeof(*priv->tx_skb),
 				    GFP_KERNEL);
 	if (!priv->tx_skb)
 		goto out;
 
-	priv->rx_bd_v = dma_zalloc_coherent(ndev->dev.parent,
+	priv->rx_bd_v = dma_zalloc_coherent(priv->sysdev,
 					    sizeof(*priv->rx_bd_v) * RX_BD_NUM,
 					    &priv->rx_bd_p, GFP_KERNEL);
 	if (!priv->rx_bd_v)
@@ -327,7 +329,7 @@ static int nixge_hw_dma_bd_init(struct net_device *ndev)
 			goto out;
 
 		nixge_hw_dma_bd_set_offset(&priv->rx_bd_v[i], skb);
-		phys = dma_map_single(ndev->dev.parent, skb->data,
+		phys = dma_map_single(priv->sysdev, skb->data,
 				      NIXGE_MAX_JUMBO_FRAME_SIZE,
 				      DMA_FROM_DEVICE);
 
@@ -438,10 +440,10 @@ static void nixge_tx_skb_unmap(struct nixge_priv *priv,
 {
 	if (tx_skb->mapping) {
 		if (tx_skb->mapped_as_page)
-			dma_unmap_page(priv->ndev->dev.parent, tx_skb->mapping,
+			dma_unmap_page(priv->sysdev, tx_skb->mapping,
 				       tx_skb->size, DMA_TO_DEVICE);
 		else
-			dma_unmap_single(priv->ndev->dev.parent,
+			dma_unmap_single(priv->sysdev,
 					 tx_skb->mapping,
 					 tx_skb->size, DMA_TO_DEVICE);
 		tx_skb->mapping = 0;
@@ -519,9 +521,9 @@ static int nixge_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		return NETDEV_TX_OK;
 	}
 
-	cur_phys = dma_map_single(ndev->dev.parent, skb->data,
+	cur_phys = dma_map_single(priv->sysdev, skb->data,
 				  skb_headlen(skb), DMA_TO_DEVICE);
-	if (dma_mapping_error(ndev->dev.parent, cur_phys))
+	if (dma_mapping_error(priv->sysdev, cur_phys))
 		goto drop;
 	nixge_hw_dma_bd_set_phys(cur_p, cur_phys);
 
@@ -539,10 +541,10 @@ static int nixge_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		tx_skb = &priv->tx_skb[priv->tx_bd_tail];
 		frag = &skb_shinfo(skb)->frags[ii];
 
-		cur_phys = skb_frag_dma_map(ndev->dev.parent, frag, 0,
+		cur_phys = skb_frag_dma_map(priv->sysdev, frag, 0,
 					    skb_frag_size(frag),
 					    DMA_TO_DEVICE);
-		if (dma_mapping_error(ndev->dev.parent, cur_phys))
+		if (dma_mapping_error(priv->sysdev, cur_phys))
 			goto frag_err;
 		nixge_hw_dma_bd_set_phys(cur_p, cur_phys);
 
@@ -579,7 +581,7 @@ static int nixge_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		cur_p = &priv->tx_bd_v[priv->tx_bd_tail];
 		cur_p->status = 0;
 	}
-	dma_unmap_single(priv->ndev->dev.parent,
+	dma_unmap_single(priv->sysdev,
 			 tx_skb->mapping,
 			 tx_skb->size, DMA_TO_DEVICE);
 drop:
@@ -611,7 +613,7 @@ static int nixge_recv(struct net_device *ndev, int budget)
 		if (length > NIXGE_MAX_JUMBO_FRAME_SIZE)
 			length = NIXGE_MAX_JUMBO_FRAME_SIZE;
 
-		dma_unmap_single(ndev->dev.parent,
+		dma_unmap_single(priv->sysdev,
 				 nixge_hw_dma_bd_get_addr(cur_p, phys),
 				 NIXGE_MAX_JUMBO_FRAME_SIZE,
 				 DMA_FROM_DEVICE);
@@ -636,10 +638,10 @@ static int nixge_recv(struct net_device *ndev, int budget)
 		if (!new_skb)
 			return packets;
 
-		cur_phys = dma_map_single(ndev->dev.parent, new_skb->data,
+		cur_phys = dma_map_single(priv->sysdev, new_skb->data,
 					  NIXGE_MAX_JUMBO_FRAME_SIZE,
 					  DMA_FROM_DEVICE);
-		if (dma_mapping_error(ndev->dev.parent, cur_phys)) {
+		if (dma_mapping_error(priv->sysdev, cur_phys)) {
 			/* FIXME: bail out and clean up */
 			netdev_err(ndev, "Failed to map ...\n");
 		}
@@ -1303,6 +1305,7 @@ static int nixge_probe(struct platform_device *pdev)
 	struct net_device *ndev;
 	struct resource *dmares;
 	struct device_node *np;
+	struct device *sysdev;
 	const u8 *mac_addr;
 	int err;
 
@@ -1331,9 +1334,20 @@ static int nixge_probe(struct platform_device *pdev)
 		eth_hw_addr_random(ndev);
 	}
 
+	sysdev = &pdev->dev;
+#ifdef CONFIG_PCI
+	/* if this is a subdevice of a PCI device we'll have to
+	 * make sure we'll use parent instead of our own platform
+	 * device to make sure  the DMA API if we use an IOMMU
+	 */
+	if (sysdev->parent && sysdev->parent->bus == &pci_bus_type)
+		sysdev = sysdev->parent;
+#endif
+
 	priv = netdev_priv(ndev);
 	priv->ndev = ndev;
 	priv->dev = &pdev->dev;
+	priv->sysdev = sysdev;
 
 	netif_napi_add(ndev, &priv->napi, nixge_poll, NAPI_POLL_WEIGHT);
 
-- 
2.18.0

^ permalink raw reply related

* [PATCH v5 1/4] gpiolib: Pass bitmaps, not integer arrays, to get/set array
From: Janusz Krzysztofik @ 2018-08-29 20:48 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Jonathan Corbet, Miguel Ojeda Sandonis, Peter Korsgaard,
	Peter Rosin, Ulf Hansson, Andrew Lunn, Florian Fainelli,
	David S. Miller, Dominik Brodowski, Greg Kroah-Hartman,
	Kishon Vijay Abraham I, Lars-Peter Clausen, Michael Hennerich,
	Jonathan Cameron, Hartmut Knaack, Peter Meerwald-Stadler,
	Jiri Slaby, Willy Tarreau, Geert Uytterhoeven
In-Reply-To: <20180829204900.19390-1-jmkrzyszt@gmail.com>

Most users of get/set array functions iterate consecutive bits of data,
usually a single integer, while processing array of results obtained
from, or building an array of values to be passed to those functions.
Save time wasted on those iterations by changing the functions' API to
accept bitmaps.

All current users are updated as well.

More benefits from the change are expected as soon as planned support
for accepting/passing those bitmaps directly from/to respective GPIO
chip callbacks if applicable is implemented.

Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>
Cc: Peter Korsgaard <peter.korsgaard@barco.com>
Cc: Peter Rosin <peda@axentia.se>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Dominik Brodowski <linux@dominikbrodowski.net>
Cc: Kishon Vijay Abraham I <kishon@ti.com>
Cc: Lars-Peter Clausen <lars@metafoo.de>
Cc: Michael Hennerich <Michael.Hennerich@analog.com>
Cc: Jonathan Cameron <jic23@kernel.org>
Cc: Hartmut Knaack <knaack.h@gmx.de>
Cc: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.com>
Signed-off-by: Janusz Krzysztofik <jmkrzyszt@gmail.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 Documentation/driver-api/gpio/consumer.rst  | 22 ++++----
 drivers/auxdisplay/hd44780.c                | 52 +++++++++--------
 drivers/bus/ts-nbus.c                       | 19 ++-----
 drivers/gpio/gpio-max3191x.c                | 17 +++---
 drivers/gpio/gpiolib.c                      | 86 +++++++++++++++--------------
 drivers/gpio/gpiolib.h                      |  4 +-
 drivers/i2c/muxes/i2c-mux-gpio.c            |  8 +--
 drivers/mmc/core/pwrseq_simple.c            | 13 ++---
 drivers/mux/gpio.c                          |  9 +--
 drivers/net/phy/mdio-mux-gpio.c             |  3 +-
 drivers/pcmcia/soc_common.c                 | 11 ++--
 drivers/phy/motorola/phy-mapphone-mdm6600.c | 17 +++---
 drivers/staging/iio/adc/ad7606.c            |  9 +--
 drivers/tty/serial/serial_mctrl_gpio.c      |  7 ++-
 include/linux/gpio/consumer.h               | 18 +++---
 15 files changed, 140 insertions(+), 155 deletions(-)

diff --git a/Documentation/driver-api/gpio/consumer.rst b/Documentation/driver-api/gpio/consumer.rst
index aa03f389d41d..ed68042ddccf 100644
--- a/Documentation/driver-api/gpio/consumer.rst
+++ b/Documentation/driver-api/gpio/consumer.rst
@@ -323,29 +323,29 @@ The following functions get or set the values of an array of GPIOs::
 
 	int gpiod_get_array_value(unsigned int array_size,
 				  struct gpio_desc **desc_array,
-				  int *value_array);
+				  unsigned long *value_bitmap);
 	int gpiod_get_raw_array_value(unsigned int array_size,
 				      struct gpio_desc **desc_array,
-				      int *value_array);
+				      unsigned long *value_bitmap);
 	int gpiod_get_array_value_cansleep(unsigned int array_size,
 					   struct gpio_desc **desc_array,
-					   int *value_array);
+					   unsigned long *value_bitmap);
 	int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
 					   struct gpio_desc **desc_array,
-					   int *value_array);
+					   unsigned long *value_bitmap);
 
 	void gpiod_set_array_value(unsigned int array_size,
 				   struct gpio_desc **desc_array,
-				   int *value_array)
+				   unsigned long *value_bitmap)
 	void gpiod_set_raw_array_value(unsigned int array_size,
 				       struct gpio_desc **desc_array,
-				       int *value_array)
+				       unsigned long *value_bitmap)
 	void gpiod_set_array_value_cansleep(unsigned int array_size,
 					    struct gpio_desc **desc_array,
-					    int *value_array)
+					    unsigned long *value_bitmap)
 	void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
 						struct gpio_desc **desc_array,
-						int *value_array)
+						unsigned long *value_bitmap)
 
 The array can be an arbitrary set of GPIOs. The functions will try to access
 GPIOs belonging to the same bank or chip simultaneously if supported by the
@@ -356,8 +356,8 @@ accessed sequentially.
 The functions take three arguments:
 	* array_size	- the number of array elements
 	* desc_array	- an array of GPIO descriptors
-	* value_array	- an array to store the GPIOs' values (get) or
-			  an array of values to assign to the GPIOs (set)
+	* value_bitmap	- a bitmap to store the GPIOs' values (get) or
+			  a bitmap of values to assign to the GPIOs (set)
 
 The descriptor array can be obtained using the gpiod_get_array() function
 or one of its variants. If the group of descriptors returned by that function
@@ -366,7 +366,7 @@ the struct gpio_descs returned by gpiod_get_array()::
 
 	struct gpio_descs *my_gpio_descs = gpiod_get_array(...);
 	gpiod_set_array_value(my_gpio_descs->ndescs, my_gpio_descs->desc,
-			      my_gpio_values);
+			      my_gpio_value_bitmap);
 
 It is also possible to access a completely arbitrary array of descriptors. The
 descriptors may be obtained using any combination of gpiod_get() and
diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c
index f1a42f0f1ded..bbbd6a29bf01 100644
--- a/drivers/auxdisplay/hd44780.c
+++ b/drivers/auxdisplay/hd44780.c
@@ -62,20 +62,19 @@ static void hd44780_strobe_gpio(struct hd44780 *hd)
 /* write to an LCD panel register in 8 bit GPIO mode */
 static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs)
 {
-	int values[10];	/* for DATA[0-7], RS, RW */
-	unsigned int i, n;
+	unsigned long value_bitmap[1];	/* for DATA[0-7], RS, RW */
+	unsigned int n;
 
-	for (i = 0; i < 8; i++)
-		values[PIN_DATA0 + i] = !!(val & BIT(i));
-	values[PIN_CTRL_RS] = rs;
+	value_bitmap[0] = val;
+	__assign_bit(PIN_CTRL_RS, value_bitmap, rs);
 	n = 9;
 	if (hd->pins[PIN_CTRL_RW]) {
-		values[PIN_CTRL_RW] = 0;
+		__clear_bit(PIN_CTRL_RW, value_bitmap);
 		n++;
 	}
 
 	/* Present the data to the port */
-	gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], values);
+	gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], value_bitmap);
 
 	hd44780_strobe_gpio(hd);
 }
@@ -83,32 +82,31 @@ static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs)
 /* write to an LCD panel register in 4 bit GPIO mode */
 static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs)
 {
-	int values[10];	/* for DATA[0-7], RS, RW, but DATA[0-3] is unused */
-	unsigned int i, n;
+	/* for DATA[0-7], RS, RW, but DATA[0-3] is unused */
+	unsigned long value_bitmap[1];
+	unsigned int n;
 
 	/* High nibble + RS, RW */
-	for (i = 4; i < 8; i++)
-		values[PIN_DATA0 + i] = !!(val & BIT(i));
-	values[PIN_CTRL_RS] = rs;
+	value_bitmap[0] = val;
+	__assign_bit(PIN_CTRL_RS, value_bitmap, rs);
 	n = 5;
 	if (hd->pins[PIN_CTRL_RW]) {
-		values[PIN_CTRL_RW] = 0;
+		__clear_bit(PIN_CTRL_RW, value_bitmap);
 		n++;
 	}
+	value_bitmap[0] >>= PIN_DATA4;
 
 	/* Present the data to the port */
-	gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4],
-				       &values[PIN_DATA4]);
+	gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], value_bitmap);
 
 	hd44780_strobe_gpio(hd);
 
 	/* Low nibble */
-	for (i = 0; i < 4; i++)
-		values[PIN_DATA4 + i] = !!(val & BIT(i));
+	value_bitmap[0] &= ~((1 << PIN_DATA4) - 1);
+	value_bitmap[0] |= val & ~((1 << PIN_DATA4) - 1);
 
 	/* Present the data to the port */
-	gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4],
-				       &values[PIN_DATA4]);
+	gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], value_bitmap);
 
 	hd44780_strobe_gpio(hd);
 }
@@ -155,23 +153,23 @@ static void hd44780_write_cmd_gpio4(struct charlcd *lcd, int cmd)
 /* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */
 static void hd44780_write_cmd_raw_gpio4(struct charlcd *lcd, int cmd)
 {
-	int values[10];	/* for DATA[0-7], RS, RW, but DATA[0-3] is unused */
+	/* for DATA[0-7], RS, RW, but DATA[0-3] is unused */
+	unsigned long value_bitmap[1];
 	struct hd44780 *hd = lcd->drvdata;
-	unsigned int i, n;
+	unsigned int n;
 
 	/* Command nibble + RS, RW */
-	for (i = 0; i < 4; i++)
-		values[PIN_DATA4 + i] = !!(cmd & BIT(i));
-	values[PIN_CTRL_RS] = 0;
+	value_bitmap[0] = cmd << PIN_DATA4;
+	__clear_bit(PIN_CTRL_RS, value_bitmap);
 	n = 5;
 	if (hd->pins[PIN_CTRL_RW]) {
-		values[PIN_CTRL_RW] = 0;
+		__clear_bit(PIN_CTRL_RW, value_bitmap);
 		n++;
 	}
+	value_bitmap[0] = value_bitmap[0] >> PIN_DATA4;
 
 	/* Present the data to the port */
-	gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4],
-				       &values[PIN_DATA4]);
+	gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], value_bitmap);
 
 	hd44780_strobe_gpio(hd);
 }
diff --git a/drivers/bus/ts-nbus.c b/drivers/bus/ts-nbus.c
index 073fd9011154..ce6c1e89236d 100644
--- a/drivers/bus/ts-nbus.c
+++ b/drivers/bus/ts-nbus.c
@@ -110,13 +110,9 @@ static void ts_nbus_set_direction(struct ts_nbus *ts_nbus, int direction)
  */
 static void ts_nbus_reset_bus(struct ts_nbus *ts_nbus)
 {
-	int i;
-	int values[8];
-
-	for (i = 0; i < 8; i++)
-		values[i] = 0;
+	unsigned long value_bitmap[1] = { 0, };
 
-	gpiod_set_array_value_cansleep(8, ts_nbus->data->desc, values);
+	gpiod_set_array_value_cansleep(8, ts_nbus->data->desc, value_bitmap);
 	gpiod_set_value_cansleep(ts_nbus->csn, 0);
 	gpiod_set_value_cansleep(ts_nbus->strobe, 0);
 	gpiod_set_value_cansleep(ts_nbus->ale, 0);
@@ -157,16 +153,9 @@ static int ts_nbus_read_byte(struct ts_nbus *ts_nbus, u8 *val)
 static void ts_nbus_write_byte(struct ts_nbus *ts_nbus, u8 byte)
 {
 	struct gpio_descs *gpios = ts_nbus->data;
-	int i;
-	int values[8];
-
-	for (i = 0; i < 8; i++)
-		if (byte & BIT(i))
-			values[i] = 1;
-		else
-			values[i] = 0;
+	unsigned long value_bitmap[1] = { byte, };
 
-	gpiod_set_array_value_cansleep(8, gpios->desc, values);
+	gpiod_set_array_value_cansleep(8, gpios->desc, value_bitmap);
 }
 
 /*
diff --git a/drivers/gpio/gpio-max3191x.c b/drivers/gpio/gpio-max3191x.c
index b5b9cb1fda50..c4ec1c82af27 100644
--- a/drivers/gpio/gpio-max3191x.c
+++ b/drivers/gpio/gpio-max3191x.c
@@ -315,17 +315,20 @@ static void gpiod_set_array_single_value_cansleep(unsigned int ndescs,
 						  struct gpio_desc **desc,
 						  int value)
 {
-	int i, *values;
+	unsigned long *value_bitmap;
 
-	values = kmalloc_array(ndescs, sizeof(*values), GFP_KERNEL);
-	if (!values)
+	value_bitmap = kmalloc_array(BITS_TO_LONGS(ndescs),
+				     sizeof(*value_bitmap), GFP_KERNEL);
+	if (!value_bitmap)
 		return;
 
-	for (i = 0; i < ndescs; i++)
-		values[i] = value;
+	if (value)
+		bitmap_fill(value_bitmap, ndescs);
+	else
+		bitmap_zero(value_bitmap, ndescs);
 
-	gpiod_set_array_value_cansleep(ndescs, desc, values);
-	kfree(values);
+	gpiod_set_array_value_cansleep(ndescs, desc, value_bitmap);
+	kfree(value_bitmap);
 }
 
 static struct gpio_descs *devm_gpiod_get_array_optional_count(
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index e8f8a1999393..f0e9ffa8cab6 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -427,7 +427,7 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
 	struct linehandle_state *lh = filep->private_data;
 	void __user *ip = (void __user *)arg;
 	struct gpiohandle_data ghd;
-	int vals[GPIOHANDLES_MAX];
+	unsigned long value_bitmap[BITS_TO_LONGS(GPIOHANDLES_MAX)];
 	int i;
 
 	if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
@@ -436,13 +436,13 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
 							true,
 							lh->numdescs,
 							lh->descs,
-							vals);
+							value_bitmap);
 		if (ret)
 			return ret;
 
 		memset(&ghd, 0, sizeof(ghd));
 		for (i = 0; i < lh->numdescs; i++)
-			ghd.values[i] = vals[i];
+			ghd.values[i] = test_bit(i, value_bitmap);
 
 		if (copy_to_user(ip, &ghd, sizeof(ghd)))
 			return -EFAULT;
@@ -461,14 +461,14 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
 
 		/* Clamp all values to [0,1] */
 		for (i = 0; i < lh->numdescs; i++)
-			vals[i] = !!ghd.values[i];
+			__assign_bit(i, value_bitmap, !!ghd.values[i]);
 
 		/* Reuse the array setting function */
 		return gpiod_set_array_value_complex(false,
 					      true,
 					      lh->numdescs,
 					      lh->descs,
-					      vals);
+					      value_bitmap);
 	}
 	return -EINVAL;
 }
@@ -2784,7 +2784,7 @@ static int gpio_chip_get_multiple(struct gpio_chip *chip,
 int gpiod_get_array_value_complex(bool raw, bool can_sleep,
 				  unsigned int array_size,
 				  struct gpio_desc **desc_array,
-				  int *value_array)
+				  unsigned long *value_bitmap)
 {
 	int i = 0;
 
@@ -2835,7 +2835,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
 
 			if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags))
 				value = !value;
-			value_array[j] = value;
+			__assign_bit(j, value_bitmap, value);
 			trace_gpio_value(desc_to_gpio(desc), 1, value);
 		}
 
@@ -2895,9 +2895,9 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
 
 /**
  * gpiod_get_raw_array_value() - read raw values from an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be read
- * @value_array: array to store the read values
+ * @value_bitmap: bitmap to store the read values
  *
  * Read the raw values of the GPIOs, i.e. the values of the physical lines
  * without regard for their ACTIVE_LOW status.  Return 0 in case of success,
@@ -2907,20 +2907,21 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
  * and it will complain if the GPIO chip functions potentially sleep.
  */
 int gpiod_get_raw_array_value(unsigned int array_size,
-			      struct gpio_desc **desc_array, int *value_array)
+			      struct gpio_desc **desc_array,
+			      unsigned long *value_bitmap)
 {
 	if (!desc_array)
 		return -EINVAL;
 	return gpiod_get_array_value_complex(true, false, array_size,
-					     desc_array, value_array);
+					     desc_array, value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value);
 
 /**
  * gpiod_get_array_value() - read values from an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be read
- * @value_array: array to store the read values
+ * @value_bitnap: bitmap to store the read values
  *
  * Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
  * into account.  Return 0 in case of success, else an error code.
@@ -2929,12 +2930,13 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value);
  * and it will complain if the GPIO chip functions potentially sleep.
  */
 int gpiod_get_array_value(unsigned int array_size,
-			  struct gpio_desc **desc_array, int *value_array)
+			  struct gpio_desc **desc_array,
+			  unsigned long *value_bitmap)
 {
 	if (!desc_array)
 		return -EINVAL;
 	return gpiod_get_array_value_complex(false, false, array_size,
-					     desc_array, value_array);
+					     desc_array, value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_get_array_value);
 
@@ -3027,7 +3029,7 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip,
 int gpiod_set_array_value_complex(bool raw, bool can_sleep,
 				   unsigned int array_size,
 				   struct gpio_desc **desc_array,
-				   int *value_array)
+				   unsigned long *value_bitmap)
 {
 	int i = 0;
 
@@ -3056,7 +3058,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
 		do {
 			struct gpio_desc *desc = desc_array[i];
 			int hwgpio = gpio_chip_hwgpio(desc);
-			int value = value_array[i];
+			int value = test_bit(i, value_bitmap);
 
 			if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags))
 				value = !value;
@@ -3152,9 +3154,9 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
 
 /**
  * gpiod_set_raw_array_value() - assign values to an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be assigned
- * @value_array: array of values to assign
+ * @value_bitmap: bitmap of values to assign
  *
  * Set the raw values of the GPIOs, i.e. the values of the physical lines
  * without regard for their ACTIVE_LOW status.
@@ -3163,20 +3165,21 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
  * complain if the GPIO chip functions potentially sleep.
  */
 int gpiod_set_raw_array_value(unsigned int array_size,
-			 struct gpio_desc **desc_array, int *value_array)
+			 struct gpio_desc **desc_array,
+			 unsigned long *value_bitmap)
 {
 	if (!desc_array)
 		return -EINVAL;
 	return gpiod_set_array_value_complex(true, false, array_size,
-					desc_array, value_array);
+					desc_array, value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
 
 /**
  * gpiod_set_array_value() - assign values to an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be assigned
- * @value_array: array of values to assign
+ * @value_bitmap: bitmap of values to assign
  *
  * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
  * into account.
@@ -3185,12 +3188,13 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
  * complain if the GPIO chip functions potentially sleep.
  */
 void gpiod_set_array_value(unsigned int array_size,
-			   struct gpio_desc **desc_array, int *value_array)
+			   struct gpio_desc **desc_array,
+			   unsigned long *value_bitmap)
 {
 	if (!desc_array)
 		return;
 	gpiod_set_array_value_complex(false, false, array_size, desc_array,
-				      value_array);
+				      value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_array_value);
 
@@ -3410,9 +3414,9 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep);
 
 /**
  * gpiod_get_raw_array_value_cansleep() - read raw values from an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be read
- * @value_array: array to store the read values
+ * @value_bitmap: bitmap to store the read values
  *
  * Read the raw values of the GPIOs, i.e. the values of the physical lines
  * without regard for their ACTIVE_LOW status.  Return 0 in case of success,
@@ -3422,21 +3426,21 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep);
  */
 int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
 				       struct gpio_desc **desc_array,
-				       int *value_array)
+				       unsigned long *value_bitmap)
 {
 	might_sleep_if(extra_checks);
 	if (!desc_array)
 		return -EINVAL;
 	return gpiod_get_array_value_complex(true, true, array_size,
-					     desc_array, value_array);
+					     desc_array, value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep);
 
 /**
  * gpiod_get_array_value_cansleep() - read values from an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be read
- * @value_array: array to store the read values
+ * @value_bitmap: bitmap to store the read values
  *
  * Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
  * into account.  Return 0 in case of success, else an error code.
@@ -3445,13 +3449,13 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep);
  */
 int gpiod_get_array_value_cansleep(unsigned int array_size,
 				   struct gpio_desc **desc_array,
-				   int *value_array)
+				   unsigned long *value_bitmap)
 {
 	might_sleep_if(extra_checks);
 	if (!desc_array)
 		return -EINVAL;
 	return gpiod_get_array_value_complex(false, true, array_size,
-					     desc_array, value_array);
+					     desc_array, value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep);
 
@@ -3493,9 +3497,9 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
 
 /**
  * gpiod_set_raw_array_value_cansleep() - assign values to an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be assigned
- * @value_array: array of values to assign
+ * @value_bitmap: bitmap of values to assign
  *
  * Set the raw values of the GPIOs, i.e. the values of the physical lines
  * without regard for their ACTIVE_LOW status.
@@ -3504,13 +3508,13 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
  */
 int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
 					struct gpio_desc **desc_array,
-					int *value_array)
+					unsigned long *value_bitmap)
 {
 	might_sleep_if(extra_checks);
 	if (!desc_array)
 		return -EINVAL;
 	return gpiod_set_array_value_complex(true, true, array_size, desc_array,
-				      value_array);
+				      value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep);
 
@@ -3533,9 +3537,9 @@ void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n)
 
 /**
  * gpiod_set_array_value_cansleep() - assign values to an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be assigned
- * @value_array: array of values to assign
+ * @value_bitmap: bitmap of values to assign
  *
  * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
  * into account.
@@ -3544,13 +3548,13 @@ void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n)
  */
 void gpiod_set_array_value_cansleep(unsigned int array_size,
 				    struct gpio_desc **desc_array,
-				    int *value_array)
+				    unsigned long *value_bitmap)
 {
 	might_sleep_if(extra_checks);
 	if (!desc_array)
 		return;
 	gpiod_set_array_value_complex(false, true, array_size, desc_array,
-				      value_array);
+				      value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep);
 
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index a7e49fef73d4..11e83d2eef89 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -187,11 +187,11 @@ struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
 int gpiod_get_array_value_complex(bool raw, bool can_sleep,
 				  unsigned int array_size,
 				  struct gpio_desc **desc_array,
-				  int *value_array);
+				  unsigned long *value_bitmap);
 int gpiod_set_array_value_complex(bool raw, bool can_sleep,
 				   unsigned int array_size,
 				   struct gpio_desc **desc_array,
-				   int *value_array);
+				   unsigned long *value_bitmap);
 
 /* This is just passed between gpiolib and devres */
 struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index 401308e3d036..4e36e0eac7a3 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -22,18 +22,16 @@ struct gpiomux {
 	struct i2c_mux_gpio_platform_data data;
 	unsigned gpio_base;
 	struct gpio_desc **gpios;
-	int *values;
+	int *values; /* FIXME: no longer needed */
 };
 
 static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
 {
+	unsigned long value_bitmap[1] = { val, };
 	int i;
 
-	for (i = 0; i < mux->data.n_gpios; i++)
-		mux->values[i] = (val >> i) & 1;
-
 	gpiod_set_array_value_cansleep(mux->data.n_gpios,
-				       mux->gpios, mux->values);
+				       mux->gpios, value_bitmap);
 }
 
 static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan)
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
index a8b9fee4d62a..0d6e3a5be3ba 100644
--- a/drivers/mmc/core/pwrseq_simple.c
+++ b/drivers/mmc/core/pwrseq_simple.c
@@ -40,18 +40,13 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
 	struct gpio_descs *reset_gpios = pwrseq->reset_gpios;
 
 	if (!IS_ERR(reset_gpios)) {
-		int i, *values;
+		unsigned long value_bitmap[1];
 		int nvalues = reset_gpios->ndescs;
 
-		values = kmalloc_array(nvalues, sizeof(int), GFP_KERNEL);
-		if (!values)
-			return;
+		value_bitmap[0] = value;
 
-		for (i = 0; i < nvalues; i++)
-			values[i] = value;
-
-		gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, values);
-		kfree(values);
+		gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc,
+					       value_bitmap);
 	}
 }
 
diff --git a/drivers/mux/gpio.c b/drivers/mux/gpio.c
index 6fdd9316db8b..734e1b43aed6 100644
--- a/drivers/mux/gpio.c
+++ b/drivers/mux/gpio.c
@@ -17,20 +17,17 @@
 
 struct mux_gpio {
 	struct gpio_descs *gpios;
-	int *val;
+	int *val; /* FIXME: no longer needed */
 };
 
 static int mux_gpio_set(struct mux_control *mux, int state)
 {
 	struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip);
+	unsigned long value_bitmap[1] = { state, };
 	int i;
 
-	for (i = 0; i < mux_gpio->gpios->ndescs; i++)
-		mux_gpio->val[i] = (state >> i) & 1;
-
 	gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs,
-				       mux_gpio->gpios->desc,
-				       mux_gpio->val);
+				       mux_gpio->gpios->desc, value_bitmap);
 
 	return 0;
 }
diff --git a/drivers/net/phy/mdio-mux-gpio.c b/drivers/net/phy/mdio-mux-gpio.c
index bc90764a8b8d..8e1ec750277e 100644
--- a/drivers/net/phy/mdio-mux-gpio.c
+++ b/drivers/net/phy/mdio-mux-gpio.c
@@ -27,6 +27,7 @@ static int mdio_mux_gpio_switch_fn(int current_child, int desired_child,
 				   void *data)
 {
 	struct mdio_mux_gpio_state *s = data;
+	unsigned long value_bitmap[1] = { desired_child, };
 	unsigned int n;
 
 	if (current_child == desired_child)
@@ -36,7 +37,7 @@ static int mdio_mux_gpio_switch_fn(int current_child, int desired_child,
 		s->values[n] = (desired_child >> n) & 1;
 
 	gpiod_set_array_value_cansleep(s->gpios->ndescs, s->gpios->desc,
-				       s->values);
+				       value_bitmap);
 
 	return 0;
 }
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index c5f2344c189b..e0f89155c474 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -351,19 +351,22 @@ static int soc_common_pcmcia_config_skt(
 
 	if (ret == 0) {
 		struct gpio_desc *descs[2];
-		int values[2], n = 0;
+		unsigned long value_bitmap[1];
+		int n = 0;
 
 		if (skt->gpio_reset) {
 			descs[n] = skt->gpio_reset;
-			values[n++] = !!(state->flags & SS_RESET);
+			__assign_bit(n++, value_bitmap,
+				     !!(state->flags & SS_RESET));
 		}
 		if (skt->gpio_bus_enable) {
 			descs[n] = skt->gpio_bus_enable;
-			values[n++] = !!(state->flags & SS_OUTPUT_ENA);
+			__assign_bit(n++, value_bitmap,
+				     !!(state->flags & SS_OUTPUT_ENA));
 		}
 
 		if (n)
-			gpiod_set_array_value_cansleep(n, descs, values);
+			gpiod_set_array_value_cansleep(n, descs, value_bitmap);
 
 		/*
 		 * This really needs a better solution.  The IRQ
diff --git a/drivers/phy/motorola/phy-mapphone-mdm6600.c b/drivers/phy/motorola/phy-mapphone-mdm6600.c
index 0075fb0bef8c..b6477c3599c4 100644
--- a/drivers/phy/motorola/phy-mapphone-mdm6600.c
+++ b/drivers/phy/motorola/phy-mapphone-mdm6600.c
@@ -157,15 +157,12 @@ static const struct phy_ops gpio_usb_ops = {
  */
 static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val)
 {
-	int values[PHY_MDM6600_NR_CMD_LINES];
-	int i;
+	unsigned long value_bitmap[1];
 
-	val &= (1 << PHY_MDM6600_NR_CMD_LINES) - 1;
-	for (i = 0; i < PHY_MDM6600_NR_CMD_LINES; i++)
-		values[i] = (val & BIT(i)) >> i;
+	value_bitmap[0] = val & ((1 << PHY_MDM6600_NR_CMD_LINES) - 1);
 
 	gpiod_set_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES,
-				       ddata->cmd_gpios->desc, values);
+				       ddata->cmd_gpios->desc, value_bitmap);
 }
 
 /**
@@ -176,7 +173,7 @@ static void phy_mdm6600_status(struct work_struct *work)
 {
 	struct phy_mdm6600 *ddata;
 	struct device *dev;
-	int values[PHY_MDM6600_NR_STATUS_LINES];
+	unsigned long value_bitmap[1] = { 0, };
 	int error, i, val = 0;
 
 	ddata = container_of(work, struct phy_mdm6600, status_work.work);
@@ -184,14 +181,14 @@ static void phy_mdm6600_status(struct work_struct *work)
 
 	error = gpiod_get_array_value_cansleep(PHY_MDM6600_NR_STATUS_LINES,
 					       ddata->status_gpios->desc,
-					       values);
+					       value_bitmap);
 	if (error)
 		return;
 
 	for (i = 0; i < PHY_MDM6600_NR_STATUS_LINES; i++) {
-		val |= values[i] << i;
+		val |= test_bit(i, value_bitmap) << i;
 		dev_dbg(ddata->dev, "XXX %s: i: %i values[i]: %i val: %i\n",
-			__func__, i, values[i], val);
+			__func__, i, test_bit(i, value_bitmap), val);
 	}
 	ddata->status = val;
 
diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c
index 25b9fcd5e3a4..0eca047bc1cc 100644
--- a/drivers/staging/iio/adc/ad7606.c
+++ b/drivers/staging/iio/adc/ad7606.c
@@ -202,7 +202,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
 			    long mask)
 {
 	struct ad7606_state *st = iio_priv(indio_dev);
-	int values[3];
+	unsigned long value_bitmap[1];
 	int ret, i;
 
 	switch (mask) {
@@ -227,13 +227,10 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
 		if (ret < 0)
 			return ret;
 
-		values[0] = (ret >> 0) & 1;
-		values[1] = (ret >> 1) & 1;
-		values[2] = (ret >> 2) & 1;
+		value_bitmap[0] = ret;
 
 		mutex_lock(&st->lock);
-		gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc,
-				      values);
+		gpiod_set_array_value(3, st->gpio_os->desc, value_bitmap);
 		st->oversampling = val;
 		mutex_unlock(&st->lock);
 
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index 1c06325beaca..bb8b4756d72d 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -40,7 +40,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
 {
 	enum mctrl_gpio_idx i;
 	struct gpio_desc *desc_array[UART_GPIO_MAX];
-	int value_array[UART_GPIO_MAX];
+	unsigned long value_bitmap[BITS_TO_LONGS(UART_GPIO_MAX)];
 	unsigned int count = 0;
 
 	if (gpios == NULL)
@@ -49,10 +49,11 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
 	for (i = 0; i < UART_GPIO_MAX; i++)
 		if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
 			desc_array[count] = gpios->gpio[i];
-			value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl);
+			__assign_bit(count, value_bitmap,
+				     !!(mctrl & mctrl_gpios_desc[i].mctrl));
 			count++;
 		}
-	gpiod_set_array_value(count, desc_array, value_array);
+	gpiod_set_array_value(count, desc_array, value_bitmap);
 }
 EXPORT_SYMBOL_GPL(mctrl_gpio_set);
 
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index 21ddbe440030..1b21dc7b0fad 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -104,36 +104,38 @@ int gpiod_direction_output_raw(struct gpio_desc *desc, int value);
 /* Value get/set from non-sleeping context */
 int gpiod_get_value(const struct gpio_desc *desc);
 int gpiod_get_array_value(unsigned int array_size,
-			  struct gpio_desc **desc_array, int *value_array);
+			  struct gpio_desc **desc_array,
+			  unsigned long *value_bitmap);
 void gpiod_set_value(struct gpio_desc *desc, int value);
 void gpiod_set_array_value(unsigned int array_size,
-			   struct gpio_desc **desc_array, int *value_array);
+			   struct gpio_desc **desc_array,
+			   unsigned long *value_bitmap);
 int gpiod_get_raw_value(const struct gpio_desc *desc);
 int gpiod_get_raw_array_value(unsigned int array_size,
 			      struct gpio_desc **desc_array,
-			      int *value_array);
+			      unsigned long *value_bitmap);
 void gpiod_set_raw_value(struct gpio_desc *desc, int value);
 int gpiod_set_raw_array_value(unsigned int array_size,
 			       struct gpio_desc **desc_array,
-			       int *value_array);
+			       unsigned long *value_bitmap);
 
 /* Value get/set from sleeping context */
 int gpiod_get_value_cansleep(const struct gpio_desc *desc);
 int gpiod_get_array_value_cansleep(unsigned int array_size,
 				   struct gpio_desc **desc_array,
-				   int *value_array);
+				   unsigned long *value_bitmap);
 void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
 void gpiod_set_array_value_cansleep(unsigned int array_size,
 				    struct gpio_desc **desc_array,
-				    int *value_array);
+				    unsigned long *value_bitmap);
 int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc);
 int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
 				       struct gpio_desc **desc_array,
-				       int *value_array);
+				       unsigned long *value_bitmap);
 void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value);
 int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
 					struct gpio_desc **desc_array,
-					int *value_array);
+					unsigned long *value_bitmap);
 
 int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
 int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);
-- 
2.16.4

^ permalink raw reply related

* IMPORTANTE: La fiscalía general le hace el segundo llamado a interrogatorio
From: Fiscalía General de la Nación @ 2018-08-29 20:37 UTC (permalink / raw)


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


Cordial saludo,


De acuerdo a la situación que se presenta y transcurre con el proceso No 305351T  Agosto de 2018, la fiscalía general le hace el segundo llamado a interrogatorio para declaraciones y pruebas al respectivo proceso.

Este interrogatorio tiene como objetivo la aclaración de hechos contundentes.

Recuerde que esta es la primera citación y así procederemos a dos citaciones más con aviso respectivo, le agradecemos su colaboración.


A continuación nos permitimos adjuntar el proceso No 305351T  y de la misma forma la citación a declaración correspondiente a usted.




IMPORTANTE:


Clave del archivo adjunto :


procesofiscalia30535120180821e68dd993c4a8bb9e3d5e6c066946se



[-- Attachment #2: Fiscalia proceso 305351T.rar --]
[-- Type: *, Size: 144622 bytes --]

^ permalink raw reply

* Re: [PATCH] hv_netvsc: Fix a deadlock by getting rtnl_lock earlier in netvsc_probe()
From: David Miller @ 2018-08-30  0:48 UTC (permalink / raw)
  To: decui
  Cc: kys, haiyangz, sthemmin, netdev, devel, linux-kernel, olaf, apw,
	jasowang, vkuznets, marcelo.cerri, jopoulso
In-Reply-To: <PU1P153MB01692432D92B3A726FBDDC68BF300@PU1P153MB0169.APCP153.PROD.OUTLOOK.COM>

From: Dexuan Cui <decui@microsoft.com>
Date: Wed, 22 Aug 2018 21:20:03 +0000

> ---
>  drivers/net/hyperv/netvsc_drv.c | 11 ++++++++++-
>  1 file changed, 10 insertions(+), 1 deletion(-)
> 
> 
> FYI: these are the related 3 paths which show the deadlock:

This incredibly useful information belongs in the commit log
message, and therefore before the --- and signoffs.

^ permalink raw reply

* RE: [PATCH] hv_netvsc: Fix a deadlock by getting rtnl_lock earlier in netvsc_probe()
From: Dexuan Cui @ 2018-08-30  0:58 UTC (permalink / raw)
  To: David Miller
  Cc: KY Srinivasan, Haiyang Zhang, Stephen Hemminger,
	netdev@vger.kernel.org, devel@linuxdriverproject.org,
	linux-kernel@vger.kernel.org, olaf@aepfle.de, apw@canonical.com,
	jasowang@redhat.com, vkuznets, marcelo.cerri@canonical.com,
	Josh Poulson
In-Reply-To: <20180829.174841.833303774555397982.davem@davemloft.net>

> From: David Miller <davem@davemloft.net>
> Sent: Wednesday, August 29, 2018 17:49
> 
> From: Dexuan Cui <decui@microsoft.com>
> Date: Wed, 22 Aug 2018 21:20:03 +0000
> 
> > ---
> >  drivers/net/hyperv/netvsc_drv.c | 11 ++++++++++-
> >  1 file changed, 10 insertions(+), 1 deletion(-)
> >
> >
> > FYI: these are the related 3 paths which show the deadlock:
> 
> This incredibly useful information belongs in the commit log
> message, and therefore before the --- and signoffs.

Hi David,
I was afraid the call-traces are too detailed. :-)

Can you please move the info to before the --- line?

Or, should I resend the patch with the commit log updated?

Thanks,
-- Dexuan

^ permalink raw reply

* Re: [PATCH] Revert "net: stmmac: Do not keep rearming the coalesce timer in stmmac_xmit"
From: David Miller @ 2018-08-30  1:03 UTC (permalink / raw)
  To: jbrunet
  Cc: peppe.cavallaro, alexandre.torgue, joabreu, netdev, linux-kernel,
	linux-amlogic, jpinto, soares, clabbe
In-Reply-To: <20180824090440.13411-1-jbrunet@baylibre.com>

From: Jerome Brunet <jbrunet@baylibre.com>
Date: Fri, 24 Aug 2018 11:04:40 +0200

> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index ff1ffb46198a..9f458bb16f2a 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -3147,16 +3147,13 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
>  	 * element in case of no SG.
>  	 */
>  	priv->tx_count_frames += nfrags + 1;
> -	if (likely(priv->tx_coal_frames > priv->tx_count_frames) &&
> -	    !priv->tx_timer_armed) {
> +	if (likely(priv->tx_coal_frames > priv->tx_count_frames)) {
>  		mod_timer(&priv->txtimer,
>  			  STMMAC_COAL_TIMER(priv->tx_coal_timer));
> -		priv->tx_timer_armed = true;
>  	} else {
>  		priv->tx_count_frames = 0;
>  		stmmac_set_tx_ic(priv, desc);
>  		priv->xstats.tx_set_ic_bit++;
> -		priv->tx_timer_armed = false;
>  	}
>  

I think we should definitely revert this because it is racey on so many
different levels.

Yes, the scheduling of the timer only occurs here and it thus protected
by the ->xmit lock.

However, the timer itself runs and ends asynchronously to this piece
of code here.  This kind of logic only works if you tightly synchronize
the full execution of the timer with the same long, _AND_ you make the
timer resample the parameters to see if there is work still to do.

The TSO xmit code doesn't have the tx_timer_armed logic.

And finally, yes, this thing locks assuming a single queue.  This code
is seriously faulty on multi-queue and will access the TX ring of an
arbitrary queue only holding netif_tx_lock().

This stuff is really broken, so I'm reverting.  Someone has to fix the
per-queue locking in stmmac_tx_timer() too.

^ permalink raw reply

* Re: [PATCH net-next 2/3] net: nixge: Add support for having nixge as subdevice
From: Moritz Fischer @ 2018-08-30  1:07 UTC (permalink / raw)
  To: davem
  Cc: keescook, f.fainelli, Linux Kernel Mailing List, netdev,
	alex.williams
In-Reply-To: <20180830004046.9417-3-mdf@kernel.org>

On Wed, Aug 29, 2018 at 5:49 PM Moritz Fischer <mdf@kernel.org> wrote:
>
> Add support for instantiating nixge as subdevice using
> fixed-link and platform data to configure it.
>
> Signed-off-by: Moritz Fischer <mdf@kernel.org>
> ---
>
> Hi,
>
> not this patch is still in the early stages,
> and as the rest of this series goes on top of [1].
>
> The actual platform data might still change since
> the parent device driver is still under development.
>
> Thanks for your time,
>
> Moritz
>
>
> [1] https://lkml.org/lkml/2018/8/28/1011
>
> ---
>  drivers/net/ethernet/ni/nixge.c     | 71 ++++++++++++++++++++++++++---
>  include/linux/platform_data/nixge.h | 19 ++++++++
>  2 files changed, 83 insertions(+), 7 deletions(-)
>  create mode 100644 include/linux/platform_data/nixge.h
>
> diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c
> index 670249313ff0..fd8e5b02c459 100644
> --- a/drivers/net/ethernet/ni/nixge.c
> +++ b/drivers/net/ethernet/ni/nixge.c
> @@ -7,6 +7,8 @@
>  #include <linux/etherdevice.h>
>  #include <linux/module.h>
>  #include <linux/netdevice.h>
> +#include <linux/phy_fixed.h>
> +#include <linux/platform_data/nixge.h>
>  #include <linux/of_address.h>
>  #include <linux/of_mdio.h>
>  #include <linux/of_net.h>
> @@ -167,6 +169,7 @@ struct nixge_priv {
>         /* Connection to PHY device */
>         struct device_node *phy_node;
>         phy_interface_t         phy_mode;
> +       struct phy_device *phydev;
>
>         int link;
>         unsigned int speed;
> @@ -859,15 +862,25 @@ static void nixge_dma_err_handler(unsigned long data)
>  static int nixge_open(struct net_device *ndev)
>  {
>         struct nixge_priv *priv = netdev_priv(ndev);
> -       struct phy_device *phy;
> +       struct phy_device *phy = NULL;
>         int ret;
>
>         nixge_device_reset(ndev);
>
> -       phy = of_phy_connect(ndev, priv->phy_node,
> -                            &nixge_handle_link_change, 0, priv->phy_mode);
> -       if (!phy)
> -               return -ENODEV;
> +       if (priv->dev->of_node) {
> +               phy = of_phy_connect(ndev, priv->phy_node,
> +                                    &nixge_handle_link_change, 0,
> +                                    priv->phy_mode);
> +               if (!phy)
> +                       return -ENODEV;
> +       } else if (priv->phydev) {
> +               ret = phy_connect_direct(ndev, priv->phydev,
> +                                        &nixge_handle_link_change,
> +                                        priv->phy_mode);
> +               if (ret)
> +                       return ret;
> +               phy = priv->phydev;
> +       }
>
>         phy_start(phy);
>
> @@ -1215,10 +1228,41 @@ static int nixge_of_get_phy(struct nixge_priv *priv, struct device_node *np)
>         return 0;
>  }
>
> +static int nixge_pdata_get_phy(struct nixge_priv *priv,
> +                              struct nixge_platform_data *pdata)
> +{
> +       struct phy_device *phy = NULL;
> +
> +       if (!pdata)
> +               return -EINVAL;
> +
> +       if (pdata && pdata->phy_interface == PHY_INTERFACE_MODE_NA) {
> +               struct fixed_phy_status fphy_status = {
> +                       .link = 1,
> +                       .duplex = pdata->phy_duplex,
> +                       .speed = pdata->phy_speed,
> +                       .pause = 0,
> +                       .asym_pause = 0,
> +               };
> +
> +               /* TODO: Pull out GPIO from pdata */
> +               phy = fixed_phy_register(PHY_POLL, &fphy_status, -1,
> +                                        NULL);
> +               if (IS_ERR_OR_NULL(phy)) {
> +                       dev_err(priv->dev,
> +                               "failed to register fixed PHY device\n");
> +                       return -ENODEV;
> +               }
> +       }
> +       priv->phy_mode = pdata->phy_interface;
> +       priv->phydev = phy;
> +
> +       return 0;
> +}
> +
>  static int nixge_mdio_setup(struct nixge_priv *priv, struct device_node *np)
>  {
>         struct mii_bus *bus;
> -       int err;
>
>         bus = devm_mdiobus_alloc(priv->dev);
>         if (!bus)
> @@ -1254,6 +1298,7 @@ static void *nixge_get_nvmem_address(struct device *dev)
>
>  static int nixge_probe(struct platform_device *pdev)
>  {
> +       struct nixge_platform_data *pdata = NULL;
>         struct nixge_priv *priv;
>         struct net_device *ndev;
>         struct resource *dmares;
> @@ -1320,10 +1365,16 @@ static int nixge_probe(struct platform_device *pdev)
>                 err = nixge_of_get_phy(priv, np);
>                 if (err)
>                         goto free_netdev;
> +       } else {
> +               pdata = dev_get_platdata(&pdev->dev);
> +               err = nixge_pdata_get_phy(priv, pdata);
> +               if (err)
> +                       goto free_netdev;
>         }
>
>         /* only if it's not a fixed link, do we care about MDIO at all */
> -       if (priv->phy_node && !of_phy_is_fixed_link(np)) {
> +       if ((priv->phy_node && !of_phy_is_fixed_link(np)) ||
> +           (pdata && pdata->phy_interface != PHY_INTERFACE_MODE_NA)) {

Must've messed up the rebase. Missing a parents. I'll resubmit this
one. Sorry for the noise.
>                 err = nixge_mdio_setup(priv, np);
>                 if (err) {
>                         dev_err(&pdev->dev, "error registering mdio bus");
> @@ -1347,6 +1398,9 @@ static int nixge_probe(struct platform_device *pdev)
>                 of_phy_deregister_fixed_link(np);
>                 of_node_put(np);
>         }
> +
> +       if (priv->phydev && phy_is_pseudo_fixed_link(priv->phydev))
> +               fixed_phy_unregister(priv->phydev);
>  free_netdev:
>         free_netdev(ndev);
>
> @@ -1357,6 +1411,7 @@ static int nixge_remove(struct platform_device *pdev)
>  {
>         struct net_device *ndev = platform_get_drvdata(pdev);
>         struct nixge_priv *priv = netdev_priv(ndev);
> +       struct device_node *np = pdev->dev.of_node;
>
>         unregister_netdev(ndev);
>
> @@ -1365,6 +1420,8 @@ static int nixge_remove(struct platform_device *pdev)
>
>         if (np && of_phy_is_fixed_link(np))
>                 of_phy_deregister_fixed_link(np);
> +       else if (priv->phydev && phy_is_pseudo_fixed_link(priv->phydev))
> +               fixed_phy_unregister(priv->phydev);
>
>         free_netdev(ndev);
>
> diff --git a/include/linux/platform_data/nixge.h b/include/linux/platform_data/nixge.h
> new file mode 100644
> index 000000000000..aa5dd5760074
> --- /dev/null
> +++ b/include/linux/platform_data/nixge.h
> @@ -0,0 +1,19 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (c) 2018 National Instruments Corp.
> + *
> + * Author: Moritz Fischer <mdf@kernel.org>
> + */
> +
> +#ifndef __NIXGE_PDATA_H__
> +#define __NIXGE_PDATA_H__
> +
> +#include <linux/phy.h>
> +
> +struct nixge_platform_data {
> +       phy_interface_t phy_interface;
> +       int phy_speed;
> +       int phy_duplex;
> +};
> +
> +#endif /* __NIXGE_PDATA_H__ */
> +
> --
> 2.18.0
>

Thanks,
Moritz

^ permalink raw reply

* Re: [PATCH V2 net 0/2] net: hns: fix some bugs about speed and duplex change
From: David Miller @ 2018-08-30  1:08 UTC (permalink / raw)
  To: lipeng321; +Cc: netdev, linux-kernel, linuxarm, yisen.zhuang, salil.mehta
In-Reply-To: <1535335170-111030-1-git-send-email-lipeng321@huawei.com>

From: Peng Li <lipeng321@huawei.com>
Date: Mon, 27 Aug 2018 09:59:28 +0800

> If there are packets in hardware when changing the spped
> or duplex, it may cause hardware hang up.
> 
> This patchset adds the code for waiting chip to clean the all
> pkts(TX & RX) in chip when the driver uses the function named
> "adjust link".
> 
> This patchset cleans the pkts as follows:
> 1) close rx of chip, close tx of protocol stack.
> 2) wait rcb, ppe, mac to clean.
> 3) adjust link
> 4) open rx of chip, open tx of protocol stack.

Series applied, thank you.

^ permalink raw reply

* Re: [PATCH 2/2] net/ibm/emac: deletion of unneeded macros definitions
From: David Miller @ 2018-08-30  1:10 UTC (permalink / raw)
  To: ivan; +Cc: netdev, chunkeey, linux-kernel
In-Reply-To: <20180827164336.8815-2-ivan@de.ibm.com>

From: Ivan Mikhaylov <ivan@de.ibm.com>
Date: Mon, 27 Aug 2018 19:43:36 +0300

> Signed-off-by: Ivan Mikhaylov <ivan@de.ibm.com>

Please do not delete these, they could be useful for other
developers and people reading this driver.

^ permalink raw reply

* [PATCH V1] add huawei ibma driver modules The driver is used for communication between in-band management agent(iBMA) and out-of-band management controller(iBMC) via pcie bus in Huawei V3 server. The driver provides character device,VNIC and black box interface for application layer.
From: xiongsujuan @ 2018-08-30  1:11 UTC (permalink / raw)
  To: davem, zhaochen6, aviad.krawczyk, romain.perier, bhelgaas,
	keescook, colin.king
  Cc: netdev, linux-kernel

---
 drivers/net/ethernet/huawei/Kconfig               |    5 +-
 drivers/net/ethernet/huawei/Makefile              |    1 +
 drivers/net/ethernet/huawei/ibma/Kconfig          |   17 +
 drivers/net/ethernet/huawei/ibma/Makefile         |   12 +
 drivers/net/ethernet/huawei/ibma/bma_cdev.c       |  374 ++++
 drivers/net/ethernet/huawei/ibma/bma_devintf.c    |  619 ++++++
 drivers/net/ethernet/huawei/ibma/bma_devintf.h    |   39 +
 drivers/net/ethernet/huawei/ibma/bma_include.h    |  119 +
 drivers/net/ethernet/huawei/ibma/bma_ker_intf.h   |   89 +
 drivers/net/ethernet/huawei/ibma/bma_pci.c        |  515 +++++
 drivers/net/ethernet/huawei/ibma/bma_pci.h        |   87 +
 drivers/net/ethernet/huawei/ibma/edma_cmd.h       |   81 +
 drivers/net/ethernet/huawei/ibma/edma_host.c      | 1547 +++++++++++++
 drivers/net/ethernet/huawei/ibma/edma_host.h      |  357 +++
 drivers/net/ethernet/huawei/ibma/kbox_dump.c      |  141 ++
 drivers/net/ethernet/huawei/ibma/kbox_dump.h      |   35 +
 drivers/net/ethernet/huawei/ibma/kbox_hook.c      |  105 +
 drivers/net/ethernet/huawei/ibma/kbox_hook.h      |   34 +
 drivers/net/ethernet/huawei/ibma/kbox_include.h   |   44 +
 drivers/net/ethernet/huawei/ibma/kbox_main.c      |  207 ++
 drivers/net/ethernet/huawei/ibma/kbox_main.h      |   25 +
 drivers/net/ethernet/huawei/ibma/kbox_mce.c       |  293 +++
 drivers/net/ethernet/huawei/ibma/kbox_mce.h       |   25 +
 drivers/net/ethernet/huawei/ibma/kbox_panic.c     |  195 ++
 drivers/net/ethernet/huawei/ibma/kbox_panic.h     |   27 +
 drivers/net/ethernet/huawei/ibma/kbox_printk.c    |  377 ++++
 drivers/net/ethernet/huawei/ibma/kbox_printk.h    |   35 +
 drivers/net/ethernet/huawei/ibma/kbox_ram_drive.c |  212 ++
 drivers/net/ethernet/huawei/ibma/kbox_ram_drive.h |   33 +
 drivers/net/ethernet/huawei/ibma/kbox_ram_image.c |  138 ++
 drivers/net/ethernet/huawei/ibma/kbox_ram_image.h |   91 +
 drivers/net/ethernet/huawei/ibma/kbox_ram_op.c    | 1003 +++++++++
 drivers/net/ethernet/huawei/ibma/kbox_ram_op.h    |   77 +
 drivers/net/ethernet/huawei/ibma/memcpy_s.c       |   90 +
 drivers/net/ethernet/huawei/ibma/memset_s.c       |   71 +
 drivers/net/ethernet/huawei/ibma/securec.h        |   87 +
 drivers/net/ethernet/huawei/ibma/veth_hb.c        | 2467 +++++++++++++++++++++
 drivers/net/ethernet/huawei/ibma/veth_hb.h        |  578 +++++
 38 files changed, 10251 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/huawei/ibma/Kconfig
 create mode 100644 drivers/net/ethernet/huawei/ibma/Makefile
 create mode 100644 drivers/net/ethernet/huawei/ibma/bma_cdev.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/bma_devintf.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/bma_devintf.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/bma_include.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/bma_ker_intf.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/bma_pci.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/bma_pci.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/edma_cmd.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/edma_host.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/edma_host.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_dump.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_dump.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_hook.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_hook.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_include.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_main.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_main.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_mce.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_mce.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_panic.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_panic.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_printk.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_printk.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_ram_drive.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_ram_drive.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_ram_image.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_ram_image.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_ram_op.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/kbox_ram_op.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/memcpy_s.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/memset_s.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/securec.h
 create mode 100644 drivers/net/ethernet/huawei/ibma/veth_hb.c
 create mode 100644 drivers/net/ethernet/huawei/ibma/veth_hb.h

diff --git a/drivers/net/ethernet/huawei/Kconfig b/drivers/net/ethernet/huawei/Kconfig
index c1a95ae..68748e9 100644
--- a/drivers/net/ethernet/huawei/Kconfig
+++ b/drivers/net/ethernet/huawei/Kconfig
@@ -4,7 +4,7 @@
 
 config NET_VENDOR_HUAWEI
 	bool "Huawei devices"
-	default y
+	default y 
 	---help---
 	  If you have a network (Ethernet) card belonging to this class, say Y.
 	  Note that the answer to this question doesn't directly affect the
@@ -16,4 +16,7 @@ if NET_VENDOR_HUAWEI
 
 source "drivers/net/ethernet/huawei/hinic/Kconfig"
 
+source "drivers/net/ethernet/huawei/ibma/Kconfig"
+
+
 endif # NET_VENDOR_HUAWEI
diff --git a/drivers/net/ethernet/huawei/Makefile b/drivers/net/ethernet/huawei/Makefile
index 5c37cc8..2221f48 100644
--- a/drivers/net/ethernet/huawei/Makefile
+++ b/drivers/net/ethernet/huawei/Makefile
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_HINIC) += hinic/
+obj-$(CONFIG_IBMANIC) += ibma/
diff --git a/drivers/net/ethernet/huawei/ibma/Kconfig b/drivers/net/ethernet/huawei/ibma/Kconfig
new file mode 100644
index 0000000..810cc60
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/Kconfig
@@ -0,0 +1,17 @@
+#
+# Huawei driver configuration
+#
+
+config IBMANIC
+	tristate "Huawei IBMA PCIE Network Interface Card"
+	depends on (PCI_MSI && X86)
+	---help---
+	  This driver supports IBMANIC PCIE Ethernet cards.
+	  To compile this driver as part of the kernel, choose Y here.
+	  If unsure, choose N.
+	  The default is compiled as module.
+
+
+
+
+
diff --git a/drivers/net/ethernet/huawei/ibma/Makefile b/drivers/net/ethernet/huawei/ibma/Makefile
new file mode 100644
index 0000000..b37fb48
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/Makefile
@@ -0,0 +1,12 @@
+
+
+
+obj-$(CONFIG_IBMANIC) += host_edma_drv.o host_cdev_drv.o host_veth_drv.o host_kbox_drv.o
+host_edma_drv-y := bma_pci.o bma_devintf.o edma_host.o memcpy_s.o memset_s.o
+
+host_cdev_drv-y := bma_cdev.o
+
+host_veth_drv-y := veth_hb.o
+
+host_kbox_drv-y := kbox_main.o kbox_ram_drive.o kbox_ram_image.o kbox_ram_op.o kbox_printk.o kbox_dump.o kbox_hook.o kbox_mce.o kbox_panic.o
+
diff --git a/drivers/net/ethernet/huawei/ibma/bma_cdev.c b/drivers/net/ethernet/huawei/ibma/bma_cdev.c
new file mode 100644
index 0000000..95eb606
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/bma_cdev.c
@@ -0,0 +1,374 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/miscdevice.h>
+#include "bma_include.h"
+#include "bma_ker_intf.h"
+
+#define CDEV_NAME_PREFIX	"hwibmc"
+
+#ifdef DRV_VERSION
+#define CDEV_VERSION		MICRO_TO_STR(DRV_VERSION)
+#else
+#define CDEV_VERSION		"0.2.9"
+#endif
+
+#define CDEV_DEFAULT_NUM	4
+#define CDEV_MAX_NUM		8
+
+#define CDEV_NAME_MAX_LEN	32
+#define CDEV_INVALID_ID		(0xffffffff)
+
+struct cdev_statistics_s {
+	unsigned int recv_bytes;
+	unsigned int send_bytes;
+	unsigned int send_pkgs;
+	unsigned int recv_pkgs;
+	unsigned int send_failed_count;
+	unsigned int recv_failed_count;
+	unsigned int open_status;
+};
+
+struct cdev_dev {
+	struct miscdevice dev_struct;
+	struct cdev_statistics_s s;
+	char dev_name[CDEV_NAME_MAX_LEN];
+	dev_t dev_id;
+	void *dev_data;
+	atomic_t open;
+	int type;
+};
+
+struct cdev_dev_set {
+	struct cdev_dev dev_list[CDEV_MAX_NUM];
+	int dev_num;
+	unsigned int init_time;
+};
+
+int dev_num = CDEV_DEFAULT_NUM;	/* the dev num want to create */
+int debug = DLOG_ERROR;                  /* debug switch */
+module_param(dev_num, int, 0640);
+MODULE_PARM_DESC(dev_num, "cdev num you want");
+MODULE_PARM_DESC(debug, "Debug switch (0=close debug, 1=open debug)");
+
+#define CDEV_LOG(level, fmt, args...) do {\
+	if (debug >= level) {\
+		printk(KERN_NOTICE "edma_cdev: %s, %d, " fmt"\n", \
+		__func__, __LINE__, ## args);\
+		} \
+	} while (0)
+
+static int cdev_open(struct inode *inode, struct file *filp);
+static int cdev_release(struct inode *inode, struct file *filp);
+static unsigned int cdev_poll(struct file *file, poll_table *wait);
+static ssize_t cdev_read(struct file *filp, char __user  *data, size_t count,
+			 loff_t *ppos);
+static ssize_t cdev_write(struct file *filp, const char __user *data,
+			  size_t count, loff_t *ppos);
+
+struct cdev_dev_set g_cdev_set;
+
+#define INC_CDEV_STATS(pdev, name, count) \
+	(((struct cdev_dev *)pdev)->s.name += (count))
+#define GET_PRIVATE_DATA(f) (((struct cdev_dev *)((f)->private_data))->dev_data)
+
+module_param_call(debug, &edma_param_set_debug, &param_get_int, &debug, 0644);
+
+static int cdev_param_get_statics(char *buf, struct kernel_param *kp)
+{
+	int len = 0;
+	int i = 0;
+	__kernel_time_t running_time = 0;
+
+	if (!buf)
+		return 0;
+
+	GET_SYS_SECONDS(running_time);
+	running_time -= g_cdev_set.init_time;
+	len += sprintf(buf + len,
+		       "============================CDEV_DRIVER_INFO=======================\n");
+	len += sprintf(buf + len, "version      :%s\n", CDEV_VERSION);
+
+	len += sprintf(buf + len, "running_time :%luD %02lu:%02lu:%02lu\n",
+		       running_time / (SECONDS_PER_DAY),
+		       running_time % (SECONDS_PER_DAY) / SECONDS_PER_HOUR,
+		       running_time % SECONDS_PER_HOUR / SECONDS_PER_MINUTE,
+		       running_time % SECONDS_PER_MINUTE);
+
+	for (i = 0; i < g_cdev_set.dev_num; i++) {
+		len += sprintf(buf + len,
+			       "===================================================\n");
+		len += sprintf(buf + len, "name      :%s\n",
+			       g_cdev_set.dev_list[i].dev_name);
+		len +=
+		    sprintf(buf + len, "dev_id    :%08x\n",
+			    g_cdev_set.dev_list[i].dev_id);
+		len += sprintf(buf + len, "type      :%u\n",
+			       g_cdev_set.dev_list[i].type);
+		len += sprintf(buf + len, "status    :%s\n",
+			       g_cdev_set.dev_list[i].s.open_status ==
+			       1 ? "open" : "close");
+		len += sprintf(buf + len, "send_pkgs :%u\n",
+			       g_cdev_set.dev_list[i].s.send_pkgs);
+		len +=
+		    sprintf(buf + len, "send_bytes:%u\n",
+			    g_cdev_set.dev_list[i].s.send_bytes);
+		len += sprintf(buf + len, "send_failed_count:%u\n",
+			       g_cdev_set.dev_list[i].s.send_failed_count);
+		len += sprintf(buf + len, "recv_pkgs :%u\n",
+			       g_cdev_set.dev_list[i].s.recv_pkgs);
+		len += sprintf(buf + len, "recv_bytes:%u\n",
+			       g_cdev_set.dev_list[i].s.recv_bytes);
+		len += sprintf(buf + len, "recv_failed_count:%u\n",
+			       g_cdev_set.dev_list[i].s.recv_failed_count);
+	}
+
+	return len;
+}
+module_param_call(statistics, NULL, cdev_param_get_statics, &debug, 0444);
+MODULE_PARM_DESC(statistics, "Statistics info of cdev driver,readonly");
+
+const struct file_operations g_bma_cdev_fops = {
+	.owner = THIS_MODULE,
+	.open = cdev_open,
+	.release = cdev_release,
+	.poll = cdev_poll,
+	.read = cdev_read,
+	.write = cdev_write,
+};
+
+static int __init bma_cdev_init(void)
+{
+	int i = 0;
+
+	int ret = 0;
+	int err_count = 0;
+
+	if (!bma_intf_check_edma_supported())
+		return -ENXIO;
+
+	if (dev_num <= 0 || dev_num > CDEV_MAX_NUM)
+		return -EINVAL;
+
+	memset(&g_cdev_set, 0, sizeof(struct cdev_dev_set));
+	g_cdev_set.dev_num = dev_num;
+
+	for (i = 0; i < dev_num; i++) {
+		struct cdev_dev *pDev = &g_cdev_set.dev_list[i];
+
+		sprintf(pDev->dev_name, "%s%d", CDEV_NAME_PREFIX, i);
+		pDev->dev_struct.name = pDev->dev_name;
+		pDev->dev_struct.minor = MISC_DYNAMIC_MINOR;
+		pDev->dev_struct.fops = &g_bma_cdev_fops;
+
+		pDev->dev_id = CDEV_INVALID_ID;
+
+		ret = misc_register(&pDev->dev_struct);
+
+		if (ret) {
+			CDEV_LOG(DLOG_DEBUG, "misc_register failed %d", i);
+			err_count++;
+			continue;
+		}
+
+		pDev->dev_id = MKDEV(MISC_MAJOR, pDev->dev_struct.minor);
+
+		ret = bma_intf_register_type(TYPE_CDEV + i, 0, INTR_DISABLE,
+					     &pDev->dev_data);
+
+		if (ret) {
+			CDEV_LOG(DLOG_ERROR,
+				 "cdev %d open failed ,result = %d",
+				 i, ret);
+		misc_deregister(&pDev->dev_struct);
+		pDev->dev_id = CDEV_INVALID_ID;
+		err_count++;
+		continue;
+		} else {
+			pDev->type = TYPE_CDEV + i;
+			atomic_set(&pDev->open, 1);
+		}
+
+		CDEV_LOG(DLOG_DEBUG, "%s id is %08x", pDev->dev_struct.name,
+			 pDev->dev_id);
+	}
+
+	if (err_count == dev_num) {
+		CDEV_LOG(DLOG_ERROR, "init cdev failed!");
+		return -EFAULT;
+	}
+	GET_SYS_SECONDS(g_cdev_set.init_time);
+	return 0;
+}
+
+static void __exit bma_cdev_exit(void)
+{
+	while (dev_num--) {
+		struct cdev_dev *pDev = &g_cdev_set.dev_list[dev_num];
+
+		if (pDev->dev_id != CDEV_INVALID_ID) {
+			if (pDev->dev_data != NULL && pDev->type != 0)
+				(void)bma_intf_unregister_type(&pDev->dev_data);
+
+			(void)misc_deregister(
+				&g_cdev_set.dev_list[dev_num].dev_struct);
+		}
+	}
+}
+
+int cdev_open(struct inode *inode_prt, struct file *filp)
+{
+	int i = 0;
+	struct cdev_dev *pDev = NULL;
+
+	if (!inode_prt)
+		return -EFAULT;
+	if (!filp)
+		return -EFAULT;
+
+	if (dev_num <= 0) {
+		CDEV_LOG(DLOG_ERROR, "dev_num error");
+		return -EFAULT;
+	}
+
+	for (i = 0; i < dev_num; i++) {
+		pDev = &g_cdev_set.dev_list[i];
+
+		if (pDev->dev_id == inode_prt->i_rdev)
+			break;
+	}
+
+	if (i == dev_num) {
+		CDEV_LOG(DLOG_ERROR, "can not find dev id %08x",
+			 inode_prt->i_rdev);
+		return -ENODEV;
+	}
+	/*each device can be opened only onece */
+	if (atomic_dec_and_test(&pDev->open) == 0) {
+
+		CDEV_LOG(DLOG_ERROR, "%s is already opened",
+				 pDev->dev_name);
+			atomic_inc(&pDev->open);
+			return -EBUSY;	/* already opened */
+	}
+
+	filp->private_data = &g_cdev_set.dev_list[i];
+	bma_intf_set_open_status(pDev->dev_data, DEV_OPEN);
+	INC_CDEV_STATS(filp->private_data, open_status, 1);
+
+	return 0;
+
+}
+
+int cdev_release(struct inode *inode_prt, struct file *filp)
+{
+	struct cdev_dev *pDev = NULL;
+
+	if (!filp)
+		return 0;
+
+	pDev = (struct cdev_dev *)filp->private_data;
+	if (pDev) {
+		INC_CDEV_STATS(filp->private_data, open_status, -1);
+		bma_intf_set_open_status(pDev->dev_data, DEV_CLOSE);
+		atomic_inc(&pDev->open);
+		filp->private_data = NULL;
+	}
+
+	return 0;
+}
+
+unsigned int cdev_poll(struct file *filp, poll_table *wait)
+{
+	unsigned int mask = 0;
+	wait_queue_head_t *queue_head = NULL;
+
+	if (!filp)
+		return 0;
+	queue_head = (wait_queue_head_t *)
+	    bma_cdev_get_wait_queue(GET_PRIVATE_DATA(filp));
+
+	if (!queue_head)
+		return 0;
+
+	poll_wait(filp, queue_head, wait);
+
+	if (bma_cdev_check_recv(GET_PRIVATE_DATA(filp)))
+		mask |= (POLLIN | POLLRDNORM);
+
+	CDEV_LOG(DLOG_DEBUG, "poll return %08x", mask);
+
+	return mask;
+}
+
+ssize_t cdev_read(struct file *filp, char __user *data, size_t count,
+		  loff_t *ppos)
+{
+	int ret = 0;
+
+	CDEV_LOG(DLOG_DEBUG, "data is %p,count is %u", data,
+		 (unsigned int)count);
+
+	if (!data || count <= 0)
+		return -EFAULT;
+
+	ret = bma_cdev_recv_msg(GET_PRIVATE_DATA(filp), data, count);
+
+	if (ret > 0) {
+		INC_CDEV_STATS(filp->private_data, recv_bytes, ret);
+		INC_CDEV_STATS(filp->private_data, recv_pkgs, 1);
+	} else {
+		INC_CDEV_STATS(filp->private_data, recv_failed_count, 1);
+	}
+
+	return ret;
+
+}
+
+ssize_t cdev_write(struct file *filp, const char __user *data, size_t count,
+		   loff_t *ppos)
+{
+	int ret = 0;
+
+	if (!data || count <= 0)
+		return -EFAULT;
+
+	CDEV_LOG(DLOG_DEBUG, "data is %p,count is %u", data,
+		 (unsigned int)count);
+	ret = bma_cdev_add_msg(GET_PRIVATE_DATA(filp), data, count);
+
+	if (ret > 0) {
+		INC_CDEV_STATS(filp->private_data, send_bytes, ret);
+		INC_CDEV_STATS(filp->private_data, send_pkgs, 1);
+	} else {
+		INC_CDEV_STATS(filp->private_data, send_failed_count, 1);
+	}
+
+	return ret;
+}
+
+MODULE_AUTHOR("HUAWEI TECHNOLOGIES CO., LTD.");
+MODULE_DESCRIPTION("HUAWEI CDEV DRIVER");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CDEV_VERSION);
+
+module_init(bma_cdev_init);
+module_exit(bma_cdev_exit);
diff --git a/drivers/net/ethernet/huawei/ibma/bma_devintf.c b/drivers/net/ethernet/huawei/ibma/bma_devintf.c
new file mode 100644
index 0000000..af5efc6
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/bma_devintf.c
@@ -0,0 +1,619 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <asm/ioctls.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/notifier.h>
+#include "bma_ker_intf.h"
+#include "bma_include.h"
+#include "bma_devintf.h"
+#include "bma_pci.h"
+#include "edma_host.h"
+
+static struct bma_dev_s *g_bma_dev;
+
+static ATOMIC_NOTIFIER_HEAD(bma_int_notify_list);
+
+static int bma_priv_insert_priv_list(struct bma_priv_data_s *priv, u32 type,
+				     u32 sub_type)
+{
+	unsigned long flags = 0;
+	int ret = 0;
+	struct edma_user_inft_s *user_inft = NULL;
+
+	if (type >= TYPE_MAX || !priv)
+		return -EFAULT;
+
+	user_inft = edma_host_get_user_inft(type);
+
+	if (user_inft && user_inft->user_register) {
+		ret = user_inft->user_register(priv);
+		if (ret) {
+			BMA_LOG(DLOG_ERROR, "register failed\n");
+			return -EFAULT;
+		}
+	} else {
+		if (!g_bma_dev)
+			return -ENXIO;
+
+		if (atomic_dec_and_test(&(g_bma_dev->au_count[type])) == 0) {
+
+			BMA_LOG(DLOG_ERROR,
+				"busy, init_dev_type.type = %d, au_count = %d\n",
+				type,
+				atomic_read(&(g_bma_dev->au_count[type])));
+			atomic_inc(&g_bma_dev->au_count[type]);
+			return -EBUSY;	/* already register */
+		}
+
+		priv->user.type = type;
+		priv->user.sub_type = sub_type;
+		priv->user.user_id = 0;
+
+		spin_lock_irqsave(&g_bma_dev->priv_list_lock, flags);
+
+		list_add_rcu(&priv->user.link, &g_bma_dev->priv_list);
+
+		spin_unlock_irqrestore(&g_bma_dev->priv_list_lock, flags);
+	}
+
+	return 0;
+}
+static int bma_priv_delete_priv_list(struct bma_priv_data_s *priv)
+{
+	unsigned long flags = 0;
+	struct edma_user_inft_s *user_inft = NULL;
+
+	if (!priv || priv->user.type >= TYPE_MAX)
+		return -EFAULT;
+	user_inft = edma_host_get_user_inft(priv->user.type);
+	if (user_inft && user_inft->user_register) {
+		user_inft->user_unregister(priv);
+	} else {
+		if (!g_bma_dev)
+			return -ENXIO;
+		spin_lock_irqsave(&g_bma_dev->priv_list_lock, flags);
+		list_del_rcu(&priv->user.link);
+		spin_unlock_irqrestore(&g_bma_dev->priv_list_lock,
+								flags);
+		/* release the type */
+		atomic_inc(&g_bma_dev->au_count[priv->user.type]);
+	}
+	return 0;
+}
+
+static int bma_priv_init(struct bma_priv_data_s **bma_priv)
+{
+	struct bma_priv_data_s *priv = NULL;
+
+	if (!bma_priv)
+		return -EFAULT;
+
+	priv = kmalloc(sizeof(struct bma_priv_data_s),
+					GFP_KERNEL); /*lint !e64*/
+	if (!priv) {
+		BMA_LOG(DLOG_ERROR, "malloc priv failed\n");
+		return -ENOMEM;
+	}
+
+	(void)memset_s(priv, sizeof(struct bma_priv_data_s), 0,
+		       sizeof(struct bma_priv_data_s));
+
+	spin_lock_init(&priv->recv_msg_lock);
+	INIT_LIST_HEAD(&priv->recv_msgs);
+	init_waitqueue_head(&priv->wait);
+
+	priv->user.type = TYPE_UNKNOWN;
+	priv->user.sub_type = 0;
+	priv->user.dma_transfer = 0;
+	priv->user.seq = 0;
+	priv->user.cur_recvmsg_nums = 0;
+	priv->user.max_recvmsg_nums = DEFAULT_MAX_RECV_MSG_NUMS;
+
+	*bma_priv = priv;
+
+	return 0;
+}
+
+static void bma_priv_clean_up(struct bma_priv_data_s *bma_priv)
+{
+	int ret = 0;
+	int i = 0;
+	struct bma_priv_data_s *priv = bma_priv;
+	struct edma_recv_msg_s *msg = NULL;
+
+	if (!priv)
+		return;
+
+	if (priv->user.type == TYPE_UNKNOWN) {
+		BMA_LOG(DLOG_ERROR, "already unknown type\n");
+		return;
+	}
+
+	for (i = 0; i < priv->user.max_recvmsg_nums; i++) {
+		ret = edma_host_recv_msg(&g_bma_dev->edma_host, priv, &msg);
+		if (ret)
+			break;
+
+		kfree(msg);
+	}
+
+	priv->user.type = TYPE_UNKNOWN;
+	priv->user.sub_type = 0;
+	priv->user.dma_transfer = 0;
+	priv->user.seq = 0;
+	priv->user.cur_recvmsg_nums = 0;
+	priv->user.max_recvmsg_nums = DEFAULT_MAX_RECV_MSG_NUMS;
+	kfree(priv);
+}
+
+static irqreturn_t bma_irq_handle(int irq, void *data)
+{
+	struct bma_dev_s *bma_dev = (struct bma_dev_s *)data;
+
+	if (!bma_dev)
+		return IRQ_HANDLED;
+
+	bma_dev->edma_host.statistics.b2h_int++;
+
+	if (!is_edma_b2h_int(&bma_dev->edma_host))
+		return edma_host_irq_handle(&bma_dev->edma_host);
+
+	return (irqreturn_t) atomic_notifier_call_chain(&bma_int_notify_list, 0,
+							data);
+}
+
+int bma_devinft_init(struct bma_pci_dev_s *bma_pci_dev)
+{
+	int ret = 0;
+	int i = 0;
+	struct bma_dev_s *bma_dev = NULL;
+
+	if (!bma_pci_dev)
+		return -EFAULT;
+
+	bma_dev = kmalloc(sizeof(struct bma_dev_s),
+						(int)GFP_KERNEL); /*lint !e64*/
+	if (!bma_dev)
+		return -ENOMEM;
+
+	(void)memset_s(bma_dev, sizeof(struct bma_dev_s), 0,
+		       sizeof(struct bma_dev_s));
+
+	bma_dev->bma_pci_dev = bma_pci_dev;
+	bma_pci_dev->bma_dev = bma_dev;
+
+	INIT_LIST_HEAD(&(bma_dev->priv_list));
+	spin_lock_init(&bma_dev->priv_list_lock);
+
+	for (i = 0; i < TYPE_MAX; i++)
+		atomic_set(&(bma_dev->au_count[i]), 1);
+
+	ret = edma_host_init(&bma_dev->edma_host);
+	if (ret) {
+		BMA_LOG(DLOG_ERROR, "init edma host failed!err = %d\n", ret);
+		goto err_free_bma_dev;
+	}
+
+	BMA_LOG(DLOG_DEBUG, "irq = %d\n", bma_pci_dev->pdev->irq);
+
+	ret = request_irq(bma_pci_dev->pdev->irq, bma_irq_handle, IRQF_SHARED,
+			"EDMA_IRQ", (void *)bma_dev);
+	if (ret) {
+		BMA_LOG(DLOG_ERROR, "request_irq failed!err = %d\n", ret);
+		goto err_edma_host_exit;
+	}
+
+	g_bma_dev = bma_dev;
+	BMA_LOG(DLOG_DEBUG, "ok\n");
+
+	return 0;
+
+err_edma_host_exit:
+	edma_host_cleanup(&bma_dev->edma_host);
+
+err_free_bma_dev:
+	kfree(bma_dev);
+	bma_pci_dev->bma_dev = NULL;
+
+	return ret;
+}
+
+void bma_devinft_cleanup(struct bma_pci_dev_s *bma_pci_dev)
+{
+	if (g_bma_dev) {
+		if ((bma_pci_dev) && (bma_pci_dev->pdev)
+		    && (bma_pci_dev->pdev->irq)) {
+			BMA_LOG(DLOG_DEBUG, "irq = %d\n",
+				bma_pci_dev->pdev->irq);
+			free_irq(bma_pci_dev->pdev->irq,
+				 (void *)bma_pci_dev->bma_dev);
+		}
+
+		edma_host_cleanup(&g_bma_dev->edma_host);
+
+		if ((bma_pci_dev) && (bma_pci_dev->bma_dev)) {
+			kfree(bma_pci_dev->bma_dev);
+			bma_pci_dev->bma_dev = NULL;
+		}
+
+		g_bma_dev = NULL;
+	}
+}
+
+int bma_intf_register_int_notifier(struct notifier_block *nb)
+{
+	if (!nb)
+		return -1;
+
+	return atomic_notifier_chain_register(&bma_int_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(bma_intf_register_int_notifier);
+
+void bma_intf_unregister_int_notifier(struct notifier_block *nb)
+{
+	if (!nb)
+		return;
+
+	atomic_notifier_chain_unregister(&bma_int_notify_list, nb);
+}
+EXPORT_SYMBOL_GPL(bma_intf_unregister_int_notifier);
+
+int bma_intf_register_type(u32 type, u32 sub_type, enum intr_mod support_int,
+			   void **handle)
+{
+	int ret = 0;
+	struct bma_priv_data_s *priv = NULL;
+
+	if (!handle)
+		return -EFAULT;
+
+	ret = bma_priv_init(&priv);
+	if (ret) {
+		BMA_LOG(DLOG_ERROR, "bma_priv_init failed! ret = %d\n", ret);
+		return ret;
+	}
+
+	ret = bma_priv_insert_priv_list(priv, type, sub_type);
+	if (ret) {
+		bma_priv_clean_up(priv);
+		BMA_LOG(DLOG_ERROR,
+			"bma_priv_insert_priv_list failed! ret = %d\n", ret);
+		return ret;
+	}
+
+	if (support_int)
+		priv->user.support_int = INTR_ENABLE;
+
+	if (type == TYPE_VETH) {
+		priv->specific.veth.pdev = g_bma_dev->bma_pci_dev->pdev;
+
+		priv->specific.veth.veth_swap_phy_addr =
+		    g_bma_dev->bma_pci_dev->veth_swap_phy_addr;
+		priv->specific.veth.veth_swap_addr =
+		    g_bma_dev->bma_pci_dev->veth_swap_addr;
+		priv->specific.veth.veth_swap_len =
+		    g_bma_dev->bma_pci_dev->veth_swap_len;
+	}
+
+	*handle = priv;
+
+	return 0;
+}
+EXPORT_SYMBOL(bma_intf_register_type);
+
+int bma_intf_unregister_type(void **handle)
+{
+	struct bma_priv_data_s *priv = NULL;
+
+	if (!handle) {
+		BMA_LOG(DLOG_ERROR, "edna_priv is NULL\n");
+		return -EFAULT;
+	}
+
+	priv = (struct bma_priv_data_s *)*handle;
+	*handle = NULL;
+
+	priv->user.cur_recvmsg_nums++;
+	wake_up_interruptible(&(priv->wait));
+
+	msleep(500);
+
+	bma_priv_delete_priv_list(priv);
+
+	bma_priv_clean_up(priv);
+
+	return 0;
+}
+EXPORT_SYMBOL(bma_intf_unregister_type);
+
+int bma_intf_check_edma_supported(void)
+{
+	return !(g_bma_dev == NULL);
+}
+EXPORT_SYMBOL(bma_intf_check_edma_supported);
+
+int bma_intf_check_dma_status(enum dma_direction_e dir)
+{
+	return edma_host_check_dma_status(dir);
+}
+EXPORT_SYMBOL(bma_intf_check_dma_status);
+
+void bma_intf_reset_dma(enum dma_direction_e dir)
+{
+	edma_host_reset_dma(&g_bma_dev->edma_host, dir);
+}
+EXPORT_SYMBOL(bma_intf_reset_dma);
+
+void bma_intf_clear_dma_int(enum dma_direction_e dir)
+{
+	if (dir == BMC_TO_HOST)
+		clear_int_dmab2h(&g_bma_dev->edma_host);
+	else if (dir == HOST_TO_BMC)
+		clear_int_dmah2b(&g_bma_dev->edma_host);
+	else
+		return;
+}
+EXPORT_SYMBOL(bma_intf_clear_dma_int);
+
+int bma_intf_start_dma(void *handle, struct bma_dma_transfer_s *dma_transfer)
+{
+	int ret = 0;
+	struct bma_priv_data_s *priv = (struct bma_priv_data_s *)handle;
+
+	if (!handle || !dma_transfer)
+		return -EFAULT;
+
+	ret = edma_host_dma_start(&g_bma_dev->edma_host, priv);
+	if (ret) {
+		BMA_LOG(DLOG_ERROR,
+			"edma_host_dma_start failed! result = %d\n", ret);
+		return ret;
+	}
+
+	ret = edma_host_dma_transfer(&g_bma_dev->edma_host, priv, dma_transfer);
+	if (ret)
+		BMA_LOG(DLOG_ERROR,
+			"edma_host_dma_transfer failed! ret = %d\n", ret);
+
+	ret = edma_host_dma_stop(&g_bma_dev->edma_host, priv);
+	if (ret) {
+		BMA_LOG(DLOG_ERROR,
+			"edma_host_dma_stop failed! result = %d\n", ret);
+		return ret;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(bma_intf_start_dma);
+
+int bma_intf_int_to_bmc(void *handle)
+{
+	struct bma_priv_data_s *priv = (struct bma_priv_data_s *)handle;
+
+	if (!handle) {
+		BMA_LOG(DLOG_ERROR, "input NULL! bma_priv = %p\n", handle);
+		return -EFAULT;
+	}
+
+	if (priv->user.support_int == 0) {
+		BMA_LOG(DLOG_ERROR, "not support int to bmc.\n");
+		return -EFAULT;
+	}
+
+	edma_int_to_bmc(&g_bma_dev->edma_host);
+
+	return 0;
+}
+EXPORT_SYMBOL(bma_intf_int_to_bmc);
+
+int bma_intf_is_link_ok(void)
+{
+	return (g_bma_dev->edma_host.statistics.remote_status ==
+		REGISTERED) ? 1 : 0;
+}
+EXPORT_SYMBOL(bma_intf_is_link_ok);
+
+int bma_cdev_recv_msg(void *handle, char __user *data, size_t count)
+{
+	struct bma_priv_data_s *priv = NULL;
+	struct edma_recv_msg_s *msg = NULL;
+	int result = 0;
+	int len = 0;
+	int ret = 0;
+
+	if ((!handle) || (!data) || (count == 0)) {
+		BMA_LOG(DLOG_DEBUG, "input NULL point!\n");
+		return -EFAULT;
+	}
+
+	priv = (struct bma_priv_data_s *)handle;
+
+	result = edma_host_recv_msg(&g_bma_dev->edma_host, priv, &msg);
+	if (result != 0) {
+		ret = -ENODATA;
+		goto failed;
+	}
+
+	if (msg->msg_len > count) {
+		ret = -EFAULT;
+		goto failed;
+	}
+
+	if (copy_to_user(data, (void *)(msg->msg_data), msg->msg_len)) {
+		ret = -EFAULT;
+		goto failed;
+	}
+
+	len = msg->msg_len;
+
+	kfree(msg);
+
+	return len;
+failed:
+	kfree(msg);
+
+	return ret;
+
+}
+EXPORT_SYMBOL_GPL(bma_cdev_recv_msg);
+
+int bma_cdev_add_msg(void *handle, const char __user *msg, size_t msg_len)
+{
+	struct bma_priv_data_s *priv = NULL;
+	struct edma_msg_hdr_s *hdr = NULL;
+	unsigned long flags = 0;
+	int total_len = 0;
+	int ret = 0;
+
+	if ((!handle) || (!msg) || (msg_len == 0)) {
+		BMA_LOG(DLOG_DEBUG, "input NULL point!\n");
+		return -EFAULT;
+	}
+
+	if (msg_len > CDEV_MAX_WRITE_LEN) {
+		BMA_LOG(DLOG_DEBUG, "input data is overlen!\n");
+		return -EINVAL;
+	}
+
+	priv = (struct bma_priv_data_s *)handle;
+
+	if (priv->user.type >= TYPE_MAX) {
+		BMA_LOG(DLOG_DEBUG, "error type = %d\n", priv->user.type);
+		return -EFAULT;
+	}
+	total_len = SIZE_OF_MSG_HDR + msg_len;
+
+	spin_lock_irqsave(&g_bma_dev->edma_host.send_msg_lock, flags);
+
+	if (g_bma_dev->edma_host.msg_send_write + total_len <=
+	    HOST_MAX_SEND_MBX_LEN - SIZE_OF_MBX_HDR) {
+		hdr = (struct edma_msg_hdr_s *)(
+				g_bma_dev->edma_host.msg_send_buf
+				+ g_bma_dev->edma_host.msg_send_write);
+		hdr->type = priv->user.type;
+		hdr->sub_type = priv->user.sub_type;
+		hdr->user_id = priv->user.user_id;
+		hdr->datalen = msg_len;
+		BMA_LOG(DLOG_DEBUG, "hdr->data is %p\n", hdr->data);
+		BMA_LOG(DLOG_DEBUG,
+			"g_edmaprivate.msg_send_buf is %p\n",
+			g_bma_dev->edma_host.msg_send_buf);
+		BMA_LOG(DLOG_DEBUG, "msg is %p\n", msg);
+		BMA_LOG(DLOG_DEBUG, "msg_len is %ld\n", msg_len);
+
+		if (copy_from_user(hdr->data, msg, msg_len)) {
+			BMA_LOG(DLOG_ERROR, "copy_from_user error\n");
+		ret = -EFAULT;
+		goto end;
+		}
+
+		g_bma_dev->edma_host.msg_send_write += total_len;
+		g_bma_dev->edma_host.statistics.send_bytes += total_len;
+		g_bma_dev->edma_host.statistics.send_pkgs++;
+#ifdef EDMA_TIMER
+		(void)mod_timer(&g_bma_dev->edma_host.timer,
+				jiffies_64);
+#endif
+		BMA_LOG(DLOG_DEBUG, "msg_send_write = %d\n",
+			g_bma_dev->edma_host.msg_send_write);
+
+		ret = msg_len;
+		goto end;
+	} else {
+
+		BMA_LOG(DLOG_DEBUG,
+			"msg lost,msg_send_write: %d,msg_len:%d,max_len: %d\n",
+			g_bma_dev->edma_host.msg_send_write, total_len,
+			HOST_MAX_SEND_MBX_LEN);
+		ret = -ENOSPC;
+		goto end;
+	}
+
+end:
+	spin_unlock_irqrestore(&(g_bma_dev->edma_host.send_msg_lock), flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(bma_cdev_add_msg);
+
+unsigned int bma_cdev_check_recv(void *handle)
+{
+	struct bma_priv_data_s *priv = (struct bma_priv_data_s *)handle;
+	unsigned long flags = 0;
+	unsigned int result = 0;
+
+	if (priv != NULL) {
+		spin_lock_irqsave(&priv->recv_msg_lock, flags);
+
+		if (!list_empty(&priv->recv_msgs))
+			result = 1;
+
+		spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
+	}
+
+	return result;
+}
+EXPORT_SYMBOL_GPL(bma_cdev_check_recv);
+
+void *bma_cdev_get_wait_queue(void *handle)
+{
+	struct bma_priv_data_s *priv = (struct bma_priv_data_s *)handle;
+
+	return priv ? ((void *)&priv->wait) : NULL;
+}
+EXPORT_SYMBOL_GPL(bma_cdev_get_wait_queue);
+
+void bma_intf_set_open_status(void *handle, int s)
+{
+	struct bma_priv_data_s *priv = (struct bma_priv_data_s *)handle;
+	int i = 0;
+	int ret = 0;
+	unsigned long flags = 0;
+	char drv_msg[3] = { 0 };
+	struct edma_recv_msg_s *tmp_msg = NULL;
+
+	if (priv == NULL || priv->user.type >= TYPE_MAX)
+		return;
+
+	drv_msg[0] = 1;
+	drv_msg[1] = priv->user.type;
+	drv_msg[2] = s;
+
+	(void)edma_host_send_driver_msg((void *)drv_msg, sizeof(drv_msg),
+						DEV_OPEN_STATUS_ANS);
+
+		spin_lock_irqsave(&priv->recv_msg_lock, flags);
+		g_bma_dev->edma_host.local_open_status[priv->user.type] = s;
+
+		if (s == DEV_CLOSE && priv->user.cur_recvmsg_nums > 0) {
+			for (i = 0; i < priv->user.max_recvmsg_nums; i++) {
+				ret = edma_host_recv_msg(&g_bma_dev->edma_host,
+						priv, &tmp_msg);
+				if (ret < 0)
+					break;
+
+				kfree(tmp_msg);
+				tmp_msg = NULL;
+			}
+		}
+
+		spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
+}
+EXPORT_SYMBOL_GPL(bma_intf_set_open_status);
diff --git a/drivers/net/ethernet/huawei/ibma/bma_devintf.h b/drivers/net/ethernet/huawei/ibma/bma_devintf.h
new file mode 100644
index 0000000..25ad9a5
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/bma_devintf.h
@@ -0,0 +1,39 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _BMA_DEVINTF_H_
+#define _BMA_DEVINTF_H_
+
+#include <linux/mutex.h>
+#include "bma_pci.h"
+#include "edma_host.h"
+
+struct bma_dev_s {
+	/* proc */
+	struct proc_dir_entry *proc_bma_root;
+
+	atomic_t au_count[TYPE_MAX];
+
+	struct list_head priv_list;
+	spinlock_t priv_list_lock;
+
+	struct bma_pci_dev_s *bma_pci_dev;
+	struct edma_host_s edma_host;
+};
+
+int bma_devinft_init(struct bma_pci_dev_s *bma_pci_dev);
+void bma_devinft_cleanup(struct bma_pci_dev_s *bma_pci_dev);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/ibma/bma_include.h b/drivers/net/ethernet/huawei/ibma/bma_include.h
new file mode 100644
index 0000000..5950be2
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/bma_include.h
@@ -0,0 +1,119 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _BMA_INCLUDE_H_
+#define _BMA_INCLUDE_H_
+
+#include <linux/slab.h>
+#include <asm/ioctls.h>
+#include <linux/capability.h>
+#include <linux/uaccess.h>	/* copy_*_user */
+#include <linux/delay.h>	/* udelay */
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>	/*tasklet */
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18))	/*lint !e30 !e553 */
+#include <asm/semaphore.h>
+#else
+#include <linux/semaphore.h>
+#endif
+#include <linux/sched.h>
+#include "securec.h"
+
+#define UNUSED(x) (x = x)
+#define KBOX_FALSE (-1)
+#define KBOX_TRUE 0
+
+#define KBOX_IOC_MAGIC (0xB2)
+
+#define DEFAULT_MAX_RECV_MSG_NUMS   32
+#define MAX_RECV_MSG_NUMS 1024
+
+#define STRFICATION(R) #R
+#define MICRO_TO_STR(R) STRFICATION(R)
+
+
+enum {
+	DLOG_ERROR = 0,
+	DLOG_DEBUG = 1,
+};
+
+enum {
+	DEV_CLOSE = 0,
+	DEV_OPEN = 1,
+	DEV_OPEN_STATUS_REQ = 0xf0,
+	DEV_OPEN_STATUS_ANS
+};
+
+#define BAD_FUNC_ADDR(x) ((0xFFFFFFFF == (x)) || (0 == (x)))
+
+
+struct bma_user_s {
+	struct list_head link;
+
+	u32 type;
+	u32 sub_type;
+	u8 user_id;
+
+	u8 dma_transfer:1, support_int:1;
+
+	u8 reserve1[2];
+	u32 seq;
+	u16 cur_recvmsg_nums;
+	u16 max_recvmsg_nums;
+};
+
+struct bma_priv_data_veth_s {
+	struct pci_dev *pdev;
+
+	unsigned long veth_swap_phy_addr;
+	void __iomem *veth_swap_addr;
+	unsigned long veth_swap_len;
+};
+
+struct bma_priv_data_s {
+	struct bma_user_s user;
+	spinlock_t recv_msg_lock;
+	struct list_head recv_msgs;
+	struct file *file;
+	wait_queue_head_t wait;
+
+	union {
+		struct bma_priv_data_veth_s veth;
+	} specific;
+};
+
+void __iomem *kbox_get_base_addr(void);
+unsigned long kbox_get_io_len(void);
+unsigned long kbox_get_base_phy_addr(void);
+int edma_param_set_debug(const char *buf, struct kernel_param *kp);
+#define GET_SYS_SECONDS(t) do \
+	{\
+		struct timespec uptime;\
+		get_monotonic_boottime(&uptime);\
+		t = uptime.tv_sec;\
+	} while (0)
+
+
+#define SECONDS_PER_DAY (24*3600)
+#define SECONDS_PER_HOUR (3600)
+#define SECONDS_PER_MINUTE (60)
+
+#endif
diff --git a/drivers/net/ethernet/huawei/ibma/bma_ker_intf.h b/drivers/net/ethernet/huawei/ibma/bma_ker_intf.h
new file mode 100644
index 0000000..5e91925
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/bma_ker_intf.h
@@ -0,0 +1,89 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _BMA_KER_INTF_H_
+#define _BMA_KER_INTF_H_
+
+enum {
+	/* 0 -127 msg */
+	TYPE_LOGIC_PARTITION = 0,
+	TYPE_UPGRADE = 1,
+	TYPE_CDEV = 2,
+	TYPE_VETH = 0x40,
+	TYPE_MAX = 128,
+
+	TYPE_KBOX = 129,
+	TYPE_EDMA_DRIVER = 130,
+	TYPE_UNKNOWN = 0xff,
+};
+
+enum dma_direction_e {
+	BMC_TO_HOST = 0,
+	HOST_TO_BMC = 1,
+};
+
+enum dma_type_e {
+	DMA_NOT_LIST = 0,
+	DMA_LIST = 1,
+};
+
+enum intr_mod {
+	INTR_DISABLE = 0,
+	INTR_ENABLE = 1,
+};
+struct bma_dma_addr_s {
+	dma_addr_t dma_addr;
+	u32 dma_data_len;
+};
+
+struct dma_transfer_s {
+	struct bma_dma_addr_s host_addr;
+	struct bma_dma_addr_s bmc_addr;
+};
+
+struct dmalist_transfer_s {
+	dma_addr_t dma_addr;
+};
+
+struct bma_dma_transfer_s {
+	enum dma_type_e type;
+	enum dma_direction_e dir;
+
+	union {
+		struct dma_transfer_s nolist;
+		struct dmalist_transfer_s list;
+	} transfer;
+};
+
+int bma_intf_register_int_notifier(struct notifier_block *nb);
+void bma_intf_unregister_int_notifier(struct notifier_block *nb);
+int bma_intf_register_type(u32 type, u32 sub_type, enum intr_mod support_int,
+			   void **handle);
+int bma_intf_unregister_type(void **handle);
+int bma_intf_check_dma_status(enum dma_direction_e dir);
+int bma_intf_start_dma(void *handle, struct bma_dma_transfer_s *dma_transfer);
+int bma_intf_int_to_bmc(void *handle);
+void bma_intf_set_open_status(void *handle, int s);
+int bma_intf_is_link_ok(void);
+void bma_intf_reset_dma(enum dma_direction_e dir);
+void bma_intf_clear_dma_int(enum dma_direction_e dir);
+
+int bma_cdev_recv_msg(void *handle, char __user *data, size_t count);
+int bma_cdev_add_msg(void *handle, const char __user *msg, size_t msg_len);
+
+unsigned int bma_cdev_check_recv(void *handle);
+void *bma_cdev_get_wait_queue(void *handle);
+int bma_intf_check_edma_supported(void);
+#endif
diff --git a/drivers/net/ethernet/huawei/ibma/bma_pci.c b/drivers/net/ethernet/huawei/ibma/bma_pci.c
new file mode 100644
index 0000000..55c4bd9
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/bma_pci.c
@@ -0,0 +1,515 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/pci.h>
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include "bma_include.h"
+#include "bma_devintf.h"
+#include "bma_pci.h"
+
+#define PCI_KBOX_MODULE_NAME		"edma_drv"
+#define PCI_VENDOR_ID_HUAWEI_FPGA	0x19aa
+#define PCI_DEVICE_ID_KBOX_0		0xe004
+
+#define PCI_VENDOR_ID_HUAWEI_PME	0x19e5
+#define PCI_DEVICE_ID_KBOX_0_PME	0x1710
+#define PCI_PME_USEABLE_SPACE		(4 * 1024 * 1024)
+
+#define PCI_BAR0_PME_1710		0x85800000
+#define PCI_BAR0			0
+#define PCI_BAR1			1
+#define PCI_USING_DAC_DEFAULT 0
+
+int pci_using_dac = PCI_USING_DAC_DEFAULT;
+int debug = DLOG_ERROR;
+MODULE_PARM_DESC(debug, "Debug switch (0=close debug, 1=open debug)");
+
+static struct bma_pci_dev_s *g_bma_pci_dev;
+
+static int bma_pci_suspend(struct pci_dev *pdev, pm_message_t state);
+static int bma_pci_resume(struct pci_dev *pdev);
+static int bma_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void bma_pci_remove(struct pci_dev *pdev);
+
+static const struct pci_device_id bma_pci_tbl[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_HUAWEI_FPGA, PCI_DEVICE_ID_KBOX_0)},
+	{PCI_DEVICE(PCI_VENDOR_ID_HUAWEI_PME, PCI_DEVICE_ID_KBOX_0_PME)},
+	{}
+};
+MODULE_DEVICE_TABLE(pci, bma_pci_tbl);/*lint !e19*/
+
+int edma_param_get_statics(char *buf, struct kernel_param *kp)
+{
+	if (!buf)
+		return 0;
+
+	return edmainfo_show(buf);
+}
+
+
+module_param_call(statistics, NULL, edma_param_get_statics, &debug, 0444);
+MODULE_PARM_DESC(statistics, "Statistics info of edma driver,readonly");
+
+int edma_param_set_debug(const char *buf, struct kernel_param *kp)
+{
+	unsigned long val = 0;
+	int ret = 0;
+
+	if (!buf)
+		return -EINVAL;
+#if (KERNEL_VERSION(3, 0, 0) < LINUX_VERSION_CODE)
+	ret = kstrtoul(buf, 0, &val);
+#else
+	ret = strict_strtoul(buf, 0, &val);
+#endif
+	if (ret)
+		return ret;
+
+	if (val > 1)
+		return -EINVAL;
+
+	return param_set_int(buf, kp);
+}
+EXPORT_SYMBOL_GPL(edma_param_set_debug);
+
+module_param_call(debug, &edma_param_set_debug, &param_get_int, &debug, 0644);
+
+
+void __iomem *kbox_get_base_addr(void)
+{
+	if ((!g_bma_pci_dev)
+		|| (!(g_bma_pci_dev->kbox_base_addr))) {
+		BMA_LOG(DLOG_ERROR, "kbox_base_addr NULL point\n");
+		return NULL;
+	}
+
+	return g_bma_pci_dev->kbox_base_addr;
+}
+EXPORT_SYMBOL_GPL(kbox_get_base_addr);
+
+unsigned long kbox_get_io_len(void)
+{
+	if (!g_bma_pci_dev) {
+		BMA_LOG(DLOG_ERROR, "kbox_io_len is error,can not get it\n");
+		return 0;
+	}
+
+	return g_bma_pci_dev->kbox_base_len;
+}
+EXPORT_SYMBOL_GPL(kbox_get_io_len);
+
+unsigned long kbox_get_base_phy_addr(void)
+{
+	if ((!g_bma_pci_dev) || (!g_bma_pci_dev->kbox_base_phy_addr)) {
+		BMA_LOG(DLOG_ERROR, "kbox_base_phy_addr NULL point\n");
+		return 0;
+	}
+
+	return g_bma_pci_dev->kbox_base_phy_addr;
+}
+EXPORT_SYMBOL_GPL(kbox_get_base_phy_addr);
+
+static struct pci_driver bma_driver = {
+	.name = PCI_KBOX_MODULE_NAME,
+	.id_table = bma_pci_tbl,
+	.probe = bma_pci_probe,
+	.remove = bma_pci_remove,
+	.suspend = bma_pci_suspend,
+	.resume = bma_pci_resume,
+};
+
+s32 __atu_config_H(struct pci_dev *pdev, unsigned int region,
+		   unsigned int hostaddr_h, unsigned int hostaddr_l,
+		   unsigned int bmcaddr_h, unsigned int bmcaddr_l,
+		   unsigned int len)
+{
+
+	/*  atu index reg,inbound and region*//*lint -e648 */
+	(void)pci_write_config_dword(pdev, ATU_VIEWPORT,
+		REGION_DIR_INPUT + (region & REGION_INDEX_MASK));
+	(void)pci_write_config_dword(pdev, ATU_BASE_LOW, hostaddr_l);
+	(void)pci_write_config_dword(pdev, ATU_BASE_HIGH, hostaddr_h);
+	(void)pci_write_config_dword(pdev, ATU_LIMIT, hostaddr_l + len - 1);
+	(void)pci_write_config_dword(pdev, ATU_TARGET_LOW, bmcaddr_l);
+	(void)pci_write_config_dword(pdev, ATU_TARGET_HIGH, bmcaddr_h);
+	/*  atu ctrl1 reg   */
+	(void)pci_write_config_dword(pdev, ATU_REGION_CTRL1, ATU_CTRL1_DEFAULT);
+	/*  atu ctrl2 reg   */
+	(void)pci_write_config_dword(pdev, ATU_REGION_CTRL2, REGION_ENABLE);
+	/*lint +e648 */
+	return 0;
+}
+
+static void iounmap_bar_mem(struct bma_pci_dev_s *bma_pci_dev)
+{
+	if (bma_pci_dev->kbox_base_addr) {
+		iounmap(bma_pci_dev->kbox_base_addr);
+		bma_pci_dev->kbox_base_addr = NULL;
+	}
+
+	if (bma_pci_dev->bma_base_addr) {
+		iounmap(bma_pci_dev->bma_base_addr);
+		bma_pci_dev->bma_base_addr = NULL;
+		bma_pci_dev->edma_swap_addr = NULL;
+		bma_pci_dev->hostrtc_viraddr = NULL;
+	}
+}
+
+static int ioremap_bar_mem(struct pci_dev *pdev,
+			   struct bma_pci_dev_s *bma_pci_dev)
+{
+	int err = 0;
+	unsigned long bar0_resource_flag = 0;
+	unsigned long bar1_resource_flag = 0;
+	u32 data = 0;
+
+	BMA_LOG(DLOG_DEBUG, "pdev : %p\n", pdev);
+
+	bar0_resource_flag = pci_resource_flags(pdev, PCI_BAR0);
+
+	if (!(bar0_resource_flag & IORESOURCE_MEM)) {
+		BMA_LOG(DLOG_ERROR,
+			"Cannot find proper PCI device base address, aborting\n");
+		err = -ENODEV;
+		return err;
+	}
+
+	bma_pci_dev->kbox_base_phy_addr = pci_resource_start(pdev, PCI_BAR0);
+
+	bma_pci_dev->kbox_base_len = pci_resource_len(pdev, PCI_BAR0);
+
+	BMA_LOG(DLOG_DEBUG,
+		"bar0: kbox_base_phy_addr = 0x%lx, base_len = %ld(0x%lx)\n",
+		bma_pci_dev->kbox_base_phy_addr, bma_pci_dev->kbox_base_len,
+		bma_pci_dev->kbox_base_len);
+
+	if ((pdev->device == PCI_DEVICE_ID_KBOX_0_PME)
+	    && (pdev->vendor == PCI_VENDOR_ID_HUAWEI_PME)) {
+
+		bma_pci_dev->kbox_base_len = PCI_PME_USEABLE_SPACE;
+		BMA_LOG(DLOG_DEBUG, "1710\n");
+
+		bma_pci_dev->bma_base_phy_addr =
+		    pci_resource_start(pdev, PCI_BAR1);
+		bar1_resource_flag = pci_resource_flags(pdev, PCI_BAR1);
+
+		if (!(bar1_resource_flag & IORESOURCE_MEM)) {
+			BMA_LOG(DLOG_ERROR,
+				"Cannot find proper PCI device base address, aborting\n");
+			return -ENODEV;
+		}
+
+		bma_pci_dev->bma_base_len = pci_resource_len(pdev, PCI_BAR1);
+		bma_pci_dev->edma_swap_len = EDMA_SWAP_DATA_SIZE;
+		bma_pci_dev->veth_swap_len = VETH_SWAP_DATA_SIZE;
+
+		BMA_LOG(DLOG_DEBUG,
+			"bar1: bma_base_len = 0x%lx, edma_swap_len = %ld, veth_swap_len = %ld(0x%lx)\n",
+			bma_pci_dev->bma_base_len, bma_pci_dev->edma_swap_len,
+			bma_pci_dev->veth_swap_len, bma_pci_dev->veth_swap_len);
+
+		bma_pci_dev->hostrtc_phyaddr = bma_pci_dev->bma_base_phy_addr;
+		/* edma */
+		bma_pci_dev->edma_swap_phy_addr =
+			bma_pci_dev->bma_base_phy_addr + EDMA_SWAP_BASE_OFFSET;
+		/* veth */
+		bma_pci_dev->veth_swap_phy_addr =
+			bma_pci_dev->edma_swap_phy_addr + EDMA_SWAP_DATA_SIZE;
+
+		BMA_LOG(DLOG_DEBUG,
+			"bar1: hostrtc_phyaddr = 0x%lx, edma_swap_phy_addr = 0x%lx, veth_swap_phy_addr = 0x%lx\n",
+			bma_pci_dev->hostrtc_phyaddr,
+			bma_pci_dev->edma_swap_phy_addr,
+			bma_pci_dev->veth_swap_phy_addr);
+
+		__atu_config_H(pdev, 0, (sizeof(unsigned long) == 8) ?
+		((u64)(bma_pci_dev->kbox_base_phy_addr) >> 32)
+		: 0,/*lint !e506 !e572 */
+		((u64)(bma_pci_dev->kbox_base_phy_addr) &
+		0xffffffff), 0, PCI_BAR0_PME_1710,
+		PCI_PME_USEABLE_SPACE);
+
+		__atu_config_H(pdev, 1, (sizeof(unsigned long) == 8) ?
+		(bma_pci_dev->hostrtc_phyaddr >> 32) : 0,/*lint !e506 !e572 */
+		(bma_pci_dev->hostrtc_phyaddr & 0xffffffff),
+		0, HOSTRTC_REG_BASE, HOSTRTC_REG_SIZE);
+
+		__atu_config_H(pdev, 2, (sizeof(unsigned long) == 8) ?
+		(bma_pci_dev->edma_swap_phy_addr >> 32)
+		: 0,/*lint !e506 !e572 */
+		(bma_pci_dev->edma_swap_phy_addr & 0xffffffff),
+		0, EDMA_SWAP_DATA_BASE, EDMA_SWAP_DATA_SIZE);
+
+		__atu_config_H(pdev, 3, (sizeof(unsigned long) == 8) ?
+		(bma_pci_dev->veth_swap_phy_addr >> 32)
+		: 0,/*lint !e506 !e572 */
+		(bma_pci_dev->veth_swap_phy_addr & 0xffffffff),
+		0, VETH_SWAP_DATA_BASE, VETH_SWAP_DATA_SIZE);
+
+		if (bar1_resource_flag & IORESOURCE_CACHEABLE) {
+			bma_pci_dev->bma_base_addr =
+			    ioremap(bma_pci_dev->bma_base_phy_addr,
+				    bma_pci_dev->bma_base_len);
+		} else {
+			bma_pci_dev->bma_base_addr =
+			    ioremap_nocache(bma_pci_dev->bma_base_phy_addr,
+					    bma_pci_dev->bma_base_len);
+		}
+
+		if (!bma_pci_dev->bma_base_addr) {
+			BMA_LOG(DLOG_ERROR,
+				"Cannot map device registers, aborting\n");
+
+			return -ENODEV;
+		} else {
+			bma_pci_dev->hostrtc_viraddr =
+			    bma_pci_dev->bma_base_addr;
+			bma_pci_dev->edma_swap_addr =
+			    (unsigned char *)bma_pci_dev->bma_base_addr +
+			    EDMA_SWAP_BASE_OFFSET;
+			bma_pci_dev->veth_swap_addr =
+			    (unsigned char *)bma_pci_dev->edma_swap_addr +
+			    EDMA_SWAP_DATA_SIZE;
+
+		(void)pci_read_config_dword(pdev, 0x78, &data);
+			data = data & 0xfffffff0;
+			(void)pci_write_config_dword(pdev, 0x78, data);
+		(void)pci_read_config_dword(pdev, 0x78, &data);
+
+			BMA_LOG(DLOG_DEBUG,
+				"hostrtc_viraddr = %p, edma_swap_addr = %p, veth_swap_addr = %p\n",
+				bma_pci_dev->hostrtc_viraddr,
+				bma_pci_dev->edma_swap_addr,
+				bma_pci_dev->veth_swap_addr);
+		}
+	}
+
+	BMA_LOG(DLOG_DEBUG, "remap BAR0 KBOX\n");
+
+	if (bar0_resource_flag & IORESOURCE_CACHEABLE) {
+		bma_pci_dev->kbox_base_addr =
+		    ioremap(bma_pci_dev->kbox_base_phy_addr,
+			    bma_pci_dev->kbox_base_len);
+	} else {
+		bma_pci_dev->kbox_base_addr =
+		    ioremap_nocache(bma_pci_dev->kbox_base_phy_addr,
+				    bma_pci_dev->kbox_base_len);
+	}
+
+	BMA_LOG(DLOG_DEBUG, "kbox_base_addr = %p\n",
+		bma_pci_dev->kbox_base_addr);
+
+	if (!bma_pci_dev->kbox_base_addr) {
+		BMA_LOG(DLOG_ERROR, "Cannot map device registers, aborting\n");
+
+		iounmap(bma_pci_dev->bma_base_addr);
+		bma_pci_dev->bma_base_addr = NULL;
+		bma_pci_dev->edma_swap_addr = NULL;
+		bma_pci_dev->hostrtc_viraddr = NULL;
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int bma_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int err = 0;
+	struct bma_pci_dev_s *bma_pci_dev = NULL;
+
+	UNUSED(ent);
+
+	if (g_bma_pci_dev)
+		return -EPERM;
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		BMA_LOG(DLOG_ERROR, "Cannot enable PCI device,aborting\n");
+		return err;
+	}
+
+	if ((pdev->device == PCI_DEVICE_ID_KBOX_0_PME)
+	    && (pdev->vendor == PCI_VENDOR_ID_HUAWEI_PME)) {
+		pci_set_master(pdev);
+
+#ifdef CONFIG_PCI_MSI
+	if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
+		BMA_LOG(DLOG_DEBUG, "support msi\n");
+	} else {
+		BMA_LOG(DLOG_ERROR, "not support msi\n");
+		goto err_out_disable_pdev;
+	}
+
+		err = pci_enable_msi(pdev);
+		if (err) {
+			BMA_LOG(DLOG_ERROR, "pci_enable_msi failed\n");
+			goto err_out_disable_pdev;
+		}
+#endif
+	}
+
+	BMA_LOG(DLOG_DEBUG, "pdev->device = 0x%x\n", pdev->device);
+	BMA_LOG(DLOG_DEBUG, "pdev->vendor = 0x%x\n", pdev->vendor);
+
+	bma_pci_dev = kmalloc(sizeof(struct bma_pci_dev_s),
+						GFP_KERNEL); /*lint !e64*/
+	if (!bma_pci_dev) {
+		err = -ENOMEM;
+		goto err_out_disable_msi;
+	}
+
+	bma_pci_dev->pdev = pdev;
+
+	err = pci_request_regions(pdev, PCI_KBOX_MODULE_NAME);
+	if (err) {
+		BMA_LOG(DLOG_ERROR, "Cannot obtain PCI resources, aborting\n");
+		goto err_out_free_dev;
+	}
+
+	err = ioremap_bar_mem(pdev, bma_pci_dev);
+	if (err) {
+		BMA_LOG(DLOG_ERROR, "ioremap_edma_io_mem failed\n");
+		goto err_out_release_regions;
+	}
+
+	g_bma_pci_dev = bma_pci_dev;
+
+	err = dma_set_mask(&(pdev->dev), DMA_BIT_MASK(64));
+
+	if (err) {
+		err = dma_set_coherent_mask(&(pdev->dev),
+				DMA_BIT_MASK(64)); /*lint !e1055*/
+
+		if (err) {
+
+			BMA_LOG(DLOG_ERROR,
+				"No usable DMA ,configuration, aborting,goto failed2!!!\n");
+			goto err_out_unmap_bar;
+		}
+	}
+
+	g_bma_pci_dev = bma_pci_dev;
+
+	if ((pdev->device == PCI_DEVICE_ID_KBOX_0_PME)
+	    && (pdev->vendor == PCI_VENDOR_ID_HUAWEI_PME)) {
+		err = bma_devinft_init(bma_pci_dev);
+		if (err) {
+			BMA_LOG(DLOG_ERROR, "bma_devinft_init failed\n");
+			goto err_out_clean_devinft;
+		}
+	} else {
+		BMA_LOG(DLOG_DEBUG, "edma is not supported on this pcie\n");
+	}
+
+	pci_set_drvdata(pdev, bma_pci_dev);
+
+	return 0;
+
+err_out_clean_devinft:
+	bma_devinft_cleanup(bma_pci_dev);
+err_out_unmap_bar:
+	iounmap_bar_mem(bma_pci_dev);
+	g_bma_pci_dev = NULL;
+err_out_release_regions:
+	pci_release_regions(pdev);
+err_out_free_dev:
+	kfree(bma_pci_dev);
+	bma_pci_dev = NULL;
+
+err_out_disable_msi:
+
+#ifdef CONFIG_PCI_MSI
+	pci_disable_msi(pdev);
+#endif
+err_out_disable_pdev:
+
+	pci_disable_device(pdev);
+
+	return err;
+}
+
+static void bma_pci_remove(struct pci_dev *pdev)
+{
+	struct bma_pci_dev_s *bma_pci_dev =
+		(struct bma_pci_dev_s *)pci_get_drvdata(pdev);	/*lint !e1055 */
+
+	g_bma_pci_dev = NULL;
+	(void)pci_set_drvdata(pdev, NULL);
+
+	if (bma_pci_dev) {
+		bma_devinft_cleanup(bma_pci_dev);
+
+		iounmap_bar_mem(bma_pci_dev);
+
+		kfree(bma_pci_dev);
+	}
+
+	pci_release_regions(pdev);
+
+
+#ifdef CONFIG_PCI_MSI
+	pci_disable_msi(pdev);
+#endif
+	pci_disable_device(pdev);
+}
+
+static int bma_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	UNUSED(pdev);
+	UNUSED(state);
+
+	return 0;
+}
+
+static int bma_pci_resume(struct pci_dev *pdev)
+{
+	UNUSED(pdev);
+
+	return 0;
+}
+
+int __init bma_pci_init(void)
+{
+	int ret = 0;
+
+	BMA_LOG(DLOG_DEBUG, "\n");
+
+	ret = pci_register_driver(&bma_driver);
+	if (ret)
+		BMA_LOG(DLOG_ERROR, "pci_register_driver failed\n");
+
+	return ret;
+}
+
+void __exit bma_pci_cleanup(void)
+{
+	BMA_LOG(DLOG_DEBUG, "\n");
+
+	pci_unregister_driver(&bma_driver);
+}
+
+/*lint -e19*/
+MODULE_AUTHOR("HUAWEI TECHNOLOGIES CO., LTD.");
+MODULE_DESCRIPTION("HUAWEI EDMA DRIVER");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(BMA_VERSION);
+#ifndef _lint
+
+module_init(bma_pci_init);
+module_exit(bma_pci_cleanup);
+#endif
+/*lint +e19*/
diff --git a/drivers/net/ethernet/huawei/ibma/bma_pci.h b/drivers/net/ethernet/huawei/ibma/bma_pci.h
new file mode 100644
index 0000000..41bd4b7
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/bma_pci.h
@@ -0,0 +1,87 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _BMA_PCI_H_
+#define _BMA_PCI_H_
+
+#include "bma_devintf.h"
+#include "bma_include.h"
+
+#define EDMA_SWAP_BASE_OFFSET	0x10000
+
+#define HOSTRTC_REG_BASE	0x2f000000
+#define HOSTRTC_REG_SIZE	EDMA_SWAP_BASE_OFFSET
+
+#define EDMA_SWAP_DATA_BASE	0x84810000
+#define EDMA_SWAP_DATA_SIZE	65536
+
+#define VETH_SWAP_DATA_BASE	0x84820000
+#define VETH_SWAP_DATA_SIZE	0xdf000
+
+#define ATU_VIEWPORT		0x900
+#define	ATU_REGION_CTRL1	0x904
+#define ATU_REGION_CTRL2	0x908
+#define ATU_BASE_LOW		0x90C
+#define ATU_BASE_HIGH		0x910
+#define ATU_LIMIT		0x914
+#define	ATU_TARGET_LOW		0x918
+#define ATU_TARGET_HIGH		0x91C
+#define REGION_DIR_OUTPUT	(0x0 << 31)
+#define REGION_DIR_INPUT	(0x1 << 31)
+#define REGION_INDEX_MASK	0x7
+#define	REGION_ENABLE		(0x1 << 31)
+#define	ATU_CTRL1_DEFAULT	0x0
+struct bma_pci_dev_s {
+	unsigned long kbox_base_phy_addr;
+	void __iomem *kbox_base_addr;
+	unsigned long kbox_base_len;
+
+	unsigned long bma_base_phy_addr;
+	void __iomem *bma_base_addr;
+	unsigned long bma_base_len;
+
+	unsigned long hostrtc_phyaddr;
+	void __iomem *hostrtc_viraddr;
+
+	unsigned long edma_swap_phy_addr;
+	void __iomem *edma_swap_addr;
+	unsigned long edma_swap_len;
+
+	unsigned long veth_swap_phy_addr;
+	void __iomem *veth_swap_addr;
+	unsigned long veth_swap_len;
+
+	struct pci_dev *pdev;
+	struct bma_dev_s *bma_dev;
+};
+
+#ifdef DRV_VERSION
+#define BMA_VERSION MICRO_TO_STR(DRV_VERSION)
+#else
+#define BMA_VERSION "0.2.9"
+#endif
+
+extern int debug;
+
+#define BMA_LOG(level, fmt, args...) \
+	do { \
+		if (debug >= level)\
+			printk(KERN_ALERT "edma: %s, %d, " fmt, \
+				__func__, __LINE__, ## args); \
+	} while (0)
+
+int edmainfo_show(char *buff);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/ibma/edma_cmd.h b/drivers/net/ethernet/huawei/ibma/edma_cmd.h
new file mode 100644
index 0000000..d14804d
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/edma_cmd.h
@@ -0,0 +1,81 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _EDMA_CMD_H_
+#define _EDMA_CMD_H_
+
+#include <linux/types.h>
+
+/* direction */
+#define CMD_H2B		0x80000000	/* H2B */
+#define CMD_B2H		0x00000000	/* B2H */
+
+/* logic partition */
+#define CMD_LP			0x00000100
+#define CMD_H2B_LP_HEARTBEAT	(CMD_H2B | CMD_LP | 0x00000000)
+#define CMD_H2B_LP_DMA_TRANSFER	(CMD_H2B | CMD_LP | 0x00000002)
+#define CMD_B2H_LP_CONFIG	(CMD_B2H | CMD_LP | 0x00000004)
+#define CMD_B2H_LP_UPGRADE	(CMD_B2H | CMD_LP | 0x00000006)
+
+/* uograde */
+#define CMD_UPGRADE			0x00000200
+#define CMD_H2B_UPGRADE_DMA_TRANSFER	(CMD_H2B | CMD_UPGRADE | 0x00000000)
+
+/* ipmi */
+#define CMD_IPMI			0x00000300
+#define CMD_H2B_IPMI_CMD		(CMD_H2B | CMD_IPMI | 0x00000000)
+
+struct edma_msg_hdr_s {
+	u32 command;
+	u32 type;
+	u32 sub_type;
+	u32 msg_id;
+	u8 user_id;
+	u8 need_response;
+	u8 reserve1[2];
+	u32 datalen;
+	u32 reserve2[2];
+} __attribute__((packed));
+
+#define SIZE_OF_MSG_HDR (sizeof(struct edma_msg_hdr_s))
+
+struct edma_msg_resp_s {
+	struct edma_msg_hdr_s hdr;
+	u8 complete_code;
+	u8 reserve1[3];
+} __attribute__((packed));
+
+struct lp_heartbeat_msg_s {
+	struct edma_msg_hdr_s hdr;
+} __attribute__((packed));
+
+struct lp_dma_transfer_msg_s {
+	struct edma_msg_hdr_s hdr;
+	u32 dmadata_len;
+} __attribute__((packed));
+
+struct lp_config_msg_s {
+	struct edma_msg_hdr_s hdr;
+	u8 conf_data[0];
+} __attribute__((packed));
+
+struct lp_upgrade_msg_s {
+	struct edma_msg_hdr_s hdr;
+	u32 dmadata_len;
+	u32 cur_packet_num;
+	u32 total_packet_nums;
+} __attribute__((packed));
+
+#endif
diff --git a/drivers/net/ethernet/huawei/ibma/edma_host.c b/drivers/net/ethernet/huawei/ibma/edma_host.c
new file mode 100644
index 0000000..04ea816
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/edma_host.c
@@ -0,0 +1,1547 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/errno.h>
+#include <linux/kthread.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include "bma_pci.h"
+#include "edma_host.h"
+
+static struct edma_user_inft_s *g_user_func[TYPE_MAX] = { 0 };
+
+static struct bma_dev_s *g_bma_dev;
+static int edma_host_dma_interrupt(struct edma_host_s *edma_host);
+
+int edmainfo_show(char *buf)
+{
+	struct bma_user_s *user_ptr = NULL;
+	struct edma_host_s *host_ptr = NULL;
+	int len = 0;
+	__kernel_time_t running_time = 0;
+	static const char * const host_status[] = { "deregistered",
+								"registered",
+								"lost" };
+
+	if (!buf)
+		return 0;
+
+	if (!g_bma_dev) {
+		len += sprintf(buf, "EDMA IS NOT SUPPORTED");
+		return len;
+	}
+
+	host_ptr = &g_bma_dev->edma_host;
+
+	GET_SYS_SECONDS(running_time);
+	running_time -= host_ptr->statistics.init_time;
+	len += sprintf(buf + len,
+		    "============================EDMA_DRIVER_INFO============================\n");
+	len += sprintf(buf + len, "version      :" BMA_VERSION "\n");
+
+	len += sprintf(buf + len, "running_time :%luD %02lu:%02lu:%02lu\n",
+		    running_time / SECONDS_PER_DAY,
+		    running_time % SECONDS_PER_DAY / SECONDS_PER_HOUR,
+		    running_time % SECONDS_PER_HOUR / SECONDS_PER_MINUTE,
+		    running_time % SECONDS_PER_MINUTE);
+
+	len += sprintf(buf + len, "remote_status:%s\n",
+		    host_status[host_ptr->statistics.remote_status]);
+	len += sprintf(buf + len, "lost_count   :%d\n",
+		    host_ptr->statistics.lost_count);
+	len += sprintf(buf + len, "b2h_int      :%d\n",
+		    host_ptr->statistics.b2h_int);
+	len += sprintf(buf + len, "h2b_int      :%d\n",
+		    host_ptr->statistics.h2b_int);
+	len += sprintf(buf + len, "dma_count    :%d\n",
+		    host_ptr->statistics.dma_count);
+	len += sprintf(buf + len, "recv_bytes   :%d\n",
+		    host_ptr->statistics.recv_bytes);
+	len += sprintf(buf + len, "send_bytes   :%d\n",
+		    host_ptr->statistics.send_bytes);
+	len += sprintf(buf + len, "recv_pkgs    :%d\n",
+		    host_ptr->statistics.recv_pkgs);
+	len += sprintf(buf + len, "send_pkgs    :%d\n",
+		    host_ptr->statistics.send_pkgs);
+	len += sprintf(buf + len, "drop_pkgs    :%d\n",
+		    host_ptr->statistics.drop_pkgs);
+	len += sprintf(buf + len, "fail_count   :%d\n",
+		    host_ptr->statistics.failed_count);
+	len += sprintf(buf + len, "debug        :%d\n", debug);
+	len += sprintf(buf + len,
+		    "================================USER_INFO===============================\n");
+
+	list_for_each_entry_rcu(user_ptr, &(g_bma_dev->priv_list), link) {
+		len += sprintf(buf + len,
+			    "type: %d\nsub type: %d\nopen:%d\nmax recvmsg nums: %d\ncur recvmsg nums: %d\n",
+			    user_ptr->type, user_ptr->sub_type,
+			    host_ptr->local_open_status[user_ptr->type],
+			    user_ptr->max_recvmsg_nums,
+			    user_ptr->cur_recvmsg_nums);
+		len += sprintf(buf + len,
+			    "========================================================================\n");
+
+	}
+
+	return len;
+}
+
+
+
+int is_edma_b2h_int(struct edma_host_s *edma_host)
+{
+	struct notify_msg *pnm = NULL;
+
+	if (!edma_host)
+		return -1;
+
+	pnm = (struct notify_msg *)edma_host->edma_flag;
+	if (!pnm) {
+		BMA_LOG(DLOG_ERROR, "pnm is 0\n");
+		return -1;
+	}
+
+	if (IS_EDMA_B2H_INT(pnm->int_flag)) {
+		CLEAR_EDMA_B2H_INT(pnm->int_flag);
+		return 0;
+	}
+
+	return -1;
+}
+
+void edma_int_to_bmc(struct edma_host_s *edma_host)
+{
+	unsigned int data = 0;
+
+	if (!edma_host)
+		return;
+
+	edma_host->statistics.h2b_int++;
+
+	data = *(unsigned int *)((char *)edma_host->hostrtc_viraddr +
+				  HOSTRTC_INT_OFFSET);
+
+	data |= 0x00000001;
+
+	*(unsigned int *)((char *)edma_host->hostrtc_viraddr +
+			  HOSTRTC_INT_OFFSET) = data;
+}
+
+static void edma_host_int_to_bmc(struct edma_host_s *edma_host)
+{
+	struct notify_msg *pnm = NULL;
+
+	if (!edma_host)
+		return;
+
+	pnm = (struct notify_msg *)edma_host->edma_flag;
+	if (pnm) {
+		SET_EDMA_H2B_INT(pnm->int_flag);
+		edma_int_to_bmc(edma_host);
+	}
+}
+
+static int check_status_dmah2b(struct edma_host_s *edma_host)
+{
+	unsigned int data = 0;
+	struct pci_dev *pdev = NULL;
+
+	if (!edma_host)
+		return 0;
+
+	pdev = edma_host->pdev;
+	if (!pdev)
+		return 0;
+
+	(void)pci_read_config_dword(pdev, REG_PCIE1_DMAREAD_STATUS,
+				    (u32 *)&data);
+
+	if (data & (1 << SHIFT_PCIE1_DMAREAD_STATUS))
+		return 1;	/* ok */
+	else
+		return 0;	/* busy */
+}
+
+static int check_status_dmab2h(struct edma_host_s *edma_host)
+{
+	unsigned int data = 0;
+	struct pci_dev *pdev = NULL;
+
+	if (!edma_host)
+		return 0;
+
+	pdev = edma_host->pdev;
+	if (!pdev)
+		return 0;
+
+	(void)pci_read_config_dword(pdev, REG_PCIE1_DMAWRITE_STATUS,
+				    (u32 *)&data);
+
+	if (data & (1 << SHIFT_PCIE1_DMAWRITE_STATUS))
+		return 1;	/* ok */
+	else
+		return 0;	/* busy */
+}
+
+void clear_int_dmah2b(struct edma_host_s *edma_host)
+{
+	unsigned int data = 0;
+	struct pci_dev *pdev = NULL;
+
+	if (!edma_host)
+		return;
+
+	pdev = edma_host->pdev;
+	if (!pdev)
+		return;
+
+	(void)pci_read_config_dword(pdev, REG_PCIE1_DMAREADINT_CLEAR,
+				    (u32 *)&data);
+	data = data & (~((1 << SHIFT_PCIE1_DMAREADINT_CLEAR)));
+	data = data | (1 << SHIFT_PCIE1_DMAREADINT_CLEAR);
+	(void)pci_write_config_dword(pdev, REG_PCIE1_DMAREADINT_CLEAR, data);
+}
+
+void clear_int_dmab2h(struct edma_host_s *edma_host)
+{
+	unsigned int data = 0;
+	struct pci_dev *pdev = NULL;
+
+	if (!edma_host)
+		return;
+
+	pdev = edma_host->pdev;
+	if (!pdev)
+		return;
+
+	(void)pci_read_config_dword(pdev, REG_PCIE1_DMAWRITEINT_CLEAR,
+				    (u32 *)&data);
+	data = data & (~((1 << SHIFT_PCIE1_DMAWRITEINT_CLEAR)));
+	data = data | (1 << SHIFT_PCIE1_DMAWRITEINT_CLEAR);
+	(void)pci_write_config_dword(pdev, REG_PCIE1_DMAWRITEINT_CLEAR, data);
+}
+
+int edma_host_check_dma_status(enum dma_direction_e dir)
+{
+	int ret = 0;
+
+	switch (dir) {
+	case BMC_TO_HOST:
+		ret = check_status_dmab2h(&g_bma_dev->edma_host);
+		if (ret == 1)
+			clear_int_dmab2h(&g_bma_dev->edma_host);
+
+		break;
+
+	case HOST_TO_BMC:
+		ret = check_status_dmah2b(&g_bma_dev->edma_host);
+		if (ret == 1)
+			clear_int_dmah2b(&g_bma_dev->edma_host);
+
+		break;
+
+	default:
+		BMA_LOG(DLOG_ERROR, "direction failed, dir = %d\n", dir);
+		ret = -EFAULT;
+		break;
+	}
+
+	return ret;
+}
+
+#ifdef USE_DMA
+
+static int start_transfer_h2b(struct edma_host_s *edma_host, unsigned int len,
+			      unsigned int src_h, unsigned int src_l,
+			      unsigned int dst_h, unsigned int dst_l)
+{
+	unsigned long flags = 0;
+	struct pci_dev *pdev = edma_host->pdev;
+
+	spin_lock_irqsave(&edma_host->reg_lock, flags);
+	/*  read engine enable    */
+	(void)pci_write_config_dword(pdev, 0x99c, 0x00000001);
+	/*  read ch,ch index 0   */
+	(void)pci_write_config_dword(pdev, 0xa6c, 0x80000000);
+	/*  ch ctrl,local int enable */
+	(void)pci_write_config_dword(pdev, 0xa70, 0x00000008);
+	/*  size    */
+	(void)pci_write_config_dword(pdev, 0xa78, len);
+	/*  src lower 32b    */
+	(void)pci_write_config_dword(pdev, 0xa7c, src_l);
+	/*  src upper 32b    */
+	(void)pci_write_config_dword(pdev, 0xa80, src_h);
+	/*  dst lower 32b    */
+	(void)pci_write_config_dword(pdev, 0xa84, dst_l);
+	/*  dst upper 32b    */
+	(void)pci_write_config_dword(pdev, 0xa88, dst_h);
+	/*  start read dma,ch 0   */
+	(void)pci_write_config_dword(pdev, 0x9a0, 0x00000000);
+	spin_unlock_irqrestore(&edma_host->reg_lock, flags);
+	return 0;
+}
+
+static int start_transfer_b2h(struct edma_host_s *edma_host, unsigned int len,
+			      unsigned int src_h, unsigned int src_l,
+			      unsigned int dst_h, unsigned int dst_l)
+{
+	unsigned long flags = 0;
+	struct pci_dev *pdev = edma_host->pdev;
+
+	BMA_LOG(DLOG_DEBUG,
+		"len = 0x%8x,src_h = 0x%8x,src_l = 0x%8x,dst_h = 0x%8x,dst_l = 0x%8x\n",
+		len, src_h, src_l, dst_h, dst_l);
+
+	spin_lock_irqsave(&edma_host->reg_lock, flags);
+	/*  write engine enable    */
+	(void)pci_write_config_dword(pdev, 0x97c, 0x00000001);
+	/*  write ch,ch index 0   */
+	(void)pci_write_config_dword(pdev, 0xa6c, 0x00000000);
+	/*  ch ctrl,local int enable */
+	(void)pci_write_config_dword(pdev, 0xa70, 0x00000008);
+	/*  size    */
+	(void)pci_write_config_dword(pdev, 0xa78, len);
+	/*  src lower 32b    */
+	(void)pci_write_config_dword(pdev, 0xa7c, src_l);
+	/*  src upper 32b    */
+	(void)pci_write_config_dword(pdev, 0xa80, src_h);
+	/*  dst lower 32b    */
+	(void)pci_write_config_dword(pdev, 0xa84, dst_l);
+	/*  dst upper 32b    */
+	(void)pci_write_config_dword(pdev, 0xa88, dst_h);
+	/*  start write dma,ch 0   */
+	(void)pci_write_config_dword(pdev, 0x980, 0x00000000);
+	spin_unlock_irqrestore(&edma_host->reg_lock, flags);
+
+	return 0;
+}
+#endif
+
+static void start_listtransfer_h2b(struct edma_host_s *edma_host,
+				   unsigned int list_h, unsigned int list_l)
+{
+	unsigned long flags = 0;
+	struct pci_dev *pdev = NULL;
+
+	if (!edma_host)
+		return;
+
+	pdev = edma_host->pdev;
+	if (!pdev)
+		return;
+
+	spin_lock_irqsave(&edma_host->reg_lock, flags);
+
+	/*  write engine enable    */
+	(void)pci_write_config_dword(pdev, 0x700 + 0x29c, 0x00000001);
+	/*  write list err enable   */
+	(void)pci_write_config_dword(pdev, 0x700 + 0x334, 0x00010000);
+	/* (void)pci_write_config_dword(pdev, 0x700+0x334, 0x00000001); */
+	/*  write ch,ch index 0   */
+	(void)pci_write_config_dword(pdev, 0x700 + 0x36c, 0x80000000);
+	/*  ch ctrl,local int enable */
+	(void)pci_write_config_dword(pdev, 0x700 + 0x370, 0x00000300);
+	/*  list lower 32b    */
+	(void)pci_write_config_dword(pdev, 0x700 + 0x38c, list_l);
+	/*  list upper 32b    */
+	(void)pci_write_config_dword(pdev, 0x700 + 0x390, list_h);
+	/*  start write dma,ch 0   */
+	(void)pci_write_config_dword(pdev, 0x700 + 0x2a0, 0x00000000);
+
+	spin_unlock_irqrestore(&edma_host->reg_lock, flags);
+}
+
+static void start_listtransfer_b2h(struct edma_host_s *edma_host,
+				   unsigned int list_h, unsigned int list_l)
+{
+	unsigned long flags = 0;
+	struct pci_dev *pdev = NULL;
+
+	if (!edma_host)
+		return;
+
+	pdev = edma_host->pdev;
+	if (!pdev)
+		return;
+
+	spin_lock_irqsave(&edma_host->reg_lock, flags);
+
+	/*  write engine enable    */
+	(void)pci_write_config_dword(pdev, 0x700 + 0x27c, 0x00000001);
+	/*  write list err enable   */
+	(void)pci_write_config_dword(pdev, 0x700 + 0x300, 0x00000001);
+	/*  write ch,ch index 0   */
+	(void)pci_write_config_dword(pdev, 0x700 + 0x36c, 0x00000000);
+	/*  ch ctrl,local int enable */
+	(void)pci_write_config_dword(pdev, 0x700 + 0x370, 0x00000300);
+	/*  list lower 32b    */
+	(void)pci_write_config_dword(pdev, 0x700 + 0x38c, list_l);
+	/*  list upper 32b    */
+	(void)pci_write_config_dword(pdev, 0x700 + 0x390, list_h);
+	/*  start write dma,ch 0   */
+	(void)pci_write_config_dword(pdev, 0x700 + 0x280, 0x00000000);
+
+	spin_unlock_irqrestore(&edma_host->reg_lock, flags);
+}
+
+int edma_host_dma_start(struct edma_host_s *edma_host,
+			struct bma_priv_data_s *priv)
+{
+
+	struct bma_user_s *pUser = NULL;
+	struct bma_dev_s *bma_dev = NULL;
+	unsigned long flags = 0;
+
+	if (!edma_host || !priv)
+		return -EFAULT;
+
+	bma_dev = list_entry(edma_host, struct bma_dev_s, edma_host);
+
+	spin_lock_irqsave(&bma_dev->priv_list_lock, flags);
+
+	list_for_each_entry_rcu(pUser, &(bma_dev->priv_list), link) {
+		if (pUser->dma_transfer) {
+
+			spin_unlock_irqrestore(&bma_dev->priv_list_lock, flags);
+			BMA_LOG(DLOG_ERROR, "type = %d dma is started\n",
+				pUser->type);
+
+			return -EBUSY;
+		}
+	}
+
+	priv->user.dma_transfer = 1;
+
+	spin_unlock_irqrestore(&bma_dev->priv_list_lock, flags);
+
+	return 0;
+}
+
+#ifdef USE_DMA
+
+static int edma_host_dma_h2b(struct edma_host_s *edma_host,
+			     struct bma_dma_addr_s *host_addr,
+			     struct bma_dma_addr_s *bmc_addr)
+{
+	int ret = 0;
+	struct notify_msg *pnm = (struct notify_msg *)edma_host->edma_flag;
+	unsigned long host_h2b_addr = 0;
+	unsigned long bmc_h2b_addr = 0;
+	unsigned int bmc_h2b_size = 0;
+	unsigned int src_h, src_l, dst_h, dst_l;
+
+	if (!host_addr) {
+		BMA_LOG(DLOG_ERROR, "host_addr is NULL\n");
+		return -EFAULT;
+	}
+
+	BMA_LOG(DLOG_DEBUG, "host_addr->dma_addr = 0x%llx\n",
+		host_addr->dma_addr);
+
+	if (host_addr->dma_addr)
+		host_h2b_addr = (unsigned long)(host_addr->dma_addr);
+	else
+		host_h2b_addr = edma_host->h2b_addr.dma_addr;
+
+	bmc_h2b_addr = pnm->h2b_addr;
+	bmc_h2b_size = pnm->h2b_size;
+
+	BMA_LOG(DLOG_DEBUG,
+		"host_h2b_addr = 0x%lx, dma_data_len = %d, bmc_h2b_addr = 0x%lx, bmc_h2b_size = %d\n",
+		host_h2b_addr, host_addr->dma_data_len, bmc_h2b_addr,
+		bmc_h2b_size);
+
+	if ((host_addr->dma_data_len > EDMA_DMABUF_SIZE) || (bmc_h2b_addr == 0)
+	    || (host_addr->dma_data_len > bmc_h2b_size)) {
+		BMA_LOG(DLOG_ERROR,
+			"dma_data_len too large = %d, bmc_h2b_size = %d\n",
+			host_addr->dma_data_len, bmc_h2b_size);
+		return -EFAULT;
+	}
+
+	edma_host->h2b_state = H2BSTATE_WAITDMA;
+
+	src_h = (unsigned int)((sizeof(unsigned long) == 8) ?
+					(host_h2b_addr >> 32) : 0);
+	src_l = (unsigned int)(host_h2b_addr & 0xffffffff);
+	dst_h = (unsigned int)((sizeof(unsigned long) == 8) ?
+					(bmc_h2b_addr >> 32) : 0);
+	dst_l = (unsigned int)(bmc_h2b_addr & 0xffffffff);
+	(void)start_transfer_h2b(edma_host,
+		host_addr->dma_data_len, src_h,	/*lint !e506 !e572 */
+		src_l, dst_h, dst_l);	/*lint !e506 !e572 */
+
+
+	(void)mod_timer(&(edma_host->dma_timer),
+			jiffies_64 + TIMER_INTERVAL_CHECK);
+
+	ret = wait_event_interruptible_timeout(edma_host->wq_dmah2b,
+					     (edma_host->h2b_state ==
+					      H2BSTATE_IDLE),
+					     EDMA_DMA_TRANSFER_WAIT_TIMEOUT);
+
+	if (ret == -ERESTARTSYS) {
+		BMA_LOG(DLOG_ERROR, "eintr 1\n");
+		ret = -EINTR;
+		goto end;
+	} else if (ret == 0) {
+		BMA_LOG(DLOG_ERROR, "timeout 2\n");
+		ret = -ETIMEDOUT;
+		goto end;
+	} else {
+		ret = 0;
+		BMA_LOG(DLOG_ERROR, "h2b dma successful\n");
+	}
+
+end:
+
+	return ret;
+}
+
+static int edma_host_dma_b2h(struct edma_host_s *edma_host,
+			     struct bma_dma_addr_s *host_addr,
+			     struct bma_dma_addr_s *bmc_addr)
+{
+	int ret = 0;
+	struct notify_msg *pnm = (struct notify_msg *)edma_host->edma_flag;
+	unsigned long bmc_b2h_addr = 0;
+	unsigned long host_b2h_addr = 0;
+	unsigned int src_h, src_l, dst_h, dst_l;
+
+	if (!bmc_addr)
+		return -EFAULT;
+
+	if (host_addr->dma_addr)
+		host_b2h_addr = (unsigned long)(host_addr->dma_addr);
+	else
+		host_b2h_addr = edma_host->b2h_addr.dma_addr;
+
+	if (bmc_addr->dma_addr)
+		bmc_b2h_addr = (unsigned long)(bmc_addr->dma_addr);
+	else
+		bmc_b2h_addr = pnm->b2h_addr;
+
+	BMA_LOG(DLOG_DEBUG,
+		"bmc_b2h_addr = 0x%lx, host_b2h_addr = 0x%lx, dma_data_len = %d\n",
+		bmc_b2h_addr, host_b2h_addr, bmc_addr->dma_data_len);
+
+	if ((bmc_addr->dma_data_len > EDMA_DMABUF_SIZE)
+	    || (bmc_addr->dma_data_len > edma_host->b2h_addr.len)) {
+		BMA_LOG(DLOG_ERROR,
+			"dma_data_len too large = %d, b2h_addr = %d\n",
+			host_addr->dma_data_len, edma_host->b2h_addr.len);
+		return -EFAULT;
+	}
+
+	edma_host->b2h_state = B2HSTATE_WAITDMA;
+
+	src_h = (unsigned int)((sizeof(unsigned long) == 8) ?
+					(bmc_b2h_addr >> 32) : 0);
+	src_l = (unsigned int)(bmc_b2h_addr & 0xffffffff);
+	dst_h = (unsigned int)((sizeof(unsigned long) == 8) ?
+					(host_b2h_addr >> 32) : 0);
+	dst_l = (unsigned int)(host_b2h_addr & 0xffffffff);
+	(void)start_transfer_b2h(edma_host,
+		bmc_addr->dma_data_len, src_h,	/*lint !e506 !e572 */
+		src_l, dst_h, dst_l);	/*lint !e506 !e572 */
+
+	(void)mod_timer(&(edma_host->dma_timer),
+			jiffies_64 + TIMER_INTERVAL_CHECK);
+
+	ret = wait_event_interruptible_timeout(edma_host->wq_dmab2h,
+					     (edma_host->b2h_state ==
+					      B2HSTATE_IDLE),
+					     EDMA_DMA_TRANSFER_WAIT_TIMEOUT);
+
+	if (ret == -ERESTARTSYS) {
+		BMA_LOG(DLOG_ERROR, "eintr 1\n");
+		ret = -EINTR;
+		goto end;
+	} else if (ret == 0) {
+		BMA_LOG(DLOG_ERROR, "timeout 2\n");
+		ret = -ETIMEDOUT;
+		goto end;
+	} else {
+		BMA_LOG(DLOG_DEBUG, "h2b dma successful\n");
+	}
+
+end:
+
+	return ret;
+}
+#endif
+
+int edma_host_dma_transfer(struct edma_host_s *edma_host,
+			   struct bma_priv_data_s *priv,
+			   struct bma_dma_transfer_s *dma_transfer)
+{
+
+	int ret = 0;
+	unsigned long flags = 0;
+	struct bma_dev_s *bma_dev = NULL;
+
+	if (!edma_host || !priv || !dma_transfer)
+		return -EFAULT;
+
+	bma_dev = list_entry(edma_host, struct bma_dev_s, edma_host);
+
+	spin_lock_irqsave(&bma_dev->priv_list_lock, flags);
+
+	if (priv->user.dma_transfer == 0) {
+		spin_unlock_irqrestore(&bma_dev->priv_list_lock, flags);
+		BMA_LOG(DLOG_ERROR, "dma_transfer = %hhd\n",
+			priv->user.dma_transfer);
+		return -EFAULT;
+	}
+
+	spin_unlock_irqrestore(&bma_dev->priv_list_lock, flags);
+
+	edma_host->statistics.dma_count++;
+
+	if (dma_transfer->type == DMA_NOT_LIST) {
+#ifdef USE_DMA
+		switch (dma_transfer->dir) {
+		case BMC_TO_HOST:
+			ret = edma_host_dma_b2h(edma_host,
+				&(dma_transfer->transfer.nolist.host_addr),
+				&(dma_transfer->transfer.nolist.bmc_addr));
+			break;
+
+		case HOST_TO_BMC:
+			ret = edma_host_dma_h2b(edma_host,
+				&(dma_transfer->transfer.nolist.host_addr),
+				&(dma_transfer->transfer.nolist.bmc_addr));
+			break;
+
+		default:
+			BMA_LOG(DLOG_ERROR, "direction failed, dir = %d\n",
+				dma_transfer->dir);
+			ret = -EFAULT;
+			break;
+		}
+
+#endif
+	} else if (dma_transfer->type == DMA_LIST) {
+		unsigned int list_h;
+		unsigned int list_l;
+
+		list_h = (unsigned int)((sizeof(unsigned long) == 8) ?
+			(dma_transfer->transfer.list.dma_addr >> 32)
+			: 0);/*lint !e506 !e572 */
+		list_l = (unsigned int)(dma_transfer->transfer.list.dma_addr
+					& 0xffffffff);
+
+		switch (dma_transfer->dir) {
+		case BMC_TO_HOST:
+			start_listtransfer_b2h(edma_host, list_h, list_l);
+
+			break;
+
+		case HOST_TO_BMC:
+			start_listtransfer_h2b(edma_host, list_h, list_l);
+
+			break;
+
+		default:
+			BMA_LOG(DLOG_ERROR, "direction failed, dir = %d\n\n",
+				dma_transfer->dir);
+			ret = -EFAULT;
+			break;
+		}
+	} else {
+		BMA_LOG(DLOG_ERROR, "type failed! type = %d\n",
+			dma_transfer->type);
+		return -EFAULT;
+	}
+
+	return ret;
+}
+
+void edma_host_reset_dma(struct edma_host_s *edma_host, int dir)
+{
+	u32 data = 0;
+	u32 reg_addr = 0;
+	unsigned long flags = 0;
+	int count = 0;
+	struct pci_dev *pdev = NULL;
+
+	if (!edma_host)
+		return;
+
+	pdev = edma_host->pdev;
+	if (!pdev)
+		return;
+
+	if (dir == BMC_TO_HOST)
+		reg_addr = REG_PCIE1_DMA_READ_ENGINE_ENABLE;
+	else if (dir == HOST_TO_BMC)
+		reg_addr = REG_PCIE1_DMA_WRITE_ENGINE_ENABLE;
+	else
+		return;
+
+	spin_lock_irqsave(&edma_host->reg_lock, flags);
+
+	(void)pci_read_config_dword(pdev, reg_addr, &data);
+	data &= ~(1 << SHIFT_PCIE1_DMA_ENGINE_ENABLE);
+	(void)pci_write_config_dword(pdev, reg_addr, data);
+
+	while (count++ < 10) {
+		(void)pci_read_config_dword(pdev, reg_addr, &data);
+
+		if (0 == (data & (1 << SHIFT_PCIE1_DMA_ENGINE_ENABLE))) {
+			BMA_LOG(DLOG_DEBUG, "reset dma succesfull\n");
+			break;
+		}
+
+		mdelay(100);
+	}
+
+	spin_unlock_irqrestore(&edma_host->reg_lock, flags);
+	BMA_LOG(DLOG_DEBUG, "reset dma reg_addr=0x%x count=%d data=0x%08x\n",
+		reg_addr, count, data);
+
+}
+
+int edma_host_dma_stop(struct edma_host_s *edma_host,
+		       struct bma_priv_data_s *priv)
+{
+
+	unsigned long flags = 0;
+	struct bma_dev_s *bma_dev = NULL;
+
+	if (!edma_host || !priv)
+		return -1;
+
+	bma_dev = list_entry(edma_host, struct bma_dev_s, edma_host);
+
+	spin_lock_irqsave(&bma_dev->priv_list_lock, flags);
+	priv->user.dma_transfer = 0;
+	spin_unlock_irqrestore(&bma_dev->priv_list_lock, flags);
+
+	return 0;
+}
+
+static int edma_host_send_msg(struct edma_host_s *edma_host)
+{
+	void *vaddr = NULL;
+	unsigned long flags = 0;
+	struct edma_mbx_hdr_s *send_mbx_hdr = NULL;
+	static unsigned long last_timer_record;
+
+	if (!edma_host)
+		return 0;
+
+	send_mbx_hdr = (struct edma_mbx_hdr_s *)edma_host->edma_send_addr;
+
+	if (send_mbx_hdr->mbxlen > 0) {
+		if (send_mbx_hdr->mbxlen > HOST_MAX_SEND_MBX_LEN) {
+			/*share memory is disable */
+			send_mbx_hdr->mbxlen = 0;
+			BMA_LOG(DLOG_ERROR, "mbxlen is too long\n");
+			return -EFAULT;
+		}
+
+		if (time_after(jiffies, last_timer_record + 10 * HZ)) {
+			BMA_LOG(DLOG_ERROR, "no response in 10s,clean msg\n");
+			edma_host->statistics.failed_count++;
+			send_mbx_hdr->mbxlen = 0;
+			return -EFAULT;
+		}
+
+		BMA_LOG(DLOG_DEBUG,
+			"still have msg : mbxlen: %d, msg_send_write: %d\n",
+			send_mbx_hdr->mbxlen, edma_host->msg_send_write);
+
+		/*  resend door bell */
+		if (time_after(jiffies, last_timer_record + 5 * HZ))
+			edma_host_int_to_bmc(edma_host);
+
+		return -EFAULT;
+	}
+
+	vaddr =
+		(void *)((unsigned char *)edma_host->edma_send_addr +
+			 SIZE_OF_MBX_HDR);
+
+	last_timer_record = jiffies;
+
+	spin_lock_irqsave(&(edma_host->send_msg_lock), flags);
+
+	if (edma_host->msg_send_write == 0) {
+		spin_unlock_irqrestore(&(edma_host->send_msg_lock),
+					   flags);
+		return 0;
+	}
+
+	if (EOK !=
+		memcpy_s(vaddr, HOST_MAX_SEND_MBX_LEN - SIZE_OF_MBX_HDR,
+			 edma_host->msg_send_buf,
+			 edma_host->msg_send_write)) {
+		BMA_LOG(DLOG_ERROR, "memcpy_s error,len=%d\n",
+			edma_host->msg_send_write);
+		edma_host->msg_send_write = 0;
+		spin_unlock_irqrestore(&(edma_host->send_msg_lock),
+					   flags);
+		return 0;
+	}
+
+	send_mbx_hdr->mbxlen = edma_host->msg_send_write;
+	edma_host->msg_send_write = 0;
+
+	spin_unlock_irqrestore(&(edma_host->send_msg_lock), flags);
+
+	edma_host_int_to_bmc(edma_host);
+
+	BMA_LOG(DLOG_DEBUG,
+		"vaddr: %p, mbxlen : %d, msg_send_write: %d\n", vaddr,
+		send_mbx_hdr->mbxlen, edma_host->msg_send_write);
+
+	return -EAGAIN;
+}
+
+#ifdef EDMA_TIMER
+
+static void edma_host_timeout(unsigned long data)
+{
+	int ret = 0;
+	unsigned long flags = 0;
+	struct edma_host_s *edma_host = (struct edma_host_s *)data;
+
+	ret = edma_host_send_msg(edma_host);
+	if (ret < 0) {
+		spin_lock_irqsave(&g_bma_dev->edma_host.send_msg_lock, flags);
+		(void)mod_timer(&(edma_host->timer),
+				jiffies_64 + TIMER_INTERVAL_CHECK);
+		spin_unlock_irqrestore(&edma_host->send_msg_lock, flags);
+	}
+}
+
+static void edma_host_heartbeat_timer(unsigned long data)
+{
+	static unsigned int bmc_heartbeat_count;
+	struct edma_host_s *edma_host = (struct edma_host_s *)data;
+	unsigned int remote_status = edma_host->statistics.remote_status;
+	struct notify_msg *pnm = (struct notify_msg *)edma_host->edma_flag;
+
+	if (pnm) {
+		if (pnm->bmc_registered) {
+			if ((pnm->host_heartbeat & 7) == 0) {
+				if (bmc_heartbeat_count != pnm->bmc_heartbeat) {
+					if (remote_status != REGISTERED) {
+						BMA_LOG(DLOG_DEBUG,
+							"bmc is registered\n");
+						edma_host->statistics.remote_status = REGISTERED;
+
+					}
+
+					bmc_heartbeat_count = pnm->bmc_heartbeat;
+				} else {
+					if (remote_status == REGISTERED) {
+						edma_host->statistics.remote_status = LOST;
+						edma_host->statistics.lost_count++;
+						BMA_LOG(DLOG_DEBUG,
+							"bmc is lost\n");
+					}
+				}
+			}
+		} else {
+			if (edma_host->statistics.remote_status == REGISTERED)
+				BMA_LOG(DLOG_DEBUG, "bmc is deregistered\n");
+
+			edma_host->statistics.remote_status = DEREGISTERED;
+		}
+
+		pnm->host_heartbeat++;
+	}
+
+	(void)mod_timer(&edma_host->heartbeat_timer,
+			jiffies_64 + HEARTBEAT_TIMER_INTERVAL_CHECK);
+}
+
+#ifdef USE_DMA
+
+static void edma_host_dma_timeout(unsigned long data)
+{
+	int ret = 0;
+	struct edma_host_s *edma_host = (struct edma_host_s *)data;
+
+	ret = edma_host_dma_interrupt(edma_host);
+	if (ret < 0)
+		(void)mod_timer(&(edma_host->dma_timer),
+				jiffies_64 + DMA_TIMER_INTERVAL_CHECK);
+}
+#endif
+#else
+
+static int edma_host_thread(void *arg)
+{
+	struct edma_host_s *edma_host = (struct edma_host_s *)arg;
+
+	BMA_LOG(DLOG_ERROR, "edma host thread\n");
+
+	while (!kthread_should_stop()) {
+		wait_for_completion_interruptible_timeout(&edma_host->msg_ready,
+							1 * HZ);
+		edma_host_send_msg(edma_host);
+		(void)edma_host_dma_interrupt(edma_host);
+	}
+
+	BMA_LOG(DLOG_ERROR, "edma host thread exiting\n");
+
+	return 0;
+}
+
+#endif
+
+int edma_host_send_driver_msg(void *msg, size_t msg_len, int subtype)
+{
+	int ret = 0;
+	unsigned long flags = 0;
+	struct edma_host_s *edma_host = NULL;
+	struct edma_msg_hdr_s *hdr = NULL;
+	int total_len = msg_len + SIZE_OF_MSG_HDR;
+
+	if (!msg || !g_bma_dev)
+		return -1;
+
+	edma_host = &g_bma_dev->edma_host;
+	if (!edma_host)
+		return -1;
+
+	spin_lock_irqsave(&(edma_host->send_msg_lock), flags);
+
+	if (edma_host->msg_send_write + total_len <=
+	    (HOST_MAX_SEND_MBX_LEN - SIZE_OF_MBX_HDR)) {
+		hdr = (struct edma_msg_hdr_s *)(edma_host->msg_send_buf +
+					      edma_host->msg_send_write);
+		hdr->type = TYPE_EDMA_DRIVER;
+		hdr->sub_type = subtype;
+		hdr->datalen = msg_len;
+
+		(void)memcpy_s(hdr->data,
+			       HOST_MAX_SEND_MBX_LEN - SIZE_OF_MBX_HDR -
+			       edma_host->msg_send_write - SIZE_OF_MSG_HDR, msg,
+			       msg_len);
+
+		edma_host->msg_send_write += total_len;
+
+		spin_unlock_irqrestore(&(edma_host->send_msg_lock), flags);
+
+		(void)mod_timer(&(edma_host->timer), jiffies_64);
+		BMA_LOG(DLOG_DEBUG, "msg_send_write = %d\n",
+			edma_host->msg_send_write);
+	} else {
+		ret = -ENOSPC;
+		spin_unlock_irqrestore(&(edma_host->send_msg_lock), flags);
+
+		BMA_LOG(DLOG_DEBUG,
+			"msg lost,msg_send_write: %d,msg_len:%d,max_len: %d\n",
+			edma_host->msg_send_write, total_len,
+			HOST_MAX_SEND_MBX_LEN);
+	}
+
+	return ret;
+}
+
+static int edma_host_insert_recv_msg(struct edma_host_s *edma_host,
+				     struct edma_msg_hdr_s *msg_header)
+{
+	unsigned long flags = 0, msg_flags = 0;
+	struct bma_dev_s *bma_dev = NULL;
+	struct bma_priv_data_s *priv = NULL;
+	struct bma_user_s *pUser = NULL;
+	struct list_head *entry = NULL;
+	struct edma_recv_msg_s *msg_tmp = NULL;
+	struct bma_user_s usertmp = { };
+	struct edma_recv_msg_s *recv_msg = NULL;
+
+	if (!edma_host || !msg_header
+	    || msg_header->datalen > CDEV_MAX_WRITE_LEN) {
+		return -EFAULT;
+	}
+
+	bma_dev = list_entry(edma_host, struct bma_dev_s, edma_host);
+
+	recv_msg = kmalloc(sizeof(*recv_msg) + msg_header->datalen,
+						GFP_ATOMIC); /*lint !e64*/
+	if (!recv_msg) {
+		BMA_LOG(DLOG_ERROR, "malloc recv_msg failed\n");
+		return -ENOMEM;
+	}
+
+	recv_msg->msg_len = msg_header->datalen;
+	(void)memcpy_s(recv_msg->msg_data, msg_header->datalen,
+		       msg_header->data, msg_header->datalen);
+
+	spin_lock_irqsave(&bma_dev->priv_list_lock, flags);
+	list_for_each_entry_rcu(pUser, &(bma_dev->priv_list), link) {
+
+		if ((pUser->type != msg_header->type)
+		|| (pUser->sub_type != msg_header->sub_type))
+			continue;
+
+		priv = list_entry(pUser, struct bma_priv_data_s, user);
+
+		(void)memcpy_s(&usertmp, sizeof(struct bma_user_s),
+			       pUser, sizeof(struct bma_user_s));
+
+		spin_lock_irqsave(&priv->recv_msg_lock, msg_flags);
+
+		if ((pUser->cur_recvmsg_nums >= pUser->max_recvmsg_nums)
+		|| (pUser->cur_recvmsg_nums >= MAX_RECV_MSG_NUMS)) {
+
+			entry = priv->recv_msgs.next;
+			msg_tmp =
+			    list_entry(entry, struct edma_recv_msg_s,
+				       link);
+			list_del(entry);
+			pUser->cur_recvmsg_nums--;
+			kfree(msg_tmp);
+		}
+
+		if (edma_host->local_open_status[pUser->type]
+			== DEV_OPEN) {
+			list_add_tail(&recv_msg->link, &priv->recv_msgs);
+			pUser->cur_recvmsg_nums++;
+			usertmp.cur_recvmsg_nums =
+			    pUser->cur_recvmsg_nums;
+			spin_unlock_irqrestore(&priv->recv_msg_lock,
+					       msg_flags);
+
+		} else {
+			spin_unlock_irqrestore(&priv->recv_msg_lock,
+					       msg_flags);
+			break;
+		}
+
+		wake_up_interruptible(&(priv->wait));
+		spin_unlock_irqrestore(&bma_dev->priv_list_lock, flags);
+
+		BMA_LOG(DLOG_DEBUG,
+			"find user, type = %d, sub_type = %d, user_id = %d, insert msg\n",
+			usertmp.type, usertmp.sub_type,
+			usertmp.user_id);
+		BMA_LOG(DLOG_DEBUG,
+			"msg_len = %d, cur_recvmsg_nums: %d, max_recvmsg_nums: %d\n",
+			recv_msg->msg_len, usertmp.cur_recvmsg_nums,
+			usertmp.max_recvmsg_nums);
+
+		return 0;
+	}
+
+	spin_unlock_irqrestore(&bma_dev->priv_list_lock, flags);
+	kfree(recv_msg);
+	edma_host->statistics.drop_pkgs++;
+	BMA_LOG(DLOG_DEBUG,
+		"insert msg failed! not find user, type = %d, sub_type = %d\n",
+		msg_header->type, msg_header->sub_type);
+
+	return -EFAULT;
+}
+
+int edma_host_recv_msg(struct edma_host_s *edma_host,
+		       struct bma_priv_data_s *priv,
+		       struct edma_recv_msg_s **msg)
+{
+	unsigned long flags = 0;
+	struct list_head *entry = NULL;
+	struct edma_recv_msg_s *msg_tmp = NULL;
+	struct bma_dev_s *bma_dev = NULL;
+
+	if (!edma_host || !priv || !msg)
+		return -EAGAIN;
+
+	bma_dev = list_entry(edma_host, struct bma_dev_s, edma_host);
+
+	spin_lock_irqsave(&bma_dev->priv_list_lock, flags);
+
+	if (list_empty(&priv->recv_msgs)) {
+		priv->user.cur_recvmsg_nums = 0;
+		spin_unlock_irqrestore(&bma_dev->priv_list_lock, flags);
+		BMA_LOG(DLOG_DEBUG, "recv msgs empty\n");
+		return -EAGAIN;
+	}
+
+	entry = priv->recv_msgs.next;
+	msg_tmp = list_entry(entry, struct edma_recv_msg_s, link);
+	list_del(entry);
+
+	if (priv->user.cur_recvmsg_nums > 0)
+		priv->user.cur_recvmsg_nums--;
+
+	spin_unlock_irqrestore(&bma_dev->priv_list_lock, flags);
+
+	*msg = msg_tmp;
+
+	BMA_LOG(DLOG_DEBUG, "msg->msg_len = %d\n", (int)msg_tmp->msg_len);
+
+	return 0;
+}
+
+static int edma_host_msg_process(struct edma_host_s *edma_host,
+				 struct edma_msg_hdr_s *msg_header)
+{
+	struct bma_user_s *user_ptr = NULL;
+	char drv_msg[TYPE_MAX * 2 + 1] = { 0 };
+
+	if (!edma_host || !msg_header)
+		return 0;
+
+	if (msg_header->type != TYPE_EDMA_DRIVER)
+		return -1;
+
+	if (msg_header->sub_type != DEV_OPEN_STATUS_REQ)
+		return 0;
+
+
+	list_for_each_entry_rcu(user_ptr, &(g_bma_dev->priv_list), link) {
+		drv_msg[drv_msg[0] * 2 + 1] = user_ptr->type;
+		drv_msg[drv_msg[0] * 2 + 2] =
+		    edma_host->local_open_status[user_ptr->type];
+		BMA_LOG(DLOG_DEBUG,
+			"send DEV_OPEN_STATUS_ANS index=%d type=%d status=%d\n",
+			drv_msg[0], drv_msg[drv_msg[0] * 2 + 1],
+			drv_msg[drv_msg[0] * 2 + 2]);
+		drv_msg[0]++;
+
+	}
+
+	if (drv_msg[0]) {
+		(void)edma_host_send_driver_msg((void *)drv_msg,
+						drv_msg[0] * 2 +
+						1,
+						DEV_OPEN_STATUS_ANS);
+		BMA_LOG(DLOG_DEBUG,
+			"send DEV_OPEN_STATUS_ANS %d\n",
+			drv_msg[0]);
+	}
+
+	return 0;
+}
+
+void edma_host_isr_tasklet(unsigned long data)
+{
+	int result = 0;
+	u16 len = 0;
+	u16 off = 0;
+	u16 msg_cnt = 0;
+	struct edma_mbx_hdr_s *recv_mbx_hdr = NULL;
+	struct edma_host_s *edma_host = (struct edma_host_s *)data;
+	struct edma_msg_hdr_s *msg_header = NULL;
+	unsigned char *ptr = NULL;
+
+	if (!edma_host)
+		return;
+
+	recv_mbx_hdr = (struct edma_mbx_hdr_s *)(edma_host->edma_recv_addr);
+	msg_header =
+		(struct edma_msg_hdr_s *)((char *)(edma_host->edma_recv_addr) +
+				SIZE_OF_MBX_HDR + recv_mbx_hdr->mbxoff);
+
+	off = readw((unsigned char *)edma_host->edma_recv_addr
+			+ EDMA_B2H_INT_FLAG);
+	len = readw((unsigned char *)edma_host->edma_recv_addr) - off;
+
+	BMA_LOG(DLOG_DEBUG,
+		" edma_host->edma_recv_addr = %p, len = %d, off = %d, mbxlen = %d\n",
+		edma_host->edma_recv_addr, len, off, recv_mbx_hdr->mbxlen);
+	edma_host->statistics.recv_bytes += (recv_mbx_hdr->mbxlen - off);
+
+	if (len == 0) {
+		writel(0, (void *)(edma_host->edma_recv_addr));
+		return;
+	}
+
+	while (recv_mbx_hdr->mbxlen - off) {
+		if (len == 0) {
+			BMA_LOG(DLOG_DEBUG, " recieve done\n");
+			break;
+		}
+
+		if (len < (SIZE_OF_MSG_HDR + msg_header->datalen)) {
+			BMA_LOG(DLOG_ERROR, " len too less, is %d\n", len);
+			break;
+		}
+
+		edma_host->statistics.recv_pkgs++;
+
+		if (edma_host_msg_process(edma_host, msg_header) == -1) {
+			result = edma_host_insert_recv_msg(edma_host,
+							   msg_header);
+			if (result < 0)
+				BMA_LOG(DLOG_DEBUG,
+					"edma_host_insert_recv_msg failed\n");
+		}
+
+		BMA_LOG(DLOG_DEBUG, "len = %d\n", len);
+		BMA_LOG(DLOG_DEBUG, "off = %d\n", off);
+		len -= (msg_header->datalen + SIZE_OF_MSG_HDR);
+		BMA_LOG(DLOG_DEBUG,
+			"msg_header->datalen = %d, SIZE_OF_MSG_HDR=%d\n",
+			msg_header->datalen, (int)SIZE_OF_MSG_HDR);
+		off += (msg_header->datalen + SIZE_OF_MSG_HDR);
+
+		msg_cnt++;
+
+		ptr = (unsigned char *)msg_header;
+		msg_header = (struct edma_msg_hdr_s *)(ptr +
+					      (msg_header->datalen +
+					       SIZE_OF_MSG_HDR));
+
+		if (msg_cnt > 2) {
+			recv_mbx_hdr->mbxoff = off;
+			BMA_LOG(DLOG_DEBUG, "len = %d\n", len);
+			BMA_LOG(DLOG_DEBUG, "off = %d\n", off);
+			BMA_LOG(DLOG_DEBUG, "off works\n");
+
+			tasklet_hi_schedule(&(edma_host->tasklet));
+
+			break;
+		}
+
+		if (!len) {
+			writel(0, (void *)(edma_host->edma_recv_addr));
+			recv_mbx_hdr->mbxoff = 0;
+		}
+	}
+}
+
+static int edma_host_dma_interrupt(struct edma_host_s *edma_host)
+{
+	if (!edma_host)
+		return 0;
+
+	if (check_status_dmah2b(edma_host)) {
+		clear_int_dmah2b(edma_host);
+
+		edma_host->h2b_state = H2BSTATE_IDLE;
+		wake_up_interruptible(&edma_host->wq_dmah2b);
+		return 0;
+	}
+
+	if (check_status_dmab2h(edma_host)) {
+		clear_int_dmab2h(edma_host);
+
+		edma_host->b2h_state = B2HSTATE_IDLE;
+		wake_up_interruptible(&edma_host->wq_dmab2h);
+
+		return 0;
+	}
+
+	return -EAGAIN;
+}
+
+irqreturn_t edma_host_irq_handle(struct edma_host_s *edma_host)
+{
+	if (edma_host) {
+		(void)edma_host_dma_interrupt(edma_host);
+
+		tasklet_hi_schedule(&(edma_host->tasklet));
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int edma_host_malloc_dma_buf(struct bma_dev_s *bma_dev)
+{
+	void *vphys = NULL;
+	dma_addr_t dma_addr = 0;
+	struct edma_host_s *edma_host = NULL;
+
+	if (!bma_dev)
+		return -EFAULT;
+
+	edma_host = &(bma_dev->edma_host);
+
+	(void)memset_s(&(edma_host->h2b_addr), sizeof(edma_host->h2b_addr),
+		       0, sizeof(edma_host->h2b_addr));
+	(void)memset_s(&(edma_host->b2h_addr), sizeof(edma_host->h2b_addr),
+		       0, sizeof(edma_host->h2b_addr));
+
+	vphys = pci_alloc_consistent(bma_dev->bma_pci_dev->pdev,
+				     EDMA_DMABUF_SIZE, &dma_addr);
+	if (!vphys) {
+		BMA_LOG(DLOG_ERROR, "pci_alloc_consistent h2b error\n");
+		return -ENOMEM;
+	}
+
+	edma_host->h2b_addr.kvaddr = vphys;
+	edma_host->h2b_addr.dma_addr = dma_addr;
+	edma_host->h2b_addr.len = EDMA_DMABUF_SIZE;
+
+	BMA_LOG(DLOG_DEBUG, "h2b - kvaddr = %p, dma_addr = 0x%llx, len = %d\n",
+		vphys, dma_addr, EDMA_DMABUF_SIZE);
+
+	vphys = pci_alloc_consistent(bma_dev->bma_pci_dev->pdev,
+				     EDMA_DMABUF_SIZE, &dma_addr);
+
+	if (!vphys) {
+		BMA_LOG(DLOG_ERROR, "pci_alloc_consistent b2h error\n");
+		pci_free_consistent(edma_host->pdev,
+				    edma_host->h2b_addr.len,
+				    edma_host->h2b_addr.kvaddr,
+				    edma_host->h2b_addr.dma_addr);
+		edma_host->h2b_addr.kvaddr = NULL;
+		edma_host->h2b_addr.dma_addr = 0;
+		edma_host->h2b_addr.len = 0;
+		return -ENOMEM;
+	}
+
+	edma_host->b2h_addr.kvaddr = vphys;
+	edma_host->b2h_addr.dma_addr = dma_addr;
+	edma_host->b2h_addr.len = EDMA_DMABUF_SIZE;
+
+	BMA_LOG(DLOG_DEBUG, "b2h - kvaddr = %p, dma_addr = 0x%llx, len = %d\n",
+		vphys, dma_addr, EDMA_DMABUF_SIZE);
+	return 0;
+}
+
+static void edma_host_free_dma_buf(struct bma_dev_s *bma_dev)
+{
+	struct edma_host_s *edma_host = NULL;
+
+	if (!bma_dev)
+		return;
+
+	edma_host = &bma_dev->edma_host;
+
+	if (edma_host->h2b_addr.kvaddr) {
+		BMA_LOG(DLOG_DEBUG,
+			"free h2b_addr dma mem, vphys: %p, dma_addr: 0x%llx\n",
+			edma_host->h2b_addr.kvaddr,
+			edma_host->h2b_addr.dma_addr);
+
+		pci_free_consistent(edma_host->pdev,
+				    edma_host->h2b_addr.len,
+				    edma_host->h2b_addr.kvaddr,
+				    edma_host->h2b_addr.dma_addr);
+
+		edma_host->h2b_addr.kvaddr = NULL;
+		edma_host->h2b_addr.dma_addr = 0;
+		edma_host->h2b_addr.len = 0;
+	}
+
+	if (edma_host->b2h_addr.kvaddr) {
+		BMA_LOG(DLOG_DEBUG,
+			"free b2h_addr dma mem, vphys: %p, dma_addr: 0x%llx\n",
+			edma_host->b2h_addr.kvaddr,
+			edma_host->b2h_addr.dma_addr);
+
+		pci_free_consistent(edma_host->pdev,
+				    edma_host->b2h_addr.len,
+				    edma_host->b2h_addr.kvaddr,
+				    edma_host->b2h_addr.dma_addr);
+
+		edma_host->b2h_addr.kvaddr = NULL;
+		edma_host->b2h_addr.dma_addr = 0;
+		edma_host->b2h_addr.len = 0;
+	}
+}
+
+struct edma_user_inft_s *edma_host_get_user_inft(u32 type)
+{
+	if (type >= TYPE_MAX) {
+		BMA_LOG(DLOG_ERROR, "type error %d\n", type);
+		return NULL;
+	}
+
+	return g_user_func[type];
+}
+
+int edma_host_user_register(u32 type, struct edma_user_inft_s *func)
+{
+	if (type >= TYPE_MAX) {
+		BMA_LOG(DLOG_ERROR, "type error %d\n", type);
+		return -EFAULT;
+	}
+
+	if (!func) {
+		BMA_LOG(DLOG_ERROR, "func is NULL\n");
+		return -EFAULT;
+	}
+
+	g_user_func[type] = func;
+
+	return 0;
+}
+
+int edma_host_user_unregister(u32 type)
+{
+	if (type >= TYPE_MAX) {
+		BMA_LOG(DLOG_ERROR, "type error %d\n", type);
+		return -EFAULT;
+	}
+
+	g_user_func[type] = NULL;
+
+	return 0;
+}
+
+int edma_host_init(struct edma_host_s *edma_host)
+{
+	int ret = 0;
+	struct bma_dev_s *bma_dev = NULL;
+	struct notify_msg *pnm = NULL;
+
+	if (!edma_host)
+		return -1;
+
+	bma_dev = list_entry(edma_host, struct bma_dev_s, edma_host);
+	g_bma_dev = bma_dev;
+
+	edma_host->pdev = bma_dev->bma_pci_dev->pdev;
+
+#ifdef EDMA_TIMER
+	setup_timer(&edma_host->timer, edma_host_timeout,
+		    (unsigned long)edma_host);
+	(void)mod_timer(&edma_host->timer, jiffies_64 + TIMER_INTERVAL_CHECK);
+#ifdef USE_DMA
+	setup_timer(&edma_host->dma_timer, edma_host_dma_timeout,
+		    (unsigned long)edma_host);
+	(void)mod_timer(&edma_host->dma_timer,
+			jiffies_64 + DMA_TIMER_INTERVAL_CHECK);
+#endif
+
+#else
+	init_completion(&(edma_host->msg_ready));
+
+	edma_host->edma_thread =
+	    kthread_run(edma_host_thread, (void *)edma_host, "edma_host_msg");
+
+	if (IS_ERR(edma_host->edma_thread)) {
+		BMA_LOG(DLOG_ERROR, "kernel_run  edma_host_msg failed\n");
+		return PTR_ERR(edma_host->edma_thread);
+	}
+#endif
+	edma_host->msg_send_buf = kmalloc(HOST_MAX_SEND_MBX_LEN,
+						GFP_KERNEL); /*lint !e64*/
+	if (!edma_host->msg_send_buf) {
+		BMA_LOG(DLOG_ERROR, "malloc msg_send_buf failed!");
+		ret = -ENOMEM;
+		goto failed1;
+	}
+
+	edma_host->msg_send_write = 0;
+
+	spin_lock_init(&(edma_host->send_msg_lock));
+
+	tasklet_init(&(edma_host->tasklet),
+		     (void (*)(unsigned long))edma_host_isr_tasklet,
+		     (unsigned long)edma_host);
+
+	edma_host->edma_flag = bma_dev->bma_pci_dev->edma_swap_addr;
+
+	edma_host->edma_send_addr =
+	    (void *)((unsigned char *)bma_dev->bma_pci_dev->edma_swap_addr +
+		     HOST_DMA_FLAG_LEN);
+	(void)memset_s(edma_host->edma_send_addr, SIZE_OF_MBX_HDR, 0,
+		       SIZE_OF_MBX_HDR);
+
+	edma_host->edma_recv_addr =
+	    (void *)((unsigned char *)edma_host->edma_send_addr +
+		     HOST_MAX_SEND_MBX_LEN);
+
+	BMA_LOG(DLOG_DEBUG,
+		"edma_flag = %p, edma_send_addr = %p, edma_recv_addr = %p\n",
+		edma_host->edma_flag, edma_host->edma_send_addr,
+		edma_host->edma_recv_addr);
+
+	edma_host->hostrtc_viraddr = bma_dev->bma_pci_dev->hostrtc_viraddr;
+
+	ret = edma_host_malloc_dma_buf(bma_dev);
+	if (ret) {
+		BMA_LOG(DLOG_DEBUG, "edma_host_malloc_dma_buf fail!\n");
+		goto failed2;
+	}
+
+	init_waitqueue_head(&edma_host->wq_dmah2b);
+	init_waitqueue_head(&edma_host->wq_dmab2h);
+
+	spin_lock_init(&edma_host->reg_lock);
+
+	edma_host->h2b_state = H2BSTATE_IDLE;
+	edma_host->b2h_state = B2HSTATE_IDLE;
+
+	setup_timer(&edma_host->heartbeat_timer, edma_host_heartbeat_timer,
+		    (unsigned long)edma_host);
+	(void)mod_timer(&edma_host->heartbeat_timer,
+			jiffies_64 + HEARTBEAT_TIMER_INTERVAL_CHECK);
+
+	pnm = (struct notify_msg *)edma_host->edma_flag;
+	if (pnm)
+		pnm->host_registered = REGISTERED;
+
+	GET_SYS_SECONDS(edma_host->statistics.init_time);
+
+
+#ifdef EDMA_TIMER
+	BMA_LOG(DLOG_DEBUG, "timer ok\n");
+#else
+	BMA_LOG(DLOG_ERROR, "thread ok\n");
+#endif
+	return 0;
+failed2:
+	tasklet_kill(&(edma_host->tasklet));
+	kfree(edma_host->msg_send_buf);
+	edma_host->msg_send_buf = NULL;
+
+failed1:
+#ifdef EDMA_TIMER
+	(void)del_timer_sync(&edma_host->timer);
+#ifdef USE_DMA
+	(void)del_timer_sync(&edma_host->dma_timer);
+#endif
+#else
+	kthread_stop(edma_host->edma_thread);
+	complete(&(edma_host->msg_ready));
+#endif
+	return ret;
+}
+
+void edma_host_cleanup(struct edma_host_s *edma_host)
+{
+	struct bma_dev_s *bma_dev = NULL;
+	struct notify_msg *pnm = NULL;
+
+	if (!edma_host)
+		return;
+
+	bma_dev = list_entry(edma_host, struct bma_dev_s, edma_host);
+	(void)del_timer_sync(&edma_host->heartbeat_timer);
+	pnm = (struct notify_msg *)edma_host->edma_flag;
+
+	if (pnm)
+		pnm->host_registered = DEREGISTERED;
+
+	tasklet_kill(&(edma_host->tasklet));
+
+	kfree(edma_host->msg_send_buf);
+	edma_host->msg_send_buf = NULL;
+#ifdef EDMA_TIMER
+	(void)del_timer_sync(&edma_host->timer);
+#ifdef USE_DMA
+	(void)del_timer_sync(&edma_host->dma_timer);
+#endif
+
+#else
+	kthread_stop(edma_host->edma_thread);
+
+	complete(&(edma_host->msg_ready));
+#endif
+
+	edma_host_free_dma_buf(bma_dev);
+}
diff --git a/drivers/net/ethernet/huawei/ibma/edma_host.h b/drivers/net/ethernet/huawei/ibma/edma_host.h
new file mode 100644
index 0000000..578e0f5
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/edma_host.h
@@ -0,0 +1,357 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _EDMA_HOST_H_
+#define _EDMA_HOST_H_
+
+#include "bma_include.h"
+#include "bma_ker_intf.h"
+
+#define EDMA_TIMER
+
+#ifndef IN
+#define IN
+#endif
+
+#ifndef OUT
+#define OUT
+#endif
+
+#ifndef UNUSED
+#define UNUSED
+#endif
+
+/*
+ * vm_flags in vm_area_struct, see mm_types.h.
+ */
+#define VM_NONE		0x00000000
+
+#define VM_READ		0x00000001	/* currently active flags */
+#define VM_WRITE	0x00000002
+#define VM_EXEC		0x00000004
+#define VM_SHARED	0x00000008
+
+#define VM_MAYREAD	0x00000010	/* limits for mprotect() etc */
+#define VM_MAYWRITE	0x00000020
+#define VM_MAYEXEC	0x00000040
+#define VM_MAYSHARE	0x00000080
+
+#define VM_GROWSDOWN	0x00000100	/* general info on the segment */
+/* Page-ranges managed without "struct page", just pure PFN */
+#define VM_PFNMAP	0x00000400
+#define VM_DENYWRITE	0x00000800	/* ETXTBSY on write attempts.. */
+
+#define VM_LOCKED	0x00002000
+#define VM_IO           0x00004000	/* Memory mapped I/O or similar */
+
+					/* Used by sys_madvise() */
+#define VM_SEQ_READ	0x00008000	/* App will access data sequentially */
+/* App will not benefit from clustered reads */
+#define VM_RAND_READ	0x00010000
+
+#define VM_DONTCOPY	0x00020000	/* Do not copy this vma on fork */
+#define VM_DONTEXPAND	0x00040000	/* Cannot expand with mremap() */
+#define VM_ACCOUNT	0x00100000	/* Is a VM accounted object */
+#define VM_NORESERVE	0x00200000	/* should the VM suppress accounting */
+#define VM_HUGETLB	0x00400000	/* Huge TLB Page VM */
+#define VM_NONLINEAR	0x00800000	/* Is non-linear (remap_file_pages) */
+#define VM_ARCH_1	0x01000000	/* Architecture-specific flag */
+#define VM_DONTDUMP	0x04000000	/* Do not include in the core dump */
+/* Can contain "struct page" and pure PFN pages */
+#define VM_MIXEDMAP	0x10000000
+
+#define VM_MERGEABLE	0x80000000	/* KSM may merge identical pages */
+
+#if defined(CONFIG_X86)
+/* PAT reserves whole VMA at once (x86) */
+#define VM_PAT		VM_ARCH_1
+#elif defined(CONFIG_PPC)
+#define VM_SAO		VM_ARCH_1	/* Strong Access Ordering (powerpc) */
+#elif defined(CONFIG_PARISC)
+#define VM_GROWSUP	VM_ARCH_1
+#elif defined(CONFIG_METAG)
+#define VM_GROWSUP	VM_ARCH_1
+#elif defined(CONFIG_IA64)
+#define VM_GROWSUP	VM_ARCH_1
+#elif !defined(CONFIG_MMU)
+#define VM_MAPPED_COPY	VM_ARCH_1 /* T if mapped copy of data (nommu mmap) */
+#endif
+
+#ifndef VM_GROWSUP
+#define VM_GROWSUP	VM_NONE
+#endif
+
+/* Bits set in the VMA until the stack is in its final location */
+#define VM_STACK_INCOMPLETE_SETUP	(VM_RAND_READ | VM_SEQ_READ)
+
+#ifndef VM_STACK_DEFAULT_FLAGS	/* arch can override this */
+#define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
+#endif
+
+//#ifdef CONFIG_STACK_GROWSUP
+//#define VM_STACK_FLAGS	(VM_GROWSUP | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT)
+//#else
+//#define VM_STACK_FLAGS	(VM_GROWSDOWN | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT)
+//#endif
+
+#define VM_READHINTMASK			(VM_SEQ_READ | VM_RAND_READ)
+//#define VM_ClearReadHint(v)		((v)->vm_flags &= ~VM_READHINTMASK)
+#define VM_NormalReadHint(v)		(!((v)->vm_flags & VM_READHINTMASK))
+#define VM_SequentialReadHint(v)	((v)->vm_flags & VM_SEQ_READ)
+#define VM_RandomReadHint(v)		((v)->vm_flags & VM_RAND_READ)
+
+#define REG_PCIE1_DMAREAD_ENABLE	0xa18
+#define SHIFT_PCIE1_DMAREAD_ENABLE	0
+
+#define REG_PCIE1_DMAWRITE_ENABLE	0x9c4
+#define SHIFT_PCIE1_DMAWRITE_ENABLE	0
+
+#define REG_PCIE1_DMAREAD_STATUS	0xa10
+#define SHIFT_PCIE1_DMAREAD_STATUS	0
+#define REG_PCIE1_DMAREADINT_CLEAR	0xa1c
+#define SHIFT_PCIE1_DMAREADINT_CLEAR	0
+
+#define REG_PCIE1_DMAWRITE_STATUS	0x9bc
+#define SHIFT_PCIE1_DMAWRITE_STATUS	0
+#define REG_PCIE1_DMAWRITEINT_CLEAR	0x9c8
+#define SHIFT_PCIE1_DMAWRITEINT_CLEAR	0
+
+#define REG_PCIE1_DMA_READ_ENGINE_ENABLE	(0x99c)
+#define SHIFT_PCIE1_DMA_ENGINE_ENABLE		(0)
+#define REG_PCIE1_DMA_WRITE_ENGINE_ENABLE	(0x97C)
+
+#define HOSTRTC_INT_OFFSET		0x10
+
+#define H2BSTATE_IDLE			0
+#define H2BSTATE_WAITREADY		1
+#define H2BSTATE_WAITDMA		2
+#define H2BSTATE_WAITACK		3
+#define H2BSTATE_ERROR			4
+
+#define B2HSTATE_IDLE			0
+#define B2HSTATE_WAITREADY		1
+#define B2HSTATE_WAITRECV		2
+#define B2HSTATE_WAITDMA		3
+#define B2HSTATE_ERROR			4
+
+#define PAGE_ORDER			8
+#define EDMA_DMABUF_SIZE		(1 << (PAGE_SHIFT + PAGE_ORDER))
+
+#define EDMA_DMA_TRANSFER_WAIT_TIMEOUT	(10 * HZ)
+#define TIMEOUT_WAIT_NOSIGNAL		2
+
+#define TIMER_INTERVAL_CHECK		(HZ / 10)
+#define DMA_TIMER_INTERVAL_CHECK	50
+#define HEARTBEAT_TIMER_INTERVAL_CHECK	HZ
+
+#define EDMA_PCI_MSG_LEN		(56 * 1024)
+
+#define HOST_DMA_FLAG_LEN		(64)
+
+#define HOST_MAX_SEND_MBX_LEN		(40 * 1024)
+#define BMC_MAX_RCV_MBX_LEN		HOST_MAX_SEND_MBX_LEN
+
+#define HOST_MAX_RCV_MBX_LEN		(16 * 1024)
+#define BMC_MAX_SEND_MBX_LEN		HOST_MAX_RCV_MBX_LEN
+#define CDEV_MAX_WRITE_LEN		(4*1024)
+
+#define HOST_MAX_MSG_LENGTH		272
+
+#define EDMA_MMAP_H2B_DMABUF		0xf1000000
+
+#define EDMA_MMAP_B2H_DMABUF		0xf2000000
+
+#define EDMA_IOC_MAGIC			'e'
+
+#define EDMA_H_REGISTER_TYPE		_IOW(EDMA_IOC_MAGIC, 100, unsigned long)
+
+#define EDMA_H_UNREGISTER_TYPE		_IOW(EDMA_IOC_MAGIC, 101, unsigned long)
+
+#define EDMA_H_DMA_START		_IOW(EDMA_IOC_MAGIC, 102, unsigned long)
+
+#define EDMA_H_DMA_TRANSFER		_IOW(EDMA_IOC_MAGIC, 103, unsigned long)
+
+#define EDMA_H_DMA_STOP			_IOW(EDMA_IOC_MAGIC, 104, unsigned long)
+
+#define U64ADDR_H(addr)			((((u64)addr)>>32)&0xffffffff)
+#define U64ADDR_L(addr)			((addr)&0xffffffff)
+
+struct bma_register_dev_type_s {
+	u32 type;
+	u32 sub_type;
+};
+
+struct edma_mbx_hdr_s {
+	u16 mbxlen;
+	u16 mbxoff;
+	u8 reserve[28];
+} __attribute__((packed));
+
+#define SIZE_OF_MBX_HDR (sizeof(struct edma_mbx_hdr_s))
+
+struct edma_recv_msg_s {
+	struct list_head link;
+	u32 msg_len;
+	unsigned char msg_data[0];	/*lint !e1501 */
+};
+
+struct edma_dma_addr_s {
+	void *kvaddr;
+	dma_addr_t dma_addr;
+	u32 len;
+};
+
+struct edma_msg_hdr_s {
+	u32 type;
+	u32 sub_type;
+	u8 user_id;
+	u8 dma_flag;
+	u8 reserve1[2];
+	u32 datalen;
+	u8 data[0];		/*lint !e1501 */
+};
+#define SIZE_OF_MSG_HDR (sizeof(struct edma_msg_hdr_s))
+
+#pragma pack(1)
+
+#define IS_EDMA_B2H_INT(flag)		((flag) & 0x02)
+#define CLEAR_EDMA_B2H_INT(flag)	((flag) = (flag) & 0xfffffffd)
+#define SET_EDMA_H2B_INT(flag)		((flag) = (flag) | 0x01)
+#define EDMA_B2H_INT_FLAG                      0x02
+
+struct notify_msg {
+	volatile unsigned int host_registered;
+	volatile unsigned int host_heartbeat;
+	volatile unsigned int bmc_registered;
+	volatile unsigned int bmc_heartbeat;
+	volatile unsigned int int_flag;
+
+	volatile unsigned int reservrd5;
+	unsigned int h2b_addr;
+	unsigned int h2b_size;
+	unsigned int h2b_rsize;
+	unsigned int b2h_addr;
+	unsigned int b2h_size;
+	unsigned int b2h_rsize;
+};
+
+#pragma pack()
+
+struct edma_statistics_s {
+	unsigned int remote_status;
+	__kernel_time_t init_time;
+	unsigned int h2b_int;
+	unsigned int b2h_int;
+	unsigned int recv_bytes;
+	unsigned int send_bytes;
+	unsigned int send_pkgs;
+	unsigned int recv_pkgs;
+	unsigned int failed_count;
+	unsigned int drop_pkgs;
+	unsigned int dma_count;
+	unsigned int lost_count;
+};
+
+struct edma_host_s {
+	struct pci_dev *pdev;
+
+	struct tasklet_struct tasklet;
+
+	void __iomem *hostrtc_viraddr;
+
+	void __iomem *edma_flag;
+	void __iomem *edma_send_addr;
+	void __iomem *edma_recv_addr;
+#ifdef USE_DMA
+	struct timer_list dma_timer;
+#endif
+
+	struct timer_list heartbeat_timer;
+
+#ifdef EDMA_TIMER
+	struct timer_list timer;
+#else
+	struct completion msg_ready;	/* to sleep thread on      */
+	struct task_struct *edma_thread;
+#endif
+	spinlock_t send_msg_lock;
+	unsigned char *msg_send_buf;
+	unsigned int msg_send_write;
+
+	/* DMA */
+	wait_queue_head_t wq_dmah2b;
+	wait_queue_head_t wq_dmab2h;
+
+	spinlock_t reg_lock;
+	volatile int h2b_state;
+	volatile int b2h_state;
+	struct edma_dma_addr_s h2b_addr;
+	struct edma_dma_addr_s b2h_addr;
+
+	struct proc_dir_entry *proc_edma_dir;
+
+	struct edma_statistics_s statistics;
+	unsigned char local_open_status[TYPE_MAX];
+	unsigned char remote_open_status[TYPE_MAX];
+};
+
+struct edma_user_inft_s {
+	/* register user */
+	int (*user_register)(struct bma_priv_data_s *priv);
+
+	/* unregister user */
+	void (*user_unregister)(struct bma_priv_data_s *priv);
+
+	/* add msg */
+	int (*add_msg)(void *msg, size_t msg_len);
+};
+
+int is_edma_b2h_int(struct edma_host_s *edma_host);
+void edma_int_to_bmc(struct edma_host_s *edma_host);
+int edma_host_mmap(struct edma_host_s *edma_hos, struct file *filp,
+		   struct vm_area_struct *vma);
+int edma_host_copy_msg(struct edma_host_s *edma_host, void *msg,
+		       size_t msg_len);
+int edma_host_add_msg(struct edma_host_s *edma_host,
+		      struct bma_priv_data_s *priv, void *msg, size_t msg_len);
+int edma_host_recv_msg(struct edma_host_s *edma_host,
+		       struct bma_priv_data_s *priv,
+		       struct edma_recv_msg_s **msg);
+void edma_host_isr_tasklet(unsigned long data);
+int edma_host_check_dma_status(enum dma_direction_e dir);
+int edma_host_dma_start(struct edma_host_s *edma_host,
+			struct bma_priv_data_s *priv);
+int edma_host_dma_transfer(struct edma_host_s *edma_host,
+			   struct bma_priv_data_s *priv,
+			   struct bma_dma_transfer_s *dma_transfer);
+int edma_host_dma_stop(struct edma_host_s *edma_host,
+		       struct bma_priv_data_s *priv);
+irqreturn_t edma_host_irq_handle(struct edma_host_s *edma_host);
+struct edma_user_inft_s *edma_host_get_user_inft(u32 type);
+int edma_host_user_register(u32 type, struct edma_user_inft_s *func);
+int edma_host_user_unregister(u32 type);
+int edma_host_init(struct edma_host_s *edma_host);
+void edma_host_cleanup(struct edma_host_s *edma_host);
+int edma_host_send_driver_msg(void *msg, size_t msg_len, int subtype);
+void edma_host_reset_dma(struct edma_host_s *edma_host, int dir);
+void clear_int_dmah2b(struct edma_host_s *edma_host);
+void clear_int_dmab2h(struct edma_host_s *edma_host);
+
+enum EDMA_STATUS {
+	DEREGISTERED = 0,
+	REGISTERED = 1,
+	LOST,
+};
+#endif
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_dump.c b/drivers/net/ethernet/huawei/ibma/kbox_dump.c
new file mode 100644
index 0000000..d06dca7
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_dump.c
@@ -0,0 +1,141 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/spinlock.h>
+#include <linux/utsname.h>		/* system_utsname */
+#include <linux/rtc.h>		/* struct rtc_time */
+#include "kbox_include.h"
+#include "kbox_main.h"
+#include "kbox_printk.h"
+#include "kbox_ram_image.h"
+#include "kbox_ram_op.h"
+#include "kbox_dump.h"
+#include "kbox_mce.h"
+#include "kbox_panic.h"
+
+#define THREAD_TMP_BUF_SIZE 256
+
+#if (KERNEL_VERSION(3, 0, 0) < LINUX_VERSION_CODE)
+static DEFINE_SPINLOCK(g_dump_lock);
+#else
+static spinlock_t g_dump_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+static const char g_day_in_month[] = {
+	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
+#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
+#define MONTH_DAYS(month, year) (g_day_in_month[(month)] \
+				+ (int)(LEAP_YEAR(year) && (month == 1)))
+
+
+static void kbox_show_kernel_version(void)
+{
+	(void)kbox_dump_painc_info(
+				"\nOS : %s,\nRelease : %s,\nVersion : %s,\nMachine : %s,\nNodename : %s\n",
+				   init_uts_ns.name.sysname,
+				   init_uts_ns.name.release,
+				   init_uts_ns.name.version,
+				   init_uts_ns.name.machine,
+				   init_uts_ns.name.nodename);
+}
+
+static void kbox_show_version(void)
+{
+	(void)kbox_dump_painc_info("\nKBOX_VERSION         : %s\n",
+				   KBOX_VERSION);
+}
+
+static void kbox_show_time_stamps(void)
+{
+	struct rtc_time rtc_time_val = { };
+	struct timeval time_value = { };
+
+	do_gettimeofday(&time_value);
+	time_value.tv_sec = time_value.tv_sec - sys_tz.tz_minuteswest * 60;
+	rtc_time_to_tm(time_value.tv_sec, &rtc_time_val);
+
+	(void)kbox_dump_painc_info(
+		"Current time         : %04d-%02d-%02d %02d:%02d:%02d\n",
+		rtc_time_val.tm_year + 1900, rtc_time_val.tm_mon + 1,
+		rtc_time_val.tm_mday, rtc_time_val.tm_hour,
+		rtc_time_val.tm_min, rtc_time_val.tm_sec);
+}
+
+int kbox_dump_thread_info(const char *fmt, ...)
+{
+	va_list args;
+	int num = 0;
+	char tmp_buf[THREAD_TMP_BUF_SIZE] = { };
+
+	va_start(args, fmt);/*lint !e530*/
+
+	num = vscnprintf(tmp_buf, sizeof(tmp_buf) - 1, fmt, args);
+	if (num >= 0) {
+		tmp_buf[num] = '\0';
+
+		(void)kbox_write_thread_info(tmp_buf, (unsigned int)num);
+	}
+
+	va_end(args);
+
+	return num;
+}
+
+void kbox_dump_event(enum kbox_error_type_e type, unsigned long event,
+		     const char *msg)
+{
+
+	if (!spin_trylock(&g_dump_lock))
+		return;
+
+	(void)kbox_dump_painc_info("\n====kbox begin dumping...====\n");
+
+	switch (type) {
+	case KBOX_MCE_EVENT:
+
+		kbox_handle_mce_dump(msg);
+
+		break;
+	case KBOX_OPPS_EVENT:
+
+		break;
+	case KBOX_PANIC_EVENT:
+		if (kbox_handle_panic_dump(msg) == KBOX_FALSE)
+			goto end;
+
+		break;
+	default:
+		break;
+	}
+
+	kbox_show_kernel_version();
+
+	kbox_show_version();
+
+	kbox_show_time_stamps();
+
+	(void)kbox_dump_painc_info("\n====kbox end dump====\n");
+
+	kbox_ouput_syslog_info();
+	kbox_ouput_printk_info();
+
+end:
+	spin_unlock(&g_dump_lock);
+}
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_dump.h b/drivers/net/ethernet/huawei/ibma/kbox_dump.h
new file mode 100644
index 0000000..84de92e
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_dump.h
@@ -0,0 +1,35 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#ifndef _KBOX_DUMP_H_
+#define _KBOX_DUMP_H_
+
+#define DUMPSTATE_MCE_RESET 1
+#define DUMPSTATE_OPPS_RESET 2
+#define DUMPSTATE_PANIC_RESET 3
+
+enum kbox_error_type_e {
+	KBOX_MCE_EVENT = 1,
+	KBOX_OPPS_EVENT,
+	KBOX_PANIC_EVENT
+};
+
+int kbox_dump_thread_info(const char *fmt, ...);
+void kbox_dump_event(enum kbox_error_type_e type, unsigned long event,
+		     const char *msg);
+
+#endif
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_hook.c b/drivers/net/ethernet/huawei/ibma/kbox_hook.c
new file mode 100644
index 0000000..47aa355
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_hook.c
@@ -0,0 +1,105 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/notifier.h>
+#include "kbox_include.h"
+#include "kbox_dump.h"
+#include "kbox_hook.h"
+
+/*lint -e49 -e526 -e10 */
+int panic_notify(struct notifier_block *this,
+					unsigned long event,
+					void *msg);
+/*lint +e49 +e526 +e10*/
+
+static int die_notify(struct notifier_block *self,
+					unsigned long val,
+					void *data);
+
+static struct notifier_block g_panic_nb = {
+	.notifier_call = panic_notify, /*lint !e64*/
+	.priority = 100,
+};
+
+static struct notifier_block g_die_nb = {
+	.notifier_call = die_notify,
+};
+
+int panic_notify(struct notifier_block *pthis, unsigned long event, void *msg)
+{
+	UNUSED(pthis);
+	UNUSED(event);
+
+	kbox_dump_event(KBOX_PANIC_EVENT, DUMPSTATE_PANIC_RESET,
+			(const char *)msg);
+
+	return NOTIFY_OK;
+}
+
+int die_notify(struct notifier_block *self, unsigned long val, void *data)
+{
+	struct kbox_die_args *args = (struct kbox_die_args *)data;
+
+	if (!args)
+		return NOTIFY_OK;
+
+	switch (val) {
+	case 1:
+		break;
+	case 5:
+		if (strcmp(args->str, "nmi") == 0)
+			return NOTIFY_OK;
+
+		kbox_dump_event(KBOX_MCE_EVENT, DUMPSTATE_MCE_RESET, args->str);
+		break;
+
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+
+int kbox_register_hook(void)
+{
+	int ret = 0;
+
+	ret = atomic_notifier_chain_register(&panic_notifier_list, &g_panic_nb);
+	if (ret)
+		KBOX_MSG("atomic_notifier_chain_register g_panic_nb failed!\n");
+
+	ret = register_die_notifier(&g_die_nb);
+	if (ret)
+		KBOX_MSG("register_die_notifier g_die_nb failed!\n");
+
+	return ret;
+}
+
+void kbox_unregister_hook(void)
+{
+	int ret = 0;
+
+	ret =
+	    atomic_notifier_chain_unregister(&panic_notifier_list, &g_panic_nb);
+	if (ret < 0) {
+		KBOX_MSG
+		    ("atomic_notifier_chain_unregister g_panic_nb failed!\n");
+	}
+
+	ret = unregister_die_notifier(&g_die_nb);
+	if (ret < 0)
+		KBOX_MSG("unregister_die_notifier g_die_nb failed!\n");
+}
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_hook.h b/drivers/net/ethernet/huawei/ibma/kbox_hook.h
new file mode 100644
index 0000000..61d9c7b
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_hook.h
@@ -0,0 +1,34 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _KBOX_PANIC_HOOK_H_
+#define _KBOX_PANIC_HOOK_H_
+
+struct kbox_die_args {
+	struct pt_regs  *regs;
+	const char  *str;
+	long err;
+	int trapnr;
+	int signr;
+};
+
+extern int register_die_notifier(struct notifier_block *nb);
+extern int unregister_die_notifier(struct notifier_block *nb);
+
+int kbox_register_hook(void);
+void kbox_unregister_hook(void);
+
+#endif
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_include.h b/drivers/net/ethernet/huawei/ibma/kbox_include.h
new file mode 100644
index 0000000..17a912b
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_include.h
@@ -0,0 +1,44 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _KBOX_INCLUDE_H_
+#define _KBOX_INCLUDE_H_
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#ifdef DRV_VERSION
+#define KBOX_VERSION MICRO_TO_STR(DRV_VERSION)
+#else
+#define KBOX_VERSION "0.2.9"
+#endif
+
+#define UNUSED(x) (x = x)
+#define KBOX_FALSE (-1)
+#define KBOX_TRUE 0
+
+#ifdef KBOX_DEBUG
+#define KBOX_MSG(fmt, args...) do {\
+	printk(KERN_NOTICE "kbox: %s(), %d, " fmt, \
+	__func__, __LINE__, ## args);\
+	} while (0)
+#else
+#define KBOX_MSG(fmt, args...)
+#endif
+
+#define BAD_FUNC_ADDR(x) ((0xFFFFFFFF == (x)) || (0 == (x)))
+
+#endif
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_main.c b/drivers/net/ethernet/huawei/ibma/kbox_main.c
new file mode 100644
index 0000000..eb9e946
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_main.c
@@ -0,0 +1,207 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <asm/msr.h>
+#include <asm/processor.h>	/* for rdmsr and MSR_IA32_MCG_STATUS */
+#include <linux/fs.h>		/* everything... */
+#include <linux/file.h>		/*fput() */
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>		/* copy_*_user */
+#include <linux/version.h>
+#include "kbox_include.h"
+#include "kbox_mce.h"
+#include "kbox_panic.h"
+#include "kbox_main.h"
+#include "kbox_printk.h"
+#include "kbox_ram_image.h"
+#include "kbox_ram_op.h"
+#include "kbox_dump.h"
+#include "kbox_hook.h"
+#include "kbox_ram_drive.h"
+
+#define KBOX_LOADED_FILE ("/proc/kbox")
+
+#define KBOX_ROOT_ENTRY_NAME ("kbox")
+
+int kbox_read_user_log_region(unsigned long offset, char *buf, unsigned int len)
+{
+	int ret = 0;
+
+	ret = kbox_read_from_ram(offset, len, (char *)buf, KBOX_SECTION_USER);
+
+	if (ret < 0) {
+		KBOX_MSG("kbox_read_from_ram fail!\n");
+		return ret;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(kbox_read_user_log_region);
+
+int kbox_write_user_log_region(unsigned long offset, char *buf,
+			       unsigned int len)
+{
+	int ret = 0;
+
+	ret = kbox_write_to_ram(offset, len, (char *)buf, KBOX_SECTION_USER);
+
+	if (ret < 0) {
+		KBOX_MSG("kbox_write_to_ram fail!\n");
+		return ret;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(kbox_write_user_log_region);
+
+int kbox_memset_user_log_region(unsigned long offset, char set_byte,
+				unsigned int len)
+{
+	int ret = 0;
+
+	ret = kbox_memset_ram(offset, len, set_byte, KBOX_SECTION_USER);
+
+	if (ret < 0) {
+		KBOX_MSG("kbox_memset_ram fail!\n");
+		return ret;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(kbox_memset_user_log_region);
+
+static int kbox_is_loaded(void)
+{
+	struct file *fp = NULL;
+	mm_segment_t old_fs = { };
+
+	old_fs = get_fs();		/* save old flag */
+	set_fs(KERNEL_DS);	/*lint !e501*//* mark data from kernel space */
+
+	fp = filp_open(KBOX_LOADED_FILE, O_RDONLY, 0);
+
+	if (IS_ERR(fp)) {
+		set_fs(old_fs);
+		return KBOX_FALSE;
+	}
+
+	(void)filp_close(fp, NULL);
+
+	set_fs(old_fs);		/* restore old flag */
+
+	return KBOX_TRUE;
+}
+
+static int kbox_printk_proc_init(void)
+{
+	struct proc_dir_entry *kbox_entry = NULL;
+
+	if (kbox_is_loaded() != KBOX_TRUE) {
+		kbox_entry = proc_mkdir(KBOX_ROOT_ENTRY_NAME, NULL);
+		if (!kbox_entry) {
+			KBOX_MSG("can not create %s entry\n",
+				 KBOX_ROOT_ENTRY_NAME);
+			return -ENOMEM;
+		}
+	}
+
+	return KBOX_TRUE;
+}
+
+int __init kbox_init(void)
+{
+	int ret = KBOX_TRUE;
+	int kbox_proc_exist = 0;
+
+	if (!kbox_get_base_phy_addr())
+		return -ENXIO;
+
+	ret = kbox_super_block_init();
+	if (ret) {
+		KBOX_MSG("kbox_super_block_init failed!\n");
+		return ret;
+	}
+
+	if (kbox_is_loaded() == KBOX_TRUE)
+		kbox_proc_exist = 1;
+
+	ret = kbox_printk_init(kbox_proc_exist);
+	if (ret)
+		KBOX_MSG("kbox_printk_init failed!\n");
+
+	ret = kbox_panic_init();
+	if (ret) {
+		KBOX_MSG("kbox_panic_init failed!\n");
+		goto fail1;
+	}
+
+	ret = kbox_register_hook();
+	if (ret) {
+		KBOX_MSG("kbox_register_hook failed!\n");
+		goto fail2;
+	}
+
+	(void)kbox_mce_init();
+	ret = Kbox_read_super_block();
+	if (ret) {
+		KBOX_MSG("kbox_mce_init failed!\n");
+		goto fail3;
+	}
+
+	if (kbox_printk_proc_init() != 0) {
+		KBOX_MSG("kbox_printk_proc_init failed!\n");
+		goto fail4;
+	}
+
+	ret = kbox_drive_init();
+	if (ret) {
+		KBOX_MSG("kbox_drive_init failed!\n");
+		goto fail5;
+	}
+
+	return KBOX_TRUE;
+
+fail5:
+fail4:
+fail3:
+	kbox_mce_exit();
+	kbox_unregister_hook();
+fail2:
+	kbox_panic_exit();
+fail1:
+	kbox_printk_exit();
+
+	return ret;
+}
+
+void __exit kbox_cleanup(void)
+{
+	kbox_drive_cleanup();
+	kbox_mce_exit();
+	kbox_unregister_hook();
+	kbox_panic_exit();
+	kbox_printk_exit();
+}
+
+MODULE_AUTHOR("HUAWEI TECHNOLOGIES CO., LTD.");
+MODULE_DESCRIPTION("HUAWEI KBOX DRIVER");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(KBOX_VERSION);
+#ifndef _lint
+module_init(kbox_init);
+module_exit(kbox_cleanup);
+#endif
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_main.h b/drivers/net/ethernet/huawei/ibma/kbox_main.h
new file mode 100644
index 0000000..1e132bd
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_main.h
@@ -0,0 +1,25 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#ifndef _KBOX_MAIN_H_
+#define _KBOX_MAIN_H_
+
+#include "bma_include.h"
+int kbox_init(void);
+void kbox_cleanup(void);
+
+#endif
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_mce.c b/drivers/net/ethernet/huawei/ibma/kbox_mce.c
new file mode 100644
index 0000000..fc72077
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_mce.c
@@ -0,0 +1,293 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/atomic.h>
+#include <linux/smp.h>
+#include <linux/notifier.h>
+#include <asm/mce.h>
+#include <asm/msr.h>
+
+#include "kbox_include.h"
+#include "kbox_mce.h"
+#include "kbox_dump.h"
+#include "kbox_printk.h"
+#include "kbox_panic.h"
+
+enum context {
+	KBOX_IN_KERNEL = 1, KBOX_IN_USER = 2
+};
+
+enum ser {
+	KBOX_SER_REQUIRED = 1, KBOX_NO_SER = 2
+};
+
+enum severity_level {
+	KBOX_MCE_NO_SEVERITY,
+	KBOX_MCE_KEEP_SEVERITY,
+	KBOX_MCE_SOME_SEVERITY,
+	KBOX_MCE_AO_SEVERITY,
+	KBOX_MCE_UC_SEVERITY,
+	KBOX_MCE_AR_SEVERITY,
+	KBOX_MCE_PANIC_SEVERITY,
+};
+
+static struct severity {
+	u64 kbox_mask;
+	u64 kbox_result;
+	unsigned char kbox_sev;
+	unsigned char kbox_mcgmask;
+	unsigned char kbox_mcgres;
+	unsigned char kbox_ser;
+	unsigned char kbox_context;
+	unsigned char kbox_covered;
+	char *kbox_msg;
+} kbox_severities[] = {
+
+#if (KERNEL_VERSION(2, 6, 18) >= LINUX_VERSION_CODE)
+#define MSR_IA32_MCx_CTL(x)         (MSR_IA32_MC0_CTL + 4*(x))
+#define MSR_IA32_MCx_STATUS(x)      (MSR_IA32_MC0_STATUS + 4*(x))
+#define MSR_IA32_MCx_ADDR(x)        (MSR_IA32_MC0_ADDR + 4*(x))
+#define MSR_IA32_MCx_MISC(x)        (MSR_IA32_MC0_MISC + 4*(x))
+#define MCI_STATUS_S    (1ULL<<56)		/* Signaled machine check */
+#define MCI_STATUS_AR   (1ULL<<55)	/* Action required */
+#define MCG_BANKCNT_MASK    0xff		/* Number of Banks */
+/* MCA recovery/new status bits */
+#define MCG_SER_P       (1ULL<<24)
+
+#endif
+
+/*lint -e665*/
+#define KBOX_KERNEL .kbox_context = KBOX_IN_KERNEL
+#define KBOX_USER .kbox_context = KBOX_IN_USER
+#define KBOX_SER .kbox_ser      = KBOX_SER_REQUIRED
+#define KBOX_NOSER .kbox_ser    = KBOX_NO_SER
+#define KBOX_SEV(s) .kbox_sev   = KBOX_MCE_ ## s ## _SEVERITY
+#define KBOX_BITCLR(x, s, m, r...) \
+	{ .kbox_mask = x,   .kbox_result = 0, KBOX_SEV(s), .kbox_msg = m, ## r }
+#define KBOX_BITSET(x, s, m, r...) \
+	{ .kbox_mask = x,   .kbox_result = x, KBOX_SEV(s), .kbox_msg = m, ## r }
+#define KBOX_MCGMASK(x, res, s, m, r...) \
+	{\
+		.kbox_mcgmask = x, \
+		.kbox_mcgres = res, \
+		KBOX_SEV(s), \
+		.kbox_msg = m, \
+		## r }
+#define KBOX_MASK(x, y, s, m, r...) \
+	{ .kbox_mask = x, .kbox_result = y, KBOX_SEV(s), .kbox_msg = m, ## r }
+#define KBOX_MCI_UC_S (MCI_STATUS_UC | MCI_STATUS_S)
+#define KBOX_MCI_UC_SAR (MCI_STATUS_UC | MCI_STATUS_S | MCI_STATUS_AR)
+#define KBOX_MCACOD 0xffff
+
+KBOX_BITCLR(MCI_STATUS_VAL, NO, "Invalid"),
+KBOX_BITCLR(MCI_STATUS_EN, NO, "Not enabled"),
+KBOX_BITSET(MCI_STATUS_PCC, PANIC, "Processor context corrupt"),
+
+KBOX_MCGMASK(MCG_STATUS_MCIP, 0, PANIC, "MCIP not set in MCA handler"),
+
+KBOX_MCGMASK(MCG_STATUS_RIPV | MCG_STATUS_EIPV, 0, PANIC,
+	"Neither restart nor error IP"),
+KBOX_MCGMASK(MCG_STATUS_RIPV, 0, PANIC, "In kernel and no restart IP",
+	KBOX_KERNEL),
+KBOX_BITCLR(MCI_STATUS_UC, KEEP, "Corrected error", KBOX_NOSER),
+KBOX_MASK(MCI_STATUS_OVER | MCI_STATUS_UC | MCI_STATUS_EN, MCI_STATUS_UC, SOME,
+	"Spurious not enabled", KBOX_SER),
+
+KBOX_MASK(KBOX_MCI_UC_SAR, MCI_STATUS_UC, KEEP,
+	"Uncorrected no action required", KBOX_SER),
+KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR, MCI_STATUS_UC | MCI_STATUS_AR,
+	PANIC, "Illegal combination (UCNA with AR=1)", KBOX_SER),
+KBOX_MASK(MCI_STATUS_S, 0, KEEP, "Non signalled machine check", KBOX_SER),
+
+KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR, MCI_STATUS_OVER | KBOX_MCI_UC_SAR,
+	PANIC, "Action required with lost events", KBOX_SER),
+KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR | KBOX_MCACOD, KBOX_MCI_UC_SAR,
+	PANIC, "Action required; unknown MCACOD", KBOX_SER),
+
+KBOX_MASK(KBOX_MCI_UC_SAR | MCI_STATUS_OVER | 0xfff0, KBOX_MCI_UC_S | 0xc0,
+	AO, "Action optional: memory scrubbing error", KBOX_SER),
+KBOX_MASK(KBOX_MCI_UC_SAR | MCI_STATUS_OVER | KBOX_MCACOD,
+	KBOX_MCI_UC_S | 0x17a, AO,
+	"Action optional: last level cache writeback error", KBOX_SER),
+
+KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR, KBOX_MCI_UC_S, SOME,
+	"Action optional unknown MCACOD", KBOX_SER),
+KBOX_MASK(MCI_STATUS_OVER | KBOX_MCI_UC_SAR, KBOX_MCI_UC_S | MCI_STATUS_OVER,
+	SOME, "Action optional with lost events", KBOX_SER),
+KBOX_BITSET(MCI_STATUS_UC | MCI_STATUS_OVER, PANIC, "Overflowed uncorrected"),
+KBOX_BITSET(MCI_STATUS_UC, UC, "Uncorrected"),
+KBOX_BITSET(0, SOME, "No match")
+};
+/*lint -e665*/
+
+
+
+static unsigned int g_kbox_nr_mce_banks;
+static unsigned int g_kbox_mce_ser;
+static atomic_t g_mce_dump_state = ATOMIC_INIT(0);
+
+static int kbox_mce_severity(u64 mcgstatus, u64 status)
+{
+	struct severity *s;
+
+	for (s = kbox_severities;; s++) {
+		if ((status & s->kbox_mask) != s->kbox_result)
+			continue;
+
+		if ((mcgstatus & s->kbox_mcgmask) != s->kbox_mcgres)
+			continue;
+
+		if ((s->kbox_ser == KBOX_SER_REQUIRED) && !g_kbox_mce_ser)
+			continue;
+
+		if ((s->kbox_ser == KBOX_NO_SER) && g_kbox_mce_ser)
+			continue;
+
+		break;
+	}
+
+	return s->kbox_sev;
+}
+
+static u64 kbox_mce_rdmsrl(u32 ulmsr)
+{
+	u64 ullv = 0;
+#if (KERNEL_VERSION(2, 6, 18) >= LINUX_VERSION_CODE)
+	rdmsrl(ulmsr, ullv);
+#else
+	if (rdmsrl_safe(ulmsr, &ullv)) {
+		(void)kbox_dump_painc_info("mce: Unable to read msr %d!\n",
+					   ulmsr);
+		ullv = 0;
+	}
+#endif
+
+	return ullv;
+}
+
+static int kbox_intel_machine_check(void)
+{
+	unsigned int idx = 0;
+	u64 mcgstatus = 0;
+	int worst = 0;
+
+	mcgstatus = kbox_mce_rdmsrl(MSR_IA32_MCG_STATUS);
+
+	(void)
+	    kbox_dump_painc_info
+	    ("CPU %d: Machine Check Exception MCG STATUS: 0x%016llx\n",
+	     smp_processor_id(), mcgstatus);
+
+	if (!(mcgstatus & MCG_STATUS_RIPV))
+		(void)kbox_dump_painc_info("Unable to continue\n");
+
+	for (idx = 0; idx < g_kbox_nr_mce_banks; idx++) {
+		u64 status = 0;
+		u64 misc = 0;
+		u64 addr = 0;
+		int lseverity = 0;
+
+		status = kbox_mce_rdmsrl(MSR_IA32_MCx_STATUS(idx));
+
+		(void)kbox_dump_painc_info("Bank %d STATUS: 0x%016llx\n", idx,
+					   status);
+
+		if (0 == (status & MCI_STATUS_VAL))
+			continue;
+
+		lseverity = kbox_mce_severity(mcgstatus, status);
+		if ((lseverity == KBOX_MCE_KEEP_SEVERITY)
+		    || (lseverity == KBOX_MCE_NO_SEVERITY))
+			continue;
+
+		(void)kbox_dump_painc_info("severity = %d\n", lseverity);
+
+		if (status & MCI_STATUS_MISCV) {
+			misc = kbox_mce_rdmsrl(MSR_IA32_MCx_MISC(idx));
+			(void)kbox_dump_painc_info("misc = 0x%016llx\n", misc);
+		}
+
+		if (status & MCI_STATUS_ADDRV) {
+			addr = kbox_mce_rdmsrl(MSR_IA32_MCx_ADDR(idx));
+			(void)kbox_dump_painc_info("addr = 0x%016llx\n", addr);
+		}
+
+		(void)kbox_dump_painc_info("\n");
+
+		if (lseverity > worst)
+			worst = lseverity;
+	}
+
+	if (worst >= KBOX_MCE_UC_SEVERITY)
+		return KBOX_FALSE;
+
+	(void)kbox_dump_painc_info("Attempting to continue.\n");
+
+	return KBOX_TRUE;
+}
+
+int kbox_handle_mce_dump(const char *msg)
+{
+	int mce_recoverable = KBOX_FALSE;
+
+	atomic_read(&g_mce_dump_state);
+
+	mce_recoverable = kbox_intel_machine_check();
+	if (mce_recoverable != KBOX_TRUE) {
+
+		static atomic_t mce_entry_tmp;
+
+		int flag = atomic_add_return(1, &mce_entry_tmp);
+
+		if (flag != 1)
+			return KBOX_FALSE;
+
+	}
+
+	atomic_set(&g_mce_dump_state, DUMPSTATE_MCE_RESET);
+
+	if (msg != NULL) {
+		(void)
+		    kbox_dump_painc_info
+		    ("-------[ System may reset by %s! ]-------\n\n", msg);
+	}
+
+	return KBOX_TRUE;
+}
+
+int kbox_mce_init(void)
+{
+	u64 cap = 0;
+
+	cap = kbox_mce_rdmsrl(MSR_IA32_MCG_CAP);
+	g_kbox_nr_mce_banks = cap & MCG_BANKCNT_MASK;
+
+	if (cap & MCG_SER_P)
+		g_kbox_mce_ser = 1;
+
+	KBOX_MSG("get nr_mce_banks:%d, g_kbox_mce_ser = %d, cap = 0x%016llx\n",
+		 g_kbox_nr_mce_banks, g_kbox_mce_ser, cap);
+
+	return KBOX_TRUE;
+}
+
+void kbox_mce_exit(void)
+{
+	g_kbox_nr_mce_banks = 0;
+	g_kbox_mce_ser = 0;
+}
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_mce.h b/drivers/net/ethernet/huawei/ibma/kbox_mce.h
new file mode 100644
index 0000000..68bb52e
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_mce.h
@@ -0,0 +1,25 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#ifndef _KBOX_MCE_H_
+#define _KBOX_MCE_H_
+
+int kbox_handle_mce_dump(const char *msg);
+int kbox_mce_init(void);
+void kbox_mce_exit(void);
+
+#endif
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_panic.c b/drivers/net/ethernet/huawei/ibma/kbox_panic.c
new file mode 100644
index 0000000..d1565fe
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_panic.c
@@ -0,0 +1,195 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/types.h>
+#include <asm/msr.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include "kbox_include.h"
+#include "kbox_panic.h"
+#include "kbox_ram_op.h"
+
+#define PANIC_TMP_BUF_SIZE 256
+
+static int g_panic_init_ok = KBOX_FALSE;
+
+static char  *g_panic_info_buf_tmp;
+static char  *g_panic_info_buf;
+
+static unsigned int g_panic_info_start;
+
+static unsigned int g_panic_info_end;
+
+static unsigned int g_panic_info_len;
+
+#if (KERNEL_VERSION(3, 0, 0) < LINUX_VERSION_CODE)
+static DEFINE_SPINLOCK(g_panic_buf_lock);
+#else
+static spinlock_t g_panic_buf_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+static void kbox_emit_syslog_char(const char c)
+{
+	if (unlikely(!g_panic_info_buf))
+		return;
+
+	 *(g_panic_info_buf + (g_panic_info_end % SLOT_LENGTH)) = c;
+	g_panic_info_end++;
+
+	if (g_panic_info_end > SLOT_LENGTH)
+		g_panic_info_start++;
+
+	if (g_panic_info_len < SLOT_LENGTH)
+		g_panic_info_len++;
+
+}
+
+static int kbox_duplicate_syslog_info(const char  *syslog_buf,
+				      unsigned int buf_len)
+{
+	unsigned int idx = 0;
+	unsigned long flags = 0;
+
+	if (!syslog_buf)
+		return 0;
+
+	spin_lock_irqsave(&g_panic_buf_lock, flags);
+
+	for (idx = 0; idx < buf_len; idx++)
+		kbox_emit_syslog_char(*syslog_buf++);
+
+	spin_unlock_irqrestore(&g_panic_buf_lock, flags);
+
+	return buf_len;
+}
+
+int kbox_dump_painc_info(const char  *fmt, ...)
+{
+	va_list args;
+	int num = 0;
+	char tmp_buf[PANIC_TMP_BUF_SIZE] = { };
+
+	va_start(args, fmt);/* lint !e530 */
+
+	num = vsnprintf(tmp_buf, sizeof(tmp_buf) - 1, fmt, args);
+	if (num >= 0)
+		(void)kbox_duplicate_syslog_info(tmp_buf, num);
+
+	va_end(args);
+
+	return num;
+}
+
+void kbox_ouput_syslog_info(void)
+{
+	unsigned int start_tmp = 0;
+	unsigned int end_tmp = 0;
+	unsigned int len_tmp = 0;
+	unsigned long flags = 0;
+
+	if (unlikely
+	    ((!g_panic_info_buf) || (!g_panic_info_buf_tmp)))
+		return;
+
+	spin_lock_irqsave(&g_panic_buf_lock, flags);
+	if (g_panic_info_len == 0) {
+		spin_unlock_irqrestore(&g_panic_buf_lock, flags);
+		return;
+	}
+
+	start_tmp = (g_panic_info_start % SLOT_LENGTH);
+	end_tmp = ((g_panic_info_end - 1) % SLOT_LENGTH);
+	len_tmp = g_panic_info_len;
+
+	if (start_tmp > end_tmp) {
+		memcpy(g_panic_info_buf_tmp,
+			(g_panic_info_buf + start_tmp),
+			len_tmp - start_tmp);/* lint !e522 !e64 */
+		memcpy((g_panic_info_buf_tmp + len_tmp - start_tmp),
+			g_panic_info_buf,
+			end_tmp + 1);/* lint !e522 !e64 */
+	} else {
+		memcpy(g_panic_info_buf_tmp,
+			(char  *)(g_panic_info_buf + start_tmp),
+			len_tmp);/* lint !e522 !e64 */
+	}
+
+	spin_unlock_irqrestore(&g_panic_buf_lock, flags);
+
+	(void)kbox_write_panic_info(g_panic_info_buf_tmp, len_tmp);
+
+}
+
+int kbox_panic_init(void)
+{
+	int ret = KBOX_TRUE;
+
+	g_panic_info_buf = kmalloc(SLOT_LENGTH, GFP_KERNEL); /* lint !e64 */
+	if (IS_ERR(g_panic_info_buf) || (!g_panic_info_buf)) {
+		KBOX_MSG("kmalloc g_panic_info_buf fail!\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	memset(g_panic_info_buf, 0, SLOT_LENGTH);
+
+	g_panic_info_buf_tmp = kmalloc(SLOT_LENGTH, GFP_KERNEL); /* lint !e64 */
+	if (IS_ERR(g_panic_info_buf_tmp) || (!g_panic_info_buf_tmp)) {
+		KBOX_MSG("kmalloc g_panic_info_buf_tmp fail!\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	memset(g_panic_info_buf_tmp, 0, SLOT_LENGTH);
+
+	g_panic_init_ok = KBOX_TRUE;
+
+	return ret;
+fail:
+
+	kfree(g_panic_info_buf);
+	g_panic_info_buf = NULL;
+
+	kfree(g_panic_info_buf_tmp);
+	g_panic_info_buf_tmp = NULL;
+
+	return ret;
+}
+
+void kbox_panic_exit(void)
+{
+	if (g_panic_init_ok != KBOX_TRUE)
+		return;
+
+	kfree(g_panic_info_buf);
+	g_panic_info_buf = NULL;
+
+	kfree(g_panic_info_buf_tmp);
+	g_panic_info_buf_tmp = NULL;
+
+	/* (void)unregister_console(&g_syslog_console); */
+}
+
+int kbox_handle_panic_dump(const char  *msg)
+{
+
+	if (msg)
+		(void)kbox_dump_painc_info("panic string: %s\n", msg);
+
+
+	return KBOX_TRUE;
+}
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_panic.h b/drivers/net/ethernet/huawei/ibma/kbox_panic.h
new file mode 100644
index 0000000..33181ef
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_panic.h
@@ -0,0 +1,27 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#ifndef _KBOX_PANIC_H_
+#define _KBOX_PANIC_H_
+
+int kbox_handle_panic_dump(const char  *msg);
+void kbox_ouput_syslog_info(void);
+int kbox_dump_painc_info(const char  *fmt, ...);
+int kbox_panic_init(void);
+void kbox_panic_exit(void);
+
+#endif
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_printk.c b/drivers/net/ethernet/huawei/ibma/kbox_printk.c
new file mode 100644
index 0000000..0271680
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_printk.c
@@ -0,0 +1,377 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/console.h>		/* struct console */
+#include <linux/slab.h>
+#include <linux/err.h>
+#include "kbox_include.h"
+#include "kbox_main.h"
+#include "kbox_printk.h"
+#include "kbox_ram_image.h"
+#include "kbox_ram_op.h"
+
+#define TMP_BUF_SIZE 256
+
+static int g_printk_init_ok = KBOX_FALSE;
+
+static char *g_printk_info_buf;
+static char *g_printk_info_buf_tmp;
+
+static struct printk_ctrl_block_tmp_s g_printk_ctrl_block_tmp = { };
+
+#if (KERNEL_VERSION(3, 0, 0) < LINUX_VERSION_CODE)
+static DEFINE_SPINLOCK(g_printk_buf_lock);
+#else
+static spinlock_t g_printk_buf_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+static void kbox_printk_info_write(struct console *console,
+				   const char *printk_buf,
+				   unsigned int buf_len);
+
+static struct console g_printk_console = {
+	.name = "k_prtk",
+	.flags = CON_ENABLED | CON_PRINTBUFFER,
+	.write = kbox_printk_info_write,
+};
+
+static int kbox_printk_format_is_order(struct printk_info_ctrl_block_s *
+				       printk_ctrl_blk_first,
+				       struct printk_info_ctrl_block_s *
+				       printk_ctrl_blk_second)
+{
+	if (!printk_ctrl_blk_first || !printk_ctrl_blk_second)
+		return KBOX_FALSE;
+
+	if (!memcmp
+	    (printk_ctrl_blk_first->flag, PRINTK_CURR_FLAG, PRINTK_FLAG_LEN)
+	    && !memcmp(printk_ctrl_blk_second->flag, PRINTK_LAST_FLAG,
+		       PRINTK_FLAG_LEN)) {
+		return KBOX_TRUE;
+	}
+
+	return KBOX_FALSE;
+}
+
+static void kbox_printk_format(struct printk_info_ctrl_block_s *printk_ctrl_blk,
+			       char *flag)
+{
+	if (!printk_ctrl_blk || !flag)
+		return;
+
+	memset(printk_ctrl_blk, 0, sizeof(struct printk_info_ctrl_block_s));
+	memcpy(printk_ctrl_blk->flag, flag, PRINTK_FLAG_LEN);/*lint !e522 !e64*/
+
+}
+
+static void kbox_printk_init_info_first(struct image_super_block_s
+							*kbox_super_block)
+{
+	KBOX_MSG("\n");
+	if (kbox_printk_format_is_order(kbox_super_block->printk_ctrl_blk,
+					kbox_super_block->printk_ctrl_blk +
+					1) == KBOX_TRUE) {
+		memcpy(kbox_super_block->printk_ctrl_blk[0].flag,
+			PRINTK_LAST_FLAG,
+			PRINTK_FLAG_LEN);	/*lint !e64 !e522 */
+		memcpy(kbox_super_block->printk_ctrl_blk[1].flag,
+			PRINTK_CURR_FLAG,
+			PRINTK_FLAG_LEN);	/*lint !e64 !e522 */
+
+		kbox_super_block->printk_ctrl_blk[1].len = 0;
+		g_printk_ctrl_block_tmp.printk_region = 1;
+		g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK2;
+		(void)kbox_clear_region(KBOX_SECTION_PRINTK2);
+	} else if (kbox_printk_format_is_order(
+			kbox_super_block->printk_ctrl_blk + 1,
+			kbox_super_block->printk_ctrl_blk) == KBOX_TRUE) {
+
+		memcpy(kbox_super_block->printk_ctrl_blk[1].flag,
+			PRINTK_LAST_FLAG,
+			PRINTK_FLAG_LEN);	/*lint !e522 !e64*/
+		memcpy(kbox_super_block->printk_ctrl_blk[0].flag,
+			PRINTK_CURR_FLAG,
+			PRINTK_FLAG_LEN);	/*lint !e522 !e64*/
+
+		kbox_super_block->printk_ctrl_blk[0].len = 0;
+		g_printk_ctrl_block_tmp.printk_region = 0;
+		g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK1;
+		(void)kbox_clear_region(KBOX_SECTION_PRINTK1);
+	} else {
+		kbox_printk_format(kbox_super_block->printk_ctrl_blk,
+				   PRINTK_CURR_FLAG);
+		kbox_printk_format(kbox_super_block->printk_ctrl_blk + 1,
+				   PRINTK_LAST_FLAG);
+		g_printk_ctrl_block_tmp.printk_region = 0;
+		g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK1;
+		(void)kbox_clear_region(KBOX_SECTION_PRINTK1);
+		(void)kbox_clear_region(KBOX_SECTION_PRINTK2);
+	}
+
+	g_printk_ctrl_block_tmp.start = 0;
+	g_printk_ctrl_block_tmp.end = 0;
+	g_printk_ctrl_block_tmp.valid_len = 0;
+
+}
+
+static void kbox_printk_init_info_not_first(struct image_super_block_s
+					    *kbox_super_block)
+{
+	KBOX_MSG("\n");
+	if (KBOX_TRUE ==
+	    kbox_printk_format_is_order(kbox_super_block->printk_ctrl_blk,
+					kbox_super_block->printk_ctrl_blk +
+					1)) {
+		g_printk_ctrl_block_tmp.printk_region = 0;
+		g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK1;
+
+	} else if (KBOX_TRUE ==
+		   kbox_printk_format_is_order(
+		   kbox_super_block->printk_ctrl_blk + 1,
+		   kbox_super_block->printk_ctrl_blk)) {
+		g_printk_ctrl_block_tmp.printk_region = 1;
+		g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK2;
+
+	} else {
+		kbox_printk_format(kbox_super_block->printk_ctrl_blk,
+				   PRINTK_CURR_FLAG);
+		kbox_printk_format(kbox_super_block->printk_ctrl_blk + 1,
+				   PRINTK_LAST_FLAG);
+		g_printk_ctrl_block_tmp.printk_region = 0;
+		g_printk_ctrl_block_tmp.section = KBOX_SECTION_PRINTK1;
+		(void)kbox_clear_region(KBOX_SECTION_PRINTK1);
+		(void)kbox_clear_region(KBOX_SECTION_PRINTK2);
+
+	}
+
+	g_printk_ctrl_block_tmp.start = 0;
+
+}
+
+static int kbox_printk_init_info(int kbox_proc_exist)
+{
+	struct image_super_block_s kbox_super_block = { };
+	unsigned int read_len = 0;
+	unsigned int write_len = 0;
+
+	read_len =
+	    kbox_read_from_ram(SECTION_KERNEL_OFFSET,
+			       (unsigned int)sizeof(struct image_super_block_s),
+			       (char *)&kbox_super_block, KBOX_SECTION_KERNEL);
+	if (read_len != sizeof(struct image_super_block_s)) {
+		KBOX_MSG("fail to get superblock data!\n");
+		return KBOX_FALSE;
+	}
+
+	if (kbox_proc_exist) {
+		kbox_printk_init_info_not_first(&kbox_super_block);
+		if (KBOX_TRUE !=
+		    kbox_read_printk_info(g_printk_info_buf,
+					  &g_printk_ctrl_block_tmp)) {
+			g_printk_ctrl_block_tmp.end = 0;
+			g_printk_ctrl_block_tmp.valid_len = 0;
+		}
+	} else {
+		kbox_printk_init_info_first(&kbox_super_block);
+	}
+
+	kbox_super_block.checksum = 0;
+	kbox_super_block.checksum =
+	    ~((unsigned char)
+	      Kbox_checksum((char *)&kbox_super_block,
+			(unsigned int)sizeof(struct image_super_block_s))) + 1;
+	write_len =
+	    kbox_write_to_ram(SECTION_KERNEL_OFFSET,
+			      (unsigned int)sizeof(struct image_super_block_s),
+			      (char *)&kbox_super_block, KBOX_SECTION_KERNEL);
+	if (write_len <= 0) {
+		KBOX_MSG("fail to write superblock data!\n");
+		return KBOX_FALSE;
+	}
+
+	return KBOX_TRUE;
+}
+
+void kbox_ouput_printk_info(void)
+{
+	unsigned int start_tmp = 0;
+	unsigned int end_tmp = 0;
+	unsigned int len_tmp = 0;
+	unsigned long flags = 0;
+
+	if (unlikely((!g_printk_info_buf) || (!g_printk_info_buf_tmp)))
+		return;
+
+	if (g_printk_init_ok != KBOX_TRUE)
+		return;
+
+	spin_lock_irqsave(&g_printk_buf_lock, flags);
+	if (g_printk_ctrl_block_tmp.valid_len == 0) {
+		spin_unlock_irqrestore(&g_printk_buf_lock, flags);
+		return;
+	}
+
+	start_tmp = (g_printk_ctrl_block_tmp.start % SECTION_PRINTK_LEN);
+	end_tmp = ((g_printk_ctrl_block_tmp.end - 1) % SECTION_PRINTK_LEN);
+	len_tmp = g_printk_ctrl_block_tmp.valid_len;
+
+	if (start_tmp > end_tmp) {
+		memcpy(g_printk_info_buf_tmp,
+			g_printk_info_buf + start_tmp,
+			len_tmp - start_tmp);	/*lint !e64 !e522 */
+		memcpy(g_printk_info_buf_tmp + len_tmp - start_tmp,
+			g_printk_info_buf,
+			end_tmp + 1);	/*lint !e64 !e522 */
+	} else {
+		memcpy(g_printk_info_buf_tmp,
+			g_printk_info_buf + start_tmp,
+			len_tmp);	/*lint !e64 !e522 */
+	}
+
+	spin_unlock_irqrestore(&g_printk_buf_lock, flags);
+
+	(void)kbox_write_printk_info(g_printk_info_buf_tmp,
+				     &g_printk_ctrl_block_tmp);
+
+}
+
+static void kbox_emit_printk_char(const char c)
+{
+	if (unlikely(!g_printk_info_buf))
+		return;
+
+	*(g_printk_info_buf +
+	  (g_printk_ctrl_block_tmp.end % SECTION_PRINTK_LEN)) = c;
+	g_printk_ctrl_block_tmp.end++;
+
+	if (g_printk_ctrl_block_tmp.end > SECTION_PRINTK_LEN)
+		g_printk_ctrl_block_tmp.start++;
+
+	if (g_printk_ctrl_block_tmp.end < SECTION_PRINTK_LEN)
+		g_printk_ctrl_block_tmp.valid_len++;
+
+}
+
+static int kbox_duplicate_printk_info(const char *printk_buf,
+				      unsigned int buf_len)
+{
+	unsigned int idx = 0;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&g_printk_buf_lock, flags);
+	for (idx = 0; idx < buf_len; idx++)
+		kbox_emit_printk_char(*printk_buf++);
+
+	spin_unlock_irqrestore(&g_printk_buf_lock, flags);
+
+	return buf_len;
+}
+
+int kbox_dump_printk_info(const char *fmt, ...)
+{
+	va_list args;
+	int num = 0;
+	char tmp_buf[TMP_BUF_SIZE] = { };
+
+	if (g_printk_init_ok != KBOX_TRUE)
+		return 0;
+
+	va_start(args, fmt);	/*lint !e530*/
+
+	num = vsnprintf(tmp_buf, sizeof(tmp_buf) - 1, fmt, args);
+	if (num >= 0)
+		(void)kbox_duplicate_printk_info(tmp_buf, num);
+
+	va_end(args);
+
+	return num;
+}
+
+static void kbox_printk_info_write(struct console *pconsole,
+				   const char *printk_buf, unsigned int buf_len)
+{
+	UNUSED(pconsole);
+
+	if (unlikely(!printk_buf))
+		return;
+
+	(void)kbox_duplicate_printk_info(printk_buf, buf_len);
+}
+
+int kbox_printk_init(int kbox_proc_exist)
+{
+	int ret = KBOX_TRUE;
+
+	g_printk_info_buf = kmalloc(SECTION_PRINTK_LEN,
+					GFP_KERNEL); /*lint !e64*/
+	if (IS_ERR(g_printk_info_buf) || (!g_printk_info_buf)) {
+		KBOX_MSG("kmalloc g_printk_info_buf fail!\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	memset(g_printk_info_buf, 0, SECTION_PRINTK_LEN);
+
+	g_printk_info_buf_tmp = kmalloc(SECTION_PRINTK_LEN,
+						GFP_KERNEL); /*lint !e64*/
+	if (IS_ERR(g_printk_info_buf_tmp) || (g_printk_info_buf_tmp == NULL)) {
+		KBOX_MSG("kmalloc g_printk_info_buf_tmp fail!\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	memset(g_printk_info_buf_tmp, 0, SECTION_PRINTK_LEN);
+
+	ret = kbox_printk_init_info(kbox_proc_exist);
+	if (ret != KBOX_TRUE) {
+		KBOX_MSG("kbox_printk_init_info failed!\n");
+		goto fail;
+	}
+
+	register_console(&g_printk_console);
+
+	g_printk_init_ok = KBOX_TRUE;
+
+	return ret;
+fail:
+
+	kfree(g_printk_info_buf);
+	g_printk_info_buf = NULL;
+
+	kfree(g_printk_info_buf_tmp);
+	g_printk_info_buf_tmp = NULL;
+
+	return ret;
+}
+
+void kbox_printk_exit(void)
+{
+	int ret = 0;
+
+	if (g_printk_init_ok != KBOX_TRUE)
+		return;
+
+	kfree(g_printk_info_buf);
+	g_printk_info_buf = NULL;
+
+	kfree(g_printk_info_buf_tmp);
+	g_printk_info_buf_tmp = NULL;
+
+	ret = unregister_console(&g_printk_console);
+	if (ret)
+		KBOX_MSG("unregister_console failed!\n");
+}
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_printk.h b/drivers/net/ethernet/huawei/ibma/kbox_printk.h
new file mode 100644
index 0000000..e88afb1
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_printk.h
@@ -0,0 +1,35 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#ifndef _KBOX_PRINTK_H_
+#define _KBOX_PRINTK_H_
+#include "kbox_ram_image.h"
+
+struct printk_ctrl_block_tmp_s {
+	int            printk_region;
+	enum kbox_section_e  section;
+	unsigned int   start;
+	unsigned int   end;
+	unsigned int   valid_len;/* valid length of printk section */
+};
+
+int  kbox_printk_init(int kbox_proc_exist);
+void kbox_ouput_printk_info(void);
+int  kbox_dump_printk_info(const char *fmt, ...);
+void kbox_printk_exit(void);
+
+#endif
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_ram_drive.c b/drivers/net/ethernet/huawei/ibma/kbox_ram_drive.c
new file mode 100644
index 0000000..1d0e4a5
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_ram_drive.c
@@ -0,0 +1,212 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/fs.h>		/* everything... */
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <asm/ioctls.h>
+#include <linux/slab.h>
+#include "kbox_include.h"
+#include "kbox_ram_drive.h"
+#include "kbox_main.h"
+#include "kbox_ram_image.h"
+#include "kbox_ram_op.h"
+
+#define KBOX_DEVICE_NAME "kbox"
+#define KBOX_DEVICE_MINOR 255
+
+static struct kbox_dev_s *g_kbox_dev;
+/*lint -e145*/
+static ssize_t kbox_read(struct file *filp, char __user *data, size_t count,
+			 loff_t *ppos);
+static ssize_t kbox_write(struct file *filp, const char __user *data,
+			  size_t count, loff_t *ppos);
+/*lint +e145*/
+
+#if (KERNEL_VERSION(3, 0, 0) < LINUX_VERSION_CODE)
+static long kbox_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+#else
+static int kbox_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		      unsigned long arg);
+#endif
+static int kbox_mmap(struct file *filp, struct vm_area_struct *vma);
+static int kbox_open(struct inode *inode, struct file *filp);
+static int kbox_release(struct inode *inode, struct file *filp);
+
+const struct file_operations kbox_fops = {
+	.owner = THIS_MODULE,
+	.read = kbox_read,
+	.write = kbox_write,
+#if (KERNEL_VERSION(3, 0, 0) < LINUX_VERSION_CODE)
+	.unlocked_ioctl = kbox_ioctl,
+#else
+	.ioctl = kbox_ioctl,
+#endif
+	.mmap = kbox_mmap,
+	.open = kbox_open,
+	.release = kbox_release,
+};
+
+static struct miscdevice kbox_device = {
+	KBOX_DEVICE_MINOR,
+	KBOX_DEVICE_NAME,
+	&kbox_fops,
+};
+
+static ssize_t kbox_read(struct file *filp, char __user *data, size_t count,
+			 loff_t *ppos)
+{
+	int read_len = 0;
+
+	if ((!filp) || (!data) || (!ppos)) {
+		KBOX_MSG("input NULL point!\n");
+		return -EFAULT;
+	}
+
+	read_len = kbox_read_op((unsigned long)(*ppos),
+				count,
+				data,
+				KBOX_SECTION_USER);
+	if (read_len < 0)
+		return -EFAULT;
+
+	*ppos += read_len;	/*lint !e56 !e110 */
+
+	return read_len;
+}
+
+static ssize_t kbox_write(struct file *filp, const char __user *data,
+			  size_t count, loff_t *ppos)
+{
+	int write_len = 0;
+
+	if ((!filp) || (!data) || (!ppos)) {
+		KBOX_MSG("input NULL point!\n");
+		return -EFAULT;
+	}
+
+	write_len = kbox_write_op((unsigned long)(*ppos),
+				count,
+				data,
+				KBOX_SECTION_USER);
+	if (write_len < 0)
+		return -EFAULT;
+
+	*ppos += write_len;
+
+	return write_len;
+}
+
+#if (KERNEL_VERSION(3, 0, 0) < LINUX_VERSION_CODE)
+static long kbox_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+#else
+static int kbox_ioctl(struct inode *pinode, struct file *filp, unsigned int cmd,
+		      unsigned long arg)
+#endif
+{
+	UNUSED(filp);
+
+	if (kbox_ioctl_detail(cmd, arg) < 0)
+		return -ENOTTY;
+
+	return 0;
+}
+
+static int kbox_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+
+	if ((!filp) || (!vma)) {
+		KBOX_MSG("input NULL point!\n");
+		return -EFAULT;
+	}
+
+	if (kbox_mmap_ram(filp, vma, KBOX_SECTION_USER) < 0)
+		return -EFAULT;
+
+	return 0;
+}
+
+static int kbox_open(struct inode *pinode, struct file *filp)
+{
+	UNUSED(pinode);
+
+	if ((g_kbox_dev) && (!atomic_dec_and_test(&g_kbox_dev->au_count))) {
+		atomic_inc(&g_kbox_dev->au_count);
+		KBOX_MSG("EBUSY\n");
+		return -EBUSY;
+	}
+
+	filp->private_data = (void *)g_kbox_dev;
+
+	return 0;
+}
+
+int kbox_release(struct inode *pinode, struct file *filp)
+{
+	struct kbox_dev_s *kbox_dev = (struct kbox_dev_s *)filp->private_data;
+
+	UNUSED(pinode);
+
+	KBOX_MSG("\n");
+
+	if (kbox_dev)
+		atomic_inc(&kbox_dev->au_count);
+
+	return 0;
+}
+
+int kbox_drive_init(void)
+{
+	int ret = 0;
+
+	KBOX_MSG("\n");
+
+	g_kbox_dev =
+	    kmalloc(sizeof(struct kbox_dev_s), GFP_KERNEL); /*lint !e64*/
+	if (!g_kbox_dev)
+		return -ENOMEM;
+
+	ret = misc_register(&kbox_device);
+	if (ret)
+		goto fail;
+
+	atomic_set(&g_kbox_dev->au_count, 1);
+
+	KBOX_MSG("ok!\n");
+
+	return ret;
+
+fail:
+	kfree(g_kbox_dev);
+	g_kbox_dev = NULL;
+
+	return ret;
+}
+
+void kbox_drive_cleanup(void)
+{
+	if (!g_kbox_dev)
+		return;
+
+#if (KERNEL_VERSION(4, 4, 0) < LINUX_VERSION_CODE)
+	misc_deregister(&kbox_device);
+#else
+	(void)misc_deregister(&kbox_device);
+#endif
+
+	kfree(g_kbox_dev);
+	g_kbox_dev = NULL;
+
+}
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_ram_drive.h b/drivers/net/ethernet/huawei/ibma/kbox_ram_drive.h
new file mode 100644
index 0000000..3231cbc
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_ram_drive.h
@@ -0,0 +1,33 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#ifndef _KBOX_RAM_DRIVE_H_
+#define _KBOX_RAM_DRIVE_H_
+
+#include <linux/types.h>
+#include <linux/atomic.h>
+
+struct kbox_dev_s {
+	atomic_t au_count;
+
+	struct kbox_pci_dev_s *kbox_pci_dev;
+};
+
+int kbox_drive_init(void);
+void kbox_drive_cleanup(void);
+
+#endif
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_ram_image.c b/drivers/net/ethernet/huawei/ibma/kbox_ram_image.c
new file mode 100644
index 0000000..0b9ac6f
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_ram_image.c
@@ -0,0 +1,138 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "kbox_include.h"
+#include "kbox_main.h"
+#include "kbox_ram_image.h"
+
+/*lint -e124*/
+void __iomem *kbox_get_section_addr(enum kbox_section_e  kbox_section)
+{
+	void __iomem *kbox_addr = kbox_get_base_addr();
+	unsigned long kbox_len = kbox_get_io_len();
+
+	if ((!kbox_addr) || (kbox_len == 0)) {
+		KBOX_MSG("get kbox_addr or kbox_len failed!\n");
+		return NULL;
+	}
+
+	switch (kbox_section) {
+	case KBOX_SECTION_KERNEL:
+		return kbox_addr;
+
+	case KBOX_SECTION_PANIC:
+		return kbox_addr + SECTION_KERNEL_LEN;
+
+	case KBOX_SECTION_THREAD:
+		return kbox_addr + SECTION_KERNEL_LEN + SECTION_PANIC_LEN;
+
+	case KBOX_SECTION_PRINTK1:
+		return kbox_addr + (kbox_len - (2 * SECTION_PRINTK_LEN) -
+				    SECTION_USER_LEN);
+
+	case KBOX_SECTION_PRINTK2:
+		return kbox_addr + (kbox_len - SECTION_PRINTK_LEN -
+				    SECTION_USER_LEN);
+
+	case KBOX_SECTION_USER:
+		return kbox_addr + (kbox_len - SECTION_USER_LEN);
+
+	case KBOX_SECTION_ALL:
+		return kbox_addr;
+
+	default:
+		KBOX_MSG("input kbox_section error!\n");
+		return NULL;
+	}
+}
+/*lint -e124*/
+
+unsigned long kbox_get_section_len(enum kbox_section_e  kbox_section)
+{
+	unsigned long kbox_len = kbox_get_io_len();
+
+	if (kbox_len == 0) {
+		KBOX_MSG("get kbox_len failed!\n");
+		return 0;
+	}
+
+	switch (kbox_section) {
+	case KBOX_SECTION_KERNEL:
+		return SECTION_KERNEL_LEN;
+
+	case KBOX_SECTION_PANIC:
+		return SECTION_PANIC_LEN;
+
+	case KBOX_SECTION_THREAD:
+		return (kbox_len - (2 * SECTION_PRINTK_LEN) -
+			SECTION_USER_LEN - SECTION_KERNEL_LEN -
+			SECTION_PANIC_LEN);
+
+	case KBOX_SECTION_PRINTK1:
+	case KBOX_SECTION_PRINTK2:
+		return SECTION_PRINTK_LEN;
+
+	case KBOX_SECTION_USER:
+		return SECTION_USER_LEN;
+
+	case KBOX_SECTION_ALL:
+		return kbox_len - SECTION_KERNEL_LEN;
+
+	default:
+		KBOX_MSG("input kbox_section error!\n");
+		return 0;
+	}
+}
+
+unsigned long kbox_get_section_phy_addr(enum kbox_section_e  kbox_section)
+{
+	unsigned long kbox_phy_addr = kbox_get_base_phy_addr();
+	unsigned long kbox_len = kbox_get_io_len();
+
+	if ((kbox_phy_addr == 0) || (kbox_len == 0)) {
+		KBOX_MSG("get kbox_phy_addr or kbox_len failed!\n");
+		return 0;
+	}
+
+	switch (kbox_section) {
+	case KBOX_SECTION_KERNEL:
+		return kbox_phy_addr;
+
+	case KBOX_SECTION_PANIC:
+		return kbox_phy_addr + SECTION_KERNEL_LEN;
+
+	case KBOX_SECTION_THREAD:
+		return kbox_phy_addr + SECTION_KERNEL_LEN + SECTION_PANIC_LEN;
+
+	case KBOX_SECTION_PRINTK1:
+		return kbox_phy_addr + (kbox_len - (2 * SECTION_PRINTK_LEN) -
+					SECTION_USER_LEN);
+
+	case KBOX_SECTION_PRINTK2:
+		return kbox_phy_addr + (kbox_len - SECTION_PRINTK_LEN -
+					SECTION_USER_LEN);
+
+	case KBOX_SECTION_USER:
+		return kbox_phy_addr + (kbox_len - SECTION_USER_LEN);
+
+	case KBOX_SECTION_ALL:
+		return kbox_phy_addr;
+
+	default:
+		KBOX_MSG("input kbox_section error!\n");
+		return 0;
+	}
+}
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_ram_image.h b/drivers/net/ethernet/huawei/ibma/kbox_ram_image.h
new file mode 100644
index 0000000..4d7513a
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_ram_image.h
@@ -0,0 +1,91 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _KBOX_RAM_IMAGE_H_
+#define _KBOX_RAM_IMAGE_H_
+
+enum kbox_section_e {
+	KBOX_SECTION_KERNEL = 1,
+	KBOX_SECTION_PANIC = 2,
+	KBOX_SECTION_THREAD = 3,
+	KBOX_SECTION_PRINTK1 = 4,
+	KBOX_SECTION_PRINTK2 = 5,
+	KBOX_SECTION_USER = 6,
+	KBOX_SECTION_ALL = 7
+};
+
+#define KBOX_BIG_ENDIAN (0x2B)
+#define KBOX_LITTLE_ENDIAN (0xB2)
+#define IMAGE_VER (0x0001)
+#define IMAGE_MAGIC (0xB202C086)
+#define VALID_IMAGE(x) (IMAGE_MAGIC == (x)->magic_flag)
+#define SLOT_NUM (8)
+#define SLOT_LENGTH (16 * 1024)
+#define MAX_RECORD_NO (0xFF)
+#define MAX_USE_NUMS (0xFF)
+
+#define PRINTK_NUM (2)
+#define PRINTK_CURR_FLAG ("curr")
+#define PRINTK_LAST_FLAG ("last")
+#define PRINTK_FLAG_LEN (4)
+
+struct panic_ctrl_block_s {
+	unsigned char use_nums;
+	unsigned char number;
+	unsigned short len;
+	unsigned int time;
+};
+
+struct thread_info_ctrl_block_s {
+	unsigned int thread_info_len;
+};
+
+struct printk_info_ctrl_block_s {
+	unsigned char flag[PRINTK_FLAG_LEN];
+	unsigned int len;
+};
+
+struct image_super_block_s {
+	unsigned char byte_order;
+	unsigned char checksum;
+	unsigned short version;
+	unsigned int magic_flag;
+	unsigned int panic_nums;
+	struct panic_ctrl_block_s panic_ctrl_blk[SLOT_NUM];
+	struct printk_info_ctrl_block_s printk_ctrl_blk[PRINTK_NUM];
+	struct thread_info_ctrl_block_s thread_ctrl_blk;
+};
+
+#define SECTION_KERNEL_LEN (sizeof(struct image_super_block_s))
+#define SECTION_PANIC_LEN (8 * SLOT_LENGTH)
+
+#if (KERNEL_VERSION(2, 6, 18) >= LINUX_VERSION_CODE)
+#define SECTION_PRINTK_LEN (128 * 1024)
+#else
+#define SECTION_PRINTK_LEN (512 * 1024)
+#endif
+
+#define SECTION_USER_LEN (2 * 1024 * 1024)
+
+#define SECTION_KERNEL_OFFSET (0)
+#define SECTION_PANIC_OFFSET SECTION_KERNEL_LEN
+#define SECTION_THREAD_OFFSET (SECTION_KERNEL_LEN + SECTION_PANIC_LEN)
+
+void __iomem *kbox_get_section_addr(enum kbox_section_e  kbox_section);
+unsigned long kbox_get_section_len(enum kbox_section_e  kbox_section);
+unsigned long kbox_get_section_phy_addr(enum kbox_section_e  kbox_section);
+
+#endif
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_ram_op.c b/drivers/net/ethernet/huawei/ibma/kbox_ram_op.c
new file mode 100644
index 0000000..ed329a4
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_ram_op.c
@@ -0,0 +1,1003 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#if (KERNEL_VERSION(2, 6, 18) >= LINUX_VERSION_CODE)
+#include <asm/semaphore.h>
+#else
+#include <linux/semaphore.h>
+#endif
+#include <linux/slab.h>
+#include <linux/capability.h>
+#include <linux/uaccess.h>		/* copy_*_user */
+#include <linux/delay.h>		/* udelay */
+#include <linux/mm.h>
+#include "kbox_include.h"
+#include "kbox_main.h"
+#include "kbox_ram_image.h"
+#include "kbox_ram_op.h"
+
+#ifndef VM_RESERVED
+#define VM_RESERVED 0x00080000
+#endif
+
+#if (KERNEL_VERSION(3, 0, 0) < LINUX_VERSION_CODE)
+
+static DEFINE_SPINLOCK(g_kbox_super_block_lock);
+static DEFINE_SEMAPHORE(user_sem);
+#else
+static spinlock_t g_kbox_super_block_lock = SPIN_LOCK_UNLOCKED;
+static DECLARE_MUTEX(user_sem);
+#endif
+
+union char_int_transfer_u {
+	int data_int;
+	char data_char[KBOX_RW_UNIT];
+};
+
+static struct image_super_block_s g_kbox_super_block = { };
+
+void kbox_write_to_pci(void __iomem *dest, const void *src, int len,
+		       unsigned long offset)
+{
+	union char_int_transfer_u transfer = { };
+	int idx = 0;
+	int j = 0;
+	int four_byte_len = 0;
+	int left_len = 0;
+	char *src_temp = (char *)src;
+	char *dest_temp = (char *)dest;
+	int first_write_num = 0;
+
+	if ((offset % KBOX_RW_UNIT) != 0) {
+		transfer.data_int =
+		    *(int *)(dest_temp + offset - (offset % KBOX_RW_UNIT));
+		/*lint -e123*/
+		rmb();/* memory barriers. */
+		first_write_num =
+		    ((len + (offset % KBOX_RW_UNIT)) >
+		     KBOX_RW_UNIT) ? (KBOX_RW_UNIT -
+				      (offset % KBOX_RW_UNIT)) : len;
+		for (idx = (int)(offset % KBOX_RW_UNIT);
+		     idx < (int)(first_write_num + (offset % KBOX_RW_UNIT));
+		     idx++) {
+			if (!src_temp)
+				return;
+
+			transfer.data_char[idx] = *src_temp;
+			src_temp++;
+		}
+		*(int *)(dest_temp + offset - (offset % KBOX_RW_UNIT)) =
+		    transfer.data_int;
+		wmb();/* memory barriers. */
+		len -= first_write_num;
+		offset += first_write_num;
+	}
+
+	four_byte_len = (len / KBOX_RW_UNIT);
+	left_len = (len % KBOX_RW_UNIT);
+	for (idx = 0; idx < four_byte_len; idx++) {
+		for (j = 0; j < KBOX_RW_UNIT; j++) {
+			if (!src_temp)
+				return;
+
+			transfer.data_char[j] = *src_temp;
+			src_temp++;
+		}
+		*(int *)(dest_temp + offset) = transfer.data_int;
+		wmb();/* memory barriers. */
+		offset += KBOX_RW_UNIT;
+	}
+
+	if (left_len != 0) {
+		transfer.data_int = *(int *)(dest_temp + offset);
+		rmb();/* memory barriers. */
+		for (idx = 0; idx < left_len; idx++) {
+			if (!src_temp)
+				return;
+
+			transfer.data_char[idx] = *src_temp;
+			src_temp++;
+		}
+		*(int *)(dest_temp + offset) = transfer.data_int;
+		wmb();/* memory barriers. */
+		/*lint -e123*/
+	}
+
+	udelay(1);
+
+}
+
+void kbox_read_from_pci(void *dest, void __iomem *src, int len,
+			unsigned long offset)
+{
+	union char_int_transfer_u transfer = { };
+	int idx = 0;
+	int j = 0;
+	int four_byte_len = 0;
+	int left_len = 0;
+	char *dest_temp = (char *)dest;
+	char *src_temp = (char *)src;
+	int first_read_num = 0;
+
+	if ((offset % KBOX_RW_UNIT) != 0) {
+		transfer.data_int =
+		    *(int *)(src_temp + offset - (offset % KBOX_RW_UNIT));
+		first_read_num =
+		    ((len + (offset % KBOX_RW_UNIT)) >
+		     KBOX_RW_UNIT) ? (KBOX_RW_UNIT -
+				      (offset % KBOX_RW_UNIT)) : len;
+		rmb();/* memory barriers. */
+		for (idx = (int)(offset % KBOX_RW_UNIT);
+		     idx < (int)(first_read_num + (offset % KBOX_RW_UNIT));
+		     idx++) {
+			if (!dest_temp)
+				return;
+
+			*dest_temp = transfer.data_char[idx];
+			dest_temp++;
+		}
+		len -= first_read_num;
+		offset += first_read_num;
+	}
+
+	four_byte_len = (len / KBOX_RW_UNIT);
+	left_len = (len % KBOX_RW_UNIT);
+	for (idx = 0; idx < four_byte_len; idx++) {
+		transfer.data_int = *(int *)(src_temp + offset);
+		rmb();/* memory barriers. */
+		for (j = 0; j < KBOX_RW_UNIT; j++) {
+			if (!dest_temp)
+				return;
+
+			*dest_temp = transfer.data_char[j];
+			dest_temp++;
+		}
+		offset += KBOX_RW_UNIT;
+	}
+
+	if (left_len != 0) {
+		transfer.data_int = *(int *)(src_temp + offset);
+		rmb();/* memory barriers. */
+		for (idx = 0; idx < left_len; idx++) {
+			if (!dest_temp)
+				return;
+
+			*dest_temp = transfer.data_char[idx];
+			dest_temp++;
+		}
+	}
+
+}
+
+void kbox_memset_pci(void __iomem *dest, const char set_byte, int len,
+		     unsigned long offset)
+{
+	union char_int_transfer_u transfer = { };
+	int idx = 0;
+	int four_byte_len = 0;
+	int left_len = 0;
+	char *dest_temp = (char *)dest;
+	int first_memset_num = 0;
+
+	if ((offset % KBOX_RW_UNIT) != 0) {
+		transfer.data_int =
+		    *(int *)(dest_temp + offset - (offset % KBOX_RW_UNIT));
+		/*lint -e123 */
+		rmb();/* memory barriers. */
+		first_memset_num =
+		    ((len + (offset % KBOX_RW_UNIT)) >
+		     KBOX_RW_UNIT) ? (KBOX_RW_UNIT -
+				      (offset % KBOX_RW_UNIT)) : len;
+		for (idx = (int)(offset % KBOX_RW_UNIT);
+		     idx < (int)(first_memset_num + (offset % KBOX_RW_UNIT));
+		     idx++) {
+			transfer.data_char[idx] = set_byte;
+		}
+		*(int *)(dest_temp + offset - (offset % KBOX_RW_UNIT)) =
+		    transfer.data_int;
+		wmb();/* memory barriers. */
+		len -= first_memset_num;
+		offset += first_memset_num;
+	}
+
+	four_byte_len = (len / KBOX_RW_UNIT);
+	left_len = (len % KBOX_RW_UNIT);
+	for (idx = 0; idx < KBOX_RW_UNIT; idx++)
+		transfer.data_char[idx] = set_byte;
+
+	for (idx = 0; idx < four_byte_len; idx++) {
+		*(int *)(dest_temp + offset) = transfer.data_int;
+		wmb();/* memory barriers. */
+		offset += KBOX_RW_UNIT;
+	}
+
+	if (left_len != 0) {
+		transfer.data_int = *(int *)(dest_temp + offset);
+		rmb();/* memory barriers. */
+		for (idx = 0; idx < left_len; idx++)
+			transfer.data_char[idx] = set_byte;
+
+		*(int *)(dest_temp + offset) = transfer.data_int;
+		wmb();/* memory barriers. */
+	}
+
+	udelay(1);
+
+}
+
+int kbox_read_from_ram(unsigned long offset, unsigned int count, char *data,
+		       enum kbox_section_e  section)
+{
+	unsigned int read_len_total = count;
+	unsigned long offset_temp = offset;
+	void __iomem *kbox_section_addr = kbox_get_section_addr(section);
+	unsigned long kbox_section_len = kbox_get_section_len(section);
+	unsigned int read_len_real = 0;
+
+	if (!data) {
+		KBOX_MSG("input NULL point!\n");
+		return -EFAULT;
+	}
+
+	if ((!kbox_section_addr) || (kbox_section_len == 0)) {
+		KBOX_MSG("get kbox_section_addr or kbox_section_len failed!\n");
+		return -EFAULT;
+	}
+
+	if (offset >= kbox_section_len) {
+		KBOX_MSG("input offset is error!\n");
+		return -EFAULT;
+	}
+
+	if ((offset + count) > kbox_section_len)
+		read_len_total = (unsigned int)(kbox_section_len - offset);
+
+	while (1) {
+		unsigned int read_bytes = 0;
+
+		if (read_len_real >= count)
+			break;
+
+		read_bytes =
+		    (read_len_total >
+		     TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : read_len_total;
+
+		kbox_read_from_pci(data, kbox_section_addr, read_bytes,
+				   offset_temp);
+
+		read_len_total -= read_bytes;
+		read_len_real += read_bytes;
+		data += read_bytes;
+		offset_temp += read_bytes;
+	}
+
+	return (int)read_len_real;
+}
+
+int kbox_write_to_ram(unsigned long offset, unsigned int count,
+		      const char *data, enum kbox_section_e  section)
+{
+	unsigned int write_len_total = count;
+	unsigned long offset_temp = offset;
+	void __iomem *kbox_section_addr = kbox_get_section_addr(section);
+	unsigned long kbox_section_len = kbox_get_section_len(section);
+	unsigned int write_len_real = 0;
+
+	if (!data) {
+		KBOX_MSG("input NULL point!\n");
+		return -EFAULT;
+	}
+
+	if ((!kbox_section_addr) || (kbox_section_len == 0)) {
+		KBOX_MSG("get kbox_section_addr or kbox_section_len failed!\n");
+		return -EFAULT;
+	}
+
+	if (offset >= kbox_section_len) {
+		KBOX_MSG("input offset is error!\n");
+		return -EFAULT;
+	}
+
+	if ((offset + count) > kbox_section_len)
+		write_len_total = (unsigned int)(kbox_section_len - offset);
+
+	KBOX_MSG("struct image_super_block_s = %x\n", count);
+	while (1) {
+		unsigned int write_bytes = 0;
+
+		if (write_len_real >= count) {
+			KBOX_MSG("write_len_real = %x\n", write_len_real);
+			break;
+		}
+		KBOX_MSG("write_len_total = %x\n", write_len_total);
+
+		write_bytes =
+		    (write_len_total >
+		     TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : write_len_total;
+		KBOX_MSG("write_bytes = %x\n", write_bytes);
+
+		kbox_write_to_pci(kbox_section_addr, data, write_bytes,
+				  offset_temp);
+
+		write_len_total -= write_bytes;
+		write_len_real += write_bytes;
+		data += write_bytes;
+		offset_temp += write_bytes;
+	}
+
+	return (int)write_len_real;
+}
+
+int kbox_memset_ram(unsigned long offset, unsigned int count,
+		    const char set_byte, enum kbox_section_e  section)
+{
+	unsigned int memset_len = count;
+	void __iomem *kbox_section_addr = kbox_get_section_addr(section);
+	unsigned long kbox_section_len = kbox_get_section_len(section);
+
+	if ((!kbox_section_addr) || (kbox_section_len == 0)) {
+		KBOX_MSG("get kbox_section_addr or kbox_section_len failed!\n");
+		return -EFAULT;
+	}
+
+	if (offset >= kbox_section_len) {
+		KBOX_MSG("input offset is error!\n");
+		return -EFAULT;
+	}
+
+	if ((offset + count) > kbox_section_len)
+		memset_len = (unsigned int)(kbox_section_len - offset);
+
+	kbox_memset_pci(kbox_section_addr, set_byte, memset_len, offset);
+
+	return KBOX_TRUE;
+}
+
+int kbox_read_op(unsigned long offset, unsigned int count, char __user *data,
+		 enum kbox_section_e  section)
+{
+	unsigned int read_len = 0;
+	unsigned int left_len = count;
+	char *user_buf = data;
+	char *temp_buf_char = NULL;
+	unsigned long offset_tmp = offset;
+
+	if (!data) {
+		KBOX_MSG("input NULL point!\n");
+		return -EFAULT;
+	}
+
+	if (down_interruptible(&user_sem) != 0)
+		return KBOX_FALSE;
+
+	temp_buf_char = kmalloc(TEMP_BUF_DATA_SIZE, GFP_KERNEL); /*lint !e64*/
+	if (IS_ERR(temp_buf_char)) {
+		KBOX_MSG("kmalloc temp_buf_char fail!\n");
+		up(&user_sem);
+		return -ENOMEM;
+	}
+	memset((void *)temp_buf_char, 0, TEMP_BUF_DATA_SIZE);
+
+	while (1) {
+		unsigned int read_bytes = 0;
+
+		if (read_len >= count)
+			break;
+
+		read_bytes =
+		    (left_len >
+		     TEMP_BUF_DATA_SIZE) ? TEMP_BUF_DATA_SIZE : left_len;
+
+		if (kbox_read_from_ram
+		    (offset_tmp, read_bytes, temp_buf_char, section) < 0) {
+			KBOX_MSG("kbox_read_from_ram fail!\n");
+			break;
+		}
+
+		if (copy_to_user(user_buf, temp_buf_char, read_bytes)) {
+			KBOX_MSG("copy_to_user fail!\n");
+			break;
+		}
+
+		left_len -= read_bytes;
+		read_len += read_bytes;
+		user_buf += read_bytes;
+
+		offset_tmp += read_bytes;
+		memset((void *)temp_buf_char, 0, TEMP_BUF_DATA_SIZE);
+
+		msleep(20);
+	}
+
+	kfree(temp_buf_char);
+
+	up(&user_sem);
+
+	return (int)read_len;
+}
+
+int kbox_write_op(unsigned long offset, unsigned int count,
+		  const char __user *data, enum kbox_section_e  section)
+{
+	unsigned int write_len = 0;
+	unsigned int left_len = count;
+	const char *user_buf = data;
+	char *temp_buf_char = NULL;
+	unsigned long offset_tmp = offset;
+
+	if (!data) {
+		KBOX_MSG("input NULL point!\n");
+		return -EFAULT;
+	}
+
+	if (down_interruptible(&user_sem) != 0)
+		return KBOX_FALSE;
+
+	temp_buf_char = kmalloc(TEMP_BUF_DATA_SIZE, GFP_KERNEL); /*lint !e64*/
+	if (!temp_buf_char || IS_ERR(temp_buf_char)) {
+		KBOX_MSG("kmalloc temp_buf_char fail!\n");
+		up(&user_sem);
+		return -ENOMEM;
+	}
+
+	memset((void *)temp_buf_char, 0, TEMP_BUF_DATA_SIZE);
+
+	while (1) {
+		unsigned int write_bytes = 0;
+
+		if (write_len >= count)
+			break;
+
+		write_bytes =
+		    (left_len >
+		     TEMP_BUF_DATA_SIZE) ? TEMP_BUF_DATA_SIZE : left_len;
+
+		if (copy_from_user(temp_buf_char, user_buf, write_bytes)) {
+			KBOX_MSG("copy_from_user fail!\n");
+			break;
+		}
+
+		if (kbox_write_to_ram
+		    (offset_tmp, write_bytes, temp_buf_char, section) < 0) {
+			KBOX_MSG("kbox_write_to_ram fail!\n");
+			break;
+		}
+
+		left_len -= write_bytes;
+		write_len += write_bytes;
+		user_buf += write_bytes;
+
+		offset_tmp += write_bytes;
+		memset((void *)temp_buf_char, 0, TEMP_BUF_DATA_SIZE);
+
+		msleep(20);
+	}
+
+	kfree(temp_buf_char);
+
+	up(&user_sem);
+
+	return (int)write_len;
+}
+
+char Kbox_checksum(char *input_buf, unsigned int len)
+{
+	unsigned int idx = 0;
+	char checksum = 0;
+
+	for (idx = 0; idx < len; idx++)
+		checksum += input_buf[idx];
+
+	return checksum;
+}
+
+static int Kbox_update_super_block(void)
+{
+	int write_len = 0;
+
+	g_kbox_super_block.checksum = 0;
+	g_kbox_super_block.checksum =
+	    ~((unsigned char)
+	      Kbox_checksum((char *)&g_kbox_super_block,
+			(unsigned int)sizeof(struct image_super_block_s))) + 1;
+	write_len =
+	    kbox_write_to_ram(SECTION_KERNEL_OFFSET,
+			      (unsigned int)sizeof(struct image_super_block_s),
+			      (char *)&g_kbox_super_block, KBOX_SECTION_KERNEL);
+	if (write_len <= 0) {
+		KBOX_MSG("fail to write superblock data!\n");
+		return KBOX_FALSE;
+	}
+
+	return KBOX_TRUE;
+}
+
+int Kbox_read_super_block(void)
+{
+	int read_len = 0;
+
+	read_len =
+	    kbox_read_from_ram(SECTION_KERNEL_OFFSET,
+			       (unsigned int)sizeof(struct image_super_block_s),
+			       (char *)&g_kbox_super_block,
+			       KBOX_SECTION_KERNEL);
+	if (read_len != sizeof(struct image_super_block_s)) {
+		KBOX_MSG("fail to get superblock data!\n");
+		return KBOX_FALSE;
+	}
+
+	return KBOX_TRUE;
+}
+
+static unsigned char Kbox_get_byte_order(void)
+{
+	unsigned short data_short = 0xB22B;
+	unsigned char *data_char = (unsigned char *)&data_short;
+
+	return (unsigned char)((*data_char == 0xB2) ? KBOX_BIG_ENDIAN :
+			       KBOX_LITTLE_ENDIAN);
+}
+
+int kbox_super_block_init(void)
+{
+	int ret = 0;
+
+	ret = Kbox_read_super_block();
+	if (ret != KBOX_TRUE) {
+		KBOX_MSG("Kbox_read_super_block fail!\n");
+		return ret;
+	}
+
+	if (!VALID_IMAGE(&g_kbox_super_block)
+	    || 0 != Kbox_checksum((char *)&g_kbox_super_block,
+			(unsigned int)sizeof(struct image_super_block_s))) {
+		if (!VALID_IMAGE(&g_kbox_super_block)) {
+			memset((void *)&g_kbox_super_block, 0x00,
+			       sizeof(struct image_super_block_s));
+		}
+
+		g_kbox_super_block.byte_order = Kbox_get_byte_order();
+		g_kbox_super_block.version = IMAGE_VER;
+		g_kbox_super_block.magic_flag = IMAGE_MAGIC;
+	}
+
+	g_kbox_super_block.thread_ctrl_blk.thread_info_len = 0;
+
+	if (Kbox_update_super_block() != KBOX_TRUE) {
+		KBOX_MSG("Kbox_update_super_block failed!\n");
+		return KBOX_FALSE;
+	}
+
+	return KBOX_TRUE;
+}
+
+static unsigned char kbox_get_write_slot_num(void)
+{
+	struct panic_ctrl_block_s *panic_ctrl_block = NULL;
+	unsigned int idx = 0;
+	unsigned char slot_num = 0;
+	unsigned char min_use_nums = 0;
+
+	panic_ctrl_block = g_kbox_super_block.panic_ctrl_blk;
+	min_use_nums = panic_ctrl_block->use_nums;
+
+	for (idx = 1; idx < SLOT_NUM; idx++) {
+		panic_ctrl_block++;
+		if (panic_ctrl_block->use_nums < min_use_nums) {
+			min_use_nums = panic_ctrl_block->use_nums;
+			slot_num = (unsigned char)idx;
+		}
+	}
+
+	if (min_use_nums == MAX_USE_NUMS) {
+		panic_ctrl_block = g_kbox_super_block.panic_ctrl_blk;
+		for (idx = 0; idx < SLOT_NUM; idx++) {
+			panic_ctrl_block->use_nums = 1;
+			panic_ctrl_block++;
+		}
+	}
+
+	return slot_num;
+}
+
+static unsigned char kbox_get_new_record_number(void)
+{
+	struct panic_ctrl_block_s *panic_ctrl_block = NULL;
+	unsigned int idx = 0;
+	unsigned char max_number = 0;
+
+	panic_ctrl_block = g_kbox_super_block.panic_ctrl_blk;
+	for (idx = 0; idx < SLOT_NUM; idx++) {
+		if (panic_ctrl_block->number >= max_number)
+			max_number = panic_ctrl_block->number;
+
+		panic_ctrl_block++;
+	}
+
+	return (unsigned char)((max_number + 1) % MAX_RECORD_NO);
+}
+
+int kbox_write_panic_info(const char *input_data, unsigned int data_len)
+{
+	int write_len = 0;
+	unsigned int offset = 0;
+	struct panic_ctrl_block_s *panic_ctrl_block = NULL;
+	unsigned long time = get_seconds();
+	unsigned char slot_num = 0;
+	unsigned long flags = 0;
+
+	if ((!input_data) || (data_len == 0)) {
+		KBOX_MSG("input parameter error!\n");
+		return KBOX_FALSE;
+	}
+
+	if (data_len > SLOT_LENGTH)
+		data_len = SLOT_LENGTH;
+
+	spin_lock_irqsave(&g_kbox_super_block_lock, flags);
+
+	slot_num = kbox_get_write_slot_num();
+
+	panic_ctrl_block = &g_kbox_super_block.panic_ctrl_blk[slot_num];
+	panic_ctrl_block->use_nums++;
+
+	panic_ctrl_block->number = kbox_get_new_record_number();
+	panic_ctrl_block->len = 0;
+	panic_ctrl_block->time = (unsigned int)time;
+
+	g_kbox_super_block.panic_nums++;
+
+	spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+
+	offset = slot_num * SLOT_LENGTH;
+	write_len =
+	    kbox_write_to_ram(offset, data_len, input_data, KBOX_SECTION_PANIC);
+	if (write_len <= 0) {
+		KBOX_MSG("fail to save panic information!\n");
+		return KBOX_FALSE;
+	}
+
+	spin_lock_irqsave(&g_kbox_super_block_lock, flags);
+
+	panic_ctrl_block->len += (unsigned short)write_len;
+
+	if (Kbox_update_super_block() != KBOX_TRUE) {
+		KBOX_MSG("Kbox_update_super_block failed!\n");
+		spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+		return KBOX_FALSE;
+	}
+
+	spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+
+	return KBOX_TRUE;
+}
+
+int kbox_write_thread_info(const char *input_data, unsigned int data_len)
+{
+	int write_len = 0;
+	unsigned int offset = 0;
+	unsigned long flags = 0;
+	unsigned int date_len_tmp = data_len;
+
+	if ((!input_data) || (date_len_tmp == 0)) {
+		KBOX_MSG("input parameter error!\n");
+		return KBOX_FALSE;
+	}
+
+	spin_lock_irqsave(&g_kbox_super_block_lock, flags);
+
+	offset = g_kbox_super_block.thread_ctrl_blk.thread_info_len;
+	write_len =
+	    kbox_write_to_ram(offset, date_len_tmp, input_data,
+			      KBOX_SECTION_THREAD);
+	if (write_len <= 0) {
+		KBOX_MSG("fail to save thread information!\n");
+		spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+		return KBOX_FALSE;
+	}
+
+	g_kbox_super_block.thread_ctrl_blk.thread_info_len += write_len;
+
+	if (Kbox_update_super_block() != KBOX_TRUE) {
+		KBOX_MSG("Kbox_update_super_block failed!\n");
+		spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+		return KBOX_FALSE;
+	}
+
+	spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+
+	return KBOX_TRUE;
+}
+
+int kbox_read_printk_info(char *input_data,
+		struct printk_ctrl_block_tmp_s *printk_ctrl_block_tmp)
+{
+	int read_len = 0;
+	int printk_region = printk_ctrl_block_tmp->printk_region;
+	unsigned int len = 0;
+
+	if (!input_data) {
+		KBOX_MSG("input parameter error!\n");
+		return KBOX_FALSE;
+	}
+
+	len = g_kbox_super_block.printk_ctrl_blk[printk_region].len;
+	if (len <= 0) {
+		printk_ctrl_block_tmp->end = 0;
+		printk_ctrl_block_tmp->valid_len = 0;
+		return KBOX_TRUE;
+	}
+
+	read_len =
+	    kbox_read_from_ram(0, len, input_data,
+			       printk_ctrl_block_tmp->section);
+	if (read_len < 0) {
+		KBOX_MSG("fail to read printk information!(1)\n");
+		return KBOX_FALSE;
+	}
+
+	printk_ctrl_block_tmp->end = len;
+	printk_ctrl_block_tmp->valid_len = len;
+
+	return KBOX_TRUE;
+}
+
+int kbox_write_printk_info(const char *input_data,
+			struct printk_ctrl_block_tmp_s *printk_ctrl_block_tmp)
+{
+	int write_len = 0;
+	int printk_region = printk_ctrl_block_tmp->printk_region;
+	unsigned long flags = 0;
+	unsigned int len = 0;
+
+	if (!input_data) {
+		KBOX_MSG("input parameter error!\n");
+		return KBOX_FALSE;
+	}
+
+	len = printk_ctrl_block_tmp->valid_len;
+	write_len =
+	    kbox_write_to_ram(0, len, input_data,
+			      printk_ctrl_block_tmp->section);
+	if (write_len <= 0) {
+		KBOX_MSG("fail to save printk information!(1)\n");
+		return KBOX_FALSE;
+	}
+
+	spin_lock_irqsave(&g_kbox_super_block_lock, flags);
+
+	g_kbox_super_block.printk_ctrl_blk[printk_region].len = len;
+
+	if (Kbox_update_super_block() != KBOX_TRUE) {
+		KBOX_MSG("Kbox_update_super_block failed!\n");
+		spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+		return KBOX_FALSE;
+	}
+
+	spin_unlock_irqrestore(&g_kbox_super_block_lock, flags);
+
+	return KBOX_TRUE;
+}
+
+static int kbox_read_region(unsigned long arg)
+{
+	unsigned int read_len = 0;
+	struct kbox_region_arg_s region_arg = { };
+
+	if (copy_from_user
+	    ((void *)&region_arg, (void __user *)arg,
+	     sizeof(struct kbox_region_arg_s))) {
+		KBOX_MSG("fail to copy_from_user!\n");
+		return KBOX_FALSE;
+	}
+
+	read_len = kbox_read_op(region_arg.offset, region_arg.count,
+				(char __user *)region_arg.data,
+				KBOX_SECTION_ALL);
+	if (read_len <= 0) {
+		KBOX_MSG("fail to get kbox data!\n");
+		return KBOX_FALSE;
+	}
+
+	if (copy_to_user
+	    ((void __user *)arg, (void *)&region_arg,
+	     sizeof(struct kbox_region_arg_s))) {
+		KBOX_MSG("fail to copy_to_user!\n");
+		return KBOX_FALSE;
+	}
+
+	return KBOX_TRUE;
+}
+
+static int kbox_writer_region(unsigned long arg)
+{
+	unsigned int write_len = 0;
+	struct kbox_region_arg_s region_arg = { };
+
+	if (copy_from_user
+	    ((void *)&region_arg, (void __user *)arg,
+	     sizeof(struct kbox_region_arg_s))) {
+		KBOX_MSG("fail to copy_from_user!\n");
+		return KBOX_FALSE;
+	}
+
+	write_len = kbox_write_op(region_arg.offset, region_arg.count,
+				  (char __user *)region_arg.data,
+				  KBOX_SECTION_ALL);
+	if (write_len <= 0) {
+		KBOX_MSG("fail to write kbox data!\n");
+		return KBOX_FALSE;
+	}
+
+	if (copy_to_user
+	    ((void __user *)arg, (void *)&region_arg,
+	     sizeof(struct kbox_region_arg_s))) {
+		KBOX_MSG("fail to copy_to_user!\n");
+		return KBOX_FALSE;
+	}
+
+	return KBOX_TRUE;
+}
+
+int kbox_clear_region(enum kbox_section_e  section)
+{
+	int ret = KBOX_TRUE;
+	unsigned long kbox_section_len = kbox_get_section_len(section);
+
+	if (kbox_section_len == 0) {
+		KBOX_MSG("get kbox_section_len failed!\n");
+		return -EFAULT;
+	}
+
+	ret = kbox_memset_ram(0, (unsigned int)kbox_section_len, 0, section);
+	if (ret != KBOX_TRUE) {
+		KBOX_MSG("kbox_memset_ram failed!\n");
+		return -EFAULT;
+	}
+
+	return KBOX_TRUE;
+}
+
+static int kbox_get_image_len(unsigned long arg)
+{
+	unsigned long __user *ptr = (unsigned long __user *)arg;
+	unsigned long kbox_len = 0;
+
+	kbox_len = kbox_get_section_len(KBOX_SECTION_ALL);
+	if (kbox_len == 0) {
+		KBOX_MSG("kbox_get_section_len section all fail!\n");
+		return -EFAULT;
+	}
+
+	return put_user(kbox_len, ptr);
+}
+
+static int kbox_get_user_region_len(unsigned long arg)
+{
+	unsigned long __user *ptr = (unsigned long __user *)arg;
+	unsigned long kbox_user_region_len = 0;
+
+	kbox_user_region_len = kbox_get_section_len(KBOX_SECTION_USER);
+	if (kbox_user_region_len == 0) {
+		KBOX_MSG("kbox_get_section_len section user fail!\n");
+		return -EFAULT;
+	}
+
+	/*lint -e123 */
+	return put_user(kbox_user_region_len, ptr);
+	/*lint +e123 */
+}
+
+static int kbox_ioctl_verify_cmd(unsigned int cmd, unsigned long arg)
+{
+
+	if ((arg == 0) || (_IOC_TYPE(cmd) != KBOX_IOC_MAGIC))
+		return KBOX_FALSE;
+
+	if (_IOC_NR(cmd) > KBOX_IOC_MAXNR)
+		return KBOX_FALSE;
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		KBOX_MSG("permit error\n");
+		return KBOX_FALSE;
+	}
+
+	return KBOX_TRUE;
+}
+
+int kbox_ioctl_detail(unsigned int cmd, unsigned long arg)
+{
+	if (kbox_ioctl_verify_cmd(cmd, arg) != KBOX_TRUE)
+		return -EFAULT;
+
+	switch (cmd) {
+	case GET_KBOX_TOTAL_LEN:	/*lint !e30 !e506 */
+		return kbox_get_image_len(arg);
+
+	case GET_KBOX_REGION_USER_LEN:	/*lint !e30 !e506 !e142 */
+		return kbox_get_user_region_len(arg);
+
+	case KBOX_REGION_READ:	/*lint !e30 !e506 !e142 */
+		return kbox_read_region(arg);
+
+	case KBOX_REGION_WRITE:	/*lint !e30 !e506 !e142 */
+		return kbox_writer_region(arg);
+
+	case CLEAR_KBOX_REGION_ALL:	/*lint !e30 !e506 */
+		return kbox_clear_region(KBOX_SECTION_ALL);
+
+	case CLEAR_KBOX_REGION_USER:	/*lint !e30 !e506 */
+		return kbox_clear_region(KBOX_SECTION_USER);
+
+	default:
+		return -ENOTTY;
+	}
+}
+
+int kbox_mmap_ram(struct file *pfile, struct vm_area_struct *vma,
+		  enum kbox_section_e  section)
+{
+	unsigned long kbox_section_phy_addr =
+	    kbox_get_section_phy_addr(section);
+	unsigned long kbox_section_len = kbox_get_section_len(section);
+	unsigned long offset = 0;
+	unsigned long length = 0;
+	unsigned long vm_size = 0;
+	int ret = 0;
+
+	UNUSED(pfile);
+
+	if ((kbox_section_phy_addr == 0) || (kbox_section_len == 0)) {
+		KBOX_MSG
+		    ("get kbox_section_phy_addr or kbox_section_len failed!\n");
+		return -EFAULT;
+	}
+
+	offset = vma->vm_pgoff << PAGE_SHIFT;
+	vm_size = vma->vm_end - vma->vm_start;
+
+	if (offset >= kbox_section_len) {
+		KBOX_MSG("vma offset is invalid!\n");
+		return -ESPIPE;
+	}
+
+	if (vma->vm_flags & VM_LOCKED) {
+		KBOX_MSG("vma is locked!\n");
+		return -EPERM;
+	}
+
+	length = kbox_section_len - offset;
+	if (vm_size > length) {
+		KBOX_MSG("vm_size is invalid!\n");
+		return -ENOSPC;
+	}
+
+	vma->vm_flags |= VM_RESERVED;
+	vma->vm_flags |= VM_IO;
+
+	ret = remap_pfn_range(vma,
+			      vma->vm_start,
+			      (unsigned long)(kbox_section_phy_addr >>
+					      PAGE_SHIFT), vm_size,
+			      vma->vm_page_prot);
+	if (ret) {
+		KBOX_MSG("remap_pfn_range failed! ret = %d\n", ret);
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
diff --git a/drivers/net/ethernet/huawei/ibma/kbox_ram_op.h b/drivers/net/ethernet/huawei/ibma/kbox_ram_op.h
new file mode 100644
index 0000000..f74a96f
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/kbox_ram_op.h
@@ -0,0 +1,77 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _KBOX_RAM_OP_H_
+#define _KBOX_RAM_OP_H_
+
+#include <asm/ioctls.h>
+
+
+#include "kbox_printk.h"
+
+
+#define KBOX_IOC_MAGIC (0xB2)
+
+#define GET_KBOX_TOTAL_LEN _IOR(KBOX_IOC_MAGIC, 0, unsigned long)
+
+#define GET_KBOX_REGION_USER_LEN  _IOR(KBOX_IOC_MAGIC, 1, unsigned long)
+
+#define CLEAR_KBOX_REGION_ALL _IO(KBOX_IOC_MAGIC, 2)
+
+#define CLEAR_KBOX_REGION_USER _IO(KBOX_IOC_MAGIC, 3)
+
+#define KBOX_REGION_READ _IOR(KBOX_IOC_MAGIC, 4, struct kbox_region_arg_s)
+
+#define KBOX_REGION_WRITE _IOW(KBOX_IOC_MAGIC, 5, struct kbox_region_arg_s)
+
+#define KBOX_IOC_MAXNR 6
+
+#define TEMP_BUF_SIZE (32 * 1024)
+#define TEMP_BUF_DATA_SIZE (128 * 1024)
+#define KBOX_RW_UNIT 4
+
+struct kbox_region_arg_s {
+	unsigned long offset;
+	unsigned int count;
+	char *data;
+};
+
+int kbox_read_op(unsigned long offset, unsigned int count, char __user *data,
+		 enum kbox_section_e section);
+int kbox_write_op(unsigned long offset, unsigned int count,
+		  const char __user *data, enum kbox_section_e section);
+int Kbox_read_super_block(void);
+int kbox_super_block_init(void);
+int kbox_write_panic_info(const char *input_data, unsigned int data_len);
+int kbox_write_thread_info(const char *input_data, unsigned int data_len);
+int kbox_write_printk_info(const char *input_data,
+			   struct printk_ctrl_block_tmp_s
+			   *printk_ctrl_block_tmp);
+int kbox_read_printk_info(char *input_data,
+			  struct printk_ctrl_block_tmp_s
+			  *printk_ctrl_block_tmp);
+int kbox_ioctl_detail(unsigned int cmd, unsigned long arg);
+int kbox_mmap_ram(struct file *file, struct vm_area_struct *vma,
+		  enum kbox_section_e section);
+char Kbox_checksum(char *input_buf, unsigned int len);
+int kbox_write_to_ram(unsigned long offset, unsigned int count,
+		      const char *data, enum kbox_section_e section);
+int kbox_read_from_ram(unsigned long offset, unsigned int count, char *data,
+		       enum kbox_section_e section);
+int kbox_clear_region(enum kbox_section_e section);
+int kbox_memset_ram(unsigned long offset, unsigned int count,
+		    const char set_byte, enum kbox_section_e section);
+
+#endif
diff --git a/drivers/net/ethernet/huawei/ibma/memcpy_s.c b/drivers/net/ethernet/huawei/ibma/memcpy_s.c
new file mode 100644
index 0000000..6dd66638
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/memcpy_s.c
@@ -0,0 +1,90 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include "securec.h"
+
+/*******************************************************************************
+ * <NAME>
+ *    memcpy_s
+ *
+ * <SYNOPSIS>
+ *    int memcpy_s(void *dest, size_t destMax, const void *src, size_t count);
+ *
+ * <FUNCTION DESCRIPTION>
+ *    memcpy_s copies count bytes from src to dest
+ *
+ * <INPUT PARAMETERS>
+ *    dest                       new buffer.
+ *    destMax                    Size of the destination buffer.
+ *    src                        Buffer to copy from.
+ *    count                      Number of characters to copy
+ *
+ * <OUTPUT PARAMETERS>
+ *    dest buffer                is updated.
+ *
+ * <RETURN VALUE>
+ *    EOK                        Success
+ *    EINVAL                     dest == NULL or strSrc == NULL
+ *    ERANGE                     count > destMax or destMax >
+ *                               SECUREC_MEM_MAX_LEN or destMax == 0
+ *    EOVERLAP                   dest buffer and source buffer are overlapped
+ *
+ *    if an error occured, dest will be filled with 0.
+ *    If the source and destination overlap, the behavior of memcpy_s
+ *    is undefined. Use memmove_s to handle overlapping regions.
+ *******************************************************************************
+ */
+
+int memcpy_s(void *dest, size_t destMax, const void *src, size_t count)
+{
+	if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) {
+		SECUREC_ERROR_INVALID_RANGE("memcpy_s");
+		return ERANGE;
+	}
+
+	if (!dest || !src) {
+		if (dest != NULL)
+			(void)memset(dest, 0, destMax);
+		SECUREC_ERROR_INVALID_PARAMTER("memcpy_s");
+		return EINVAL;
+	}
+	if (count > destMax) {
+		(void)memset(dest, 0, destMax);
+		SECUREC_ERROR_INVALID_RANGE("memcpy_s");
+		return ERANGE;
+	}
+	if (dest == src) {
+		return EOK;
+	}
+	if ((dest > src && dest < (void *)((uint8_t *) src + count)) ||
+	    (src > dest && src < (void *)((uint8_t *) dest + count))) {
+		(void)memset(dest, 0, destMax);
+		SECUREC_ERROR_BUFFER_OVERLAP("memcpy_s");
+		return EOVERLAP;
+	}
+#ifdef CALL_LIBC_COR_API
+	/*use underlying memcpy for performance consideration */
+	(void)memcpy(dest, src, count);	/*lint !e64 */
+#else
+	// User can use gcc's __SIZEOF_POINTER__ macro to
+	// copy memory by single byte, 4 bytes or 8 bytes.
+	// User can reference memcpy_32b() and memcpy_64b() in securecutil.c
+	memcpy_8b(dest, src, count);
+#endif
+
+	return EOK;
+}
+EXPORT_SYMBOL(memcpy_s);
diff --git a/drivers/net/ethernet/huawei/ibma/memset_s.c b/drivers/net/ethernet/huawei/ibma/memset_s.c
new file mode 100644
index 0000000..f513733
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/memset_s.c
@@ -0,0 +1,71 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include "securec.h"
+
+/*******************************************************************************
+ * <NAME>
+ *    memset_s
+ *
+ * <SYNOPSIS>
+ *    errno_t memset_s(void* dest, size_t destMax, int c, size_t count)
+ *
+ * <FUNCTION DESCRIPTION>
+ *    Sets buffers to a specified character.
+ *
+ * <INPUT PARAMETERS>
+ *    dest               Pointer to destination.
+ *    destMax            The size of the buffer.
+ *    c                  Character to set.
+ *    count              Number of characters.
+ *
+ * <OUTPUT PARAMETERS>
+ *    dest buffer        is uptdated.
+ *
+ * <RETURN VALUE>
+ *    EOK                Success
+ *    EINVAL             dest == NULL
+ *    ERANGE             count > destMax or destMax > SECUREC_MEM_MAX_LEN
+ *                       or destMax == 0
+ *******************************************************************************
+ */
+
+int memset_s(void *dest, size_t destMax, int c, size_t count)
+{
+	if (destMax == 0 || destMax > SECUREC_MEM_MAX_LEN) {
+		SECUREC_ERROR_INVALID_RANGE("memset_s");
+		return ERANGE;
+	}
+	if (!dest) {
+		SECUREC_ERROR_INVALID_PARAMTER("memset_s");
+		return EINVAL;
+	}
+	if (count > destMax) {
+		/*set entire buffer to value c */
+		(void)memset(dest, c, destMax);
+		SECUREC_ERROR_INVALID_RANGE("memset_s");
+		return ERANGE;
+	}
+#ifdef CALL_LIBC_COR_API
+	/*use underlying memcpy for performance consideration */
+	(void)memset(dest, c, count);
+#else
+	util_memset(dest, c, count);
+#endif
+
+	return EOK;
+}
+EXPORT_SYMBOL(memset_s);
diff --git a/drivers/net/ethernet/huawei/ibma/securec.h b/drivers/net/ethernet/huawei/ibma/securec.h
new file mode 100644
index 0000000..6a252c28
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/securec.h
@@ -0,0 +1,87 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#ifndef __SECUREC_H__5D13A042_DC3F_4ED9_A8D1_882811274C27
+#define __SECUREC_H__5D13A042_DC3F_4ED9_A8D1_882811274C27
+
+#include <linux/kernel.h>	/*printk */
+#include <linux/module.h>
+#include <linux/errno.h>
+
+#define SECUREC_MEM_MAX_LEN (0x7fffffffUL)
+
+#define SECUREC_ERROR_INVALID_PARAMTER(msg) printk(\
+	KERN_NOTICE "edma_securec: %s invalid argument\n", \
+	msg)
+
+#define SECUREC_ERROR_INVALID_RANGE(msg)    printk(\
+	KERN_NOTICE "edma_securec: %s invalid dest buffer size\n", \
+	msg)
+
+#define SECUREC_ERROR_BUFFER_OVERLAP(msg)   printk(\
+	KERN_NOTICE "edma_securec: %s buffer overlap\n", \
+	msg)
+
+/* for performance consideration, the following macro will the corresponding API
+ * of libC for memcpy, memmove and memset
+ */
+#define CALL_LIBC_COR_API
+/*define error code*/
+
+/* success */
+#define EOK (0)
+
+/* invalid parameter */
+#ifdef EINVAL
+#undef EINVAL
+#endif
+#define EINVAL (22)
+
+/* invalid parameter range */
+#ifdef ERANGE
+#undef ERANGE			/* to avoid redefinition */
+#endif
+#define ERANGE (34)
+
+/* A wide-character code has been detected that does not correspond to a
+ * valid character, or a byte sequence does not form a valid wide-character code
+ */
+#ifdef EILSEQ
+#undef EILSEQ
+#endif
+#define EILSEQ (42)
+
+#ifdef EOVERLAP
+#undef EOVERLAP
+#endif
+#define EOVERLAP (54)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+	/* memset  */
+	int memset_s(void *dest, size_t destMax, int c, size_t count);
+
+	/* memcpy */
+	int memcpy_s(void *dest, size_t destMax, const void *src,
+			 size_t count);
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+#endif	/* __SECUREC_H__5D13A042_DC3F_4ED9_A8D1_882811274C27 */
+
diff --git a/drivers/net/ethernet/huawei/ibma/veth_hb.c b/drivers/net/ethernet/huawei/ibma/veth_hb.c
new file mode 100644
index 0000000..0578dea
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/veth_hb.c
@@ -0,0 +1,2467 @@
+/*
+ * Huawei iBMA driver.
+ * Copyright (c) 2017, Huawei Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/vmalloc.h>
+#include <linux/atomic.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/gfp.h>
+#include <asm/page.h>
+
+#include <linux/ip.h>
+
+#include "veth_hb.h"
+
+static u32 veth_ethtool_get_link(struct net_device *dev);
+
+int debug;			/* debug switch*/
+module_param_call(debug, &edma_param_set_debug, &param_get_int, &debug, 0644);
+
+MODULE_PARM_DESC(debug, "Debug switch (0=close debug, 1=open debug)");
+
+#ifdef __UT_TEST
+u32 g_testdma;
+
+u32 g_testlbk;
+
+#endif
+
+struct bspveth_device g_bspveth_dev = {};
+
+static int veth_int_handler(struct notifier_block *pthis, unsigned long ev,
+			    void *unuse);
+
+static struct notifier_block g_veth_int_nb = {
+	.notifier_call = veth_int_handler,
+};
+
+static const struct veth_stats veth_gstrings_stats[] = {
+	{"rx_packets", NET_STAT(stats.rx_packets)},
+	{"rx_bytes", NET_STAT(stats.rx_bytes)},
+	{"rx_dropped", NET_STAT(stats.rx_dropped)},
+	{"rx_head", QUEUE_RX_STAT(head)},
+	{"rx_tail", QUEUE_RX_STAT(tail)},
+	{"rx_next_to_fill", QUEUE_RX_STAT(next_to_fill)},
+	{"rx_shmq_head", SHMQ_RX_STAT(head)},
+	{"rx_shmq_tail", SHMQ_RX_STAT(tail)},
+	{"rx_shmq_next_to_free", SHMQ_RX_STAT(next_to_free)},
+	{"rx_queue_full", QUEUE_RX_STAT(s.q_full)},
+	{"rx_dma_busy", QUEUE_RX_STAT(s.dma_busy)},
+	{"rx_dma_faild", QUEUE_RX_STAT(s.dma_faild)},
+
+	{"tx_packets", NET_STAT(stats.tx_packets)},
+	{"tx_bytes", NET_STAT(stats.tx_bytes)},
+	{"tx_dropped", NET_STAT(stats.tx_dropped)},
+
+	{"tx_head", QUEUE_TX_STAT(head)},
+	{"tx_tail", QUEUE_TX_STAT(tail)},
+	{"tx_next_to_free", QUEUE_TX_STAT(next_to_free)},
+	{"tx_shmq_head", SHMQ_TX_STAT(head)},
+	{"tx_shmq_tail", SHMQ_TX_STAT(tail)},
+	{"tx_shmq_next_to_free", SHMQ_TX_STAT(next_to_free)},
+
+	{"tx_queue_full", QUEUE_TX_STAT(s.q_full)},
+	{"tx_dma_busy", QUEUE_TX_STAT(s.dma_busy)},
+	{"tx_dma_faild", QUEUE_TX_STAT(s.dma_faild)},
+
+	{"recv_int", VETH_STAT(recv_int)},
+	{"tobmc_int", VETH_STAT(tobmc_int)},
+};
+
+#define VETH_GLOBAL_STATS_LEN	\
+		(sizeof(veth_gstrings_stats) / sizeof(struct veth_stats))
+
+
+static int veth_param_get_statics(char *buf, struct kernel_param *kp)
+{
+	int len = 0;
+	int i = 0, j = 0, type = 0;
+	struct bspveth_rxtx_q *pqueue = NULL;
+	__kernel_time_t running_time = 0;
+
+	if (!buf)
+		return 0;
+
+	GET_SYS_SECONDS(running_time);
+
+	running_time -= g_bspveth_dev.init_time;
+
+	len += sprintf(buf + len,
+		    "==========================VETH INFO======================\r\n");
+	len += sprintf(buf + len, "[version     ]:" VETH_VERSION "\n");
+	len += sprintf(buf + len, "[link state  ]:%d\n",
+		    veth_ethtool_get_link(g_bspveth_dev.pnetdev));
+	len += sprintf(buf + len, "[running_time]:%luD %02lu:%02lu:%02lu\n",
+		    running_time / (SECONDS_PER_DAY),
+		    running_time % (SECONDS_PER_DAY) / SECONDS_PER_HOUR,
+		    running_time % SECONDS_PER_HOUR / SECONDS_PER_MINUTE,
+		    running_time % SECONDS_PER_MINUTE);
+	len += sprintf(buf + len,
+		    "[bspveth_dev ]:MAX_QUEUE_NUM :0x%-16x    MAX_QUEUE_BDNUM :0x%-16x\r\n",
+		    MAX_QUEUE_NUM, MAX_QUEUE_BDNUM);
+	len += sprintf(buf + len,
+		    "[bspveth_dev ]:pnetdev       :0x%-16p    ppcidev         :0x%-16p\r\n",
+		    g_bspveth_dev.pnetdev, g_bspveth_dev.ppcidev);
+	len += sprintf(buf + len,
+		    "[bspveth_dev ]:pshmpool_p    :0x%-16p    pshmpool_v      :0x%-16p\r\n"
+		    "[bspveth_dev]:shmpoolsize   :0x%-16x    g_veth_dbg_lv       :0x%-16x\r\n",
+		    g_bspveth_dev.pshmpool_p, g_bspveth_dev.pshmpool_v,
+		    g_bspveth_dev.shmpoolsize, debug);
+
+	for (i = 0; i < MAX_QUEUE_NUM; i++) {
+		for (j = 0, type = BSPVETH_RX; j < 2; j++, type++) {
+			if (type == BSPVETH_RX) {
+				pqueue = g_bspveth_dev.prx_queue[i];
+				len += sprintf(buf + len,
+					    "=============RXQUEUE STATIS============\r\n");
+			} else {
+				pqueue = g_bspveth_dev.ptx_queue[i];
+				len += sprintf(buf + len,
+					    "=============TXQUEUE STATIS============\r\n");
+			}
+
+			if (!pqueue) {
+				len += sprintf(buf + len, "NULL\r\n");
+				continue;
+			}
+
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[pkt            ] :%lld\r\n", i,
+				    pqueue->s.pkt);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[pktbyte        ] :%lld\r\n", i,
+				    pqueue->s.pktbyte);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[refill         ] :%lld\r\n", i,
+				    pqueue->s.refill);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[freetx         ] :%lld\r\n", i,
+				    pqueue->s.freetx);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[dmapkt         ] :%lld\r\n", i,
+				    pqueue->s.dmapkt);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[dmapktbyte     ] :%lld\r\n", i,
+				    pqueue->s.dmapktbyte);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[next_to_fill   ] :%d\r\n", i,
+				    pqueue->next_to_fill);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[next_to_free   ] :%d\r\n", i,
+				    pqueue->next_to_free);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[head           ] :%d\r\n", i,
+				    pqueue->head);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[tail           ] :%d\r\n", i,
+				    pqueue->tail);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[work_limit     ] :%d\r\n", i,
+				    pqueue->work_limit);
+			len += sprintf(buf + len,
+				    "=================SHARE=================\r\n");
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[next_to_fill   ] :%d\r\n", i,
+				    pqueue->pshmqhd_v->next_to_fill);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[next_to_free   ] :%d\r\n", i,
+				    pqueue->pshmqhd_v->next_to_free);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[head           ] :%d\r\n", i,
+				    pqueue->pshmqhd_v->head);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[tail           ] :%d\r\n", i,
+				    pqueue->pshmqhd_v->tail);
+			len += sprintf(buf + len,
+				    "=======================================\r\n");
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[dropped_pkt    ] :%d\r\n", i,
+				    pqueue->s.dropped_pkt);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[netifrx_err    ] :%d\r\n", i,
+				    pqueue->s.netifrx_err);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[null_point     ] :%d\r\n", i,
+				    pqueue->s.null_point);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[retry_err      ] :%d\r\n", i,
+				    pqueue->s.retry_err);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[allocskb_err   ] :%d\r\n", i,
+				    pqueue->s.allocskb_err);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[q_full         ] :%d\r\n", i,
+				    pqueue->s.q_full);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[q_emp          ] :%d\r\n", i,
+				    pqueue->s.q_emp);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[need_fill      ] :%d\r\n", i,
+				    pqueue->s.need_fill);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[need_free      ] :%d\r\n", i,
+				    pqueue->s.need_free);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[type_err       ] :%d\r\n", i,
+				    pqueue->s.type_err);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[shm_full       ] :%d\r\n", i,
+				    pqueue->s.shm_full);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[shm_emp        ] :%d\r\n", i,
+				    pqueue->s.shm_emp);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[shmretry_err   ] :%d\r\n", i,
+				    pqueue->s.shmretry_err);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[shmqueue_noinit] :%d\r\n", i,
+				    pqueue->s.shmqueue_noinit);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[dma_busy       ] :%d\r\n", i,
+				    pqueue->s.dma_busy);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[dma_mapping_err] :%d\r\n", i,
+				    pqueue->s.dma_mapping_err);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[dma_faild      ] :%d\r\n", i,
+				    pqueue->s.dma_faild);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[dma_burst      ] :%d\r\n", i,
+				    pqueue->s.dma_burst);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[lbk_cnt        ] :%d\r\n", i,
+				    pqueue->s.lbk_cnt);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[dma_need_offset] :%d\r\n", i,
+				    pqueue->s.dma_need_offset);
+			len += sprintf(buf + len,
+				    "QUEUE[%d]--[lbk_txerr      ] :%d\r\n", i,
+				    pqueue->s.lbk_txerr);
+		}
+	}
+
+	len += sprintf(buf + len, "=============BSPVETH STATIS===========\r\n");
+	len += sprintf(buf + len, "[bspveth_dev]:run_dmaRXtask :0x%-8x(%d)\r\n",
+		    g_bspveth_dev.run_dmaRXtask, g_bspveth_dev.run_dmaRXtask);
+	len += sprintf(buf + len, "[bspveth_dev]:run_dmaTXtask :0x%-8x(%d)\r\n",
+		    g_bspveth_dev.run_dmaTXtask, g_bspveth_dev.run_dmaTXtask);
+	len += sprintf(buf + len, "[bspveth_dev]:run_skbRXtask :0x%-8x(%d)\r\n",
+		    g_bspveth_dev.run_skbRXtask, g_bspveth_dev.run_skbRXtask);
+	len += sprintf(buf + len, "[bspveth_dev]:run_skbFRtask :0x%-8x(%d)\r\n",
+		    g_bspveth_dev.run_skbFRtask, g_bspveth_dev.run_skbFRtask);
+	len += sprintf(buf + len, "[bspveth_dev]:recv_int      :0x%-8x(%d)\r\n",
+		    g_bspveth_dev.recv_int, g_bspveth_dev.recv_int);
+	len += sprintf(buf + len, "[bspveth_dev]:tobmc_int     :0x%-8x(%d)\r\n",
+		    g_bspveth_dev.tobmc_int, g_bspveth_dev.tobmc_int);
+	len += sprintf(buf + len, "[bspveth_dev]:shutdown_cnt  :0x%-8x(%d)\r\n",
+		    g_bspveth_dev.shutdown_cnt, g_bspveth_dev.shutdown_cnt);
+
+	return len;
+}
+
+module_param_call(statistics, NULL, veth_param_get_statics, &debug, 0444);
+
+MODULE_PARM_DESC(statistics, "Statistics info of veth driver,readonly");
+
+
+static void veth_reset_dma(int type)
+{
+	if (type == BSPVETH_RX)
+		bma_intf_reset_dma(BMC_TO_HOST);
+	else if (type == BSPVETH_TX)
+		bma_intf_reset_dma(HOST_TO_BMC);
+	else
+		return;
+}
+
+
+s32 bspveth_setup_tx_resources(struct bspveth_device *pvethdev,
+			       struct bspveth_rxtx_q *ptx_queue)
+{
+	int size;
+
+	if (!pvethdev || !ptx_queue)
+		return BSP_ERR_NULL_POINTER;
+
+	ptx_queue->count = MAX_QUEUE_BDNUM;
+
+	size = sizeof(struct bspveth_bd_info) * ptx_queue->count;
+	ptx_queue->pbdinfobase_v = vmalloc(size); /*lint !e64*/
+	if (!ptx_queue->pbdinfobase_v)
+		goto alloc_failed;
+
+	memset_s(ptx_queue->pbdinfobase_v, size, 0, size);
+
+	/* round up to nearest 4K */
+	ptx_queue->size = ptx_queue->count * sizeof(struct bspveth_bd_info);
+	ptx_queue->size = ALIGN(ptx_queue->size, 4096);
+
+	/* prepare  4096 send buffer */
+	ptx_queue->pbdbase_v = kmalloc(ptx_queue->size,
+						GFP_KERNEL); /*lint !e64*/
+	if (!ptx_queue->pbdbase_v) {
+		VETH_LOG(DLOG_ERROR,
+		"Unable to allocate memory for the receive descriptor ring\n");
+
+		vfree(ptx_queue->pbdinfobase_v);
+		ptx_queue->pbdinfobase_v = NULL;
+
+		goto alloc_failed;
+	}
+
+	ptx_queue->pbdbase_p = (u8 *)(__pa((BSP_VETH_T)(
+						ptx_queue->pbdbase_v)));
+
+	ptx_queue->next_to_fill = 0;
+	ptx_queue->next_to_free = 0;
+	ptx_queue->head = 0;
+	ptx_queue->tail = 0;
+	ptx_queue->work_limit = BSPVETH_WORK_LIMIT;
+
+	memset_s(&(ptx_queue->s), sizeof(struct bspveth_rxtx_statis), 0,
+		sizeof(struct bspveth_rxtx_statis));
+
+	return 0;
+
+alloc_failed:
+	return -ENOMEM;
+}
+
+
+void bspveth_free_tx_resources(struct bspveth_device *pvethdev,
+			       struct bspveth_rxtx_q *ptx_queue)
+{
+	unsigned int i;
+	unsigned long size;
+	struct bspveth_bd_info *pbdinfobase_v = NULL;
+	struct sk_buff *skb = NULL;
+
+	if (!ptx_queue || !pvethdev)
+		return;
+
+	pbdinfobase_v = ptx_queue->pbdinfobase_v;
+	if (!pbdinfobase_v)
+		return;
+
+	for (i = 0; i < ptx_queue->count; i++) {
+		skb = pbdinfobase_v[i].pdma_v;
+		if (skb)
+			dev_kfree_skb_any(skb);
+
+		pbdinfobase_v[i].pdma_v = NULL;
+	}
+
+	size = sizeof(struct bspveth_bd_info) * ptx_queue->count;
+	memset_s(ptx_queue->pbdinfobase_v, size, 0, size);
+	memset_s(ptx_queue->pbdbase_v, ptx_queue->size, 0, ptx_queue->size);
+
+	ptx_queue->next_to_fill = 0;
+	ptx_queue->next_to_free = 0;
+	ptx_queue->head = 0;
+	ptx_queue->tail = 0;
+
+	vfree(ptx_queue->pbdinfobase_v);
+	ptx_queue->pbdinfobase_v = NULL;
+
+	kfree(ptx_queue->pbdbase_v);
+	ptx_queue->pbdbase_v = NULL;
+
+	VETH_LOG(DLOG_DEBUG, "bspveth free tx resources ok, count=%d\n",
+		 ptx_queue->count);
+}
+s32 bspveth_setup_all_tx_resources(struct bspveth_device *pvethdev)
+{
+	int qid = 0;
+	int i = 0;
+	int err = 0;
+	u8 *shmq_head_p = NULL;
+	struct bspveth_shmq_hd *shmq_head = NULL;
+
+	if (!pvethdev)
+		return BSP_ERR_NULL_POINTER;
+	for (qid = 0; qid < MAX_QUEUE_NUM; qid++) {
+		pvethdev->ptx_queue[qid] = kmalloc(
+			sizeof(*pvethdev->ptx_queue[qid]),
+					GFP_KERNEL); /*lint !e64*/
+		if (!pvethdev->ptx_queue[qid]) {
+			VETH_LOG(DLOG_ERROR,
+				 "kmalloc faild for ptx_queue[%d]\n", qid);
+			err = -1;
+			goto failed;
+		}
+		memset_s(pvethdev->ptx_queue[qid],
+					sizeof(struct bspveth_rxtx_q),
+					0, sizeof(struct bspveth_rxtx_q));
+		shmq_head = (struct bspveth_shmq_hd *)(pvethdev->pshmpool_v +
+					MAX_SHAREQUEUE_SIZE * (qid));
+		pvethdev->ptx_queue[qid]->pshmqhd_v = shmq_head;
+		pvethdev->ptx_queue[qid]->pshmqhd_p = shmq_head_p =
+				pvethdev->pshmpool_p
+				+ MAX_SHAREQUEUE_SIZE * qid;
+
+		pvethdev->ptx_queue[qid]->pshmbdbase_v =
+			(struct bspveth_dma_shmbd *)((BSP_VETH_T)(shmq_head)
+			+ BSPVETH_SHMBDBASE_OFFSET); /*lint !e511*/
+		pvethdev->ptx_queue[qid]->pshmbdbase_p =
+			(u8 *)((BSP_VETH_T)(shmq_head_p)
+			+ BSPVETH_SHMBDBASE_OFFSET); /*lint !e511*/
+		pvethdev->ptx_queue[qid]->pdmalbase_v =
+			(struct bspveth_dmal *)((BSP_VETH_T)(shmq_head)
+			+ SHMDMAL_OFFSET); /*lint !e511*/
+		pvethdev->ptx_queue[qid]->pdmalbase_p =
+			(u8 *)(u64)(VETH_SHAREPOOL_BASE_INBMC
+			+ MAX_SHAREQUEUE_SIZE * qid
+			+ SHMDMAL_OFFSET);/*lint !e647*/
+
+		memset_s(pvethdev->ptx_queue[qid]->pdmalbase_v,
+					MAX_SHMDMAL_SIZE, 0, MAX_SHMDMAL_SIZE);
+
+		err = bspveth_setup_tx_resources(pvethdev,
+						 pvethdev->ptx_queue[qid]);
+		if (err) {
+			pvethdev->ptx_queue[qid]->pshmqhd_v = NULL;
+			kfree(pvethdev->ptx_queue[qid]);
+			pvethdev->ptx_queue[i] = NULL;
+			VETH_LOG(DLOG_ERROR,
+						"Allocation for Tx Queue %u failed\n",
+						qid);
+
+			goto failed;
+		}
+	}
+
+	return 0;
+failed:
+	for (i = 0; i < MAX_QUEUE_NUM; i++) {
+		bspveth_free_tx_resources(pvethdev, pvethdev->ptx_queue[i]);
+		kfree(pvethdev->ptx_queue[i]);
+		pvethdev->ptx_queue[i] = NULL;
+	}
+
+	return err;
+}
+
+
+
+void bspveth_free_all_tx_resources(struct bspveth_device *pvethdev)
+{
+	int i;
+
+	if (!pvethdev)
+		return;
+
+	for (i = 0; i < MAX_QUEUE_NUM; i++) {
+		if (pvethdev->ptx_queue[i])
+			bspveth_free_tx_resources(pvethdev,
+						  pvethdev->ptx_queue[i]);
+
+		kfree(pvethdev->ptx_queue[i]);
+		pvethdev->ptx_queue[i] = NULL;
+	}
+}
+
+
+s32 veth_alloc_one_rx_skb(struct bspveth_rxtx_q *prx_queue, int idx)
+{
+	dma_addr_t dma = 0;
+	struct sk_buff *skb;
+	struct bspveth_bd_info *pbdinfobase_v = NULL;
+	struct bspveth_dma_bd *pbdbase_v = NULL;
+
+	pbdinfobase_v = prx_queue->pbdinfobase_v;
+	pbdbase_v = prx_queue->pbdbase_v;
+
+	skb = netdev_alloc_skb(g_bspveth_dev.pnetdev,
+				     BSPVETH_SKB_SIZE + BSPVETH_CACHELINE_SIZE);
+	if (!skb) {
+		VETH_LOG(DLOG_ERROR, "netdev_alloc_skb faild\n");
+		return -ENOMEM;
+	}
+
+	/* advance the data pointer to the next cache line */
+	skb_reserve(skb, PTR_ALIGN(skb->data,
+			 BSPVETH_CACHELINE_SIZE) - skb->data);
+
+	dma = dma_map_single(&(g_bspveth_dev.ppcidev->dev),
+			skb->data, BSPVETH_SKB_SIZE, DMA_FROM_DEVICE);
+	if (DMA_MAPPING_ERROR(&(g_bspveth_dev.ppcidev->dev), dma)) {
+		VETH_LOG(DLOG_ERROR, "dma_mapping_error faild\n");
+		dev_kfree_skb_any(skb);
+		return -EFAULT;
+	}
+
+#ifdef __UT_TEST
+	if (g_testdma)
+		VETH_LOG(DLOG_ERROR,
+			 "[refill]:dma=0x%llx,skb=%p,skb->len=%d\r\n",
+			 dma, skb, skb->len);
+#endif
+
+
+	pbdinfobase_v[idx].pdma_v = skb;
+	pbdinfobase_v[idx].len = BSPVETH_SKB_SIZE;
+
+	pbdbase_v[idx].dma_p = dma;
+	pbdbase_v[idx].len = BSPVETH_SKB_SIZE;
+
+	return 0;
+}
+
+
+s32 veth_refill_rxskb(struct bspveth_rxtx_q *prx_queue, int queue)
+{
+	int i, work_limit;
+	int next_to_fill, tail;
+	int ret = BSP_OK;
+
+	if (!prx_queue)
+		return BSP_ERR_AGAIN;
+
+	work_limit = prx_queue->work_limit;
+	next_to_fill = prx_queue->next_to_fill;
+	tail = prx_queue->tail;
+
+	for (i = 0; i < work_limit; i++) {
+
+		if (!JUDGE_RX_QUEUE_SPACE(next_to_fill, tail, 1))
+			break;
+
+		ret = veth_alloc_one_rx_skb(prx_queue, next_to_fill);
+		if (ret)
+			break;
+
+		INC_STATIS_RX(queue, refill, 1);
+		next_to_fill = (next_to_fill + 1) & BSPVETH_POINT_MASK;
+	}
+
+	prx_queue->next_to_fill = next_to_fill;
+
+	tail = prx_queue->tail;
+	if (JUDGE_RX_QUEUE_SPACE(next_to_fill, tail, 1)) {
+		VETH_LOG(DLOG_DEBUG, "next_to_fill(%d) != tail(%d)\n",
+			 next_to_fill, tail);
+
+		return BSP_ERR_AGAIN;
+	}
+
+	return 0;
+}
+
+
+s32 bspveth_setup_rx_skb(struct bspveth_device *pvethdev,
+			 struct bspveth_rxtx_q *prx_queue)
+{
+	u32 idx;
+	int ret = 0;
+
+	if (!pvethdev || !prx_queue)
+		return BSP_ERR_NULL_POINTER;
+
+	VETH_LOG(DLOG_DEBUG, "waite setup rx skb ,count=%d\n",
+		 prx_queue->count);
+
+	for (idx = 0; idx < prx_queue->count - 1; idx++) {
+		ret = veth_alloc_one_rx_skb(prx_queue, idx);
+		if (ret)
+			break;
+	}
+
+	if (!idx)	/* Can't alloc even one packets */
+		return -EFAULT;
+
+	prx_queue->next_to_fill = idx;
+
+	VETH_LOG(DLOG_DEBUG, "prx_queue->next_to_fill=%d\n",
+			prx_queue->next_to_fill);
+
+	VETH_LOG(DLOG_DEBUG, "setup rx skb ok, count=%d\n", prx_queue->count);
+
+	return BSP_OK;
+}
+
+void bspveth_free_rx_skb(struct bspveth_device *pvethdev,
+			 struct bspveth_rxtx_q *prx_queue)
+{
+	u32 i = 0;
+	struct bspveth_bd_info *pbdinfobase_v = NULL;
+	struct bspveth_dma_bd *pbdbase_v = NULL;
+	struct sk_buff *skb = NULL;
+
+	if (!pvethdev || !prx_queue)
+		return;
+
+	pbdinfobase_v = prx_queue->pbdinfobase_v;
+	pbdbase_v = prx_queue->pbdbase_v;
+	if (!pbdinfobase_v || !pbdbase_v)
+		return;
+
+	/* Free all the Rx ring pages */
+	for (i = 0; i < prx_queue->count; i++) {
+		skb = pbdinfobase_v[i].pdma_v;
+		if (!skb)
+			continue;
+
+		dma_unmap_single(&(g_bspveth_dev.ppcidev->dev),
+				 pbdbase_v[i].dma_p, BSPVETH_SKB_SIZE,
+				 DMA_FROM_DEVICE);
+		dev_kfree_skb_any(skb);
+
+		pbdinfobase_v[i].pdma_v = NULL;
+	}
+
+	prx_queue->next_to_fill = 0;
+}
+
+
+s32 bspveth_setup_all_rx_skb(struct bspveth_device *pvethdev)
+{
+	int qid, i, err = BSP_OK;
+
+	if (!pvethdev)
+		return BSP_ERR_NULL_POINTER;
+
+	for (qid = 0; qid < MAX_QUEUE_NUM; qid++) {
+		err = bspveth_setup_rx_skb(pvethdev, pvethdev->prx_queue[qid]);
+		if (err) {
+			VETH_LOG(DLOG_ERROR, "queue[%d]setup RX skb failed\n",
+				qid);
+			goto failed;
+		}
+
+		VETH_LOG(DLOG_DEBUG, "queue[%d] bspveth_setup_rx_skb ok\n",
+				qid);
+	}
+
+	return 0;
+
+failed:
+	for (i = 0; i < MAX_QUEUE_NUM; i++)
+		bspveth_free_rx_skb(pvethdev, pvethdev->prx_queue[i]);
+
+	return err;
+}
+
+void bspveth_free_all_rx_skb(struct bspveth_device *pvethdev)
+{
+	int qid;
+
+	if (!pvethdev)
+		return;
+
+	/* Free all the Rx ring pages */
+	for (qid = 0; qid < MAX_QUEUE_NUM; qid++)
+		bspveth_free_rx_skb(pvethdev, pvethdev->prx_queue[qid]);
+}
+
+s32 bspveth_setup_rx_resources(struct bspveth_device *pvethdev,
+			       struct bspveth_rxtx_q *prx_queue)
+{
+	int size;
+
+	if (!pvethdev || !prx_queue)
+		return BSP_ERR_NULL_POINTER;
+
+	prx_queue->count = MAX_QUEUE_BDNUM;
+	size = sizeof(*prx_queue->pbdinfobase_v) * prx_queue->count;
+	prx_queue->pbdinfobase_v = vmalloc(size); /*lint !e64*/
+	if (!prx_queue->pbdinfobase_v) {
+		VETH_LOG(DLOG_ERROR,
+			 "Unable to vmalloc buffer memory for the receive descriptor ring\n");
+
+		goto alloc_failed;
+	}
+
+	memset_s(prx_queue->pbdinfobase_v, size, 0, size);
+
+	/* Round up to nearest 4K */
+	prx_queue->size = prx_queue->count * sizeof(*prx_queue->pbdbase_v);
+	prx_queue->size = ALIGN(prx_queue->size, 4096);
+	prx_queue->pbdbase_v = kmalloc(prx_queue->size,
+						GFP_ATOMIC); /*lint !e64*/
+	if (!prx_queue->pbdbase_v) {
+		VETH_LOG(DLOG_ERROR,
+		"Unable to allocate memory for the receive descriptor ring\n");
+
+		vfree(prx_queue->pbdinfobase_v);
+		prx_queue->pbdinfobase_v = NULL;
+
+		goto alloc_failed;
+	}
+
+	prx_queue->pbdbase_p = (u8 *)__pa((BSP_VETH_T) (prx_queue->pbdbase_v));
+
+	prx_queue->next_to_fill = 0;
+	prx_queue->next_to_free = 0;
+	prx_queue->head = 0;
+	prx_queue->tail = 0;
+
+	prx_queue->work_limit = BSPVETH_WORK_LIMIT;
+
+	memset_s(&(prx_queue->s), sizeof(struct bspveth_rxtx_statis), 0,
+		sizeof(struct bspveth_rxtx_statis));
+
+	return 0;
+
+alloc_failed:
+	return -ENOMEM;
+}
+
+void bspveth_free_rx_resources(struct bspveth_device *pvethdev,
+			       struct bspveth_rxtx_q *prx_queue)
+{
+	unsigned long size;
+	struct bspveth_bd_info *pbdinfobase_v = NULL;
+
+	if (!pvethdev || !prx_queue)
+		return;
+
+	pbdinfobase_v = prx_queue->pbdinfobase_v;
+	if (!pbdinfobase_v)
+		return;
+
+	if (!prx_queue->pbdbase_v)
+		return;
+
+	size = sizeof(struct bspveth_bd_info) * prx_queue->count;
+	memset_s(prx_queue->pbdinfobase_v, size, 0, size);
+
+	/* Zero out the descriptor ring */
+	memset_s(prx_queue->pbdbase_v, prx_queue->size, 0, prx_queue->size);
+
+	vfree(prx_queue->pbdinfobase_v);
+	prx_queue->pbdinfobase_v = NULL;
+
+	kfree(prx_queue->pbdbase_v);
+	prx_queue->pbdbase_v = NULL;
+
+	VETH_LOG(DLOG_DEBUG, "bspveth free rx resources ok!!count=%d\n",
+		 prx_queue->count);
+}
+s32 bspveth_setup_all_rx_resources(struct bspveth_device *pvethdev)
+{
+	int qid, i, err = 0;
+	struct bspveth_shmq_hd *shmq_head = NULL;
+	u8 *shmq_head_p = NULL;
+
+	if (!pvethdev)
+		return BSP_ERR_NULL_POINTER;
+
+	for (qid = 0; qid < MAX_QUEUE_NUM; qid++) {
+		pvethdev->prx_queue[qid] =
+			kmalloc(sizeof(*pvethdev->prx_queue[qid]),
+				GFP_KERNEL); /*lint !e64*/
+		if (!pvethdev->prx_queue[qid]) {
+			VETH_LOG(DLOG_ERROR,
+				 "kmalloc faild for prx_queue[%d]\n", qid);
+
+			goto failed;
+		}
+
+		memset_s(pvethdev->prx_queue[qid],
+			sizeof(struct bspveth_rxtx_q), 0,
+			sizeof(struct bspveth_rxtx_q));
+
+		shmq_head = (struct bspveth_shmq_hd *)(pvethdev->pshmpool_v +
+					   MAX_SHAREQUEUE_SIZE * (qid + 1));
+
+		pvethdev->prx_queue[qid]->pshmqhd_v = shmq_head;
+		pvethdev->prx_queue[qid]->pshmqhd_p = shmq_head_p =
+			pvethdev->pshmpool_p + MAX_SHAREQUEUE_SIZE * (qid + 1);
+		pvethdev->prx_queue[qid]->pshmbdbase_v =
+			(struct bspveth_dma_shmbd *)((BSP_VETH_T)(shmq_head)
+			+ BSPVETH_SHMBDBASE_OFFSET); /*lint !e511*/
+		pvethdev->prx_queue[qid]->pshmbdbase_p =
+			(u8 *)((BSP_VETH_T)(shmq_head_p)
+			+ BSPVETH_SHMBDBASE_OFFSET); /*lint !e511*/
+		pvethdev->prx_queue[qid]->pdmalbase_v =
+			(struct bspveth_dmal *)((BSP_VETH_T)(shmq_head)
+			+ SHMDMAL_OFFSET); /*lint !e511*/
+		pvethdev->prx_queue[qid]->pdmalbase_p =
+			(u8 *)(u64) (VETH_SHAREPOOL_BASE_INBMC
+			+ MAX_SHAREQUEUE_SIZE * (qid + 1)
+			+ SHMDMAL_OFFSET);/*lint !e647*/
+		memset_s(pvethdev->prx_queue[qid]->pdmalbase_v,
+			MAX_SHMDMAL_SIZE, 0, MAX_SHMDMAL_SIZE);
+
+		err = bspveth_setup_rx_resources(pvethdev,
+						 pvethdev->prx_queue[qid]);
+		if (err) {
+			kfree(pvethdev->prx_queue[qid]);
+			pvethdev->prx_queue[qid] = NULL;
+			VETH_LOG(DLOG_ERROR,
+					"Allocation for Rx Queue %u failed\n",
+					qid);
+
+			goto failed;
+		}
+	}
+
+	return 0;
+failed:
+	for (i = 0; i < MAX_QUEUE_NUM; i++) {
+		bspveth_free_rx_resources(pvethdev, pvethdev->prx_queue[i]);
+		kfree(pvethdev->prx_queue[i]);
+		pvethdev->prx_queue[i] = NULL;
+	}
+	return err;
+}
+
+
+void bspveth_free_all_rx_resources(struct bspveth_device *pvethdev)
+{
+	int i;
+
+	if (!pvethdev)
+		return;
+
+	for (i = 0; i < MAX_QUEUE_NUM; i++) {
+		if (pvethdev->prx_queue[i]) {
+			bspveth_free_rx_resources(pvethdev,
+						  pvethdev->prx_queue[i]);
+		}
+
+		kfree(pvethdev->prx_queue[i]);
+		pvethdev->prx_queue[i] = NULL;
+	}
+}
+
+
+s32 bspveth_dev_install(void)
+{
+	int err;
+
+	err = bspveth_setup_all_rx_resources(&g_bspveth_dev);
+	if (err != BSP_OK) {
+		err = -1;
+		goto err_setup_rx;
+	}
+
+	err = bspveth_setup_all_tx_resources(&g_bspveth_dev);
+	if (err != BSP_OK) {
+		err = -1;
+		goto err_setup_tx;
+	}
+
+	err = bspveth_setup_all_rx_skb(&g_bspveth_dev);
+	if (err != BSP_OK) {
+		err = -1;
+		goto err_setup_rx_skb;
+	}
+
+	return BSP_OK;
+
+err_setup_rx_skb:
+	bspveth_free_all_tx_resources(&g_bspveth_dev);
+
+err_setup_tx:
+	bspveth_free_all_rx_resources(&g_bspveth_dev);
+
+err_setup_rx:
+
+	return err;
+}
+
+
+s32 bspveth_dev_uninstall(void)
+{
+	int err = BSP_OK;
+
+
+	/* Free all the Rx ring pages */
+	bspveth_free_all_rx_skb(&g_bspveth_dev);
+
+	bspveth_free_all_tx_resources(&g_bspveth_dev);
+
+	VETH_LOG(DLOG_DEBUG, "bspveth_free_all_tx_resources ok\n");
+
+	bspveth_free_all_rx_resources(&g_bspveth_dev);
+
+	VETH_LOG(DLOG_DEBUG, "bspveth_free_all_rx_resources ok\n");
+
+	return err;
+}
+
+
+s32 veth_open(struct net_device *pstr_dev)
+{
+	s32 ret = BSP_OK;
+
+	if (!pstr_dev)
+		return -1;
+
+	if (!g_bspveth_dev.pnetdev)
+		g_bspveth_dev.pnetdev = pstr_dev;
+
+	ret = bspveth_dev_install();
+	if (ret != BSP_OK) {
+		ret = -1;
+		goto failed1;
+	}
+
+	veth_skbtimer_init();
+
+	veth_dmatimer_init_H();
+
+	ret = bma_intf_register_int_notifier(&g_veth_int_nb);
+	if (ret != BSP_OK) {
+		ret = -1;
+		goto failed2;
+	}
+
+	bma_intf_set_open_status(g_bspveth_dev.bma_priv, DEV_OPEN);
+
+	g_bspveth_dev.prx_queue[0]->pshmqhd_v->tail =
+				g_bspveth_dev.prx_queue[0]->pshmqhd_v->head;
+
+	bma_intf_int_to_bmc(g_bspveth_dev.bma_priv);
+
+	netif_start_queue(g_bspveth_dev.pnetdev);
+	netif_carrier_on(pstr_dev);
+
+	return BSP_OK;
+
+failed2:
+	veth_dmatimer_close_H();
+
+	veth_skbtimer_close();
+
+	(void)bspveth_dev_uninstall();
+
+failed1:
+	return ret;
+}
+
+
+s32 veth_close(struct net_device *pstr_dev)
+{
+	(void)bma_intf_unregister_int_notifier(&g_veth_int_nb);
+
+	netif_carrier_off(pstr_dev);
+
+	bma_intf_set_open_status(g_bspveth_dev.bma_priv, DEV_CLOSE);
+
+	netif_stop_queue(g_bspveth_dev.pnetdev);
+
+	(void)veth_dmatimer_close_H();
+	(void)veth_skbtimer_close();
+
+
+	(void)bspveth_dev_uninstall();
+
+	return BSP_OK;
+}
+
+
+s32 veth_config(struct net_device *pstr_dev, struct ifmap *pstr_map)
+{
+	if (!pstr_dev || !pstr_map)
+		return BSP_ERR_NULL_POINTER;
+
+	/* can't act on a running interface */
+	if (pstr_dev->flags & IFF_UP)
+		return -EBUSY;
+
+	/* Don't allow changing the I/O address */
+	if (pstr_map->base_addr != pstr_dev->base_addr)
+		return -EOPNOTSUPP;
+
+	/* ignore other fields */
+	return BSP_OK;
+}
+
+
+
+void bspveth_initstatis(void)
+{
+	int i;
+	struct bspveth_rxtx_q *prx_queue, *ptx_queue;
+
+	for (i = 0; i < MAX_QUEUE_NUM; i++) {
+		prx_queue = g_bspveth_dev.prx_queue[i];
+		ptx_queue = g_bspveth_dev.ptx_queue[i];
+
+		if (prx_queue && ptx_queue) {
+			memset_s(&(prx_queue->s),
+				sizeof(struct bspveth_rxtx_statis),
+				0, sizeof(struct bspveth_rxtx_statis));
+
+			memset_s(&(ptx_queue->s),
+				sizeof(struct bspveth_rxtx_statis),
+				0, sizeof(struct bspveth_rxtx_statis));
+		} else {
+			VETH_LOG(DLOG_ERROR,
+				 "prx_queue OR ptx_queue is NULL\n");
+		}
+	}
+
+	VETH_LOG(DLOG_DEBUG, "bspveth initstatis ok\n");
+
+}
+
+
+s32 veth_ioctl(struct net_device *pstr_dev, struct ifreq *pifr, s32 l_cmd)
+{
+	return -EFAULT;
+}
+
+
+struct net_device_stats *veth_stats(struct net_device *pstr_dev)
+{
+	return &(g_bspveth_dev.stats);
+}
+
+
+s32 veth_mac_set(struct net_device *pstr_dev, void *p_mac)
+{
+	struct sockaddr *str_addr = NULL;
+	u8 *puc_mac = NULL;
+
+	if (!pstr_dev || !p_mac)
+		return BSP_ERR_NULL_POINTER;
+
+	str_addr = (struct sockaddr *)p_mac;
+	puc_mac = (u8 *) str_addr->sa_data;
+
+	pstr_dev->dev_addr[0] = puc_mac[0];
+	pstr_dev->dev_addr[1] = puc_mac[1];
+	pstr_dev->dev_addr[2] = puc_mac[2];
+	pstr_dev->dev_addr[3] = puc_mac[3];
+	pstr_dev->dev_addr[4] = puc_mac[4];
+	pstr_dev->dev_addr[5] = puc_mac[5];
+
+	return BSP_OK;
+}
+
+void veth_tx_timeout(struct net_device *pstr_dev)
+{
+	VETH_LOG(DLOG_ERROR, "enter.\n");
+}
+
+
+static u32 veth_ethtool_get_link(struct net_device *dev)
+{
+	if (!bma_intf_is_link_ok() || !netif_running(g_bspveth_dev.pnetdev))
+		return 0;
+
+	if ((g_bspveth_dev.ptx_queue[0])
+	    && (g_bspveth_dev.ptx_queue[0]->pshmqhd_v))
+		return (u32)((BSPVETH_SHMQUEUE_INITOK ==
+			      g_bspveth_dev.ptx_queue[0]->pshmqhd_v->init)
+			      && netif_carrier_ok(dev));
+
+	return 0;
+}
+
+
+static void veth_ethtool_get_drvinfo(struct net_device *dev,
+				     struct ethtool_drvinfo *info)
+{
+	strlcpy(info->driver, MODULE_NAME, sizeof(info->driver));
+	strlcpy(info->version, VETH_VERSION, sizeof(info->version));
+
+	info->n_stats = VETH_GLOBAL_STATS_LEN;
+}
+
+
+static void veth_ethtool_get_stats(struct net_device *netdev,
+				   struct ethtool_stats *tool_stats, u64 *data)
+{
+	unsigned int i = 0;
+	char *p = NULL;
+	const struct veth_stats *p_stat = veth_gstrings_stats;
+	struct bspveth_rxtx_q *ptx_node = g_bspveth_dev.ptx_queue[0];
+	struct bspveth_rxtx_q *prx_node = g_bspveth_dev.prx_queue[0];
+
+	if (!data || !netdev || !tool_stats)
+		return;
+
+	for (i = 0; i < VETH_GLOBAL_STATS_LEN; i++) {
+		p = NULL;
+
+		switch (p_stat->type) {
+		case NET_STATS:
+			p = (char *)&g_bspveth_dev + p_stat->stat_offset;
+
+			break;
+
+		case QUEUE_RX_STATS:
+			if (prx_node)
+				p = (char *)prx_node + p_stat->stat_offset;
+
+			break;
+
+		case QUEUE_TX_STATS:
+			if (ptx_node)
+				p = (char *)ptx_node + p_stat->stat_offset;
+
+			break;
+
+		case VETH_STATS:
+			p = (char *)&g_bspveth_dev + p_stat->stat_offset;
+
+			break;
+
+		case SHMQ_RX_STATS:
+			if (prx_node && (prx_node->pshmqhd_v))
+				p = (char *)prx_node->pshmqhd_v
+					+ p_stat->stat_offset;
+
+			break;
+
+		case SHMQ_TX_STATS:
+			if (ptx_node && (ptx_node->pshmqhd_v))
+				p = (char *)ptx_node->pshmqhd_v
+					+ p_stat->stat_offset;
+
+			break;
+
+		default:
+			break;
+		}
+
+		if (p) {
+			if (p_stat->sizeof_stat == sizeof(u64))
+				data[i] = *(u64 *) p;
+			else
+				data[i] = *(u32 *) p;
+		} else {
+			data[i] = 0;
+		}
+
+		p_stat++;
+	}
+	/* BUG_ON(i != E1000_STATS_LEN); */
+}
+
+
+static void veth_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
+{
+	u8 *p = data;
+	unsigned int i;
+
+	if (!p)
+		return;
+
+	switch (stringset) {
+	case ETH_SS_STATS:
+		for (i = 0; i < VETH_GLOBAL_STATS_LEN; i++) {
+
+			memcpy_s(p, ETH_GSTRING_LEN,
+				 veth_gstrings_stats[i].stat_string,
+				 ETH_GSTRING_LEN);
+
+			p += ETH_GSTRING_LEN;
+		}
+
+		break;
+	}
+}
+
+
+static int veth_get_sset_count(struct net_device *netdev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		return VETH_GLOBAL_STATS_LEN;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+
+
+const struct ethtool_ops veth_ethtool_ops = {
+	.get_drvinfo = veth_ethtool_get_drvinfo,
+	.get_link = veth_ethtool_get_link,
+
+	.get_ethtool_stats = veth_ethtool_get_stats,
+	.get_strings = veth_get_strings,
+	.get_sset_count = veth_get_sset_count,
+
+};
+
+
+static const struct net_device_ops veth_ops = {
+	.ndo_open = veth_open,
+	.ndo_stop = veth_close,
+	.ndo_set_config = veth_config,
+	.ndo_start_xmit = veth_tx, /*lint !e64*/
+	.ndo_do_ioctl = veth_ioctl,
+	.ndo_get_stats = veth_stats,
+	.ndo_set_mac_address = veth_mac_set,
+	.ndo_tx_timeout = veth_tx_timeout,
+};
+
+
+
+void veth_netdev_func_init(struct net_device *dev)
+{
+	struct tag_pcie_comm_priv *priv =
+				(struct tag_pcie_comm_priv *)netdev_priv(dev);
+
+	VETH_LOG(DLOG_DEBUG, "eth init start\n");
+
+	ether_setup(dev);
+
+	dev->netdev_ops = &veth_ops;
+
+	dev->watchdog_timeo = BSPVETH_NET_TIMEOUT;
+	dev->mtu = BSPVETH_MTU_MAX;
+	dev->flags = IFF_BROADCAST;
+	dev->tx_queue_len = BSPVETH_MAX_QUE_DEEP;
+	dev->ethtool_ops = &veth_ethtool_ops;
+
+	/*
+	 * Then, initialize the priv field. This encloses the statistics
+	 * and a few private fields.
+	 */
+	memset_s(priv, sizeof(struct tag_pcie_comm_priv),
+			0, sizeof(struct tag_pcie_comm_priv));
+	strncpy(priv->net_type, MODULE_NAME, NET_TYPE_LEN);
+
+	/*9C:7D:A3:28:6F:F9*/
+	dev->dev_addr[0] = 0x9c;
+	dev->dev_addr[1] = 0x7d;
+	dev->dev_addr[2] = 0xa3;
+	dev->dev_addr[3] = 0x28;
+	dev->dev_addr[4] = 0x6f;
+	dev->dev_addr[5] = 0xf9;
+
+	VETH_LOG(DLOG_DEBUG, "set veth MAC addr OK\n");
+}
+
+
+s32 veth_send_one_pkt(struct sk_buff *skb, int queue)
+{
+	u32 head, next_to_free;
+	dma_addr_t dma = 0;
+	u32 off = 0;
+	int ret = 0;
+	int type = BSPVETH_TX;
+	struct bspveth_bd_info *pbdinfo_v;
+	struct bspveth_dma_bd *pbd_v;
+	struct bspveth_rxtx_q *ptx_queue = g_bspveth_dev.ptx_queue[queue];
+
+	if (!skb || !ptx_queue || !ptx_queue->pbdinfobase_v
+		|| !ptx_queue->pbdbase_v) {
+		INC_STATIS_RXTX(queue, null_point, 1, type);
+		return BSP_ERR_NULL_POINTER;
+	}
+
+	if (!bma_intf_is_link_ok()
+		|| (ptx_queue->pshmqhd_v->init != BSPVETH_SHMQUEUE_INITOK))
+		return -1;
+
+	head = ptx_queue->head;
+	next_to_free = ptx_queue->next_to_free;
+
+	/* stop to send pkt when queue is going to full */
+	if (!JUDGE_TX_QUEUE_SPACE(head, next_to_free, 3)) {
+		netif_stop_subqueue(g_bspveth_dev.pnetdev, queue);
+		//ptx_queue->s.tx_busy++;
+		VETH_LOG(DLOG_DEBUG,
+				"going to full, head: %d, nex to free: %d\n",
+				head, next_to_free);
+	}
+
+	if (!JUDGE_TX_QUEUE_SPACE(head, next_to_free, 1))
+		return BSP_NETDEV_TX_BUSY;
+
+	if (skb_shinfo(skb)->nr_frags) {
+		/* We don't support frags */
+		ret = skb_linearize(skb);
+		if (ret)
+			return -ENOMEM;
+	}
+
+
+	dma = dma_map_single(&(g_bspveth_dev.ppcidev->dev), skb->data, skb->len,
+			     DMA_TO_DEVICE);
+
+	ret = DMA_MAPPING_ERROR(&(g_bspveth_dev.ppcidev->dev), dma);
+	if (ret != BSP_OK) {
+		ret = BSP_ERR_DMA_ERR;
+		INC_STATIS_TX(queue, dma_mapping_err, 1);
+		goto failed;
+	}
+
+	off = dma & 0x3;
+	if (off)
+		INC_STATIS_TX(queue, dma_need_offset, 1);
+
+	pbdinfo_v = &(ptx_queue->pbdinfobase_v[head]);
+	pbdinfo_v->pdma_v = skb;
+	pbd_v = &(ptx_queue->pbdbase_v[head]);
+	pbd_v->dma_p = dma & (~((u64) 0x3));
+	pbd_v->off = off;
+	pbd_v->len = skb->len;
+
+	head = (head + 1) & BSPVETH_POINT_MASK;
+	ptx_queue->head = head;
+
+	VETH_LOG(DLOG_DEBUG,
+		 "[send]:oridma=0x%llx,skb=%p,skb->data=%p,skb->len=%d,head=%d,off=%d, alidma0x%llx\n",
+		 (u64) dma, skb, skb->data, skb->len, head, off,
+		 (u64) (dma & (~((u64) 0x3))));
+
+	return BSP_OK;
+
+failed:
+	return ret;
+}
+
+
+int veth_tx(struct sk_buff *skb, struct net_device *pstr_dev)
+{
+	u32 ul_ret = 0;
+	int queue = 0;
+
+	VETH_LOG(DLOG_DEBUG, "===============enter==================\n");
+
+	if (!skb || !pstr_dev) {
+		INC_STATIS_TX(queue, null_point, 1);
+		return NETDEV_TX_OK;
+	}
+
+	VETH_LOG(DLOG_DEBUG, "skb->data=%p\n", skb->data);
+	VETH_LOG(DLOG_DEBUG, "skb->len=%d\n", skb->len);
+
+	ul_ret = veth_send_one_pkt(skb, queue);
+
+
+	if (ul_ret == BSP_OK) {
+		INC_STATIS_TX_TONETSTATS(queue, pkt, 1, tx_packets);
+		INC_STATIS_TX_TONETSTATS(queue, pktbyte, skb->len, tx_bytes);
+
+#ifndef USE_TASKLET
+		(void)mod_timer(&g_bspveth_dev.dmatimer, jiffies_64);
+#else
+		tasklet_hi_schedule(&g_bspveth_dev.dma_task);
+#endif
+
+	} else {
+		VETH_LOG(DLOG_DEBUG,
+			"==========exit ret = %d=============\n",
+			ul_ret);
+		INC_STATIS_TX_TONETSTATS(queue, dropped_pkt, 1, tx_dropped);
+		dev_kfree_skb_any(skb);
+	}
+
+	return NETDEV_TX_OK;
+}
+
+
+s32 veth_free_txskb(struct bspveth_rxtx_q *ptx_queue, int queue)
+{
+	int i, work_limit;
+	int tail, next_to_free;
+	struct bspveth_bd_info *ptx_bdinfo_v;
+	struct sk_buff *skb;
+	struct bspveth_dma_bd *pbd_v;
+
+	if (!ptx_queue)
+		return BSP_ERR_AGAIN;
+
+	work_limit = ptx_queue->work_limit;
+	tail = ptx_queue->tail;
+	next_to_free = ptx_queue->next_to_free;
+
+	for (i = 0; i < work_limit; i++) {
+		if (next_to_free == tail)
+			break;
+
+		ptx_bdinfo_v = &(ptx_queue->pbdinfobase_v[next_to_free]);
+
+		pbd_v = &(ptx_queue->pbdbase_v[next_to_free]);
+
+		skb = ptx_bdinfo_v->pdma_v;
+
+		dma_unmap_single(&(g_bspveth_dev.ppcidev->dev),
+				 pbd_v->dma_p | pbd_v->off,
+				 pbd_v->len, DMA_TO_DEVICE);
+
+		if (skb)
+			dev_kfree_skb_any(skb);
+		else
+			VETH_LOG(DLOG_ERROR,
+				 "skb is NULL,tail=%d next_to_free=%d\n",
+				 tail, next_to_free);
+
+		ptx_bdinfo_v->pdma_v = NULL;
+		INC_STATIS_TX(queue, freetx, 1);
+
+		next_to_free = (next_to_free + 1) & BSPVETH_POINT_MASK;
+	}
+
+	ptx_queue->next_to_free = next_to_free;
+	tail = ptx_queue->tail;
+
+	if (next_to_free != tail) {
+		VETH_LOG(DLOG_DEBUG, "next_to_free(%d) != tail(%d)\n",
+			 next_to_free, tail);
+
+		return BSP_ERR_AGAIN;
+	}
+
+	return BSP_OK;
+}
+
+
+
+
+
+s32 veth_recv_pkt(struct bspveth_rxtx_q *prx_queue, int queue)
+{
+	int ret = BSP_OK, i, work_limit;
+	u32 tail, head;
+	struct bspveth_bd_info *prx_bdinfo_v;
+	struct bspveth_dma_bd *pbd_v;
+	struct sk_buff *skb;
+	dma_addr_t dma_map = 0;
+	u32 off = 0;
+
+	if (!prx_queue)
+		return BSP_ERR_AGAIN;
+
+	work_limit = prx_queue->work_limit;
+	tail = prx_queue->tail;
+
+	for (i = 0; i < work_limit; i++) {
+		head = prx_queue->head;
+		if (tail == head)
+			break;
+
+		prx_bdinfo_v = &(prx_queue->pbdinfobase_v[tail]);
+
+		skb = prx_bdinfo_v->pdma_v;
+		if (!skb) {
+			tail = (tail + 1) & BSPVETH_POINT_MASK;
+			continue;
+		}
+
+		prx_bdinfo_v->pdma_v = NULL;
+		pbd_v = &(prx_queue->pbdbase_v[tail]);
+
+		off = pbd_v->off;
+		if (off) {
+			skb_reserve(skb, off);
+			//pbd_v->len -= off;
+		}
+
+		dma_unmap_single(&(g_bspveth_dev.ppcidev->dev), pbd_v->dma_p,
+				 BSPVETH_SKB_SIZE, DMA_FROM_DEVICE);
+
+		tail = (tail + 1) & BSPVETH_POINT_MASK;
+
+		skb_put(skb, pbd_v->len);
+
+		skb->protocol = eth_type_trans(skb, g_bspveth_dev.pnetdev);
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+		VETH_LOG(DLOG_DEBUG,
+			 "skb->len=%d,skb->protocol=%d\n",
+			 skb->len, skb->protocol);
+
+		VETH_LOG(DLOG_DEBUG,
+			 "dma_p=0x%llx,dma_map=0x%llx,skb=%p,skb->data=%p,skb->len=%d,tail=%d,shm_off=%d\n",
+			 pbd_v->dma_p, dma_map, skb, skb->data,
+			 skb->len, tail, off);
+
+		VETH_LOG(DLOG_DEBUG,
+			"skb_transport_header=%p skb_mac_header=%p skb_network_header=%p\n",
+			 skb_transport_header(skb),
+			 skb_mac_header(skb), skb_network_header(skb));
+
+		VETH_LOG(DLOG_DEBUG,
+			  "skb->data=0x%p skb->tail=%08x skb->len=%08x\n",
+			  skb->data,
+			  (unsigned int)skb->tail,
+			  (unsigned int)skb->len);
+
+		INC_STATIS_RX_TONETSTATS(queue, pkt, 1, rx_packets);
+		INC_STATIS_RX_TONETSTATS(queue, pktbyte, skb->len, rx_bytes);
+
+		ret = netif_rx(skb);
+		if (ret == NET_RX_DROP) {
+			INC_STATIS_RX_TONETSTATS(queue, netifrx_err, 1,
+						 rx_errors);
+
+			VETH_LOG(DLOG_DEBUG, "netif_rx failed\n");
+		}
+	}
+
+	prx_queue->tail = tail;
+	head = prx_queue->head;
+
+	ret = veth_refill_rxskb(prx_queue, queue);
+	if (ret != BSP_OK)
+		VETH_LOG(DLOG_DEBUG, "veth_refill_rxskb failed\n");
+
+	if (tail != head) {
+		VETH_LOG(DLOG_DEBUG, "tail(%d) != head(%d)\n", tail, head);
+
+		return BSP_ERR_AGAIN;
+	}
+
+	return BSP_OK;
+}
+
+
+void veth_skbtrtimer_do(unsigned long data)
+{
+	int ret = 0;
+
+	ret = veth_skb_tr_task(data);
+	if (ret == BSP_ERR_AGAIN) {
+#ifndef USE_TASKLET
+		(void)mod_timer(&g_bspveth_dev.skbtrtimer, jiffies_64);
+#else
+		tasklet_hi_schedule(&g_bspveth_dev.skb_task);
+#endif
+	}
+}
+
+
+s32 veth_skbtimer_close(void)
+{
+#ifndef USE_TASKLET
+	(void)del_timer_sync(&(g_bspveth_dev.skbtrtimer));
+#else
+	tasklet_kill(&g_bspveth_dev.skb_task);
+#endif
+
+	VETH_LOG(DLOG_DEBUG, "veth skbtimer close ok\n");
+
+	return 0;
+}
+
+
+void veth_skbtimer_init(void)
+{
+#ifndef USE_TASKLET
+	setup_timer(&(g_bspveth_dev.skbtrtimer), veth_skbtrtimer_do,
+		    (unsigned long)&g_bspveth_dev);
+	(void)mod_timer(&g_bspveth_dev.skbtrtimer,
+			jiffies_64 + BSPVETH_SKBTIMER_INTERVAL);
+#else
+	tasklet_init(&g_bspveth_dev.skb_task, veth_skbtrtimer_do,
+		     (unsigned long)&g_bspveth_dev);
+#endif
+
+	VETH_LOG(DLOG_DEBUG, "veth skbtimer init OK\n");
+}
+
+
+void veth_netdev_exit(void)
+{
+	if (g_bspveth_dev.pnetdev) {
+		netif_stop_queue(g_bspveth_dev.pnetdev);
+		unregister_netdev(g_bspveth_dev.pnetdev);
+		free_netdev(g_bspveth_dev.pnetdev);
+
+		VETH_LOG(DLOG_DEBUG, "veth netdev exit OK.\n");
+	} else {
+		VETH_LOG(DLOG_DEBUG, "veth_dev.pnetdev NULL.\n");
+	}
+}
+
+
+static void veth_shutdown_task(struct work_struct *work)
+{
+	struct net_device *netdev = g_bspveth_dev.pnetdev;
+
+	VETH_LOG(DLOG_ERROR, "veth is going down, please restart it manual\n");
+
+	g_bspveth_dev.shutdown_cnt++;
+
+	if (netif_carrier_ok(netdev)) {
+		(void)bma_intf_unregister_int_notifier(&g_veth_int_nb);
+
+		netif_carrier_off(netdev);
+
+		bma_intf_set_open_status(g_bspveth_dev.bma_priv, DEV_CLOSE);
+
+		/* can't transmit any more */
+		netif_stop_queue(g_bspveth_dev.pnetdev);
+
+		(void)veth_skbtimer_close();
+
+		(void)veth_dmatimer_close_H();
+	}
+}
+
+
+s32 veth_netdev_init(void)
+{
+	s32 l_ret = 0;
+	struct net_device *netdev = NULL;
+
+#if (KERNEL_VERSION(4, 2, 0) < LINUX_VERSION_CODE)
+	netdev = alloc_netdev_mq(sizeof(struct tag_pcie_comm_priv),
+				BSPVETH_DEV_NAME, NET_NAME_UNKNOWN,
+				veth_netdev_func_init, 1);
+#else
+	netdev = alloc_netdev_mq(sizeof(struct tag_pcie_comm_priv),
+				BSPVETH_DEV_NAME, veth_netdev_func_init, 1);
+#endif
+	/* register netdev */
+	l_ret = register_netdev(netdev);
+	if (l_ret < 0) {
+		VETH_LOG(DLOG_ERROR, "register_netdev faild!ret=%d\n", l_ret);
+
+		return -ENODEV;
+	}
+
+	g_bspveth_dev.pnetdev = netdev;
+
+	VETH_LOG(DLOG_DEBUG, "veth netdev init OK\n");
+
+	INIT_WORK(&g_bspveth_dev.shutdown_task, veth_shutdown_task);
+
+	netif_carrier_off(netdev);
+
+	return BSP_OK;
+}
+
+
+int veth_skb_tr_task(unsigned long data)
+{
+	int rett = BSP_OK;
+	int retr = BSP_OK;
+	int i = 0;
+	int task_state = BSP_OK;
+	struct bspveth_rxtx_q *ptx_queue = NULL;
+	struct bspveth_rxtx_q *prx_queue = NULL;
+
+	for (i = 0; i < MAX_QUEUE_NUM; i++) {
+		prx_queue = g_bspveth_dev.prx_queue[i];
+		if (prx_queue) {
+			g_bspveth_dev.run_skbRXtask++;
+			retr = veth_recv_pkt(prx_queue, i);
+		}
+
+		ptx_queue = g_bspveth_dev.ptx_queue[i];
+		if (ptx_queue) {
+			g_bspveth_dev.run_skbFRtask++;
+			rett = veth_free_txskb(ptx_queue, i);
+			if (__netif_subqueue_stopped(g_bspveth_dev.pnetdev, i)
+				&& JUDGE_TX_QUEUE_SPACE(ptx_queue->head,
+				ptx_queue->next_to_free, 5)) {
+				netif_wake_subqueue(g_bspveth_dev.pnetdev, i);
+				VETH_LOG(DLOG_DEBUG,
+					"queue is free, head: %d, nex to free: %d\n",
+					ptx_queue->head,
+					ptx_queue->next_to_free);
+			}
+		}
+
+		if ((rett == BSP_ERR_AGAIN) || (retr == BSP_ERR_AGAIN))
+			task_state = BSP_ERR_AGAIN;
+	}
+
+	return task_state;
+}
+
+
+static int veth_int_handler(struct notifier_block *pthis, unsigned long ev,
+			    void *unuse)
+{
+	g_bspveth_dev.recv_int++;
+
+	if (netif_running(g_bspveth_dev.pnetdev)) {
+#ifndef USE_TASKLET
+		(void)mod_timer(&g_bspveth_dev.dmatimer, jiffies_64);
+#else
+		tasklet_schedule(&g_bspveth_dev.dma_task);
+
+#endif
+	} else {
+		VETH_LOG(DLOG_DEBUG, "netif is not running\n");
+	}
+
+	return IRQ_HANDLED;
+}
+
+void veth_dmaTXtimer_do_H(unsigned long data)
+{
+	int txret, rxret;
+
+	txret = veth_dma_task_H(BSPVETH_TX);
+
+	rxret = veth_dma_task_H(BSPVETH_RX);
+
+	if ((txret == BSP_ERR_AGAIN) || (rxret == BSP_ERR_AGAIN)) {
+#ifndef USE_TASKLET
+		(void)mod_timer(&g_bspveth_dev.dmatimer, jiffies_64);
+#else
+		tasklet_hi_schedule(&g_bspveth_dev.dma_task);
+#endif
+	}
+}
+
+s32 veth_dmatimer_close_H(void)
+{
+#ifndef USE_TASKLET
+	(void)del_timer_sync(&(g_bspveth_dev.dmatimer));
+#else
+	tasklet_kill(&g_bspveth_dev.dma_task);
+#endif
+
+	VETH_LOG(DLOG_DEBUG, "bspveth_dmatimer_close RXTX TIMER ok\n");
+
+	return 0;
+}
+
+
+void veth_dmatimer_init_H(void)
+{
+#ifndef USE_TASKLET
+	setup_timer(&(g_bspveth_dev.dmatimer), veth_dmaTXtimer_do_H,
+		    (unsigned long)&g_bspveth_dev);
+
+	(void)mod_timer(&g_bspveth_dev.dmatimer,
+			jiffies_64 + BSPVETH_DMATIMER_INTERVAL);
+#else
+	tasklet_init(&g_bspveth_dev.dma_task, veth_dmaTXtimer_do_H,
+		     (unsigned long)&g_bspveth_dev);
+#endif
+
+	VETH_LOG(DLOG_DEBUG, "bspveth_dmatimer_init RXTX TIMER OK\n");
+}
+
+
+s32 __check_dmacmp_H(struct bspveth_rxtx_q *prxtx_queue, u32 queue, u32 type)
+{
+	u32 cnt, len, host_head, host_tail, shm_head, shm_tail;
+	u16 start_dma = 0;
+	u16 dmacmperr = 0;
+	int i;
+	enum dma_direction_e dir;
+	struct bspveth_shmq_hd *pshmq_head = NULL;
+
+	if (!prxtx_queue || !prxtx_queue->pshmqhd_v)
+		return BSP_ERR_NULL_POINTER;
+
+	pshmq_head = prxtx_queue->pshmqhd_v;
+	dmacmperr = prxtx_queue->dmacmperr;
+	start_dma = prxtx_queue->start_dma;
+	if (!start_dma)
+		return BSP_OK;
+
+	if (dmacmperr > BSPVETH_WORK_LIMIT / 4) {
+		prxtx_queue->dmacmperr = 0;
+		prxtx_queue->start_dma = 0;
+
+		(void)veth_reset_dma(type);
+
+		if (type == BSPVETH_RX) {
+			VETH_LOG(DLOG_DEBUG,
+				 "bmc to host dma time out,dma count:%d,work_limit:%d\n",
+				 prxtx_queue->dmal_cnt,
+				 prxtx_queue->work_limit);
+
+			INC_STATIS_RX(queue, dma_faild, 1);
+		} else {
+			VETH_LOG(DLOG_DEBUG,
+				 "host to bmc dma time out,dma count:%d,work_limit:%d\n",
+				 prxtx_queue->dmal_cnt,
+				 prxtx_queue->work_limit);
+
+			INC_STATIS_TX(queue, dma_faild, 1);
+		}
+
+		if (prxtx_queue->dmal_cnt > 1)
+			prxtx_queue->work_limit = (prxtx_queue->dmal_cnt >> 1);
+
+		prxtx_queue->dma_overtime++;
+		if (prxtx_queue->dma_overtime > BSPVETH_MAX_QUE_DEEP) {
+			schedule_work(&g_bspveth_dev.shutdown_task);
+
+			return BSPVETH_DMA_BUSY;
+		}
+
+		return BSP_OK;
+	}
+
+	if (type == BSPVETH_RX)
+		dir = BMC_TO_HOST;
+	else
+		dir = HOST_TO_BMC;
+
+	for (i = 0; i < BSPVETH_CHECK_DMA_STATUS_TIMES; i++) {
+		if (bma_intf_check_dma_status(dir) == BSPVETH_DMA_OK)
+			break;
+
+		cpu_relax();
+
+		if (i > 20)
+			udelay(5);
+	}
+
+	if (i >= BSPVETH_CHECK_DMA_STATUS_TIMES) {
+		INC_STATIS_RXTX(queue, dma_busy, 1, type);
+		prxtx_queue->dmacmperr++;
+
+		return BSPVETH_DMA_BUSY;
+	}
+
+	prxtx_queue->start_dma = 0;
+	prxtx_queue->dma_overtime = 0;
+
+	if (type == BSPVETH_RX) {
+		cnt = prxtx_queue->dmal_cnt;
+		len = prxtx_queue->dmal_byte;
+
+		host_head = prxtx_queue->head;
+		shm_tail = pshmq_head->tail;
+
+		pshmq_head->tail = (shm_tail + cnt) & BSPVETH_POINT_MASK;
+		prxtx_queue->head = (host_head + cnt) & BSPVETH_POINT_MASK;
+
+		INC_STATIS_RX(queue, dmapkt, cnt);
+		INC_STATIS_RX(queue, dmapktbyte, len);
+	} else {
+
+		cnt = prxtx_queue->dmal_cnt;
+		len = prxtx_queue->dmal_byte;
+
+		host_tail = prxtx_queue->tail;
+		shm_head = pshmq_head->head;
+
+		prxtx_queue->tail = (host_tail + cnt) & BSPVETH_POINT_MASK;
+		pshmq_head->head = (shm_head + cnt) & BSPVETH_POINT_MASK;
+
+		INC_STATIS_TX(queue, dmapkt, cnt);
+		INC_STATIS_TX(queue, dmapktbyte, len);
+	}
+
+#ifndef USE_TASKLET
+	(void)mod_timer(&g_bspveth_dev.skbtrtimer, jiffies_64);
+#else
+	tasklet_hi_schedule(&g_bspveth_dev.skb_task);
+#endif
+
+	(void)bma_intf_int_to_bmc(g_bspveth_dev.bma_priv);
+
+	g_bspveth_dev.tobmc_int++;
+
+	return BSP_OK;
+}
+
+
+s32 __checkspace_H(struct bspveth_rxtx_q *prxtx_queue, u32 queue, u32 type,
+		   u32 *pcnt)
+{
+	int ret = BSP_OK;
+	u32 host_head, host_tail, host_nextfill;
+	u32 shm_head, shm_tail, shm_nextfill;
+	u32 shm_cnt, host_cnt, cnt_tmp, cnt;
+	struct bspveth_shmq_hd *pshmq_head = NULL;
+
+	if (!prxtx_queue || !prxtx_queue->pshmqhd_v)
+		return BSP_ERR_NULL_POINTER;
+
+	pshmq_head = prxtx_queue->pshmqhd_v;
+	host_head = prxtx_queue->head;
+	host_tail = prxtx_queue->tail;
+	host_nextfill = prxtx_queue->next_to_fill;
+	shm_head = pshmq_head->head;
+	shm_tail = pshmq_head->tail;
+	shm_nextfill = pshmq_head->next_to_fill;
+
+	switch (type) {
+	case BSPVETH_RX:
+		if (shm_tail == shm_head) {
+			INC_STATIS_RXTX(queue, shm_emp, 1, type);
+			ret = BSP_ERR_NOT_TO_HANDLE;
+			goto failed;
+		}
+
+		if (!JUDGE_RX_QUEUE_SPACE(host_head, host_nextfill, 1))
+			return -EFAULT;
+
+		shm_cnt = (shm_head - shm_tail) & BSPVETH_POINT_MASK;
+		cnt_tmp = min(shm_cnt, prxtx_queue->work_limit);
+
+		host_cnt = (host_nextfill - host_head) & BSPVETH_POINT_MASK;
+		cnt = min(cnt_tmp, host_cnt);
+
+		break;
+
+	case BSPVETH_TX:
+		if (host_tail == host_head) {
+			INC_STATIS_RXTX(queue, q_emp, 1, type);
+			ret = BSP_ERR_NOT_TO_HANDLE;
+			goto failed;
+		}
+
+		if (!JUDGE_TX_QUEUE_SPACE(shm_head, shm_nextfill, 1))
+			return -EFAULT;
+
+		host_cnt = (host_head - host_tail) & BSPVETH_POINT_MASK;
+		cnt_tmp = min(host_cnt, prxtx_queue->work_limit);
+		shm_cnt = (shm_nextfill - (shm_head + 1)) & BSPVETH_POINT_MASK;
+		cnt = min(cnt_tmp, shm_cnt);
+
+		break;
+
+	default:
+		INC_STATIS_RXTX(queue, type_err, 1, type);
+		ret = -EFAULT;
+		goto failed;
+	}
+
+	if (cnt > (BSPVETH_DMABURST_MAX * 7 / 8))
+		INC_STATIS_RXTX(queue, dma_burst, 1, type);
+
+#ifdef __UT_TEST
+	if (g_testdma) {
+		VETH_LOG(DLOG_ERROR,
+			 "[type %d],host_cnt=%d cnt_tmp=%d shm_cnt=%d cnt=%d\n",
+			 type, host_cnt, cnt_tmp, shm_cnt, cnt);
+	}
+#endif
+
+	*pcnt = cnt;
+
+	return BSP_OK;
+
+failed:
+	return ret;
+}
+
+
+int __make_dmalistbd_h2b_H(struct bspveth_rxtx_q *prxtx_queue, u32 cnt,
+			    u32 type)
+{
+	u32 i, len = 0, host_tail, shm_head, off;
+	struct bspveth_dmal *pdmalbase_v = NULL;
+	struct bspveth_shmq_hd *pshmq_head = NULL;
+	struct bspveth_bd_info *pbdinfobase_v = NULL;
+	struct bspveth_dma_bd *pbdbase_v = NULL;
+	struct bspveth_dma_shmbd *pshmbdbase_v = NULL;
+
+	if (!prxtx_queue)
+		return BSP_ERR_NULL_POINTER;
+
+	pdmalbase_v = prxtx_queue->pdmalbase_v;
+	pshmq_head = prxtx_queue->pshmqhd_v;
+	pbdinfobase_v = prxtx_queue->pbdinfobase_v;
+	pbdbase_v = prxtx_queue->pbdbase_v;
+	pshmbdbase_v = prxtx_queue->pshmbdbase_v;
+	if (!pdmalbase_v || !pshmq_head || !pbdinfobase_v
+		|| !pbdbase_v || !pshmbdbase_v)
+		return BSP_ERR_NULL_POINTER;
+
+	host_tail = prxtx_queue->tail;
+	shm_head = pshmq_head->head;
+
+	for (i = 0; i < cnt; i++) {
+		off = pbdbase_v[QUEUE_MASK(host_tail + i)].off;
+
+		if (i == (cnt - 1))
+			pdmalbase_v[i].chl = 0x9;
+		else
+			pdmalbase_v[i].chl = 0x0000001;
+		pdmalbase_v[i].len =
+		    (pbdinfobase_v[QUEUE_MASK(host_tail + i)].pdma_v)->len;
+		pdmalbase_v[i].slow =
+		    lower_32_bits(pbdbase_v[QUEUE_MASK(host_tail + i)].dma_p);
+		pdmalbase_v[i].shi =
+		    upper_32_bits(pbdbase_v[QUEUE_MASK(host_tail + i)].dma_p);
+		pdmalbase_v[i].dlow =
+		    lower_32_bits(pshmbdbase_v[QUEUE_MASK(shm_head + i)].dma_p);
+		pdmalbase_v[i].dhi = 0;
+
+		pshmbdbase_v[QUEUE_MASK(shm_head + i)].len = pdmalbase_v[i].len;
+
+		pdmalbase_v[i].len += off;
+
+		pshmbdbase_v[QUEUE_MASK(shm_head + i)].off = off;
+
+		len += pdmalbase_v[i].len;
+
+#ifdef __UT_TEST
+		if (g_testdma) {
+			struct sk_buff *skb =
+			    pbdinfobase_v[QUEUE_MASK(host_tail + i)].pdma_v;
+
+			VETH_LOG(DLOG_ERROR,
+				 "[%d][makebd-H2B]:chl=0x%x,len=%d,slow=0x%x,shi=0x%x,dlow=0x%x,dhi=0x%x,skb=%p,skb->data=%p,skb->len=%d,host_tail+i=%d,shm_head+i=%d,off=%d\n",
+				 i, pdmalbase_v[i].chl, pdmalbase_v[i].len,
+				 pdmalbase_v[i].slow, pdmalbase_v[i].shi,
+				 pdmalbase_v[i].dlow, pdmalbase_v[i].dhi,
+				 skb, skb->data, skb->len,
+				 QUEUE_MASK(host_tail + i),
+				 QUEUE_MASK(shm_head + i), off);
+		}
+#endif
+	}
+
+	//pdmalbase_v[i - 1].chl = 0x9;
+	pdmalbase_v[i].chl = 0x7;
+	pdmalbase_v[i].len = 0x0;
+	pdmalbase_v[i].slow = lower_32_bits((u64)prxtx_queue->pdmalbase_p);
+	pdmalbase_v[i].shi = upper_32_bits((u64)prxtx_queue->pdmalbase_p);
+	pdmalbase_v[i].dlow = 0;
+	pdmalbase_v[i].dhi = 0;
+
+	prxtx_queue->dmal_cnt = cnt;
+	prxtx_queue->dmal_byte = len;
+
+#ifdef __UT_TEST
+	if (g_testdma) {
+		VETH_LOG(DLOG_ERROR,
+			 "[END][makebd-H2B]:chl=0x%x,len=%d,slow=0x%x,shi=0x%x,dmal_cnt=%d,dmal_dir=%d,dmal_byte=%d,pdmalbase_v=%p\n",
+			 pdmalbase_v[i].chl, pdmalbase_v[i].len,
+			 pdmalbase_v[i].slow, pdmalbase_v[i].shi, cnt, type,
+			 len, pdmalbase_v);
+	}
+#endif
+
+	return 0;
+}
+
+
+int __make_dmalistbd_b2h_H(struct bspveth_rxtx_q *prxtx_queue, u32 cnt,
+			    u32 type)
+{
+	u32 i, len = 0, host_head, shm_tail, off;
+	struct bspveth_dmal *pdmalbase_v = NULL;
+	struct bspveth_shmq_hd *pshmq_head = NULL;
+	struct bspveth_bd_info *pbdinfobase_v = NULL;
+	struct bspveth_dma_bd *pbdbase_v = NULL;
+	struct bspveth_dma_shmbd *pshmbdbase_v = NULL;
+
+	if (!prxtx_queue) {
+		VETH_LOG(DLOG_ERROR,
+			 "[END][makebd-B2H]:prxtx_queue NULL!!!\n");
+		return BSP_ERR_NULL_POINTER;
+	}
+
+	pdmalbase_v = prxtx_queue->pdmalbase_v;
+	pshmq_head = prxtx_queue->pshmqhd_v;
+	pbdinfobase_v = prxtx_queue->pbdinfobase_v;
+	pbdbase_v = prxtx_queue->pbdbase_v;
+	pshmbdbase_v = prxtx_queue->pshmbdbase_v;
+	if (!pdmalbase_v || !pshmq_head || !pbdinfobase_v
+		|| !pbdbase_v || !pshmbdbase_v) {
+		VETH_LOG(DLOG_ERROR,
+			 "[END][makebd-B2H]:pdmalbase_v NULL!!!\n");
+		return BSP_ERR_NULL_POINTER;
+	}
+
+	host_head = prxtx_queue->head;
+	shm_tail = pshmq_head->tail;
+
+	for (i = 0; i < cnt; i++) {
+		off = pshmbdbase_v[QUEUE_MASK(shm_tail + i)].off;
+		if (i == (cnt - 1))
+			pdmalbase_v[i].chl = 0x9;
+		else
+			pdmalbase_v[i].chl = 0x0000001;
+		pdmalbase_v[i].len = pshmbdbase_v[QUEUE_MASK(shm_tail + i)].len;
+		pdmalbase_v[i].slow =
+		    lower_32_bits(pshmbdbase_v[QUEUE_MASK(shm_tail + i)].dma_p);
+		pdmalbase_v[i].shi = 0;
+		pdmalbase_v[i].dlow =
+		    lower_32_bits(pbdbase_v[QUEUE_MASK(host_head + i)].dma_p);
+		pdmalbase_v[i].dhi =
+		    upper_32_bits(pbdbase_v[QUEUE_MASK(host_head + i)].dma_p);
+		pdmalbase_v[i].len += off;
+
+		pbdbase_v[QUEUE_MASK(host_head + i)].off = off;
+		pbdbase_v[QUEUE_MASK(host_head + i)].len = pdmalbase_v[i].len;
+
+		len += pdmalbase_v[i].len;
+
+#ifdef __UT_TEST
+		if (g_testdma) {
+			struct sk_buff *skb =
+			    pbdinfobase_v[QUEUE_MASK(host_head + i)].pdma_v;
+
+			VETH_LOG(DLOG_ERROR,
+				 "[%d][makebd-B2H]:chl=0x%x,len=%d,slow=0x%x,shi=0x%x,dlow=0x%x,dhi=0x%x,skb=%p,skb->data=%p,skb->len=%d,shm_tail+i=%d,host_head+i=%d,off=%d\n",
+				 i, pdmalbase_v[i].chl, pdmalbase_v[i].len,
+				 pdmalbase_v[i].slow, pdmalbase_v[i].shi,
+				 pdmalbase_v[i].dlow, pdmalbase_v[i].dhi,
+				 skb, skb->data, skb->len,
+				 QUEUE_MASK(shm_tail + i),
+				 QUEUE_MASK(host_head + i), off);
+		}
+#endif
+	}
+
+	//pdmalbase_v[i - 1].chl = 0x9;
+	pdmalbase_v[i].chl = 0x0000007;
+	pdmalbase_v[i].len = 0x0;
+	pdmalbase_v[i].slow = lower_32_bits((u64)prxtx_queue->pdmalbase_p);
+	pdmalbase_v[i].shi = upper_32_bits((u64)prxtx_queue->pdmalbase_p);
+	pdmalbase_v[i].dlow = 0;
+	pdmalbase_v[i].dhi = 0;
+
+	prxtx_queue->dmal_cnt = cnt;
+	prxtx_queue->dmal_byte = len;
+
+#ifdef __UT_TEST
+	if (g_testdma) {
+		VETH_LOG(DLOG_ERROR,
+			 "[END][makebd-B2H]:chl=0x%x,len=%d,slow=0x%x,shi=0x%x,dmal_cnt=%d,dmal_dir=%d,dmal_byte=%d pdmalbase_v=%p\n",
+			 pdmalbase_v[i].chl, pdmalbase_v[i].len,
+			 pdmalbase_v[i].slow, pdmalbase_v[i].shi, cnt, type,
+			 len, pdmalbase_v);
+	}
+
+#endif
+
+	return 0;
+}
+
+
+s32 __start_dmalist_H(struct bspveth_rxtx_q *prxtx_queue, u32 cnt, u32 type)
+{
+	int ret = BSP_OK;
+	struct bma_dma_transfer_s dma_transfer = { 0 }; /*lint !e64*/
+
+	if (!prxtx_queue)
+		return -1;
+
+	switch (type) {
+	case BSPVETH_RX:
+		ret = __make_dmalistbd_b2h_H(prxtx_queue, cnt, type);
+		if (ret)
+			goto failed;
+		dma_transfer.dir = BMC_TO_HOST;
+
+		break;
+
+	case BSPVETH_TX:
+		ret = __make_dmalistbd_h2b_H(prxtx_queue, cnt, type);
+		if (ret)
+			goto failed;
+		dma_transfer.dir = HOST_TO_BMC;
+
+		break;
+
+	default:
+		ret = -1;
+		goto failed;
+
+	}
+
+	dma_transfer.type = DMA_LIST;
+	dma_transfer.transfer.list.dma_addr =
+	    (dma_addr_t) prxtx_queue->pdmalbase_p;
+
+	ret = bma_intf_start_dma(g_bspveth_dev.bma_priv, &dma_transfer);
+	if (ret < 0)
+		goto failed;
+
+	prxtx_queue->start_dma = 1;
+
+	return BSP_OK;
+
+failed:
+	return ret;
+}
+
+
+s32 __dma_rxtx_H(struct bspveth_rxtx_q *prxtx_queue, u32 queue, u32 type)
+{
+	int ret = BSP_OK;
+	u32 cnt;
+	u32 shm_init;
+	struct bspveth_shmq_hd *pshmq_head = NULL;
+
+	if (!prxtx_queue || !prxtx_queue->pshmqhd_v)
+		return BSP_ERR_NULL_POINTER;
+
+	pshmq_head = prxtx_queue->pshmqhd_v;
+	shm_init = pshmq_head->init;
+	if (shm_init != BSPVETH_SHMQUEUE_INITOK) {
+		INC_STATIS_RXTX(queue, shmqueue_noinit, 1, type);
+		ret = -EFAULT;
+		goto failed;
+	}
+
+	if (type == BSPVETH_RX) {
+		if (prxtx_queue->pshmqhd_v->head
+			== prxtx_queue->pshmqhd_v->tail)
+			return BSP_OK;
+	} else {
+		if (prxtx_queue->head == prxtx_queue->tail)
+			return BSP_OK;
+	}
+
+	if (prxtx_queue->dma_overtime > BSPVETH_MAX_QUE_DEEP)
+		return -EFAULT;
+
+	ret = __check_dmacmp_H(prxtx_queue, queue, type);
+	if (ret != BSP_OK) {
+		ret = -EFAULT;
+		goto failed;
+	}
+
+	ret = __checkspace_H(prxtx_queue, queue, type, &cnt);
+	if (ret != BSP_OK) {
+		ret = -EFAULT;
+		goto failed;
+	}
+
+	if (prxtx_queue->dmal_cnt > 1 && cnt < (prxtx_queue->work_limit / 2)
+	    && (type == BSPVETH_RX)) {
+		udelay(50);
+		prxtx_queue->dmal_cnt--;
+
+		return -EFAULT;
+	}
+
+	ret = __start_dmalist_H(prxtx_queue, cnt, type);
+	if (ret != BSP_OK) {
+		ret = -EFAULT;
+		goto failed;
+	}
+
+	if (cnt <= 16) {
+		ret = __check_dmacmp_H(prxtx_queue, queue, type);
+		if (ret != BSP_OK) {
+			ret = -EFAULT;
+			goto failed;
+		}
+	}
+
+	return BSP_OK;
+
+failed:
+	return ret;
+}
+
+
+int veth_dma_task_H(u32 type)
+{
+	int i;
+	struct bspveth_rxtx_q *prxtx_queue;
+
+	for (i = 0; i < MAX_QUEUE_NUM; i++) {
+		if (type == BSPVETH_RX) {
+			g_bspveth_dev.run_dmaRXtask++;
+			prxtx_queue = g_bspveth_dev.prx_queue[i];
+		} else {
+			g_bspveth_dev.run_dmaTXtask++;
+			prxtx_queue = g_bspveth_dev.ptx_queue[i];
+		}
+
+		if (prxtx_queue) {
+			struct bspveth_shmq_hd *pshmq_head
+				= prxtx_queue->pshmqhd_v;
+			(void)__dma_rxtx_H(prxtx_queue, i, type);
+			if (((type == BSPVETH_RX)
+			    && (pshmq_head->head != pshmq_head->tail))
+			    || ((type == BSPVETH_TX)
+			    && (prxtx_queue->head != prxtx_queue->tail)))
+				return BSP_ERR_AGAIN;
+		}
+	}
+
+	return BSP_OK;
+}
+
+#ifdef __UT_TEST
+
+s32 __atu_config_H(struct pci_dev *pdev, unsigned int region,
+		   unsigned int hostaddr_h, unsigned int hostaddr_l,
+		   unsigned int bmcaddr_h, unsigned int bmcaddr_l,
+		   unsigned int len)
+{
+	(void)pci_write_config_dword(pdev, 0x900,
+				     0x80000000 + (region & 0x00000007));
+	(void)pci_write_config_dword(pdev, 0x90c, hostaddr_l);
+	(void)pci_write_config_dword(pdev, 0x910, hostaddr_h);
+	(void)pci_write_config_dword(pdev, 0x914, hostaddr_l + len - 1);
+	(void)pci_write_config_dword(pdev, 0x918, bmcaddr_l);
+	(void)pci_write_config_dword(pdev, 0x91c, bmcaddr_h);
+	/*  atu ctrl1 reg   */
+	(void)pci_write_config_dword(pdev, 0x904, 0x00000000);
+	/*  atu ctrl2 reg   */
+	(void)pci_write_config_dword(pdev, 0x908, 0x80000000);
+
+	return 0;
+}
+
+void bspveth_atu_config_H(void)
+{
+	__atu_config_H(g_bspveth_dev.ppcidev,
+		       1,
+		       (sizeof(unsigned long) == 8) ?
+		       ((u64) (g_bspveth_dev.phostrtc_p) >> 32) : 0,
+		       ((u64) (g_bspveth_dev.phostrtc_p) & 0xffffffff),
+		       0, HOSTRTC_REG_BASE, HOSTRTC_REG_SIZE);
+
+	__atu_config_H(g_bspveth_dev.ppcidev,
+		       2,
+		       (sizeof(unsigned long) == 8) ?
+		       ((u64) (g_bspveth_dev.pshmpool_p) >> 32) : 0,
+		       ((u64) (g_bspveth_dev.pshmpool_p) & 0xffffffff),
+		       0, VETH_SHAREPOOL_BASE_INBMC, VETH_SHAREPOOL_SIZE);
+
+}
+
+void bspveth_pcie_free_H(void)
+{
+	struct pci_dev *pdev = g_bspveth_dev.ppcidev;
+
+	if (pdev)
+		pci_disable_device(pdev);
+	else
+		VETH_LOG(DLOG_ERROR, "bspveth_dev.ppcidev  IS NULL\n");
+
+	VETH_LOG(DLOG_DEBUG, "bspveth_pcie_exit_H ok\n");
+}
+
+#endif
+
+
+void bspveth_host_exit_H(void)
+{
+	int ret = 0;
+
+	ret = bma_intf_unregister_type((void **)&(g_bspveth_dev.bma_priv));
+	if (ret < 0) {
+		VETH_LOG(DLOG_ERROR, "bma_intf_unregister_type failed\n");
+
+		return;
+	}
+
+	VETH_LOG(DLOG_DEBUG, "bspveth host exit H OK\n");
+}
+
+
+s32 bspveth_host_init_H(void)
+{
+	int ret = 0;
+	struct bma_priv_data_s *bma_priv = NULL;
+
+	ret = bma_intf_register_type(TYPE_VETH, 0,
+					INTR_ENABLE, (void **)&bma_priv);
+	if (ret) {
+		ret = -1;
+		goto failed;
+	}
+
+	if (!bma_priv) {
+		VETH_LOG(DLOG_ERROR, "bma_priv is NULL\n");
+		return -1;
+	}
+
+	VETH_LOG(DLOG_DEBUG,
+		 "bma_intf_register_type pdev = %p, veth_swap_addr = %p, veth_swap_len = 0x%lx, veth_swap_phy_addr = 0x%lx\n",
+		 bma_priv->specific.veth.pdev,
+		 bma_priv->specific.veth.veth_swap_addr,
+		 bma_priv->specific.veth.veth_swap_len,
+		 bma_priv->specific.veth.veth_swap_phy_addr);
+
+	g_bspveth_dev.bma_priv = bma_priv;
+	g_bspveth_dev.ppcidev = bma_priv->specific.veth.pdev;
+
+	/*bspveth_dev.phostrtc_p = (u8 *)bar1_base;*/
+	/*bspveth_dev.phostrtc_v = (u8 *)bar1_remap;*/
+	g_bspveth_dev.pshmpool_p =
+			(u8 *)bma_priv->specific.veth.veth_swap_phy_addr;
+	g_bspveth_dev.pshmpool_v =
+			(u8 *)bma_priv->specific.veth.veth_swap_addr;
+	g_bspveth_dev.shmpoolsize = bma_priv->specific.veth.veth_swap_len;
+
+	VETH_LOG(DLOG_DEBUG, "bspveth host init H OK\n");
+
+	return BSP_OK;
+
+failed:
+	return ret;
+}
+
+
+static int __init veth_init(void)
+{
+	int ret = BSP_OK;
+	int lBufLen = 0;
+
+	if (!bma_intf_check_edma_supported())
+		return -ENXIO;
+
+	memset_s(&g_bspveth_dev, sizeof(g_bspveth_dev),
+		 0, sizeof(g_bspveth_dev));
+
+
+	lBufLen = snprintf(g_bspveth_dev.name, NET_NAME_LEN,
+			   "%s", BSPVETH_DEV_NAME);
+	if ((lBufLen < 0) || ((u32)lBufLen >= (NET_NAME_LEN))) {
+		VETH_LOG(DLOG_ERROR, "BSP_SNPRINTF lRet =0x%x\n", lBufLen);
+		return BSP_ERR_INVALID_STR;
+	}
+
+	ret = bspveth_host_init_H();
+	if (ret != BSP_OK) {
+		ret = -1;
+		goto failed1;
+	}
+
+	ret = veth_netdev_init();
+	if (ret != BSP_OK) {
+		ret = -1;
+		goto failed2;
+	}
+
+	GET_SYS_SECONDS(g_bspveth_dev.init_time);
+
+
+	return BSP_OK;
+
+failed2:
+	bspveth_host_exit_H();
+
+failed1:
+
+	return ret;
+}
+
+
+static void __exit veth_exit(void)
+{
+	veth_netdev_exit();
+
+	bspveth_host_exit_H();
+}
+
+MODULE_AUTHOR("HUAWEI TECHNOLOGIES CO., LTD.");
+MODULE_DESCRIPTION("HUAWEI VETH DRIVER");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VETH_VERSION);
+
+module_init(veth_init);
+module_exit(veth_exit);
diff --git a/drivers/net/ethernet/huawei/ibma/veth_hb.h b/drivers/net/ethernet/huawei/ibma/veth_hb.h
new file mode 100644
index 0000000..5f1f7fa
--- /dev/null
+++ b/drivers/net/ethernet/huawei/ibma/veth_hb.h
@@ -0,0 +1,578 @@
+/*
+*Huawei iBMA driver.
+*Copyright (c) 2017, Huawei Technologies Co., Ltd.
+*
+*This program is free software; you can redistribute it and/or
+*modify it under the terms of the GNU General Public License
+*as published by the Free Software Foundation; either version 2
+*of the License, or (at your option) any later version.
+*
+*This program is distributed in the hope that it will be useful,
+*but WITHOUT ANY WARRANTY; without even the implied warranty of
+*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*GNU General Public License for more details.
+*/
+
+
+#ifndef _VETH_HB_H_
+#define _VETH_HB_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <linux/interrupt.h>
+
+#define DEP_BMA
+
+#include "bma_include.h"
+#include "bma_ker_intf.h"
+
+
+#ifdef DRV_VERSION
+#define VETH_VERSION	MICRO_TO_STR(DRV_VERSION)
+#else
+#define VETH_VERSION	"0.2.9"
+#endif
+
+#define MODULE_NAME	"veth"
+#define BSP_VETH_T	u64
+
+#define BSP_OK				(0)
+#define BSP_ERR				(0xFFFFFFFF)
+#define BSP_NETDEV_TX_BUSY		(1)
+#define BSP_ERR_INIT_ERR		(BSP_NETDEV_TX_BUSY)
+#define BSP_ETH_ERR_BASE		(0x0FFFF000)
+#define BSP_ERR_OUT_OF_MEM		(BSP_ETH_ERR_BASE + 1)
+#define BSP_ERR_NULL_POINTER		(BSP_ETH_ERR_BASE + 2)
+#define BSP_ERR_INVALID_STR		(BSP_ETH_ERR_BASE + 3)
+#define BSP_ERR_INVALID_PARAM		(BSP_ETH_ERR_BASE + 4)
+#define BSP_ERR_INVALID_DATA		(BSP_ETH_ERR_BASE + 5)
+#define BSP_ERR_OUT_OF_RANGE		(BSP_ETH_ERR_BASE + 6)
+#define BSP_ERR_INVALID_CARD		(BSP_ETH_ERR_BASE + 7)
+#define BSP_ERR_INVALID_GRP		(BSP_ETH_ERR_BASE + 8)
+#define BSP_ERR_INVALID_ETH		(BSP_ETH_ERR_BASE + 9)
+#define BSP_ERR_SEND_ERR		(BSP_ETH_ERR_BASE + 10)
+#define BSP_ERR_DMA_ERR			(BSP_ETH_ERR_BASE + 11)
+#define BSP_ERR_RECV_ERR		(BSP_ETH_ERR_BASE + 12)
+#define BSP_ERR_SKB_ERR			(BSP_ETH_ERR_BASE + 13)
+#define BSP_ERR_DMA_ADDR_ERR		(BSP_ETH_ERR_BASE + 14)
+#define BSP_ERR_IOREMAP_ERR		(BSP_ETH_ERR_BASE + 15)
+#define BSP_ERR_LEN_ERR			(BSP_ETH_ERR_BASE + 16)
+#define BSP_ERR_STAT_ERR		(BSP_ETH_ERR_BASE + 17)
+#define BSP_ERR_AGAIN			(BSP_ETH_ERR_BASE + 18)
+#define BSP_ERR_NOT_TO_HANDLE		(BSP_ETH_ERR_BASE + 19)
+
+#define VETH_H2B_IRQ_NO			(113)
+#define SYSCTL_REG_BASE			(0x20000000)
+#define SYSCTL_REG_SIZE			(0x1000)
+#define PCIE1_REG_BASE			(0x29000000)
+#define PCIE1_REG_SIZE			(0x1000)
+#define VETH_SHAREPOOL_BASE_INBMC	(0x84820000)
+#define VETH_SHAREPOOL_SIZE		(0xdf000)
+#define VETH_SHAREPOOL_OFFSET		(0x10000)
+#define MAX_SHAREQUEUE_SIZE		(0x20000)
+
+#define BSPVETH_SHMBDBASE_OFFSET	(0x80)
+#define SHMDMAL_OFFSET			(0x10000)
+#define MAX_SHMDMAL_SIZE		(BSPVETH_DMABURST_MAX*32)
+
+#define BSPVETH_DMABURST_MAX		64
+#define BSPVETH_SKBTIMER_INTERVAL	(1)
+#define BSPVETH_DMATIMER_INTERVAL	(1)
+#define BSPVETH_CTLTIMER_INTERVAL	(10)
+#define BSPVETH_HDCMD_CHKTIMER_INTERVAL	(10)
+#define BSP_DMA_64BIT_MASK		(0xffffffffffffffffULL)
+#define BSP_DMA_32BIT_MASK		(0x00000000ffffffffULL)
+#define HOSTRTC_REG_BASE		(0x2f000000)
+#define HOSTRTC_REG_SIZE		(0x10000)
+#define REG_SYSCTL_HOSTINT_CLEAR	(0x44)
+#define SHIFT_SYSCTL_HOSTINT_CLEAR	(22)
+#define REG_SYSCTL_HOSTINT		(0xf4)
+#define SHIFT_SYSCTL_HOSTINT		(26)
+
+#define NET_TYPE_LEN			(16)
+
+#define MAX_QUEUE_NUM			(1)
+#define MAX_QUEUE_BDNUM			(128)
+#define BSPVETH_MAX_QUE_DEEP		(MAX_QUEUE_BDNUM)
+#define BSPVETH_POINT_MASK		(MAX_QUEUE_BDNUM-1)
+#define BSPVETH_WORK_LIMIT		(64)
+#define BSPVETH_CHECK_DMA_STATUS_TIMES	(120)
+
+#define REG_PCIE1_DMAREAD_ENABLE	(0xa18)
+#define SHIFT_PCIE1_DMAREAD_ENABLE	(0)
+#define REG_PCIE1_DMAWRITE_ENABLE	(0x9c4)
+#define SHIFT_PCIE1_DMAWRITE_ENABLE	(0)
+#define REG_PCIE1_DMAREAD_STATUS	(0xa10)
+#define SHIFT_PCIE1_DMAREAD_STATUS	(0)
+#define REG_PCIE1_DMAREADINT_CLEAR	(0xa1c)
+#define SHIFT_PCIE1_DMAREADINT_CLEAR	(0)
+#define REG_PCIE1_DMAWRITE_STATUS	(0x9bc)
+#define SHIFT_PCIE1_DMAWRITE_STATUS	(0)
+#define REG_PCIE1_DMAWRITEINT_CLEAR	(0x9c8)
+#define SHIFT_PCIE1_DMAWRITEINT_CLEAR	(0)
+
+#define BSPVETH_DMA_OK			(1)
+#define BSPVETH_DMA_BUSY		(0)
+#define BSPVETH_RX			(2)
+#define BSPVETH_TX			(3)
+#define HOSTRTC_INT_OFFSET		(0x10)
+#define BSPVETH_DEV_NAME		(MODULE_NAME)
+#define NET_NAME_LEN			(64)
+
+#ifndef PCI_VENDOR_ID_HUAWEI
+#define PCI_VENDOR_ID_HUAWEI		(0x19e5)
+#endif
+
+#define PCI_DEVICE_ID_KBOX		(0x1710)
+#define BSPVETH_MTU_MAX			(1500)
+#define BSPVETH_MTU_MIN			(64)
+#define BSPVETH_SKB_SIZE 		(1536)
+#define BSPVETH_NET_TIMEOUT		(5 * HZ)
+#define BSPVETH_QUEUE_TIMEOUT_10MS	(100)
+#define BSPVETH_SHMQUEUE_INITOK		(0x12)
+#define BSPVETH_LBK_TYPE		(0x800)
+
+#ifndef VETH_BMC
+#define BSPVETH_CACHELINE_SIZE		(64)
+#else
+#define BSPVETH_CACHELINE_SIZE		(32)
+#endif
+#define BSPVETH_HBCMD_WCMP		(0x44)
+#define BSPVETH_HBCMD_CMP		(0x55)
+#define BSPVETH_HBCMD_OK		(0x66)
+#define BSPVETH_HEART_WACK		(0x99)
+#define BSPVETH_HEART_ACK		(0xaa)
+
+#define BSPVETH_HBCMD_TIMEOUT		(1000)
+
+enum VEthHBCmd {
+	VETH_HBCMD_UNKOWN = 0x0,
+	VETH_HBCMD_SETIP,
+
+	VETH_HBCMD_MAX,
+};
+
+#define USE_TASKLET
+
+#define BSPVETH_ETHTOOL_BASE		0x89F0
+#define BSPVETH_ETHTOOL_TESTINT		(BSPVETH_ETHTOOL_BASE + 1)
+#define BSPVETH_ETHTOOL_TESTSHAREMEM	(BSPVETH_ETHTOOL_BASE + 2)
+#define BSPVETH_ETHTOOL_DUMPSHAREMEM	(BSPVETH_ETHTOOL_BASE + 3)
+#define BSPVETH_ETHTOOL_TESTDMA		(BSPVETH_ETHTOOL_BASE + 4)
+#define BSPVETH_ETHTOOL_RWPCIEREG	(BSPVETH_ETHTOOL_BASE + 5)
+#define BSPVETH_ETHTOOL_TESTLBK		(BSPVETH_ETHTOOL_BASE + 6)
+#define BSPVETH_ETHTOOL_INITSTATIS	(BSPVETH_ETHTOOL_BASE + 7)
+#define BSPVETH_HBCMD			(BSPVETH_ETHTOOL_BASE + 8)
+
+struct bspveth_test {
+	u32 intdirect;	/*0--H2B,1--B2H*/
+	u32 rwshmcheck;	/*0--w,1--r and check*/
+	u32 dshmbase;
+	u32 dshmlen;
+	u32 testdma;	/*0--disable,1---enable*/
+	u32 pcierw;	/*0--w,1---r*/
+	u32 reg;
+	u32 data;
+	u32 testlbk;	/*0--disable,1---enable*/
+};
+
+struct bspveth_hdcmd {
+	u32 cmd;
+	u32 stat;
+	u32 heart;
+	u32 err;
+	u32 sequence;
+	u32 len;
+	u8 data[256];
+};
+
+
+struct bspveth_rxtx_statis {
+	u64 pkt;
+	u64 pktbyte;
+	u64 refill;
+	u64 freetx;
+	u64 dmapkt;
+	u64 dmapktbyte;
+
+	u32 dropped_pkt;
+	u32 netifrx_err;
+	u32 null_point;
+	u32 retry_err;
+	u32 dma_mapping_err;
+	u32 allocskb_err;
+	u32 q_full;
+	u32 q_emp;
+	u32 shm_full;
+	u32 shm_emp;
+	u32 dma_busy;
+	u32 need_fill;
+	u32 need_free;
+	u32 dmacmp_err;
+	u32 type_err;
+	u32 shmqueue_noinit;
+	u32 shmretry_err;
+	u32 dma_earlyint;
+	u32 clr_dma_earlyint;
+	u32 clr_dma_int;
+	u32 dmarx_shmaddr_unalign;
+	u32 dmarx_hostaddr_unalign;
+	u32 dmatx_shmaddr_unalign;
+	u32 dmatx_hostaddr_unalign;
+	u32 dma_need_offset;
+	u32 lastdmadir_err;
+	u32 dma_faild;
+	u32 dma_burst;
+	u32 lbk_cnt;
+	u32 lbk_txerr;
+};
+
+struct bspveth_bd_info {
+	struct sk_buff *pdma_v;
+	u32 len;
+	unsigned long time_stamp;
+};
+
+struct bspveth_dma_shmbd {
+	u32 dma_p;
+	u32 len;
+	u32 off;
+};
+
+struct bspveth_shmq_hd {
+	u32 count;
+	u32 size;	/*count x sizeof(dmaBD)*/
+	u32 next_to_fill;
+	u32 next_to_free;
+	u32 head;
+	u32 tail;
+	u16 init;	/*  1--ok,0--nok*/
+};
+
+struct bspveth_dma_bd {
+	u64 dma_p;
+	u32 len;
+	u32 off;
+};
+
+
+struct bspveth_dmal {
+	u32 chl;
+	u32 len;
+	u32 slow;
+	u32 shi;
+	u32 dlow;
+	u32 dhi;
+};
+
+struct bspveth_rxtx_q {
+
+#ifndef VETH_BMC
+	struct bspveth_dma_bd *pbdbase_v;
+	u8 *pbdbase_p;
+#endif
+
+	struct bspveth_bd_info *pbdinfobase_v;
+	struct bspveth_shmq_hd *pshmqhd_v;
+	u8 *pshmqhd_p;
+
+	struct bspveth_dma_shmbd *pshmbdbase_v;
+	u8 *pshmbdbase_p;
+
+	struct bspveth_dmal *pdmalbase_v;
+	u8 *pdmalbase_p;
+
+	u32 dmal_cnt;
+	u32 dmal_byte;
+
+	u32 count;
+	u32 size;
+	u32 rx_buf_len;
+
+	u32 next_to_fill;
+	u32 next_to_free;
+	u32 head;
+	u32 tail;
+	u16 start_dma;
+	u16 dmacmperr;
+
+	u16 dma_overtime;
+
+	u32 work_limit;
+	struct bspveth_rxtx_statis s;
+};
+
+struct bspveth_device {
+	struct bspveth_rxtx_q *ptx_queue[MAX_QUEUE_NUM];
+	struct bspveth_rxtx_q *prx_queue[MAX_QUEUE_NUM];
+	struct net_device *pnetdev;
+	char name[NET_NAME_LEN];
+
+	struct pci_dev *ppcidev;
+	u8 *phostrtc_p;
+	u8 *phostrtc_v;
+
+	u8 *psysctl_v;
+	u8 *ppcie1_v;
+
+	u8 *pshmpool_p;
+	u8 *pshmpool_v;
+	u32 shmpoolsize;
+
+	u32 recv_int;
+	u32 tobmc_int;
+	u32 tohost_int;
+	u32 run_dmaTXtask;
+	u32 run_dmaRXtask;
+	u32 run_skbRXtask;
+	u32 run_skbFRtask;
+	u32 shutdown_cnt;
+	__kernel_time_t init_time;
+
+	spinlock_t reg_lock;
+#ifndef USE_TASKLET
+	struct timer_list skbtrtimer;
+	struct timer_list dmatimer;
+#else
+	struct tasklet_struct skb_task;
+	struct tasklet_struct dma_task;
+#endif
+
+	struct net_device_stats stats;
+	struct work_struct shutdown_task;
+#ifdef DEP_BMA
+	struct bma_priv_data_s *bma_priv;
+#else
+	void *edma_priv;
+#endif
+};
+
+struct tag_pcie_comm_priv {
+	char net_type[NET_TYPE_LEN];
+	struct net_device_stats stats;
+	int status;
+	int irq_enable;
+	int pcie_comm_rx_flag;
+	spinlock_t lock;
+};
+
+#define QUEUE_MASK(p)		((p) & (BSPVETH_POINT_MASK))
+
+
+#define CHECK_ADDR_ALIGN(addr, statis)\
+	do {                         \
+		if (addr & 0x3) \
+			statis;\
+	} while (0)
+
+#define VETH_LOG(lv, fmt, args...)    \
+	do {                          \
+		if (debug >= lv) \
+			printk(KERN_NOTICE "edma_veth: %s(), %d, " fmt, \
+				__func__, __LINE__, ## args); \
+	} while (0)
+
+#define PROC_P_STATIS(name, statis)\
+	do {                          \
+		PROC_DPRINTK("[%10s]:\t0x%llx", #name, statis);\
+	} while (0)
+
+#define  INC_STATIS_RX(queue, name, count) \
+	do {\
+		g_bspveth_dev.prx_queue[queue]->s.name += (count);\
+	} while (0)
+
+#define  INC_STATIS_TX(queue, name, count) \
+	do { \
+		g_bspveth_dev.ptx_queue[queue]->s.name += (count);\
+	} while (0)
+
+#define  INC_STATIS_RX_TONETSTATS(queue, name, count, netstats) \
+	do {\
+		g_bspveth_dev.prx_queue[queue]->s.name += (count);\
+		g_bspveth_dev.stats.netstats += count;\
+	} while (0)
+
+#define  INC_STATIS_TX_TONETSTATS(queue, name, count, netstats) \
+	do {                 \
+		g_bspveth_dev.ptx_queue[queue]->s.name += (count);\
+		g_bspveth_dev.stats.netstats += count;\
+	} while (0)
+
+#define  INC_STATIS_RXTX(queue, name, count, type) \
+	do {                 \
+		if (type == BSPVETH_RX)\
+			g_bspveth_dev.prx_queue[queue]->s.name += count;\
+		else\
+			g_bspveth_dev.ptx_queue[queue]->s.name += count;\
+	} while (0)
+
+#define  INC_STATIS_RXTX_TONETSTATS(queue, name, count, type, netstats) \
+	do {                 \
+		if (type == BSPVETH_RX)\
+			g_bspveth_dev.prx_queue[queue]->s.name += count;\
+		else\
+			g_bspveth_dev.ptx_queue[queue]->s.name += count;\
+		g_bspveth_dev.stats.netstats += count;\
+	} while (0)
+
+
+#define PROC_P_STATIS_QUEUE_RXTX_PARA(queue, name, type)\
+	do {                                        \
+		if (type == BSPVETH_RX) {\
+			if (g_bspveth_dev.prx_queue[queue])\
+				PROC_P_STATIS_QUEUE_32(queue, name, \
+				      g_bspveth_dev.prx_queue[queue]->name);\
+		} else {\
+			if (g_bspveth_dev.ptx_queue[queue])\
+				PROC_P_STATIS_QUEUE_32(queue, name, \
+				      g_bspveth_dev.ptx_queue[queue]->name);\
+		} \
+	} while (0)
+
+
+#define PROC_P_STATIS_QUEUE_RXTX_SHARE(queue, name, type)\
+	do {                                        \
+		if (type == BSPVETH_RX) {\
+			if (g_bspveth_dev.prx_queue[queue])\
+				PROC_P_STATIS_QUEUE_32(queue, name,\
+				g_bspveth_dev.prx_queue[queue]->pshmqhd_v->name);\
+		} else {\
+			if (g_bspveth_dev.ptx_queue[queue])\
+				PROC_P_STATIS_QUEUE_32(queue, name,\
+				g_bspveth_dev.ptx_queue[queue]->pshmqhd_v->name);\
+		} \
+	} while (0)
+
+#define PROC_P_STATIS_QUEUE_RXTX(queue, name, type)\
+	do {                                        \
+		if (type == BSPVETH_RX) {\
+			if (g_bspveth_dev.prx_queue[queue])\
+				PROC_P_STATIS_QUEUE(queue, name,\
+				      g_bspveth_dev.prx_queue[queue]->s.name);\
+		} else {\
+			if (g_bspveth_dev.ptx_queue[queue])\
+				PROC_P_STATIS_QUEUE(queue, name,\
+				      g_bspveth_dev.ptx_queue[queue]->s.name);\
+		} \
+	} while (0)
+
+#define PROC_P_STATIS_QUEUE_RXTXERR(queue, name, type)\
+	do {                                        \
+		if (type == BSPVETH_RX) {\
+			if (g_bspveth_dev.prx_queue[queue])\
+				PROC_P_STATIS_QUEUE_ERR(queue, name,\
+				     g_bspveth_dev.prx_queue[queue]->s.name);\
+		} else {\
+			if (g_bspveth_dev.ptx_queue[queue])\
+				PROC_P_STATIS_QUEUE_ERR(queue, name,\
+				      g_bspveth_dev.ptx_queue[queue]->s.name);\
+		} \
+	} while (0)
+
+#define PROC_P_STATIS_QUEUE_32(queue, name, statis)\
+	do {                                        \
+		len += sprintf(buf + len, "QUEUE[%d]--[%16s]:\t0x%x(%u)\r\n",\
+				queue, #name, statis, statis);\
+	} while (0)
+
+#define PROC_P_STATIS_QUEUE(queue, name, statis)\
+	do {                                        \
+		len += sprintf(buf + len, "QUEUE[%d]--[%16s]:\t0x%llx(%llu)\r\n",\
+				queue, #name, (u64)statis, (u64)statis);\
+	} while (0)
+
+#define PROC_P_STATIS_QUEUE_ERR(queue, name, statis)\
+	do {                                        \
+		len += sprintf(buf + len, "QUEUE[%d]--[%16s]:\t0x%x(%u)\r\n",\
+				queue, #name, statis, statis);\
+	} while (0)
+
+#define PROC_DPRINTK(fmt, args...)                       \
+	do {                                        \
+		len += sprintf(buf + len, fmt, ##args);   \
+	} while (0)
+
+
+
+#define JUDGE_TX_QUEUE_SPACE(head, tail, len) \
+	(((BSPVETH_MAX_QUE_DEEP + (tail) - (head) - 1) & BSPVETH_POINT_MASK) >= (len))
+
+#define JUDGE_RX_QUEUE_SPACE(head, tail, len) \
+	(((BSPVETH_MAX_QUE_DEEP + (tail) - (head)) & BSPVETH_POINT_MASK) > (len))
+
+
+
+#define DMA_MAPPING_ERROR(device, dma)	dma_mapping_error(device, dma)
+
+
+#ifndef VETH_BMC
+#define BSPVETH_UNMAP_DMA(data, len)\
+	do {\
+		dma_unmap_single(&(g_bspveth_dev.ppcidev->dev), \
+				 data, len, DMA_FROM_DEVICE);\
+	} while (0)
+#else
+#define BSPVETH_UNMAP_DMA(data, len)\
+	do {\
+		dma_unmap_single(NULL, data, len, DMA_FROM_DEVICE);\
+	} while (0)
+#endif
+
+int veth_tx(struct sk_buff *pstr_skb, struct net_device *pstr_dev);
+int veth_dma_task_H(u32 type);
+s32 veth_skbtimer_close(void);
+void veth_skbtimer_init(void);
+s32 veth_dmatimer_close_H(void);
+void veth_dmatimer_init_H(void);
+int veth_skb_tr_task(unsigned long data);
+
+s32 __dma_rxtx_H(struct bspveth_rxtx_q *prxtx_queue, u32 queue, u32 type);
+s32 veth_recv_pkt(struct bspveth_rxtx_q *prx_queue, int queue);
+s32 veth_free_txskb(struct bspveth_rxtx_q *ptx_queue, int queue);
+
+enum {
+	QUEUE_TX_STATS,
+	QUEUE_RX_STATS,
+	VETH_STATS,
+	SHMQ_TX_STATS,
+	SHMQ_RX_STATS,
+	NET_STATS,
+};
+
+struct veth_stats {
+	char stat_string[ETH_GSTRING_LEN];
+	int type;
+	int sizeof_stat;
+	int stat_offset;
+};
+
+#define NET_STAT(m)		NET_STATS, \
+	sizeof(((struct bspveth_device *)0)->m), \
+	offsetof(struct bspveth_device, m)
+
+#define VETH_STAT(m)		VETH_STATS, \
+	sizeof(((struct bspveth_device *)0)->m), \
+	offsetof(struct bspveth_device, m)
+
+#define QUEUE_TX_STAT(m)	QUEUE_TX_STATS, \
+	sizeof(((struct bspveth_rxtx_q *)0)->m), \
+	offsetof(struct bspveth_rxtx_q, m)
+#define QUEUE_RX_STAT(m)	QUEUE_RX_STATS, \
+	sizeof(((struct bspveth_rxtx_q *)0)->m), \
+	offsetof(struct bspveth_rxtx_q, m)
+
+#define SHMQ_RX_STAT(m)		SHMQ_RX_STATS, \
+	sizeof(((struct bspveth_shmq_hd *)0)->m), \
+	offsetof(struct bspveth_shmq_hd, m)
+
+#define SHMQ_TX_STAT(m)		SHMQ_TX_STATS, \
+	sizeof(((struct bspveth_shmq_hd *)0)->m), \
+	offsetof(struct bspveth_shmq_hd, m)
+
+#ifdef __cplusplus
+}
+#endif
+#endif
-- 
2.1.3

^ permalink raw reply related

* Motorcycle Owners List
From: Marlene Royle @ 2018-08-29 20:55 UTC (permalink / raw)
  To: netdev


Hi,

Greeting of the day!

Would you are interested in acquiring an email list of "Motorcycle Owners"? from USA.

We also having data of Harley Davidson Owners, Car Owners List, BMW Owners List, Luxury Car Owners List, RV Owners, Pick Up Truck Owners, Boat Owners, RV Owners List, HNI,Travelers List and many more...

Each record we will provide you with: Contact (First and Last name), Mailing Address and Emails Address.

All the contacts are opt-in verified, complete permission based and can be used for unlimited multi-channel marketing.

Let me know if you'd be interested in hearing more about it.

Waiting for your valuable and sincere reply.


Best Regards,
Marlene Royle
Research Analyst

^ permalink raw reply

* Re: [PATCH] net: sched: Fix memory exposure from short TCA_U32_SEL
From: Al Viro @ 2018-08-29 21:33 UTC (permalink / raw)
  To: Cong Wang
  Cc: Jamal Hadi Salim, Kees Cook, LKML, Jiri Pirko, David Miller,
	Linux Kernel Network Developers
In-Reply-To: <CAM_iQpXk48ip4dAKpc-HMwxf+wC6eYAK-atpsCSv7T7u7sLFMw@mail.gmail.com>

On Wed, Aug 29, 2018 at 12:07:09PM -0700, Cong Wang wrote:
> On Mon, Aug 27, 2018 at 5:03 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
> >
> > On Mon, Aug 27, 2018 at 02:31:41PM -0700, Cong Wang wrote:
> > > > I cant think of any challenges. Cong/Jiri? Would it require development
> > > > time classifiers/actions/qdiscs to sit in that directory (I suspect you
> > > > dont want them in include/net).
> > > > BTW, the idea of improving grep-ability of the code by prefixing the
> > > > ops appropriately makes sense. i.e we should have ops->cls_init,
> > > > ops->act_init etc.
> > >
> > > Hmm? Isn't struct tcf_proto_ops used and must be provided
> > > by each tc filter module? How does it work if you move it into
> > > net/sched/* for out-of-tree modules? Are they supposed to
> > > include "..../net/sched/tcf_proto.h"?? Or something else?
> >
> > If you care about out-of-tree modules, that could easily live in
> > include/net/tcf_proto.h, provided that it's not pulled by indirect
> > includes into hell knows how many places.  Try
> > make allmodconfig
> > make >/dev/null 2>&1
> > find -name '.*.cmd'|xargs grep sch_generic.h
> >
> > That finds 2977 files here, most of them having nothing to do with
> > net/sched.
> 
> 
> Moving it to include/net/tcf_proto.h is fine, as out-of-tree modules
> can still compile by modifying the included header path.
> 
> include/net/pkt_cls.h might be a choice here too.

Nowhere near as massive exposure (123 files vs. 2977), but still - do
ethernet drivers need that?  Because that's 77 out of 123...

^ permalink raw reply


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