Netdev List
 help / color / mirror / Atom feed
* RE: [PATCH net-next-2.6 v5 1/1] can: c_can: Added support for Bosch C_CAN controller
From: Bhupesh SHARMA @ 2011-02-08 11:36 UTC (permalink / raw)
  To: Wolfgang Grandegger
  Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org,
	netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Marc Kleine-Budde
In-Reply-To: <4D5128C8.1060208-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>



> -----Original Message-----
> From: Wolfgang Grandegger [mailto:wg-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org]
> Sent: Tuesday, February 08, 2011 4:58 PM
> To: Bhupesh SHARMA
> Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org; netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; Marc
> Kleine-Budde
> Subject: Re: [PATCH net-next-2.6 v5 1/1] can: c_can: Added support for
> Bosch C_CAN controller
> 
> On 02/08/2011 11:45 AM, Bhupesh SHARMA wrote:
> >> -----Original Message-----
> >> From: Wolfgang Grandegger [mailto:wg-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org]
> >> Sent: Tuesday, February 08, 2011 4:01 PM
> >> To: Bhupesh SHARMA
> >> Cc: socketcan-core-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org; netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; Marc
> >> Kleine-Budde
> >> Subject: Re: [PATCH net-next-2.6 v5 1/1] can: c_can: Added support
> for
> >> Bosch C_CAN controller
> >>
> >> On 02/08/2011 10:04 AM, Bhupesh SHARMA wrote:
> >>> Hi Wolfgang,
> >>>
> >>>>> + stats->rx_errors++;
> >>>>> + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
> >>>>> + cf->data[2] |= CAN_ERR_PROT_UNSPEC;
> >>>>> +
> >>>>> + switch (lec_type) {
> >>>>> + case LEC_STUFF_ERROR:
> >>>>> + netdev_dbg(dev, "stuff error\n");
> >>>>> + cf->data[2] |= CAN_ERR_PROT_STUFF;
> >>>>> + break;
> >>>>> +
> >>>>> + case LEC_FORM_ERROR:
> >>>>> + netdev_dbg(dev, "form error\n");
> >>>>> + cf->data[2] |= CAN_ERR_PROT_FORM;
> >>>>> + break;
> >>>>> +
> >>>>> + case LEC_ACK_ERROR:
> >>>>> + netdev_dbg(dev, "ack error\n");
> >>>>> + cf->data[2] |= (CAN_ERR_PROT_LOC_ACK |
> >>>>> + CAN_ERR_PROT_LOC_ACK_DEL);
> >>>>> + break;
> >>>>> +
> >>>>> + case LEC_BIT1_ERROR:
> >>>>> + netdev_dbg(dev, "bit1 error\n");
> >>>>> + cf->data[2] |= CAN_ERR_PROT_BIT1;
> >>>>> + break;
> >>>>> +
> >>>>> + case LEC_BIT0_ERROR:
> >>>>> + netdev_dbg(dev, "bit0 error\n");
> >>>>> + cf->data[2] |= CAN_ERR_PROT_BIT0;
> >>>>> + break;
> >>>>> +
> >>>>> + case LEC_CRC_ERROR:
> >>>>> + netdev_dbg(dev, "CRC error\n");
> >>>>> + cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
> >>>>> + CAN_ERR_PROT_LOC_CRC_DEL);
> >>>>> + break;
> >>>>> + }
> >>>
> >>> >From the C_CAN manual:
> >>>>
> >>>> "The LEC field holds a code which indicates the type of the last
> >> error
> >>>> to occur on the CAN bus. This field will be cleared to '0' when a
> >>>> message has been transferred (reception or transmission) without
> >> error.
> >>>> The unused code '7' may be written by the CPU to check for
> updates."
> >>>
> >>>> Not sure if it's necessary to reset the lec at init and after an
> >> error
> >>>> to 0x7 and check it. More below...
> >>>
> >>> I worked on your suggestion and instead found that the follow algo
> >> must be used
> >>> for reading updated `lec` values:
> >>> a. Init lec by 0x07 at start.
> >>> b. In function `c_can_err` check if lec is 0x7 (no bus error since
> >> this value was
> >>> written by CPU on status register) or 0x0 (no error). If so, return
> >> without
> >>> sending an error frame on stack. Else, check for the lec error type
> >> and
> >>> submit error frame on stack accordingly.
> >>> c. In case a lec error is found and served in `c_can_err` routine,
> >> write
> >>> lec value to 0x07 again in status reg to check for updated lec
> later.
> >>>
> >>> This is my understanding after reading the specs time and again and
> >>> implementing/testing the logic.
> >>>
> >>> Do you think this is fine or do you have any better approach?
> >>
> >> That's what I remember from the CC770 driver. Search for lec in:
> >>
> >>
> http://svn.berlios.de/wsvn/socketcan/trunk/kernel/2.6/drivers/net/can/c
> >> c770/cc770.c
> >>
> >
> > Seems similar. But step (c) mentioned above seems missing from
> cc770.c driver,
> > i.e. "In case a lec error is found and served (by means of sending an
> error
> > frame on the bus) write lec value to 0x07 again in status reg to
> check for updated
> > lec later-on. In my view seems logical to add it also.
> 
> It's done in cc770_status_interrupt():
> 
>         status = cc770_read_reg(priv, status);
>         /* Reset the status register including RXOK and TXOK */
>         cc770_write_reg(priv, status, STAT_LEC_MASK);
> 
Oops.. Sorry it seems I missed it.
Many Thanks for your help and comments.

Regards,
Bhupesh

^ permalink raw reply

* [net-next-2.6 01/16] e1000e: replace unbounded sprintf with snprintf
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: Bruce Allan, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Bruce Allan <bruce.w.allan@intel.com>

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/e1000e/netdev.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 5b916b0..80614c9 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -1843,7 +1843,9 @@ static int e1000_request_msix(struct e1000_adapter *adapter)
 	int err = 0, vector = 0;
 
 	if (strlen(netdev->name) < (IFNAMSIZ - 5))
-		sprintf(adapter->rx_ring->name, "%s-rx-0", netdev->name);
+		snprintf(adapter->rx_ring->name,
+			 sizeof(adapter->rx_ring->name) - 1,
+			 "%s-rx-0", netdev->name);
 	else
 		memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ);
 	err = request_irq(adapter->msix_entries[vector].vector,
@@ -1856,7 +1858,9 @@ static int e1000_request_msix(struct e1000_adapter *adapter)
 	vector++;
 
 	if (strlen(netdev->name) < (IFNAMSIZ - 5))
-		sprintf(adapter->tx_ring->name, "%s-tx-0", netdev->name);
+		snprintf(adapter->tx_ring->name,
+			 sizeof(adapter->tx_ring->name) - 1,
+			 "%s-tx-0", netdev->name);
 	else
 		memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ);
 	err = request_irq(adapter->msix_entries[vector].vector,
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 00/16][pull request] Intel Wired LAN Driver Updates
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: Jeff Kirsher, netdev, gospo, bphilips

The following series contains e1000e cleanup patches, the addition of igb
PF support for i350 devices and several ixgbe cleanup patches.

The following are changes since commit 2360d2e8f01043632d6b651672bec66c49892f94:
  enic: Update MAINTAINERS

and are available in the git repository at:
  master.kernel.org:/pub/scm/linux/kernel/git/jkirsher/net-next-2.6 master

Atita Shirwaikar (1):
  ixgbe: Adding 100MB FULL support in ethtool

Bruce Allan (4):
  e1000e: replace unbounded sprintf with snprintf
  e1000e: use correct pointer when memcpy'ing a 2-dimensional array
  e1000e: do not wakeup Tx queue until ready
  e1000e: return appropriate errors for 'ethtool -r'

Carolyn Wyborny (1):
  igb: Enable PF side of SR-IOV support for i350 devices

Don Skidmore (3):
  ixgbe: fix namespace issue with ixgbe_dcb_txq_to_tc
  ixgbe: cleanup namespace complaint by removing little used function
  ixgbe: cleanup ixgbe_init_mbx_params_pf namespace issue

John Fastabend (7):
  ixgbe: DCB, only reprogram HW if the FCoE priority is changed
  ixgbe: DCB, remove round robin mode on 82598 devices
  ixgbe: DCB, abstract out dcb_config from DCB hardware configuration
  ixgbe: DCB, implement 802.1Qaz routines
  ixgbe: DCB, do not reset on CEE pg changes
  ixgbe: DCB, remove RESET bit it is no longer needed
  ixgbe: dcb, use hardware independent routines

 drivers/net/e1000e/ethtool.c        |   13 ++-
 drivers/net/e1000e/netdev.c         |   13 +-
 drivers/net/igb/e1000_82575.c       |   10 ++-
 drivers/net/igb/e1000_mbx.c         |   38 +++----
 drivers/net/igb/igb_main.c          |    9 +-
 drivers/net/ixgbe/ixgbe.h           |    5 +-
 drivers/net/ixgbe/ixgbe_common.h    |    4 +-
 drivers/net/ixgbe/ixgbe_dcb.c       |  176 +++++++++++++++++++++++++++++-
 drivers/net/ixgbe/ixgbe_dcb.h       |   10 ++-
 drivers/net/ixgbe/ixgbe_dcb_82598.c |   94 ++++++++--------
 drivers/net/ixgbe/ixgbe_dcb_82598.h |   23 ++++-
 drivers/net/ixgbe/ixgbe_dcb_82599.c |  115 +++++++++++--------
 drivers/net/ixgbe/ixgbe_dcb_82599.h |   24 ++++-
 drivers/net/ixgbe/ixgbe_dcb_nl.c    |  211 ++++++++++++++++++++++++++--------
 drivers/net/ixgbe/ixgbe_ethtool.c   |   34 ++++++-
 drivers/net/ixgbe/ixgbe_main.c      |   18 +--
 drivers/net/ixgbe/ixgbe_mbx.c       |    2 +
 drivers/net/ixgbe/ixgbe_mbx.h       |    2 +
 include/linux/dcbnl.h               |    5 +
 19 files changed, 601 insertions(+), 205 deletions(-)

-- 
1.7.4


^ permalink raw reply

* [net-next-2.6 03/16] e1000e: do not wakeup Tx queue until ready
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: Bruce Allan, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Bruce Allan <bruce.w.allan@intel.com>

When restarting the adapter via calls to e1000e_down() followed by
e1000e_up() (for example when restarting autonegotiation via ethtool),
packets can be queued for transmit before link is actually up and
netif_carrier_on is set.  This was causing the watchdog_task to do an
extra unnecessary reset of the adapter.  Delaying the wakeup of the Tx
queue until link is up prevents the reset.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/e1000e/netdev.c |    5 +----
 1 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 80614c9..3c95d6b 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -3324,8 +3324,6 @@ int e1000e_up(struct e1000_adapter *adapter)
 		e1000_configure_msix(adapter);
 	e1000_irq_enable(adapter);
 
-	netif_wake_queue(adapter->netdev);
-
 	/* fire a link change interrupt to start the watchdog */
 	if (adapter->msix_entries)
 		ew32(ICS, E1000_ICS_LSC | E1000_ICR_OTHER);
@@ -3638,8 +3636,6 @@ static int e1000_open(struct net_device *netdev)
 
 	e1000_irq_enable(adapter);
 
-	netif_start_queue(netdev);
-
 	adapter->idle_check = true;
 	pm_runtime_put(&pdev->dev);
 
@@ -4265,6 +4261,7 @@ static void e1000_watchdog_task(struct work_struct *work)
 				phy->ops.cfg_on_link_up(hw);
 
 			netif_carrier_on(netdev);
+			netif_wake_queue(netdev);
 
 			if (!test_bit(__E1000_DOWN, &adapter->state))
 				mod_timer(&adapter->phy_info_timer,
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 02/16] e1000e: use correct pointer when memcpy'ing a 2-dimensional array
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: Bruce Allan, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Bruce Allan <bruce.w.allan@intel.com>

*e1000_gstrings_test is not the same size as e1000_gstrings_test.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/e1000e/ethtool.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index daa7fe4..0c08599 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -2006,7 +2006,7 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset,
 
 	switch (stringset) {
 	case ETH_SS_TEST:
-		memcpy(data, *e1000_gstrings_test, sizeof(e1000_gstrings_test));
+		memcpy(data, e1000_gstrings_test, sizeof(e1000_gstrings_test));
 		break;
 	case ETH_SS_STATS:
 		for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 04/16] e1000e: return appropriate errors for 'ethtool -r'
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: Bruce Allan, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Bruce Allan <bruce.w.allan@intel.com>

...when invoked while interface is not up or when auto-negotiation is
disabled as done by other drivers.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/e1000e/ethtool.c |   11 +++++++++--
 1 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 0c08599..65ef9b5 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -1963,8 +1963,15 @@ static int e1000_set_coalesce(struct net_device *netdev,
 static int e1000_nway_reset(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
-	if (netif_running(netdev))
-		e1000e_reinit_locked(adapter);
+
+	if (!netif_running(netdev))
+		return -EAGAIN;
+
+	if (!adapter->hw.mac.autoneg)
+		return -EINVAL;
+
+	e1000e_reinit_locked(adapter);
+
 	return 0;
 }
 
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 06/16] ixgbe: DCB, only reprogram HW if the FCoE priority is changed
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: John Fastabend, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: John Fastabend <john.r.fastabend@intel.com>

If the FCoE priority is not changing do not set the RESET and
APP_UPCHG bits. This causes unneeded HW resets and which can
cause unneeded LLDP frames and negotiations.

The current check is not sufficient because the FCoE priority
can change twice during a negotiation which results in the
bits being set. This occurs when the switch changes the
priority or when the link is reset with switches that do not
include the APP priority until after PFC has been negotiated.

This results in set_app being called with the local APP
priority. Then the negotiation completes and set_app
is called again with the peer APP priority. The check
fails so the device is reset and the above occurs again
resulting in an endless loop of resets.

By only resetting the device if the APP priority has really
changed we short circuit the loop.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_dcb_nl.c |   38 ++++++++++++++++++++++++++------------
 1 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
index bf566e8..4805835 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -353,6 +353,7 @@ static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority,
 static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	bool do_reset;
 	int ret;
 
 	if (!adapter->dcb_set_bitmap)
@@ -368,7 +369,9 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
 	 * Only take down the adapter if the configuration change
 	 * requires a reset.
 	 */
-	if (adapter->dcb_set_bitmap & BIT_RESETLINK) {
+	do_reset = adapter->dcb_set_bitmap & (BIT_RESETLINK | BIT_APP_UPCHG);
+
+	if (do_reset) {
 		while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
 			msleep(1);
 
@@ -408,7 +411,7 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
 		}
 	}
 
-	if (adapter->dcb_set_bitmap & BIT_RESETLINK) {
+	if (do_reset) {
 		if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) {
 			ixgbe_init_interrupt_scheme(adapter);
 			if (netif_running(netdev))
@@ -430,7 +433,7 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
 	if (adapter->dcb_cfg.pfc_mode_enable)
 		adapter->hw.fc.current_mode = ixgbe_fc_pfc;
 
-	if (adapter->dcb_set_bitmap & BIT_RESETLINK)
+	if (do_reset)
 		clear_bit(__IXGBE_RESETTING, &adapter->state);
 	adapter->dcb_set_bitmap = 0x00;
 	return ret;
@@ -568,18 +571,29 @@ static u8 ixgbe_dcbnl_setapp(struct net_device *netdev,
 	case DCB_APP_IDTYPE_ETHTYPE:
 #ifdef IXGBE_FCOE
 		if (id == ETH_P_FCOE) {
-			u8 tc;
-			struct ixgbe_adapter *adapter;
+			u8 old_tc;
+			struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
-			adapter = netdev_priv(netdev);
-			tc = adapter->fcoe.tc;
+			/* Get current programmed tc */
+			old_tc = adapter->fcoe.tc;
 			rval = ixgbe_fcoe_setapp(adapter, up);
-			if ((!rval) && (tc != adapter->fcoe.tc) &&
-			    (adapter->flags & IXGBE_FLAG_DCB_ENABLED) &&
-			    (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) {
+
+			if (rval ||
+			   !(adapter->flags & IXGBE_FLAG_DCB_ENABLED) ||
+			   !(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))
+				break;
+
+			/* The FCoE application priority may be changed multiple
+			 * times in quick sucession with switches that build up
+			 * TLVs. To avoid creating uneeded device resets this
+			 * checks the actual HW configuration and clears
+			 * BIT_APP_UPCHG if a HW configuration change is not
+			 * need
+			 */
+			if (old_tc == adapter->fcoe.tc)
+				adapter->dcb_set_bitmap &= ~BIT_APP_UPCHG;
+			else
 				adapter->dcb_set_bitmap |= BIT_APP_UPCHG;
-				adapter->dcb_set_bitmap |= BIT_RESETLINK;
-			}
 		}
 #endif
 		break;
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 05/16] igb: Enable PF side of SR-IOV support for i350 devices
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: Carolyn Wyborny, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Carolyn Wyborny <carolyn.wyborny@intel.com>

This patch adds full support for SR-IOV by enabling the PF side.
VF side has already been committed.

Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/igb/e1000_82575.c |   10 ++++++++--
 drivers/net/igb/e1000_mbx.c   |   38 ++++++++++++++++++--------------------
 drivers/net/igb/igb_main.c    |    9 +++++++--
 3 files changed, 33 insertions(+), 24 deletions(-)

diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index c1552b6..65c1833 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -238,9 +238,15 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
 		size = 14;
 	nvm->word_size = 1 << size;
 
-	/* if 82576 then initialize mailbox parameters */
-	if (mac->type == e1000_82576)
+	/* if part supports SR-IOV then initialize mailbox parameters */
+	switch (mac->type) {
+	case e1000_82576:
+	case e1000_i350:
 		igb_init_mbx_params_pf(hw);
+		break;
+	default:
+		break;
+	}
 
 	/* setup PHY parameters */
 	if (phy->media_type != e1000_media_type_copper) {
diff --git a/drivers/net/igb/e1000_mbx.c b/drivers/net/igb/e1000_mbx.c
index c474cdb..78d48c7 100644
--- a/drivers/net/igb/e1000_mbx.c
+++ b/drivers/net/igb/e1000_mbx.c
@@ -422,26 +422,24 @@ s32 igb_init_mbx_params_pf(struct e1000_hw *hw)
 {
 	struct e1000_mbx_info *mbx = &hw->mbx;
 
-	if (hw->mac.type == e1000_82576) {
-		mbx->timeout = 0;
-		mbx->usec_delay = 0;
-
-		mbx->size = E1000_VFMAILBOX_SIZE;
-
-		mbx->ops.read = igb_read_mbx_pf;
-		mbx->ops.write = igb_write_mbx_pf;
-		mbx->ops.read_posted = igb_read_posted_mbx;
-		mbx->ops.write_posted = igb_write_posted_mbx;
-		mbx->ops.check_for_msg = igb_check_for_msg_pf;
-		mbx->ops.check_for_ack = igb_check_for_ack_pf;
-		mbx->ops.check_for_rst = igb_check_for_rst_pf;
-
-		mbx->stats.msgs_tx = 0;
-		mbx->stats.msgs_rx = 0;
-		mbx->stats.reqs = 0;
-		mbx->stats.acks = 0;
-		mbx->stats.rsts = 0;
-	}
+	mbx->timeout = 0;
+	mbx->usec_delay = 0;
+
+	mbx->size = E1000_VFMAILBOX_SIZE;
+
+	mbx->ops.read = igb_read_mbx_pf;
+	mbx->ops.write = igb_write_mbx_pf;
+	mbx->ops.read_posted = igb_read_posted_mbx;
+	mbx->ops.write_posted = igb_write_posted_mbx;
+	mbx->ops.check_for_msg = igb_check_for_msg_pf;
+	mbx->ops.check_for_ack = igb_check_for_ack_pf;
+	mbx->ops.check_for_rst = igb_check_for_rst_pf;
+
+	mbx->stats.msgs_tx = 0;
+	mbx->stats.msgs_rx = 0;
+	mbx->stats.reqs = 0;
+	mbx->stats.acks = 0;
+	mbx->stats.rsts = 0;
 
 	return 0;
 }
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 200cc32..cb6bf7b 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -2287,9 +2287,14 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
 
 	spin_lock_init(&adapter->stats64_lock);
 #ifdef CONFIG_PCI_IOV
-	if (hw->mac.type == e1000_82576)
+	switch (hw->mac.type) {
+	case e1000_82576:
+	case e1000_i350:
 		adapter->vfs_allocated_count = (max_vfs > 7) ? 7 : max_vfs;
-
+		break;
+	default:
+		break;
+	}
 #endif /* CONFIG_PCI_IOV */
 	adapter->rss_queues = min_t(u32, IGB_MAX_RX_QUEUES, num_online_cpus());
 
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 07/16] ixgbe: DCB, remove round robin mode on 82598 devices
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: John Fastabend, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: John Fastabend <john.r.fastabend@intel.com>

Remove round robin configuration code for 82598 parts it
is not settable and is always false.

If we need/want this in the future we can add it back properly.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_dcb.h       |    1 -
 drivers/net/ixgbe/ixgbe_dcb_82598.c |    6 ++----
 drivers/net/ixgbe/ixgbe_main.c      |    1 -
 3 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_dcb.h b/drivers/net/ixgbe/ixgbe_dcb.h
index 1cfe38e..d0b2450 100644
--- a/drivers/net/ixgbe/ixgbe_dcb.h
+++ b/drivers/net/ixgbe/ixgbe_dcb.h
@@ -139,7 +139,6 @@ struct ixgbe_dcb_config {
 	struct tc_configuration tc_config[MAX_TRAFFIC_CLASS];
 	u8     bw_percentage[2][MAX_BW_GROUP]; /* One each for Tx/Rx */
 	bool   pfc_mode_enable;
-	bool   round_robin_enable;
 
 	enum dcb_rx_pba_cfg rx_pba_cfg;
 
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c
index 9a5e89c..19aa806 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82598.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c
@@ -146,10 +146,8 @@ static s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw,
 
 	/* Enable arbiter */
 	reg &= ~IXGBE_DPMCS_ARBDIS;
-	if (!(dcb_config->round_robin_enable)) {
-		/* Enable DFP and Recycle mode */
-		reg |= (IXGBE_DPMCS_TDPAC | IXGBE_DPMCS_TRM);
-	}
+	/* Enable DFP and Recycle mode */
+	reg |= (IXGBE_DPMCS_TDPAC | IXGBE_DPMCS_TRM);
 	reg |= IXGBE_DPMCS_TSOEF;
 	/* Configure Max TSO packet size 34KB including payload and headers */
 	reg |= (0x4 << IXGBE_DPMCS_MTSOS_SHIFT);
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 602078b..ef4a517 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -5169,7 +5169,6 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
 	adapter->dcb_cfg.bw_percentage[DCB_RX_CONFIG][0] = 100;
 	adapter->dcb_cfg.rx_pba_cfg = pba_equal;
 	adapter->dcb_cfg.pfc_mode_enable = false;
-	adapter->dcb_cfg.round_robin_enable = false;
 	adapter->dcb_set_bitmap = 0x00;
 	ixgbe_copy_dcb_cfg(&adapter->dcb_cfg, &adapter->temp_dcb_cfg,
 			   adapter->ring_feature[RING_F_DCB].indices);
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 09/16] ixgbe: DCB, implement 802.1Qaz routines
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: John Fastabend, netdev, gospo, bphilips
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: John Fastabend <john.r.fastabend@intel.com>

Implements 802.1Qaz support for ixgbe driver. Additionally,
this adds IEEE_8021QAZ_TSA_{} defines to dcbnl.h this is to
avoid having to use cryptic numeric codes for the TSA type.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
---
 drivers/net/ixgbe/ixgbe.h           |    4 ++
 drivers/net/ixgbe/ixgbe_dcb.c       |  102 +++++++++++++++++++++++++++++++++++
 drivers/net/ixgbe/ixgbe_dcb.h       |    4 ++
 drivers/net/ixgbe/ixgbe_dcb_82598.c |    2 +-
 drivers/net/ixgbe/ixgbe_dcb_nl.c    |   91 +++++++++++++++++++++++++++++++
 include/linux/dcbnl.h               |    5 ++
 6 files changed, 207 insertions(+), 1 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index 3b8c924..d04afde 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -334,6 +334,10 @@ struct ixgbe_adapter {
 	u16 bd_number;
 	struct work_struct reset_task;
 	struct ixgbe_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
+
+	/* DCB parameters */
+	struct ieee_pfc *ixgbe_ieee_pfc;
+	struct ieee_ets *ixgbe_ieee_ets;
 	struct ixgbe_dcb_config dcb_cfg;
 	struct ixgbe_dcb_config temp_dcb_cfg;
 	u8 dcb_set_bitmap;
diff --git a/drivers/net/ixgbe/ixgbe_dcb.c b/drivers/net/ixgbe/ixgbe_dcb.c
index d9bb670..0d7830f 100644
--- a/drivers/net/ixgbe/ixgbe_dcb.c
+++ b/drivers/net/ixgbe/ixgbe_dcb.c
@@ -34,6 +34,41 @@
 #include "ixgbe_dcb_82599.h"
 
 /**
+ * ixgbe_ieee_credits - This calculates the ieee traffic class
+ * credits from the configured bandwidth percentages. Credits
+ * are the smallest unit programable into the underlying
+ * hardware. The IEEE 802.1Qaz specification do not use bandwidth
+ * groups so this is much simplified from the CEE case.
+ */
+s32 ixgbe_ieee_credits(__u8 *bw, __u16 *refill, __u16 *max, int max_frame)
+{
+	int min_percent = 100;
+	int min_credit, multiplier;
+	int i;
+
+	min_credit = ((max_frame / 2) + DCB_CREDIT_QUANTUM - 1) /
+			DCB_CREDIT_QUANTUM;
+
+	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+		if (bw[i] < min_percent && bw[i])
+			min_percent = bw[i];
+	}
+
+	multiplier = (min_credit / min_percent) + 1;
+
+	/* Find out the hw credits for each TC */
+	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+		int val = min(bw[i] * multiplier, MAX_CREDIT_REFILL);
+		if (val < min_credit)
+			val = min_credit;
+		refill[i] = val;
+
+		max[i] = (bw[i] * MAX_CREDIT)/100;
+	}
+	return 0;
+}
+
+/**
  * ixgbe_dcb_calculate_tc_credits - Calculates traffic class credits
  * @ixgbe_dcb_config: Struct containing DCB settings.
  * @direction: Configuring either Tx or Rx.
@@ -236,3 +271,70 @@ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw,
 	return ret;
 }
 
+/* Helper routines to abstract HW specifics from DCB netlink ops */
+s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en)
+{
+	int ret = -EINVAL;
+
+	switch (hw->mac.type) {
+	case ixgbe_mac_82598EB:
+		ret = ixgbe_dcb_config_pfc_82598(hw, pfc_en);
+		break;
+	case ixgbe_mac_82599EB:
+	case ixgbe_mac_X540:
+		ret = ixgbe_dcb_config_pfc_82599(hw, pfc_en);
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+s32 ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw,
+			    u16 *refill, u16 *max, u8 *bwg_id, u8 *tsa)
+{
+	int i;
+	u8 prio_type[IEEE_8021QAZ_MAX_TCS];
+
+	/* Map TSA onto CEE prio type */
+	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
+		switch (tsa[i]) {
+		case IEEE_8021QAZ_TSA_STRICT:
+			prio_type[i] = 2;
+			break;
+		case IEEE_8021QAZ_TSA_ETS:
+			prio_type[i] = 0;
+			break;
+		default:
+			/* Hardware only supports priority strict or
+			 * ETS transmission selection algorithms if
+			 * we receive some other value from dcbnl
+			 * throw an error
+			 */
+			return -EINVAL;
+		}
+	}
+
+	switch (hw->mac.type) {
+	case ixgbe_mac_82598EB:
+		ixgbe_dcb_config_rx_arbiter_82598(hw, refill, max,
+							prio_type);
+		ixgbe_dcb_config_tx_desc_arbiter_82598(hw, refill, max,
+							bwg_id, prio_type);
+		ixgbe_dcb_config_tx_data_arbiter_82598(hw, refill, max,
+							bwg_id, prio_type);
+		break;
+	case ixgbe_mac_82599EB:
+	case ixgbe_mac_X540:
+		ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max,
+						  bwg_id, prio_type);
+		ixgbe_dcb_config_tx_desc_arbiter_82599(hw, refill, max,
+						       bwg_id, prio_type);
+		ixgbe_dcb_config_tx_data_arbiter_82599(hw, refill, max,
+						       bwg_id, prio_type);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
diff --git a/drivers/net/ixgbe/ixgbe_dcb.h b/drivers/net/ixgbe/ixgbe_dcb.h
index aa6cb5f..4e4a641 100644
--- a/drivers/net/ixgbe/ixgbe_dcb.h
+++ b/drivers/net/ixgbe/ixgbe_dcb.h
@@ -150,10 +150,14 @@ struct ixgbe_dcb_config {
 void ixgbe_dcb_unpack_pfc(struct ixgbe_dcb_config *cfg, u8 *pfc_en);
 
 /* DCB credits calculation */
+s32 ixgbe_ieee_credits(__u8 *bw, __u16 *refill, __u16 *max, int max_frame);
 s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *,
 				   struct ixgbe_dcb_config *, int, u8);
 
 /* DCB hw initialization */
+s32 ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw,
+			    u16 *refill, u16 *max, u8 *bwg_id, u8 *prio_type);
+s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en);
 s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *);
 
 /* DCB definitions for credit calculation */
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c
index d128806..2965edc 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82598.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c
@@ -291,7 +291,7 @@ out:
  * Configure queue statistics registers, all queues belonging to same traffic
  * class uses a single set of queue statistics counters.
  */
-static s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw)
+s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw)
 {
 	u32 reg = 0;
 	u8  i   = 0;
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
index 6ab1f1a..e75a3c9 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -606,7 +606,98 @@ static u8 ixgbe_dcbnl_setapp(struct net_device *netdev,
 	return rval;
 }
 
+static int ixgbe_dcbnl_ieee_getets(struct net_device *dev,
+				   struct ieee_ets *ets)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(dev);
+	struct ieee_ets *my_ets = adapter->ixgbe_ieee_ets;
+
+	/* No IEEE PFC settings available */
+	if (!my_ets)
+		return -EINVAL;
+
+	ets->ets_cap = MAX_TRAFFIC_CLASS;
+	ets->cbs = my_ets->cbs;
+	memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw));
+	memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw));
+	memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa));
+	memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc));
+	return 0;
+}
+
+static int ixgbe_dcbnl_ieee_setets(struct net_device *dev,
+				   struct ieee_ets *ets)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(dev);
+	__u16 refill[IEEE_8021QAZ_MAX_TCS], max[IEEE_8021QAZ_MAX_TCS];
+	int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
+	int err;
+	/* naively give each TC a bwg to map onto CEE hardware */
+	__u8 bwg_id[IEEE_8021QAZ_MAX_TCS] = {0, 1, 2, 3, 4, 5, 6, 7};
+
+	if (!adapter->ixgbe_ieee_ets) {
+		adapter->ixgbe_ieee_ets = kmalloc(sizeof(struct ieee_ets),
+						  GFP_KERNEL);
+		if (!adapter->ixgbe_ieee_ets)
+			return -ENOMEM;
+	}
+
+
+	memcpy(adapter->ixgbe_ieee_ets, ets, sizeof(*adapter->ixgbe_ieee_ets));
+
+	ixgbe_ieee_credits(ets->tc_tx_bw, refill, max, max_frame);
+	err = ixgbe_dcb_hw_ets_config(&adapter->hw, refill, max,
+				      bwg_id, ets->tc_tsa);
+	return err;
+}
+
+static int ixgbe_dcbnl_ieee_getpfc(struct net_device *dev,
+				   struct ieee_pfc *pfc)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(dev);
+	struct ieee_pfc *my_pfc = adapter->ixgbe_ieee_pfc;
+	int i;
+
+	/* No IEEE PFC settings available */
+	if (!my_pfc)
+		return -EINVAL;
+
+	pfc->pfc_cap = MAX_TRAFFIC_CLASS;
+	pfc->pfc_en = my_pfc->pfc_en;
+	pfc->mbc = my_pfc->mbc;
+	pfc->delay = my_pfc->delay;
+
+	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+		pfc->requests[i] = adapter->stats.pxoffrxc[i];
+		pfc->indications[i] = adapter->stats.pxofftxc[i];
+	}
+
+	return 0;
+}
+
+static int ixgbe_dcbnl_ieee_setpfc(struct net_device *dev,
+				   struct ieee_pfc *pfc)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(dev);
+	int err;
+
+	if (!adapter->ixgbe_ieee_pfc) {
+		adapter->ixgbe_ieee_pfc = kmalloc(sizeof(struct ieee_pfc),
+						  GFP_KERNEL);
+		if (!adapter->ixgbe_ieee_pfc)
+			return -ENOMEM;
+	}
+
+	memcpy(adapter->ixgbe_ieee_pfc, pfc, sizeof(*adapter->ixgbe_ieee_pfc));
+	err = ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc->pfc_en);
+	return err;
+}
+
 const struct dcbnl_rtnl_ops dcbnl_ops = {
+	.ieee_getets	= ixgbe_dcbnl_ieee_getets,
+	.ieee_setets	= ixgbe_dcbnl_ieee_setets,
+	.ieee_getpfc	= ixgbe_dcbnl_ieee_getpfc,
+	.ieee_setpfc	= ixgbe_dcbnl_ieee_setpfc,
 	.getstate	= ixgbe_dcbnl_get_state,
 	.setstate	= ixgbe_dcbnl_set_state,
 	.getpermhwaddr	= ixgbe_dcbnl_get_perm_hw_addr,
diff --git a/include/linux/dcbnl.h b/include/linux/dcbnl.h
index 68cd248..cd8d518 100644
--- a/include/linux/dcbnl.h
+++ b/include/linux/dcbnl.h
@@ -25,6 +25,11 @@
 /* IEEE 802.1Qaz std supported values */
 #define IEEE_8021QAZ_MAX_TCS	8
 
+#define IEEE_8021QAZ_TSA_STRICT		0
+#define IEEE_8021QAZ_TSA_CB_SHABER	1
+#define IEEE_8021QAZ_TSA_ETS		2
+#define IEEE_8021QAZ_TSA_VENDOR		255
+
 /* This structure contains the IEEE 802.1Qaz ETS managed object
  *
  * @willing: willing bit in ETS configuratin TLV
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 08/16] ixgbe: DCB, abstract out dcb_config from DCB hardware configuration
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: John Fastabend, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: John Fastabend <john.r.fastabend@intel.com>

Currently the routines that configure the HW for DCB require a
ixgbe_dcb_config structure. This structure was designed to support
the CEE standard and does not match the IEEE standard well.

This patch changes the HW routines in ixgbe_dcb_8259x.{ch} to use
raw pfc and bandwidth values. This requires some parsing of the DCB
configuration but makes the HW routines independent of the data
structure that contains the DCB configuration.

The primary advantage to doing this is we can do HW setup directly
from the 802.1Qaz ops without having to arbitrarily encapsulate this
data into the CEE structure.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_dcb.c       |   74 ++++++++++++++++++++++-
 drivers/net/ixgbe/ixgbe_dcb.h       |    1 +
 drivers/net/ixgbe/ixgbe_dcb_82598.c |   86 ++++++++++++++------------
 drivers/net/ixgbe/ixgbe_dcb_82598.h |   23 ++++++-
 drivers/net/ixgbe/ixgbe_dcb_82599.c |  115 ++++++++++++++++++++---------------
 drivers/net/ixgbe/ixgbe_dcb_82599.h |   24 ++++++-
 drivers/net/ixgbe/ixgbe_dcb_nl.c    |    9 ++-
 7 files changed, 230 insertions(+), 102 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_dcb.c b/drivers/net/ixgbe/ixgbe_dcb.c
index d16c260..d9bb670 100644
--- a/drivers/net/ixgbe/ixgbe_dcb.c
+++ b/drivers/net/ixgbe/ixgbe_dcb.c
@@ -141,6 +141,59 @@ out:
 	return ret_val;
 }
 
+void ixgbe_dcb_unpack_pfc(struct ixgbe_dcb_config *cfg, u8 *pfc_en)
+{
+	int i;
+
+	*pfc_en = 0;
+	for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
+		*pfc_en |= (cfg->tc_config[i].dcb_pfc & 0xF) << i;
+}
+
+void ixgbe_dcb_unpack_refill(struct ixgbe_dcb_config *cfg, int direction,
+			     u16 *refill)
+{
+	struct tc_bw_alloc *p;
+	int i;
+
+	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+		p = &cfg->tc_config[i].path[direction];
+		refill[i] = p->data_credits_refill;
+	}
+}
+
+void ixgbe_dcb_unpack_max(struct ixgbe_dcb_config *cfg, u16 *max)
+{
+	int i;
+
+	for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
+		max[i] = cfg->tc_config[i].desc_credits_max;
+}
+
+void ixgbe_dcb_unpack_bwgid(struct ixgbe_dcb_config *cfg, int direction,
+			    u8 *bwgid)
+{
+	struct tc_bw_alloc *p;
+	int i;
+
+	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+		p = &cfg->tc_config[i].path[direction];
+		bwgid[i] = p->bwg_id;
+	}
+}
+
+void ixgbe_dcb_unpack_prio(struct ixgbe_dcb_config *cfg, int direction,
+			    u8 *ptype)
+{
+	struct tc_bw_alloc *p;
+	int i;
+
+	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+		p = &cfg->tc_config[i].path[direction];
+		ptype[i] = p->prio_type;
+	}
+}
+
 /**
  * ixgbe_dcb_hw_config - Config and enable DCB
  * @hw: pointer to hardware structure
@@ -152,13 +205,30 @@ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw,
                         struct ixgbe_dcb_config *dcb_config)
 {
 	s32 ret = 0;
+	u8 pfc_en;
+	u8 ptype[MAX_TRAFFIC_CLASS];
+	u8 bwgid[MAX_TRAFFIC_CLASS];
+	u16 refill[MAX_TRAFFIC_CLASS];
+	u16 max[MAX_TRAFFIC_CLASS];
+
+	/* Unpack CEE standard containers */
+	ixgbe_dcb_unpack_pfc(dcb_config, &pfc_en);
+	ixgbe_dcb_unpack_refill(dcb_config, DCB_TX_CONFIG, refill);
+	ixgbe_dcb_unpack_max(dcb_config, max);
+	ixgbe_dcb_unpack_bwgid(dcb_config, DCB_TX_CONFIG, bwgid);
+	ixgbe_dcb_unpack_prio(dcb_config, DCB_TX_CONFIG, ptype);
+
 	switch (hw->mac.type) {
 	case ixgbe_mac_82598EB:
-		ret = ixgbe_dcb_hw_config_82598(hw, dcb_config);
+		ret = ixgbe_dcb_hw_config_82598(hw, dcb_config->rx_pba_cfg,
+						pfc_en, refill, max, bwgid,
+						ptype);
 		break;
 	case ixgbe_mac_82599EB:
 	case ixgbe_mac_X540:
-		ret = ixgbe_dcb_hw_config_82599(hw, dcb_config);
+		ret = ixgbe_dcb_hw_config_82599(hw, dcb_config->rx_pba_cfg,
+						pfc_en, refill, max, bwgid,
+						ptype);
 		break;
 	default:
 		break;
diff --git a/drivers/net/ixgbe/ixgbe_dcb.h b/drivers/net/ixgbe/ixgbe_dcb.h
index d0b2450..aa6cb5f 100644
--- a/drivers/net/ixgbe/ixgbe_dcb.h
+++ b/drivers/net/ixgbe/ixgbe_dcb.h
@@ -147,6 +147,7 @@ struct ixgbe_dcb_config {
 };
 
 /* DCB driver APIs */
+void ixgbe_dcb_unpack_pfc(struct ixgbe_dcb_config *cfg, u8 *pfc_en);
 
 /* DCB credits calculation */
 s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *,
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c
index 19aa806..d128806 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82598.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c
@@ -38,15 +38,14 @@
  *
  * Configure packet buffers for DCB mode.
  */
-static s32 ixgbe_dcb_config_packet_buffers_82598(struct ixgbe_hw *hw,
-						 struct ixgbe_dcb_config *dcb_config)
+static s32 ixgbe_dcb_config_packet_buffers_82598(struct ixgbe_hw *hw, u8 rx_pba)
 {
 	s32 ret_val = 0;
 	u32 value = IXGBE_RXPBSIZE_64KB;
 	u8  i = 0;
 
 	/* Setup Rx packet buffer sizes */
-	switch (dcb_config->rx_pba_cfg) {
+	switch (rx_pba) {
 	case pba_80_48:
 		/* Setup the first four at 80KB */
 		value = IXGBE_RXPBSIZE_80KB;
@@ -78,10 +77,11 @@ static s32 ixgbe_dcb_config_packet_buffers_82598(struct ixgbe_hw *hw,
  *
  * Configure Rx Data Arbiter and credits for each traffic class.
  */
-static s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw,
-                                      struct ixgbe_dcb_config *dcb_config)
+s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw,
+					u16 *refill,
+					u16 *max,
+					u8 *prio_type)
 {
-	struct tc_bw_alloc    *p;
 	u32    reg           = 0;
 	u32    credit_refill = 0;
 	u32    credit_max    = 0;
@@ -102,13 +102,12 @@ static s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw,
 
 	/* Configure traffic class credits and priority */
 	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
-		p = &dcb_config->tc_config[i].path[DCB_RX_CONFIG];
-		credit_refill = p->data_credits_refill;
-		credit_max    = p->data_credits_max;
+		credit_refill = refill[i];
+		credit_max    = max[i];
 
 		reg = credit_refill | (credit_max << IXGBE_RT2CR_MCL_SHIFT);
 
-		if (p->prio_type == prio_link)
+		if (prio_type[i] == prio_link)
 			reg |= IXGBE_RT2CR_LSP;
 
 		IXGBE_WRITE_REG(hw, IXGBE_RT2CR(i), reg);
@@ -135,10 +134,12 @@ static s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw,
  *
  * Configure Tx Descriptor Arbiter and credits for each traffic class.
  */
-static s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw,
-                                           struct ixgbe_dcb_config *dcb_config)
+s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw,
+						u16 *refill,
+						u16 *max,
+						u8 *bwg_id,
+						u8 *prio_type)
 {
-	struct tc_bw_alloc *p;
 	u32    reg, max_credits;
 	u8     i;
 
@@ -156,16 +157,15 @@ static s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw,
 
 	/* Configure traffic class credits and priority */
 	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
-		p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG];
-		max_credits = dcb_config->tc_config[i].desc_credits_max;
+		max_credits = max[i];
 		reg = max_credits << IXGBE_TDTQ2TCCR_MCL_SHIFT;
-		reg |= p->data_credits_refill;
-		reg |= (u32)(p->bwg_id) << IXGBE_TDTQ2TCCR_BWG_SHIFT;
+		reg |= refill[i];
+		reg |= (u32)(bwg_id[i]) << IXGBE_TDTQ2TCCR_BWG_SHIFT;
 
-		if (p->prio_type == prio_group)
+		if (prio_type[i] == prio_group)
 			reg |= IXGBE_TDTQ2TCCR_GSP;
 
-		if (p->prio_type == prio_link)
+		if (prio_type[i] == prio_link)
 			reg |= IXGBE_TDTQ2TCCR_LSP;
 
 		IXGBE_WRITE_REG(hw, IXGBE_TDTQ2TCCR(i), reg);
@@ -181,10 +181,12 @@ static s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw,
  *
  * Configure Tx Data Arbiter and credits for each traffic class.
  */
-static s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw,
-                                           struct ixgbe_dcb_config *dcb_config)
+s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw,
+						u16 *refill,
+						u16 *max,
+						u8 *bwg_id,
+						u8 *prio_type)
 {
-	struct tc_bw_alloc *p;
 	u32 reg;
 	u8 i;
 
@@ -198,15 +200,14 @@ static s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw,
 
 	/* Configure traffic class credits and priority */
 	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
-		p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG];
-		reg = p->data_credits_refill;
-		reg |= (u32)(p->data_credits_max) << IXGBE_TDPT2TCCR_MCL_SHIFT;
-		reg |= (u32)(p->bwg_id) << IXGBE_TDPT2TCCR_BWG_SHIFT;
+		reg = refill[i];
+		reg |= (u32)(max[i]) << IXGBE_TDPT2TCCR_MCL_SHIFT;
+		reg |= (u32)(bwg_id[i]) << IXGBE_TDPT2TCCR_BWG_SHIFT;
 
-		if (p->prio_type == prio_group)
+		if (prio_type[i] == prio_group)
 			reg |= IXGBE_TDPT2TCCR_GSP;
 
-		if (p->prio_type == prio_link)
+		if (prio_type[i] == prio_link)
 			reg |= IXGBE_TDPT2TCCR_LSP;
 
 		IXGBE_WRITE_REG(hw, IXGBE_TDPT2TCCR(i), reg);
@@ -227,13 +228,12 @@ static s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw,
  *
  * Configure Priority Flow Control for each traffic class.
  */
-s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw,
-                               struct ixgbe_dcb_config *dcb_config)
+s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en)
 {
 	u32 reg, rx_pba_size;
 	u8  i;
 
-	if (!dcb_config->pfc_mode_enable)
+	if (!pfc_en)
 		goto out;
 
 	/* Enable Transmit Priority Flow Control */
@@ -254,19 +254,20 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw,
 	 * for each traffic class.
 	 */
 	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+		int enabled = pfc_en & (1 << i);
 		rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
 		rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT;
 		reg = (rx_pba_size - hw->fc.low_water) << 10;
 
-		if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx ||
-		    dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full)
+		if (enabled == pfc_enabled_tx ||
+		    enabled == pfc_enabled_full)
 			reg |= IXGBE_FCRTL_XONE;
 
 		IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), reg);
 
 		reg = (rx_pba_size - hw->fc.high_water) << 10;
-		if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx ||
-		    dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full)
+		if (enabled == pfc_enabled_tx ||
+		    enabled == pfc_enabled_full)
 			reg |= IXGBE_FCRTH_FCEN;
 
 		IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), reg);
@@ -323,13 +324,16 @@ static s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw)
  * Configure dcb settings and enable dcb mode.
  */
 s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *hw,
-                              struct ixgbe_dcb_config *dcb_config)
+			      u8 rx_pba, u8 pfc_en, u16 *refill,
+			      u16 *max, u8 *bwg_id, u8 *prio_type)
 {
-	ixgbe_dcb_config_packet_buffers_82598(hw, dcb_config);
-	ixgbe_dcb_config_rx_arbiter_82598(hw, dcb_config);
-	ixgbe_dcb_config_tx_desc_arbiter_82598(hw, dcb_config);
-	ixgbe_dcb_config_tx_data_arbiter_82598(hw, dcb_config);
-	ixgbe_dcb_config_pfc_82598(hw, dcb_config);
+	ixgbe_dcb_config_packet_buffers_82598(hw, rx_pba);
+	ixgbe_dcb_config_rx_arbiter_82598(hw, refill, max, prio_type);
+	ixgbe_dcb_config_tx_desc_arbiter_82598(hw, refill, max,
+					       bwg_id, prio_type);
+	ixgbe_dcb_config_tx_data_arbiter_82598(hw, refill, max,
+					       bwg_id, prio_type);
+	ixgbe_dcb_config_pfc_82598(hw, pfc_en);
 	ixgbe_dcb_config_tc_stats_82598(hw);
 
 	return 0;
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.h b/drivers/net/ixgbe/ixgbe_dcb_82598.h
index abc03cc..0d2a758 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82598.h
+++ b/drivers/net/ixgbe/ixgbe_dcb_82598.h
@@ -71,9 +71,28 @@
 /* DCB hardware-specific driver APIs */
 
 /* DCB PFC functions */
-s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *, struct ixgbe_dcb_config *);
+s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *, u8 pfc_en);
 
 /* DCB hw initialization */
-s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *, struct ixgbe_dcb_config *);
+s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw,
+					u16 *refill,
+					u16 *max,
+					u8 *prio_type);
+
+s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw,
+						u16 *refill,
+						u16 *max,
+						u8 *bwg_id,
+						u8 *prio_type);
+
+s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw,
+						u16 *refill,
+						u16 *max,
+						u8 *bwg_id,
+						u8 *prio_type);
+
+s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *hw,
+			      u8 rx_pba, u8 pfc_en, u16 *refill,
+			      u16 *max, u8 *bwg_id, u8 *prio_type);
 
 #endif /* _DCB_82598_CONFIG_H */
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c
index 374e1f7..b0d97a9 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82599.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c
@@ -33,19 +33,18 @@
 /**
  * ixgbe_dcb_config_packet_buffers_82599 - Configure DCB packet buffers
  * @hw: pointer to hardware structure
- * @dcb_config: pointer to ixgbe_dcb_config structure
+ * @rx_pba: method to distribute packet buffer
  *
  * Configure packet buffers for DCB mode.
  */
-static s32 ixgbe_dcb_config_packet_buffers_82599(struct ixgbe_hw *hw,
-                                          struct ixgbe_dcb_config *dcb_config)
+static s32 ixgbe_dcb_config_packet_buffers_82599(struct ixgbe_hw *hw, u8 rx_pba)
 {
 	s32 ret_val = 0;
 	u32 value = IXGBE_RXPBSIZE_64KB;
 	u8  i = 0;
 
 	/* Setup Rx packet buffer sizes */
-	switch (dcb_config->rx_pba_cfg) {
+	switch (rx_pba) {
 	case pba_80_48:
 		/* Setup the first four at 80KB */
 		value = IXGBE_RXPBSIZE_80KB;
@@ -75,14 +74,19 @@ static s32 ixgbe_dcb_config_packet_buffers_82599(struct ixgbe_hw *hw,
 /**
  * ixgbe_dcb_config_rx_arbiter_82599 - Config Rx Data arbiter
  * @hw: pointer to hardware structure
- * @dcb_config: pointer to ixgbe_dcb_config structure
+ * @refill: refill credits index by traffic class
+ * @max: max credits index by traffic class
+ * @bwg_id: bandwidth grouping indexed by traffic class
+ * @prio_type: priority type indexed by traffic class
  *
  * Configure Rx Packet Arbiter and credits for each traffic class.
  */
-static s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw,
-                                      struct ixgbe_dcb_config *dcb_config)
+s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw,
+				      u16 *refill,
+				      u16 *max,
+				      u8 *bwg_id,
+				      u8 *prio_type)
 {
-	struct tc_bw_alloc    *p;
 	u32    reg           = 0;
 	u32    credit_refill = 0;
 	u32    credit_max    = 0;
@@ -103,15 +107,13 @@ static s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw,
 
 	/* Configure traffic class credits and priority */
 	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
-		p = &dcb_config->tc_config[i].path[DCB_RX_CONFIG];
-
-		credit_refill = p->data_credits_refill;
-		credit_max    = p->data_credits_max;
+		credit_refill = refill[i];
+		credit_max    = max[i];
 		reg = credit_refill | (credit_max << IXGBE_RTRPT4C_MCL_SHIFT);
 
-		reg |= (u32)(p->bwg_id) << IXGBE_RTRPT4C_BWG_SHIFT;
+		reg |= (u32)(bwg_id[i]) << IXGBE_RTRPT4C_BWG_SHIFT;
 
-		if (p->prio_type == prio_link)
+		if (prio_type[i] == prio_link)
 			reg |= IXGBE_RTRPT4C_LSP;
 
 		IXGBE_WRITE_REG(hw, IXGBE_RTRPT4C(i), reg);
@@ -130,14 +132,19 @@ static s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw,
 /**
  * ixgbe_dcb_config_tx_desc_arbiter_82599 - Config Tx Desc. arbiter
  * @hw: pointer to hardware structure
- * @dcb_config: pointer to ixgbe_dcb_config structure
+ * @refill: refill credits index by traffic class
+ * @max: max credits index by traffic class
+ * @bwg_id: bandwidth grouping indexed by traffic class
+ * @prio_type: priority type indexed by traffic class
  *
  * Configure Tx Descriptor Arbiter and credits for each traffic class.
  */
-static s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw,
-                                           struct ixgbe_dcb_config *dcb_config)
+s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw,
+					   u16 *refill,
+					   u16 *max,
+					   u8 *bwg_id,
+					   u8 *prio_type)
 {
-	struct tc_bw_alloc *p;
 	u32    reg, max_credits;
 	u8     i;
 
@@ -149,16 +156,15 @@ static s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw,
 
 	/* Configure traffic class credits and priority */
 	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
-		p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG];
-		max_credits = dcb_config->tc_config[i].desc_credits_max;
+		max_credits = max[i];
 		reg = max_credits << IXGBE_RTTDT2C_MCL_SHIFT;
-		reg |= p->data_credits_refill;
-		reg |= (u32)(p->bwg_id) << IXGBE_RTTDT2C_BWG_SHIFT;
+		reg |= refill[i];
+		reg |= (u32)(bwg_id[i]) << IXGBE_RTTDT2C_BWG_SHIFT;
 
-		if (p->prio_type == prio_group)
+		if (prio_type[i] == prio_group)
 			reg |= IXGBE_RTTDT2C_GSP;
 
-		if (p->prio_type == prio_link)
+		if (prio_type[i] == prio_link)
 			reg |= IXGBE_RTTDT2C_LSP;
 
 		IXGBE_WRITE_REG(hw, IXGBE_RTTDT2C(i), reg);
@@ -177,14 +183,19 @@ static s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw,
 /**
  * ixgbe_dcb_config_tx_data_arbiter_82599 - Config Tx Data arbiter
  * @hw: pointer to hardware structure
- * @dcb_config: pointer to ixgbe_dcb_config structure
+ * @refill: refill credits index by traffic class
+ * @max: max credits index by traffic class
+ * @bwg_id: bandwidth grouping indexed by traffic class
+ * @prio_type: priority type indexed by traffic class
  *
  * Configure Tx Packet Arbiter and credits for each traffic class.
  */
-static s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw,
-                                           struct ixgbe_dcb_config *dcb_config)
+s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw,
+					   u16 *refill,
+					   u16 *max,
+					   u8 *bwg_id,
+					   u8 *prio_type)
 {
-	struct tc_bw_alloc *p;
 	u32 reg;
 	u8 i;
 
@@ -205,15 +216,14 @@ static s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw,
 
 	/* Configure traffic class credits and priority */
 	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
-		p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG];
-		reg = p->data_credits_refill;
-		reg |= (u32)(p->data_credits_max) << IXGBE_RTTPT2C_MCL_SHIFT;
-		reg |= (u32)(p->bwg_id) << IXGBE_RTTPT2C_BWG_SHIFT;
+		reg = refill[i];
+		reg |= (u32)(max[i]) << IXGBE_RTTPT2C_MCL_SHIFT;
+		reg |= (u32)(bwg_id[i]) << IXGBE_RTTPT2C_BWG_SHIFT;
 
-		if (p->prio_type == prio_group)
+		if (prio_type[i] == prio_group)
 			reg |= IXGBE_RTTPT2C_GSP;
 
-		if (p->prio_type == prio_link)
+		if (prio_type[i] == prio_link)
 			reg |= IXGBE_RTTPT2C_LSP;
 
 		IXGBE_WRITE_REG(hw, IXGBE_RTTPT2C(i), reg);
@@ -233,17 +243,16 @@ static s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw,
 /**
  * ixgbe_dcb_config_pfc_82599 - Configure priority flow control
  * @hw: pointer to hardware structure
- * @dcb_config: pointer to ixgbe_dcb_config structure
+ * @pfc_en: enabled pfc bitmask
  *
  * Configure Priority Flow Control (PFC) for each traffic class.
  */
-s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw,
-                               struct ixgbe_dcb_config *dcb_config)
+s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en)
 {
 	u32 i, reg, rx_pba_size;
 
 	/* If PFC is disabled globally then fall back to LFC. */
-	if (!dcb_config->pfc_mode_enable) {
+	if (!pfc_en) {
 		for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
 			hw->mac.ops.fc_enable(hw, i);
 		goto out;
@@ -251,19 +260,18 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw,
 
 	/* Configure PFC Tx thresholds per TC */
 	for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+		int enabled = pfc_en & (1 << i);
 		rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
 		rx_pba_size >>= IXGBE_RXPBSIZE_SHIFT;
 
 		reg = (rx_pba_size - hw->fc.low_water) << 10;
 
-		if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full ||
-		    dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx)
+		if (enabled)
 			reg |= IXGBE_FCRTL_XONE;
 		IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), reg);
 
 		reg = (rx_pba_size - hw->fc.high_water) << 10;
-		if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full ||
-		    dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx)
+		if (enabled)
 			reg |= IXGBE_FCRTH_FCEN;
 		IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), reg);
 	}
@@ -349,7 +357,6 @@ static s32 ixgbe_dcb_config_tc_stats_82599(struct ixgbe_hw *hw)
 /**
  * ixgbe_dcb_config_82599 - Configure general DCB parameters
  * @hw: pointer to hardware structure
- * @dcb_config: pointer to ixgbe_dcb_config structure
  *
  * Configure general DCB parameters.
  */
@@ -406,19 +413,27 @@ static s32 ixgbe_dcb_config_82599(struct ixgbe_hw *hw)
 /**
  * ixgbe_dcb_hw_config_82599 - Configure and enable DCB
  * @hw: pointer to hardware structure
- * @dcb_config: pointer to ixgbe_dcb_config structure
+ * @rx_pba: method to distribute packet buffer
+ * @refill: refill credits index by traffic class
+ * @max: max credits index by traffic class
+ * @bwg_id: bandwidth grouping indexed by traffic class
+ * @prio_type: priority type indexed by traffic class
+ * @pfc_en: enabled pfc bitmask
  *
  * Configure dcb settings and enable dcb mode.
  */
 s32 ixgbe_dcb_hw_config_82599(struct ixgbe_hw *hw,
-                              struct ixgbe_dcb_config *dcb_config)
+			      u8 rx_pba, u8 pfc_en, u16 *refill,
+			      u16 *max, u8 *bwg_id, u8 *prio_type)
 {
-	ixgbe_dcb_config_packet_buffers_82599(hw, dcb_config);
+	ixgbe_dcb_config_packet_buffers_82599(hw, rx_pba);
 	ixgbe_dcb_config_82599(hw);
-	ixgbe_dcb_config_rx_arbiter_82599(hw, dcb_config);
-	ixgbe_dcb_config_tx_desc_arbiter_82599(hw, dcb_config);
-	ixgbe_dcb_config_tx_data_arbiter_82599(hw, dcb_config);
-	ixgbe_dcb_config_pfc_82599(hw, dcb_config);
+	ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max, bwg_id, prio_type);
+	ixgbe_dcb_config_tx_desc_arbiter_82599(hw, refill, max,
+					       bwg_id, prio_type);
+	ixgbe_dcb_config_tx_data_arbiter_82599(hw, refill, max,
+					       bwg_id, prio_type);
+	ixgbe_dcb_config_pfc_82599(hw, pfc_en);
 	ixgbe_dcb_config_tc_stats_82599(hw);
 
 	return 0;
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ixgbe/ixgbe_dcb_82599.h
index 3841649..5b0ca85 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82599.h
+++ b/drivers/net/ixgbe/ixgbe_dcb_82599.h
@@ -102,11 +102,29 @@
 /* DCB hardware-specific driver APIs */
 
 /* DCB PFC functions */
-s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw,
-                               struct ixgbe_dcb_config *dcb_config);
+s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en);
 
 /* DCB hw initialization */
+s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw,
+					u16 *refill,
+					u16 *max,
+					u8 *bwg_id,
+					u8 *prio_type);
+
+s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw,
+						u16 *refill,
+						u16 *max,
+						u8 *bwg_id,
+						u8 *prio_type);
+
+s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw,
+						u16 *refill,
+						u16 *max,
+						u8 *bwg_id,
+						u8 *prio_type);
+
 s32 ixgbe_dcb_hw_config_82599(struct ixgbe_hw *hw,
-                              struct ixgbe_dcb_config *config);
+			      u8 rx_pba, u8 pfc_en, u16 *refill,
+			      u16 *max, u8 *bwg_id, u8 *prio_type);
 
 #endif /* _DCB_82599_CONFIG_H */
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
index 4805835..6ab1f1a 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -422,12 +422,13 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
 		}
 		ret = DCB_HW_CHG_RST;
 	} else if (adapter->dcb_set_bitmap & BIT_PFC) {
+		u8 pfc_en;
+		ixgbe_dcb_unpack_pfc(&adapter->dcb_cfg, &pfc_en);
+
 		if (adapter->hw.mac.type == ixgbe_mac_82598EB)
-			ixgbe_dcb_config_pfc_82598(&adapter->hw,
-			                           &adapter->dcb_cfg);
+			ixgbe_dcb_config_pfc_82598(&adapter->hw, pfc_en);
 		else if (adapter->hw.mac.type == ixgbe_mac_82599EB)
-			ixgbe_dcb_config_pfc_82599(&adapter->hw,
-			                           &adapter->dcb_cfg);
+			ixgbe_dcb_config_pfc_82599(&adapter->hw, pfc_en);
 		ret = DCB_HW_CHG;
 	}
 	if (adapter->dcb_cfg.pfc_mode_enable)
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 12/16] ixgbe: dcb, use hardware independent routines
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: John Fastabend, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: John Fastabend <john.r.fastabend@intel.com>

This consolidates hardware specifics to ixgbe_dcb.c this simplifies
code that was previously branching based on hardware type.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_dcb_nl.c |    6 +-----
 1 files changed, 1 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
index c94adec..a977df3 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -405,11 +405,7 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
 	if (adapter->dcb_set_bitmap & BIT_PFC) {
 		u8 pfc_en;
 		ixgbe_dcb_unpack_pfc(&adapter->dcb_cfg, &pfc_en);
-
-		if (adapter->hw.mac.type == ixgbe_mac_82598EB)
-			ixgbe_dcb_config_pfc_82598(&adapter->hw, pfc_en);
-		else if (adapter->hw.mac.type == ixgbe_mac_82599EB)
-			ixgbe_dcb_config_pfc_82599(&adapter->hw, pfc_en);
+		ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc_en);
 		ret = DCB_HW_CHG;
 	}
 
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 10/16] ixgbe: DCB, do not reset on CEE pg changes
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: John Fastabend, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: John Fastabend <john.r.fastabend@intel.com>

The 82599 and 82598 devices do not require hardware resets to
configure CEE pg settings. This patch changes DCB configuration
to set the CEE pg values directly from the dcbnl ops routine.

This reduces the number of resets seen on the wire and allows
LLDP to reach a steady state faster.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_dcb.h    |    4 +++
 drivers/net/ixgbe/ixgbe_dcb_nl.c |   48 +++++++++++++++++++++++++++----------
 2 files changed, 39 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_dcb.h b/drivers/net/ixgbe/ixgbe_dcb.h
index 4e4a641..e593511 100644
--- a/drivers/net/ixgbe/ixgbe_dcb.h
+++ b/drivers/net/ixgbe/ixgbe_dcb.h
@@ -148,6 +148,10 @@ struct ixgbe_dcb_config {
 
 /* DCB driver APIs */
 void ixgbe_dcb_unpack_pfc(struct ixgbe_dcb_config *cfg, u8 *pfc_en);
+void ixgbe_dcb_unpack_refill(struct ixgbe_dcb_config *, int, u16 *);
+void ixgbe_dcb_unpack_max(struct ixgbe_dcb_config *, u16 *);
+void ixgbe_dcb_unpack_bwgid(struct ixgbe_dcb_config *, int, u8 *);
+void ixgbe_dcb_unpack_prio(struct ixgbe_dcb_config *, int, u8 *);
 
 /* DCB credits calculation */
 s32 ixgbe_ieee_credits(__u8 *bw, __u16 *refill, __u16 *max, int max_frame);
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
index e75a3c9..b3a8d24 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -225,10 +225,8 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc,
 	    (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent !=
 	     adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent) ||
 	    (adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap !=
-	     adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap)) {
+	     adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap))
 		adapter->dcb_set_bitmap |= BIT_PG_TX;
-		adapter->dcb_set_bitmap |= BIT_RESETLINK;
-	}
 }
 
 static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id,
@@ -239,10 +237,8 @@ static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id,
 	adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] = bw_pct;
 
 	if (adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] !=
-	    adapter->dcb_cfg.bw_percentage[0][bwg_id]) {
+	    adapter->dcb_cfg.bw_percentage[0][bwg_id])
 		adapter->dcb_set_bitmap |= BIT_PG_TX;
-		adapter->dcb_set_bitmap |= BIT_RESETLINK;
-	}
 }
 
 static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc,
@@ -269,10 +265,8 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc,
 	    (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent !=
 	     adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent) ||
 	    (adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap !=
-	     adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap)) {
+	     adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap))
 		adapter->dcb_set_bitmap |= BIT_PG_RX;
-		adapter->dcb_set_bitmap |= BIT_RESETLINK;
-	}
 }
 
 static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id,
@@ -283,10 +277,8 @@ static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id,
 	adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] = bw_pct;
 
 	if (adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] !=
-	    adapter->dcb_cfg.bw_percentage[1][bwg_id]) {
+	    adapter->dcb_cfg.bw_percentage[1][bwg_id])
 		adapter->dcb_set_bitmap |= BIT_PG_RX;
-		adapter->dcb_set_bitmap |= BIT_RESETLINK;
-	}
 }
 
 static void ixgbe_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int tc,
@@ -421,7 +413,9 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
 				ixgbe_up(adapter);
 		}
 		ret = DCB_HW_CHG_RST;
-	} else if (adapter->dcb_set_bitmap & BIT_PFC) {
+	}
+
+	if (adapter->dcb_set_bitmap & BIT_PFC) {
 		u8 pfc_en;
 		ixgbe_dcb_unpack_pfc(&adapter->dcb_cfg, &pfc_en);
 
@@ -431,6 +425,34 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
 			ixgbe_dcb_config_pfc_82599(&adapter->hw, pfc_en);
 		ret = DCB_HW_CHG;
 	}
+
+	if (adapter->dcb_set_bitmap & (BIT_PG_TX|BIT_PG_RX)) {
+		u16 refill[MAX_TRAFFIC_CLASS], max[MAX_TRAFFIC_CLASS];
+		u8 bwg_id[MAX_TRAFFIC_CLASS], prio_type[MAX_TRAFFIC_CLASS];
+		int max_frame = adapter->netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+
+#ifdef CONFIG_FCOE
+		if (adapter->netdev->features & NETIF_F_FCOE_MTU)
+			max_frame = max(max_frame, IXGBE_FCOE_JUMBO_FRAME_SIZE);
+#endif
+
+		ixgbe_dcb_calculate_tc_credits(&adapter->hw, &adapter->dcb_cfg,
+					       max_frame, DCB_TX_CONFIG);
+		ixgbe_dcb_calculate_tc_credits(&adapter->hw, &adapter->dcb_cfg,
+					       max_frame, DCB_RX_CONFIG);
+
+		ixgbe_dcb_unpack_refill(&adapter->dcb_cfg,
+					DCB_TX_CONFIG, refill);
+		ixgbe_dcb_unpack_max(&adapter->dcb_cfg, max);
+		ixgbe_dcb_unpack_bwgid(&adapter->dcb_cfg,
+				       DCB_TX_CONFIG, bwg_id);
+		ixgbe_dcb_unpack_prio(&adapter->dcb_cfg,
+				      DCB_TX_CONFIG, prio_type);
+
+		ixgbe_dcb_hw_ets_config(&adapter->hw, refill, max,
+					bwg_id, prio_type);
+	}
+
 	if (adapter->dcb_cfg.pfc_mode_enable)
 		adapter->hw.fc.current_mode = ixgbe_fc_pfc;
 
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 11/16] ixgbe: DCB, remove RESET bit it is no longer needed
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: John Fastabend, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: John Fastabend <john.r.fastabend@intel.com>

This removes the RESET bit previously used to force a device
reset when DCB bandwidth configurations were changed. This can
now be done dynamically without a reset so the bit is no longer
needed. The only remaining operations that force a device reset
are DCB enable/disable and FCoE application priority changes.
DCB enable/disable is a hardware requirement.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_dcb_nl.c |   37 ++++++++++++-------------------------
 1 files changed, 12 insertions(+), 25 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
index b3a8d24..c94adec 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -37,7 +37,6 @@
 #define BIT_PG_RX	0x04
 #define BIT_PG_TX	0x08
 #define BIT_APP_UPCHG	0x10
-#define BIT_RESETLINK   0x40
 #define BIT_LINKSPEED   0x80
 
 /* Responses for the DCB_C_SET_ALL command */
@@ -345,7 +344,6 @@ static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority,
 static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
 {
 	struct ixgbe_adapter *adapter = netdev_priv(netdev);
-	bool do_reset;
 	int ret;
 
 	if (!adapter->dcb_set_bitmap)
@@ -358,23 +356,17 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
 		return DCB_NO_HW_CHG;
 
 	/*
-	 * Only take down the adapter if the configuration change
-	 * requires a reset.
+	 * Only take down the adapter if an app change occured. FCoE
+	 * may shuffle tx rings in this case and this can not be done
+	 * without a reset currently.
 	 */
-	do_reset = adapter->dcb_set_bitmap & (BIT_RESETLINK | BIT_APP_UPCHG);
-
-	if (do_reset) {
+	if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) {
 		while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
 			msleep(1);
 
-		if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) {
-			if (netif_running(netdev))
-				netdev->netdev_ops->ndo_stop(netdev);
-			ixgbe_clear_interrupt_scheme(adapter);
-		} else {
-			if (netif_running(netdev))
-				ixgbe_down(adapter);
-		}
+		if (netif_running(netdev))
+			netdev->netdev_ops->ndo_stop(netdev);
+		ixgbe_clear_interrupt_scheme(adapter);
 	}
 
 	if (adapter->dcb_cfg.pfc_mode_enable) {
@@ -403,15 +395,10 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
 		}
 	}
 
-	if (do_reset) {
-		if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) {
-			ixgbe_init_interrupt_scheme(adapter);
-			if (netif_running(netdev))
-				netdev->netdev_ops->ndo_open(netdev);
-		} else {
-			if (netif_running(netdev))
-				ixgbe_up(adapter);
-		}
+	if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) {
+		ixgbe_init_interrupt_scheme(adapter);
+		if (netif_running(netdev))
+			netdev->netdev_ops->ndo_open(netdev);
 		ret = DCB_HW_CHG_RST;
 	}
 
@@ -456,7 +443,7 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
 	if (adapter->dcb_cfg.pfc_mode_enable)
 		adapter->hw.fc.current_mode = ixgbe_fc_pfc;
 
-	if (do_reset)
+	if (adapter->dcb_set_bitmap & BIT_APP_UPCHG)
 		clear_bit(__IXGBE_RESETTING, &adapter->state);
 	adapter->dcb_set_bitmap = 0x00;
 	return ret;
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 13/16] ixgbe: fix namespace issue with ixgbe_dcb_txq_to_tc
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: Don Skidmore, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Don Skidmore <donald.c.skidmore@intel.com>

We didn't need the prototype and it was causing namespace complaints so
I made it static.

Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com>
Tested-by: Stephen Ko <stephen.s.ko@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe.h      |    1 -
 drivers/net/ixgbe/ixgbe_main.c |    2 +-
 2 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index d04afde..12769b5 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -525,7 +525,6 @@ extern void ixgbe_unmap_and_free_tx_resource(struct ixgbe_ring *,
 extern void ixgbe_alloc_rx_buffers(struct ixgbe_ring *, u16);
 extern void ixgbe_write_eitr(struct ixgbe_q_vector *);
 extern int ethtool_ioctl(struct ifreq *ifr);
-extern u8 ixgbe_dcb_txq_to_tc(struct ixgbe_adapter *adapter, u8 index);
 extern s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw);
 extern s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc);
 extern s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc);
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index ef4a517..f5bdc0a 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -648,7 +648,7 @@ void ixgbe_unmap_and_free_tx_resource(struct ixgbe_ring *tx_ring,
  *
  * Returns : a tc index for use in range 0-7, or 0-3
  */
-u8 ixgbe_dcb_txq_to_tc(struct ixgbe_adapter *adapter, u8 reg_idx)
+static u8 ixgbe_dcb_txq_to_tc(struct ixgbe_adapter *adapter, u8 reg_idx)
 {
 	int tc = -1;
 	int dcb_i = adapter->ring_feature[RING_F_DCB].indices;
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 14/16] ixgbe: cleanup namespace complaint by removing little used function
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: Don Skidmore, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Don Skidmore <donald.c.skidmore@intel.com>

We had a support function that just walked a few pointers to get
from the ixgbe_hw struct to the netdev pointer.  This was causing
a namespace warning so I removed it and just reference the pointers
directly.

Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com>
Tested-by: Stephen Ko <stephen.s.ko@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_common.h |    4 ++--
 drivers/net/ixgbe/ixgbe_main.c   |   10 ----------
 2 files changed, 2 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h
index 66ed045..90cceb4 100644
--- a/drivers/net/ixgbe/ixgbe_common.h
+++ b/drivers/net/ixgbe/ixgbe_common.h
@@ -29,6 +29,7 @@
 #define _IXGBE_COMMON_H_
 
 #include "ixgbe_type.h"
+#include "ixgbe.h"
 
 u32 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw);
 s32 ixgbe_init_ops_generic(struct ixgbe_hw *hw);
@@ -110,9 +111,8 @@ void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf);
 
 #define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS)
 
-extern struct net_device *ixgbe_get_hw_dev(struct ixgbe_hw *hw);
 #define hw_dbg(hw, format, arg...) \
-	netdev_dbg(ixgbe_get_hw_dev(hw), format, ##arg)
+	netdev_dbg(((struct ixgbe_adapter *)(hw->back))->netdev, format, ##arg)
 #define e_dev_info(format, arg...) \
 	dev_info(&adapter->pdev->dev, format, ## arg)
 #define e_dev_warn(format, arg...) \
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index f5bdc0a..2dab240 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -7699,16 +7699,6 @@ static int ixgbe_notify_dca(struct notifier_block *nb, unsigned long event,
 
 #endif /* CONFIG_IXGBE_DCA */
 
-/**
- * ixgbe_get_hw_dev return device
- * used by hardware layer to print debugging information
- **/
-struct net_device *ixgbe_get_hw_dev(struct ixgbe_hw *hw)
-{
-	struct ixgbe_adapter *adapter = hw->back;
-	return adapter->netdev;
-}
-
 module_exit(ixgbe_exit_module);
 
 /* ixgbe_main.c */
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 15/16] ixgbe: cleanup ixgbe_init_mbx_params_pf namespace issue
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: Don Skidmore, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Don Skidmore <donald.c.skidmore@intel.com>

The function ixgbe_init_mbx_params_pf isn't used unless CONFIG_PCI_IOV
is defined.  This is causing namespace warnings.  So I wrapped its
definition in CONFIG_PCI_IOV too.

Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com>
Tested-by: Stephen Ko <stephen.s.ko@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_mbx.c |    2 ++
 drivers/net/ixgbe/ixgbe_mbx.h |    2 ++
 2 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_mbx.c b/drivers/net/ixgbe/ixgbe_mbx.c
index ea82c5a..f215c4c 100644
--- a/drivers/net/ixgbe/ixgbe_mbx.c
+++ b/drivers/net/ixgbe/ixgbe_mbx.c
@@ -437,6 +437,7 @@ out_no_read:
 	return ret_val;
 }
 
+#ifdef CONFIG_PCI_IOV
 /**
  *  ixgbe_init_mbx_params_pf - set initial values for pf mailbox
  *  @hw: pointer to the HW structure
@@ -465,6 +466,7 @@ void ixgbe_init_mbx_params_pf(struct ixgbe_hw *hw)
 		break;
 	}
 }
+#endif /* CONFIG_PCI_IOV */
 
 struct ixgbe_mbx_operations mbx_ops_generic = {
 	.read                   = ixgbe_read_mbx_pf,
diff --git a/drivers/net/ixgbe/ixgbe_mbx.h b/drivers/net/ixgbe/ixgbe_mbx.h
index 3df9b15..ada0ce3 100644
--- a/drivers/net/ixgbe/ixgbe_mbx.h
+++ b/drivers/net/ixgbe/ixgbe_mbx.h
@@ -86,7 +86,9 @@ s32 ixgbe_write_mbx(struct ixgbe_hw *, u32 *, u16, u16);
 s32 ixgbe_check_for_msg(struct ixgbe_hw *, u16);
 s32 ixgbe_check_for_ack(struct ixgbe_hw *, u16);
 s32 ixgbe_check_for_rst(struct ixgbe_hw *, u16);
+#ifdef CONFIG_PCI_IOV
 void ixgbe_init_mbx_params_pf(struct ixgbe_hw *);
+#endif /* CONFIG_PCI_IOV */
 
 extern struct ixgbe_mbx_operations mbx_ops_generic;
 
-- 
1.7.4


^ permalink raw reply related

* [net-next-2.6 16/16] ixgbe: Adding 100MB FULL support in ethtool
From: Jeff Kirsher @ 2011-02-08 12:29 UTC (permalink / raw)
  To: davem; +Cc: Atita Shirwaikar, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1297168167-15755-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Atita Shirwaikar <atita.shirwaikar@intel.com>

Current driver does not show 100MB support in ethtool.
Adding support for the same.

Signed-off-by: Atita Shirwaikar <atita.shirwaikar@intel.com>
Tested-by: Stephen Ko <stephen.s.ko@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethtool.c |   34 ++++++++++++++++++++++++++++++++--
 drivers/net/ixgbe/ixgbe_main.c    |    5 ++++-
 2 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 2002ea8..309272f 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -152,7 +152,17 @@ static int ixgbe_get_settings(struct net_device *netdev,
 		ecmd->supported |= (SUPPORTED_1000baseT_Full |
 		                    SUPPORTED_Autoneg);
 
+		switch (hw->mac.type) {
+		case ixgbe_mac_X540:
+			ecmd->supported |= SUPPORTED_100baseT_Full;
+			break;
+		default:
+			break;
+		}
+
 		ecmd->advertising = ADVERTISED_Autoneg;
+		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
+			ecmd->advertising |= ADVERTISED_100baseT_Full;
 		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
 			ecmd->advertising |= ADVERTISED_10000baseT_Full;
 		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
@@ -167,6 +177,15 @@ static int ixgbe_get_settings(struct net_device *netdev,
 			ecmd->advertising |= (ADVERTISED_10000baseT_Full |
 					      ADVERTISED_1000baseT_Full);
 
+		switch (hw->mac.type) {
+		case ixgbe_mac_X540:
+			if (!(ecmd->advertising & ADVERTISED_100baseT_Full))
+				ecmd->advertising |= (ADVERTISED_100baseT_Full);
+			break;
+		default:
+			break;
+		}
+
 		if (hw->phy.media_type == ixgbe_media_type_copper) {
 			ecmd->supported |= SUPPORTED_TP;
 			ecmd->advertising |= ADVERTISED_TP;
@@ -271,8 +290,19 @@ static int ixgbe_get_settings(struct net_device *netdev,
 
 	hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
 	if (link_up) {
-		ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
-		               SPEED_10000 : SPEED_1000;
+		switch (link_speed) {
+		case IXGBE_LINK_SPEED_10GB_FULL:
+			ecmd->speed = SPEED_10000;
+			break;
+		case IXGBE_LINK_SPEED_1GB_FULL:
+			ecmd->speed = SPEED_1000;
+			break;
+		case IXGBE_LINK_SPEED_100_FULL:
+			ecmd->speed = SPEED_100;
+			break;
+		default:
+			break;
+		}
 		ecmd->duplex = DUPLEX_FULL;
 	} else {
 		ecmd->speed = -1;
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 2dab240..7947063 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -6094,7 +6094,10 @@ static void ixgbe_watchdog_task(struct work_struct *work)
 			       (link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
 			       "10 Gbps" :
 			       (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
-			       "1 Gbps" : "unknown speed")),
+			       "1 Gbps" :
+			       (link_speed == IXGBE_LINK_SPEED_100_FULL ?
+			       "100 Mbps" :
+			       "unknown speed"))),
 			       ((flow_rx && flow_tx) ? "RX/TX" :
 			       (flow_rx ? "RX" :
 			       (flow_tx ? "TX" : "None"))));
-- 
1.7.4


^ permalink raw reply related

* Re: [PATCH]netdev: add driver for enc424j600 ethernet chip on SPI bus
From: Balaji Venkatachalam @ 2011-02-08 14:48 UTC (permalink / raw)
  To: netdev; +Cc: mohan, blue.cube, lanconelli.claudio, sriram, vbalaji.acs
In-Reply-To: <AANLkTint85CE2NtHW=Znj0tAoF9TCePQCdTEJJtFY6Q8@mail.gmail.com>

From: Balaji Venkatachalam <balaji.v@thotakaa.com>
Updated patch [1.30] for Microchip enc424j600 ethernet chip controlled via SPI.

I tested it on my custom board with ARM9 (Freescale i.MX233) with
Kernel 2.6.31.14.
I tested the corrected get_regs implementation with ethtool using the command:
"ethtool -d eth0".
It gives output in "Offset   Value" format.

Changes done since V1.29 to V1.30
1. Fixed Compiler Warning due to wrong get_regs implementation
2. added enc424j600_get_regs, get_regs functionality
                             for use with ethtool.
3. removed unnecessary & unformatted comments
4. replaced enc424j600_set_bits and enc424j600_clear_bits with
        		     enc424j600_write_bits.
5. removed unnecessary empty lines.

Changes done since V1.28 to V1.29
1. enc424j600_spi_trans function implementation optimized
2. Unnecessary comments and Improper Comments removed
3. Added an empty line after variable declaration in all functions
4. mapped enc424j600_dump_regs to eth_ops get_regs
5. removed the hardcoding of return type in enc424j600_probe function

Changes done since V1.27 to V1.28
1. did some code formatting

Changes done since V1.24 to V1.27
1. Timeout Mechanism implemented for enc424j600_soft_reset function
2. Timeout Mechanism implemented for enc424j600_wait_for_autoneg function
3. Window Naming changed to enum
4. Removed WRITEVERIFY functionality

Todo List:
1. Low Power Mode Functionality implementation
2. Provide Support for On-Chip DMA
3. Remove mutex_lock wherever not required

Any comments are welcome.

Signed-off-by: Balaji Venkatachalam <balaji.v@thotakaa.com>
---
diff -uprN -X a/Documentation/dontdiff a/drivers/net/enc424j600.c
b/drivers/net/enc424j600.c
--- a/drivers/net/enc424j600.c	1970-01-01 05:30:00.000000000 +0530
+++ b/drivers/net/enc424j600.c	2011-02-08 20:10:26.000000000 +0530
@@ -0,0 +1,1748 @@
+/*
+ * Microchip ENC424J600 ethernet driver (MAC + PHY) on SPI bus
+ *
+ * Copyright (C) 2011 Thotaka Technologies Pvt Ltd
+ * Author: Balaji Venkatachalam <balaji.v@thotakaa.com>
+ * based on enc424j600.c written by Kuba Marek
+ * based on enc28j60.c written by Claudio Lanconelli
+ *
+ * Changes done since V1.29 to V1.30
+ * 1. Fixed Compiler Warning due to wrong get_regs implementation
+ * 2. added enc424j600_get_regs, get_regs functionality
+ *                             for use with ethtool.
+ * 3. removed unnecessary & unformatted comments
+ * 4. replaced enc424j600_set_bits and enc424j600_clear_bits with
+ * 						enc424j600_write_bits.
+ * 5. removed unnecessary empty lines.
+ *
+ * Changes done since V1.28 to V1.29
+ * 1. enc424j600_spi_trans function implementation optimized
+ * 2. Unnecessary comments and Improper Comments removed
+ * 3. Added an empty line after variable declaration in all functions
+ * 4. mapped enc424j600_dump_regs to eth_ops get_regs
+ * 5. removed the hardcoding of return type in enc424j600_probe function
+ *
+ * Changes done since V1.27 to V1.28
+ * 1. did some code formatting
+ *
+ * Changes done since V1.24 to V1.27
+ * 1. Timeout Mechanism implemented for enc424j600_soft_reset function
+ * 2. Timeout Mechanism implemented for enc424j600_wait_for_autoneg function
+ * 3. Window Naming changed to enum
+ * 4. Removed WRITEVERIFY functionality
+ *
+ * Todo List:
+ * 1. Low Power Mode Functionality implementation
+ * 2. Provide Support for On-Chip DMA
+ * 3. Remove mutex_lock wherever not required
+ * 4. Propogate the return status code of enc424j600_hw_init
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+
+#include "enc424j600_hw.h"
+
+#define DRV_NAME "enc424j600"
+#define DRV_VERSION "1.30"
+
+#define ENC424J600_MSG_DEFAULT \
+	(NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_LINK)
+
+#define SPI_TRANSFER_BUF_LEN (4 + MAX_FRAMELEN)
+#define TX_TIMEOUT (4 * HZ)
+
+/* Max TX retries in case of collision as suggested by errata datasheet */
+#define MAX_TX_RETRYCOUNT 16
+
+#define SPI_OPLEN	1
+
+#define SRAMSIZE		0x6000
+#define TXSTART			0x0000
+#define RXSTART			0x1600
+
+/* Enable SPI DMA. Default: 0 (Off) */
+static int enc424j600_enable_dma;
+
+enum {
+	RXFILTER_NORMAL,
+	RXFILTER_MULTI,
+	RXFILTER_PROMISC
+};
+enum {
+	RXWINDOW,
+	USERWINDOW,
+	GPWINDOW
+};
+
+/* Driver local data */
+struct enc424j600_net {
+	struct net_device *netdev;
+	struct spi_device *spi;
+	struct mutex lock;
+	struct sk_buff *tx_skb;
+	struct work_struct tx_work;
+	struct work_struct irq_work;
+	struct work_struct setrx_work;
+	struct work_struct restart_work;
+	u8 bank;		/* current register bank selected */
+	u16 next_pk_ptr;	/* next packet pointer within FIFO */
+	u16 max_pk_counter;	/* statistics: max packet counter */
+	u16 tx_retry_count;
+	bool hw_enable;
+	bool full_duplex;
+	bool autoneg;
+	bool speed100;
+	int rxfilter;
+	u32 msg_enable;
+
+	u8 *spi_rx_buf;
+	u8 *spi_tx_buf;
+	dma_addr_t spi_tx_dma;
+	dma_addr_t spi_rx_dma;
+};
+
+/* use ethtool to change the level for any given device */
+static struct {
+	u32 msg_enable;
+} debug = { -1 };
+
+static int enc424j600_spi_trans(struct enc424j600_net *priv, int len)
+{
+	/*modified to suit half duplexed spi */
+	struct spi_transfer tt = {
+		.tx_buf = priv->spi_tx_buf,
+		.len = SPI_OPLEN,
+	};
+	struct spi_transfer tr = {
+		.rx_buf = priv->spi_rx_buf,
+		.len = len,
+	};
+	struct spi_message m;
+	int ret;
+
+	spi_message_init(&m);
+
+	spi_message_add_tail(&tt, &m);
+	spi_message_add_tail(&tr, &m);
+
+	ret = spi_sync(priv->spi, &m);
+
+	if (ret) {
+		dev_err(&priv->spi->dev,
+			"spi transfer failed: ret = %d\n", ret);
+		goto out;
+	}
+
+	memcpy(priv->spi_rx_buf, tr.rx_buf, len);
+
+out:
+	return ret;
+}
+
+/*Read data from chip SRAM.*/
+static int enc424j600_read_sram(struct enc424j600_net *priv,
+				u8 *dst, int len, u16 srcaddr, int window)
+{
+	int ret;
+
+	if (len > SPI_TRANSFER_BUF_LEN - 1 || len <= 0)
+		return -EINVAL;
+
+	/* First set the write pointer as per selected window */
+	if (window == RXWINDOW)
+		priv->spi_tx_buf[0] = WRXRDPT;
+	else if (window == USERWINDOW)
+		priv->spi_tx_buf[0] = WUDARDPT;
+	else if (window == GPWINDOW)
+		priv->spi_tx_buf[0] = WGPRDPT;
+
+	priv->spi_tx_buf[1] = srcaddr & 0xFF;
+	priv->spi_tx_buf[2] = srcaddr >> 8;
+	ret = spi_write(priv->spi, priv->spi_tx_buf, 3);
+
+	/* Transfer the data */
+	if (window == RXWINDOW)
+		priv->spi_tx_buf[0] = RRXDATA;
+	else if (window == USERWINDOW)
+		priv->spi_tx_buf[0] = RUDADATA;
+	else if (window == GPWINDOW)
+		priv->spi_tx_buf[0] = RGPDATA;
+
+	ret = enc424j600_spi_trans(priv, len + 1);
+
+	/* Copy the data from the rx buffer */
+	memcpy(dst, &priv->spi_rx_buf[0], len);
+
+	return ret;
+}
+
+/* Write data to chip SRAM.*/
+static int enc424j600_write_sram(struct enc424j600_net *priv,
+				const u8 *src, int len, u16 dstaddr,
+				int window)
+{
+	int ret;
+
+	if (len > SPI_TRANSFER_BUF_LEN - 1 || len <= 0)
+		return -EINVAL;
+
+	/* First set the general purpose write pointer */
+	if (window == RXWINDOW)
+		priv->spi_tx_buf[0] = WRXWRPT;
+	else if (window == USERWINDOW)
+		priv->spi_tx_buf[0] = WUDAWRPT;
+	else if (window == GPWINDOW)
+		priv->spi_tx_buf[0] = WGPWRPT;
+
+	priv->spi_tx_buf[1] = dstaddr & 0xFF;
+	priv->spi_tx_buf[2] = dstaddr >> 8;
+	ret = spi_write(priv->spi, priv->spi_tx_buf, 3);
+
+	/* Copy the data to the tx buffer */
+	memcpy(&priv->spi_tx_buf[1], src, len);
+
+	/* Transfer the data */
+	if (window == RXWINDOW)
+		priv->spi_tx_buf[0] = WRXDATA;
+	else if (window == USERWINDOW)
+		priv->spi_tx_buf[0] = WUDADATA;
+	else if (window == GPWINDOW)
+		priv->spi_tx_buf[0] = WGPDATA;
+
+	ret = spi_write(priv->spi, priv->spi_tx_buf, len + 1);
+
+	return ret;
+}
+
+/* Select the current register bank if necessary to be able to read @addr.*/
+static void enc424j600_set_bank(struct enc424j600_net *priv, u8 addr)
+{
+	u8 b = (addr & BANK_MASK) >> BANK_SHIFT;
+
+	/* These registers are present in all banks, no need to switch bank */
+	if (addr >= EUDASTL && addr <= ECON1H)
+		return;
+	if (priv->bank == b)
+		return;
+
+	priv->spi_tx_buf[0] = BXSEL(b);
+
+	enc424j600_spi_trans(priv, 1);
+	priv->bank = b;
+}
+
+/* sets and clears SFR registers */
+static void enc424j600_write_bits(struct enc424j600_net *priv, u8 addr,
+				u8 bits, u8 mask)
+{
+	enc424j600_set_bank(priv, addr);
+	priv->spi_tx_buf[0] = bits;
+	priv->spi_tx_buf[1] = mask;
+	spi_write(priv->spi, priv->spi_tx_buf, 2);
+}
+
+/* Write a 8bit special function register.
+   The @sfr parameters takes address of the register.*/
+static int enc424j600_write_8b_sfr(struct enc424j600_net *priv, u8
sfr, u8 data)
+{
+	int ret;
+
+	enc424j600_set_bank(priv, sfr);
+	priv->spi_tx_buf[0] = WCR(sfr & ADDR_MASK);
+	priv->spi_tx_buf[1] = data & 0xFF;
+	ret = spi_write(priv->spi, priv->spi_tx_buf, 2);
+
+	return ret;
+}
+
+/* Read a 8bit special function register.
+   The @sfr parameters takes address of the register.*/
+static int enc424j600_read_8b_sfr(struct enc424j600_net *priv,
+					u8 sfr, u8 *data)
+{
+	int ret;
+
+	enc424j600_set_bank(priv, sfr);
+	priv->spi_tx_buf[0] = RCR(sfr & ADDR_MASK);
+	ret = enc424j600_spi_trans(priv, 2);
+	*data = priv->spi_rx_buf[0];
+
+	return ret;
+}
+
+/* Write a 16bit special function register.
+   The @sfr parameters takes address of the low byte of the register.
+   Takes care of the endiannes & buffers.*/
+static int enc424j600_write_16b_sfr(struct enc424j600_net *priv,
+					u8 sfr, u16 data)
+{
+	int ret;
+
+	enc424j600_set_bank(priv, sfr);
+	priv->spi_tx_buf[0] = WCR(sfr & ADDR_MASK);
+	priv->spi_tx_buf[1] = data & 0xFF;
+	priv->spi_tx_buf[2] = data >> 8;
+	ret = spi_write(priv->spi, priv->spi_tx_buf, 3);
+	if (ret && netif_msg_drv(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
+				__func__, ret);
+
+	return ret;
+}
+
+/*Read a 16bit special function register.
+  The @sfr parameters takes address of the low byte of the register.
+  Takes care of the endiannes & buffers. */
+static int enc424j600_read_16b_sfr(struct enc424j600_net *priv,
+					u8 sfr, u16 *data)
+{
+	int ret;
+
+	enc424j600_set_bank(priv, sfr);
+	priv->spi_tx_buf[0] = RCR(sfr & ADDR_MASK);
+	priv->spi_tx_buf[1] = 0;
+	priv->spi_tx_buf[2] = 0;
+	priv->spi_tx_buf[3] = 0;
+	ret = enc424j600_spi_trans(priv, 3);
+	*data = priv->spi_rx_buf[0] | priv->spi_rx_buf[1] << (u16) 8;
+
+	return ret;
+}
+
+static unsigned long msec20_to_jiffies;
+
+/*Wait for bits in register to become equal to @readyMask, but at most 20ms.*/
+static int checktimeout_16bit(struct enc424j600_net *priv,
+				u8 reg, u16 mask, u16 readyMask)
+{
+	unsigned long timeout = jiffies + msec20_to_jiffies;
+	u16 value;
+
+	/* 20 msec timeout read */
+	enc424j600_read_16b_sfr(priv, reg, &value);
+	while ((value & mask) != readyMask) {
+		if (time_after(jiffies, timeout)) {
+			if (netif_msg_drv(priv))
+				dev_dbg(&priv->spi->dev,
+					"reg %02x ready timeout!\n", reg);
+			return -ETIMEDOUT;
+		}
+		cpu_relax();
+		enc424j600_read_16b_sfr(priv, reg, &value);
+	}
+
+	return 0;
+}
+
+/* wait 20 ms for (value&mask) to become readyMask*/
+static int checktimeout_8bit(struct enc424j600_net *priv,
+				u8 reg, u8 mask, u8 readyMask)
+{
+	unsigned long timeout = jiffies + msec20_to_jiffies;
+	u8 value;
+
+	/* 20 msec timeout read */
+	enc424j600_read_8b_sfr(priv, reg, &value);
+	while ((value & mask) != readyMask) {
+		if (time_after(jiffies, timeout)) {
+			if (netif_msg_drv(priv))
+				dev_dbg(&priv->spi->dev,
+					"reg %02x ready timeout!\n", reg);
+			return -ETIMEDOUT;
+		}
+		cpu_relax();
+		enc424j600_read_8b_sfr(priv, reg, &value);
+	}
+
+	return 0;
+}
+
+/* Reset the enc424j600.*/
+static int enc424j600_soft_reset(struct enc424j600_net *priv)
+{
+	int ret;
+	u16 eudast;
+
+	if (netif_msg_hw(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
+
+	enc424j600_write_16b_sfr(priv, EUDASTL, EUDAST_TEST_VAL);
+	ret = checktimeout_16bit(priv, EUDASTL, 0xFFFF, EUDAST_TEST_VAL);
+	if (ret != 0)
+		return ret;
+	ret = checktimeout_16bit(priv, ESTATH, CLKRDY, CLKRDY);
+	if (ret != 0)
+		return ret;
+
+	priv->spi_tx_buf[0] = SETETHRST;
+	enc424j600_spi_trans(priv, 1);
+	/*inline with the datasheet */
+	udelay(25);
+
+	enc424j600_read_16b_sfr(priv, EUDASTL, &eudast);
+	if (netif_msg_hw(priv) && eudast != 0)
+		printk(KERN_DEBUG DRV_NAME
+				": %s() EUDASTL is not zero!\n", __func__);
+	/*inline with the datasheet */
+	/*datasheet says to wait for 256 usec atleast */
+	udelay(300);
+	return 0;
+}
+
+/*
+ * PHY register read
+ * PHY registers are not accessed directly, but through the MII
+ */
+static int enc424j600_phy_read(struct enc424j600_net *priv,
+						u16 address, u16 *data)
+{
+	int ret;
+
+	enc424j600_write_16b_sfr(priv, MIREGADRL,
+				address | (MIREGADRH_VAL << 8));
+	enc424j600_write_16b_sfr(priv, MICMDL, MIIRD);
+	udelay(26);
+	ret = !checktimeout_8bit(priv, MISTATL, BUSY, 0);
+	enc424j600_write_16b_sfr(priv, MICMDL, 0);
+	enc424j600_read_16b_sfr(priv, MIRDL, data);
+	return ret;
+}
+
+static int enc424j600_phy_write(struct enc424j600_net *priv, u16 address,
+				u16 data)
+{
+	enc424j600_write_16b_sfr(priv, MIREGADRL,
+				address | (MIREGADRH_VAL << 8));
+	enc424j600_write_16b_sfr(priv, MIWRL, data);
+	udelay(26);
+	return !checktimeout_8bit(priv, MISTATL, BUSY, 0);
+}
+
+/* Read the hardware MAC address to dev->dev_addr. */
+static int enc424j600_get_hw_macaddr(struct net_device *ndev)
+{
+	struct enc424j600_net *priv = netdev_priv(ndev);
+	u16 maadr1, maadr2, maadr3;
+
+	mutex_lock(&priv->lock);
+
+	if (netif_msg_drv(priv))
+		printk(KERN_INFO DRV_NAME
+				": %s: Setting MAC address to %pM\n",
+				ndev->name, ndev->dev_addr);
+
+	enc424j600_read_16b_sfr(priv, MAADR3L, &maadr3);
+	ndev->dev_addr[5] = maadr3 >> 8;
+	ndev->dev_addr[4] = maadr3 & 0xff;
+	enc424j600_read_16b_sfr(priv, MAADR2L, &maadr2);
+	ndev->dev_addr[3] = maadr2 >> 8;
+	ndev->dev_addr[2] = maadr2 & 0xff;
+	enc424j600_read_16b_sfr(priv, MAADR1L, &maadr1);
+	ndev->dev_addr[1] = maadr1 >> 8;
+	ndev->dev_addr[0] = maadr1 & 0xff;
+
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+/* Program the hardware MAC address from dev->dev_addr.*/
+static int enc424j600_set_hw_macaddr(struct net_device *ndev)
+{
+	struct enc424j600_net *priv = netdev_priv(ndev);
+
+	mutex_lock(&priv->lock);
+
+	if (priv->hw_enable) {
+		if (netif_msg_drv(priv))
+			printk(KERN_DEBUG DRV_NAME
+				": %s() Hardware must be disabled to set "
+				"Mac address\n", __func__);
+		mutex_unlock(&priv->lock);
+		return -EBUSY;
+	}
+
+	if (netif_msg_drv(priv))
+		printk(KERN_INFO DRV_NAME
+				": %s: Setting MAC address to %pM\n",
+				ndev->name, ndev->dev_addr);
+
+	enc424j600_write_16b_sfr(priv, MAADR3L,
+				ndev->dev_addr[4] | ndev->dev_addr[5] << 8);
+	enc424j600_write_16b_sfr(priv, MAADR2L,
+				ndev->dev_addr[2] | ndev->dev_addr[3] << 8);
+	enc424j600_write_16b_sfr(priv, MAADR1L,
+				ndev->dev_addr[0] | ndev->dev_addr[1] << 8);
+
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+/* Store the new hardware address in dev->dev_addr, and update the MAC.*/
+static int enc424j600_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct sockaddr *address = addr;
+
+	if (netif_running(dev))
+		return -EBUSY;
+	if (!is_valid_ether_addr(address->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
+	return enc424j600_set_hw_macaddr(dev);
+}
+
+u8 nolock_regb_read(struct enc424j600_net *priv, u8 address)
+{
+	u8 data;
+
+	enc424j600_read_8b_sfr(priv, address, &data);
+	return data;
+}
+
+u16 nolock_regw_read(struct enc424j600_net *priv, u8 address)
+{
+	u16 data;
+
+	enc424j600_read_16b_sfr(priv, address, &data);
+	return data;
+}
+
+/*Debug routine to dump useful register contents*/
+static void enc424j600_dump_regs(struct enc424j600_net *priv, const char *msg)
+{
+	mutex_lock(&priv->lock);
+	printk(KERN_DEBUG DRV_NAME " %s\n"
+	       "Cntrl: ECON1H ECON1L ECON2H ECON2L ESTATH ESTATL  EIRH  "
+	       "EIRL  EIEH  EIEL\n"
+	       "       0x%02x   0x%02x   0x%02x   0x%02x   0x%02x   0x%02x    "
+	       "0x%02x  0x%02x  0x%02x  0x%02x\n"
+	       "MAC  : MACON1 MACON2\n"
+	       "       0x%04x 0x%04x\n"
+	       "Rx   : ERXST  ERXTAIL ERXHEAD  ERXWRPT ERXRDPT ERXFCON MAMXFL\n"
+	       "       0x%04x 0x%04x  0x%04x   0x%04x  0x%04x  0x%04x  0x%04x\n"
+	       "Tx   : ETXST  ETXLEN  MACLCON1 \n"
+	       "       0x%04x 0x%04x  0x%02x\n",
+	       msg,
+	       nolock_regb_read(priv, ECON1H), nolock_regb_read(priv, ECON1L),
+	       nolock_regb_read(priv, ECON2H), nolock_regb_read(priv, ECON2L),
+	       nolock_regb_read(priv, ESTATH), nolock_regb_read(priv, ESTATL),
+	       nolock_regb_read(priv, EIRH), nolock_regb_read(priv, EIRL),
+	       nolock_regb_read(priv, EIEH), nolock_regb_read(priv, EIEL),
+	       nolock_regw_read(priv, MACON1L), nolock_regw_read(priv, MACON2L),
+	       nolock_regw_read(priv, ERXSTL), nolock_regw_read(priv, ERXTAILL),
+	       nolock_regw_read(priv, ERXHEADL),
+	       nolock_regw_read(priv, ERXWRPTL), nolock_regw_read(priv,
+								  ERXRDPTL),
+	       nolock_regw_read(priv, ERXFCONL), nolock_regw_read(priv,
+								  MAMXFLL),
+	       nolock_regw_read(priv, ETXSTL), nolock_regw_read(priv, ETXLENL),
+	       nolock_regw_read(priv, MACLCONL));
+	mutex_unlock(&priv->lock);
+}
+
+/*
+ * TODO: Check the functionality
+ * Low power mode shrinks power consumption about 100x, so we'd like
+ * the chip to be in that mode whenever it's inactive. (However, we
+ * can't stay in lowpower mode during suspend with WOL active.)
+ */
+static void enc424j600_lowpower(struct enc424j600_net *priv, bool is_low)
+{
+
+	if (netif_msg_drv(priv))
+		dev_dbg(&priv->spi->dev, "%s power...\n",
+			is_low ? "low" : "high");
+
+#if 0
+	mutex_lock(&priv->lock);
+	if (is_low) {
+		nolock_reg_bfclr(priv, ECON1, ECON1_RXEN);
+		checktimeout_8bit(priv, ESTAT, ESTAT_RXBUSY, 0);
+		checktimeout_8bit(priv, ECON1, ECON1_TXRTS, 0);
+		/* ECON2_VRPS was set during initialization */
+		nolock_reg_bfset(priv, ECON2, ECON2_PWRSV);
+	} else {
+		nolock_reg_bfclr(priv, ECON2, ECON2_PWRSV);
+		checktimeout_8bit(priv, ESTAT, ESTAT_CLKRDY, ESTAT_CLKRDY);
+		/* caller sets ECON1_RXEN */
+	}
+	mutex_unlock(&priv->lock);
+#endif
+}
+
+static unsigned long msec2000_to_jiffies;
+/* Waits for autonegotiation to complete. */
+static int enc424j600_wait_for_autoneg(struct enc424j600_net *priv)
+{
+	unsigned long timeout = jiffies + msec2000_to_jiffies;
+	u16 value;
+
+	/* 20 msec timeout read */
+	enc424j600_phy_read(priv, PHSTAT1, &value);
+	while ((value & ANDONE) == 0) {
+		if (time_after(jiffies, timeout)) {
+			if (netif_msg_drv(priv))
+				dev_dbg(&priv->spi->dev,
+					"reg %02x ready timeout!\n", PHSTAT1);
+			return -ETIMEDOUT;
+		}
+		cpu_relax();
+		enc424j600_phy_read(priv, PHSTAT1, &value);
+	}
+	return 0;
+}
+
+/*
+ * Reset and initialize the chip, but don't enable interrupts and don't
+ * start receiving yet.
+ */
+static int enc424j600_hw_init(struct enc424j600_net *priv)
+{
+	u8 eidledl;
+	u16 phcon1;
+	u16 macon2;
+	u16 econ1l;
+
+	/*priv->autoneg = AUTONEG_ENABLE; */
+	if (netif_msg_drv(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() - %s\n", __func__,
+				priv->autoneg ? "Autoneg" : (priv->
+				full_duplex ? "FullDuplex" : "HalfDuplex"));
+
+	mutex_lock(&priv->lock);
+
+	priv->bank = 0;
+	priv->hw_enable = false;
+	priv->tx_retry_count = 0;
+	priv->max_pk_counter = 0;
+	priv->rxfilter = RXFILTER_NORMAL;
+
+	if (enc424j600_soft_reset(priv) != 0)
+		return 0;
+
+	/* Check the device id and silicon revision id. */
+	enc424j600_read_8b_sfr(priv, EIDLEDL, &eidledl);
+
+	if ((eidledl & DEVID_MASK) >> DEVID_SHIFT != ENC424J600_DEV_ID) {
+		if (netif_msg_drv(priv))
+			printk(KERN_DEBUG DRV_NAME
+				": %s() Invalid device ID: %d\n", __func__,
+				(eidledl & DEVID_MASK) >> DEVID_SHIFT);
+		return 0;
+	}
+
+	if (netif_msg_drv(priv))
+		printk(KERN_INFO DRV_NAME ": Silicon revision ID: 0x%02x\n",
+				(eidledl & REVID_MASK) >> REVID_SHIFT);
+
+	enc424j600_write_16b_sfr(priv, ETXSTL, TXSTART);
+	enc424j600_write_16b_sfr(priv, ERXSTL, RXSTART);
+
+	priv->next_pk_ptr = RXSTART;
+	enc424j600_write_16b_sfr(priv, ERXTAILL, SRAMSIZE - 2);
+	enc424j600_write_16b_sfr(priv, ERXFCONL, UCEN | BCEN | CRCEN | RUNTEN);
+
+	enc424j600_phy_write(priv, PHANA, PHANA_DEFAULT);
+
+	/* PHCON1 */
+	phcon1 = 0;
+	if (priv->autoneg) {
+		/* Enable autonegotiation and renegotiate */
+		phcon1 |= ANEN | RENEG;
+	} else {
+		if (priv->speed100)
+			phcon1 |= SPD100;
+		if (priv->full_duplex)
+			phcon1 |= PFULDPX;
+	}
+	enc424j600_phy_write(priv, PHCON1, phcon1);
+
+	/* MACON2
+	 * defer transmission if collision occurs (only for half duplex)
+	 * pad to 60 or 64 bytes and append CRC
+	 * enable receiving huge frames (instead of limiting packet size) */
+	macon2 = MACON2_DEFER | PADCFG2 | PADCFG0 | TXCRCEN | HFRMEN;
+
+	/* If autonegotiation is enabled, we have to wait untill it finishes
+	 * and set the PHYDPX bit in MACON2 correctly */
+	if (priv->autoneg) {
+		u8 estath;
+		if (!enc424j600_wait_for_autoneg(priv)) {
+			/* read the PHYDPX bit in ESTAT and set FULDPX in
+			   MACON2 accordingly */
+			enc424j600_read_8b_sfr(priv, ESTATH, &estath);
+			if (estath & PHYDPX)
+				macon2 |= FULDPX;
+		} else		/*if timedout, just disable autoneg */
+			priv->autoneg = AUTONEG_DISABLE;
+	} else if (priv->full_duplex)
+		macon2 |= FULDPX;
+
+	enc424j600_write_16b_sfr(priv, MACON2L, macon2);
+
+	/* MAIPGL
+	 * Recomended values for inter packet gaps */
+	if (!priv->autoneg) {
+		enc424j600_write_16b_sfr(priv, MAIPGL,
+					MAIPGL_VAL | (MAIPGH_VAL << 8));
+	}
+
+	/*
+	 * Select enabled interrupts, but don't set the global
+	 * interrupt enable flag.
+	 */
+
+	enc424j600_write_16b_sfr(priv, EIEL,
+				LINKIE << 8 | PKTIE | DMAIE | TXIE | TXABTIE |
+				RXABTIE);
+
+	enc424j600_read_16b_sfr(priv, ECON1L, &econ1l);
+	econ1l |= (RXEN);
+	enc424j600_write_16b_sfr(priv, ECON1L, econ1l);
+
+	mutex_unlock(&priv->lock);
+
+	if (netif_msg_hw(priv))
+		enc424j600_dump_regs(priv, "Hw initialized.");
+
+	return 1;
+}
+
+static void enc424j600_hw_enable(struct enc424j600_net *priv)
+{
+	if (netif_msg_hw(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() enabling interrupts.\n",
+				__func__);
+
+	mutex_lock(&priv->lock);
+
+	/* Clear any pending interrupts */
+	enc424j600_write_16b_sfr(priv, EIRL, 0);
+
+	/* Enable global interrupt flag */
+	enc424j600_write_bits(priv, EIEH, BFS(EIEH), INTIE);
+
+	/* enable receive logic */
+	enc424j600_write_bits(priv, ECON1L, BFS(ECON1L), RXEN);
+	priv->hw_enable = true;
+	mutex_unlock(&priv->lock);
+}
+
+static void enc424j600_hw_disable(struct enc424j600_net *priv)
+{
+	if (netif_msg_hw(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() disabling interrupts.\n",
+				__func__);
+
+	mutex_lock(&priv->lock);
+
+	/* disable receive logic */
+	enc424j600_write_bits(priv, ECON1L, BFC(ECON1L), RXEN);
+
+	/* Disable global interrupt flag */
+	enc424j600_write_bits(priv, EIEH, BFC(EIEH), INTIE);
+
+	priv->hw_enable = false;
+
+	mutex_unlock(&priv->lock);
+}
+
+static int
+enc424j600_setlink(struct net_device *ndev, u8 autoneg, u16 speed, u8 duplex)
+{
+	struct enc424j600_net *priv = netdev_priv(ndev);
+	int ret = 0;
+
+	if (!priv->hw_enable) {
+		/* link is in low power mode now; duplex setting
+		 * will take effect on next enc424j600_hw_init().
+		 */
+		if (speed == SPEED_10 || speed == SPEED_100) {
+			priv->autoneg = (autoneg == AUTONEG_ENABLE);
+			priv->full_duplex = (duplex == DUPLEX_FULL);
+			priv->speed100 = (speed == SPEED_100);
+		} else {
+			if (netif_msg_link(priv))
+				dev_warn(&ndev->dev,
+					"unsupported link setting\n");
+			/*speeds other than SPEED_10 and SPEED_100 */
+			/*are not supported by chip */
+			ret = -EOPNOTSUPP;
+		}
+	} else {
+		if (netif_msg_link(priv))
+			dev_warn(&ndev->dev, "Warning: hw must be disabled "
+				"to set link mode\n");
+		ret = -EBUSY;
+	}
+	return ret;
+}
+
+/*
+ * Receive Status vector
+ */
+static void enc424j600_dump_rsv(struct enc424j600_net *priv, const char *msg,
+				u16 pk_ptr, int len, u16 sts)
+{
+	printk(KERN_DEBUG DRV_NAME ": %s - NextPk: 0x%04x - RSV:\n",
+			msg, pk_ptr);
+	printk(KERN_DEBUG DRV_NAME ": ByteCount: %d, DribbleNibble: %d\n", len,
+			RSV_GETBIT(sts, RSV_DRIBBLENIBBLE));
+	printk(KERN_DEBUG DRV_NAME ": RxOK: %d, CRCErr:%d, LenChkErr: %d,"
+			" LenOutOfRange: %d\n", RSV_GETBIT(sts, RSV_RXOK),
+			RSV_GETBIT(sts, RSV_CRCERROR),
+			RSV_GETBIT(sts, RSV_LENCHECKERR),
+			RSV_GETBIT(sts, RSV_LENOUTOFRANGE));
+	printk(KERN_DEBUG DRV_NAME ": Multicast: %d, Broadcast: %d, "
+			"LongDropEvent: %d, CarrierEvent: %d\n",
+			RSV_GETBIT(sts, RSV_RXMULTICAST),
+			RSV_GETBIT(sts, RSV_RXBROADCAST),
+			RSV_GETBIT(sts, RSV_RXLONGEVDROPEV),
+			RSV_GETBIT(sts, RSV_CARRIEREV));
+	printk(KERN_DEBUG DRV_NAME ": ControlFrame: %d, PauseFrame: %d,"
+			" UnknownOp: %d, VLanTagFrame: %d\n",
+			RSV_GETBIT(sts, RSV_RXCONTROLFRAME),
+			RSV_GETBIT(sts, RSV_RXPAUSEFRAME),
+			RSV_GETBIT(sts, RSV_RXUNKNOWNOPCODE),
+			RSV_GETBIT(sts, RSV_RXTYPEVLAN));
+}
+
+static void dump_packet(const char *msg, int len, const char *data)
+{
+
+	printk(KERN_ALERT ": %s - packet len:%d\n", msg, len);
+	print_hex_dump(KERN_ALERT, "pk data: ", DUMP_PREFIX_OFFSET, 16, 1,
+			data, len, true);
+}
+
+/*
+ * Calculate wrap around when reading beyond the end of the RX buffer
+ */
+static u16 rx_packet_start(u16 ptr)
+{
+	if (ptr + RSV_SIZE > RXEND_INIT)
+		return (ptr + RSV_SIZE) - (RXEND_INIT - RXSTART + 1);
+	else
+		return ptr + RSV_SIZE;
+}
+
+/*
+ * ERXRDPT need to be set always at odd addresses, refer to errata datasheet
+ */
+static u16 erxrdpt_workaround(u16 next_packet_ptr, u16 start, u16 end)
+{
+	u16 erxrdpt;
+
+	if ((next_packet_ptr - 1 < start) || (next_packet_ptr - 1 > end))
+		erxrdpt = end;
+	else
+		erxrdpt = next_packet_ptr - 1;
+
+	return erxrdpt;
+}
+
+static void nolock_rxfifo_init(struct enc424j600_net *priv, u16 start, u16 end)
+{
+	u16 erxrdpt;
+
+	if (start > 0x5FFF || end > 0x5FFF || start > end) {
+		if (netif_msg_drv(priv))
+			printk(KERN_ERR DRV_NAME ": %s(%d, %d) RXFIFO "
+				"bad parameters!\n", __func__, start, end);
+		return;
+	}
+	/* set receive buffer start + end */
+	priv->next_pk_ptr = start;
+	enc424j600_write_16b_sfr(priv, ERXSTL, start);
+	erxrdpt = erxrdpt_workaround(priv->next_pk_ptr, start, end);
+	enc424j600_write_16b_sfr(priv, ERXRDPTL, erxrdpt);
+	enc424j600_write_16b_sfr(priv, ERXTAILL, end);
+}
+
+/*
+ * Hardware receive function.
+ * Read the buffer memory, update the FIFO pointer to free the buffer,
+ * check the status vector and decrement the packet counter.
+ */
+static void enc424j600_hw_rx(struct net_device *ndev)
+{
+	struct enc424j600_net *priv = netdev_priv(ndev);
+	struct sk_buff *skb = NULL;
+	u16 erxrdpt, next_packet, rxstat;
+	u8 pkcnt;
+	u16 head, tail;
+	u8 rsv[RSV_SIZE];
+	u16 newrxtail;
+	int len;
+
+	if (netif_msg_rx_status(priv))
+		printk(KERN_DEBUG DRV_NAME ": RX pk_addr:0x%04x\n",
+				priv->next_pk_ptr);
+	if (unlikely(priv->next_pk_ptr > RXEND_INIT)) {
+		if (netif_msg_rx_err(priv))
+			dev_err(&ndev->dev,
+				"%s() Invalid packet address!! 0x%04x\n",
+				__func__, priv->next_pk_ptr);
+		mutex_lock(&priv->lock);
+		enc424j600_write_bits(priv, ECON1L, BFC(ECON1L), RXEN);
+		enc424j600_write_bits(priv, ECON2L, BFS(ECON2L), RXRST);
+		enc424j600_write_bits(priv, ECON2L, BFC(ECON2L), RXRST);
+		nolock_rxfifo_init(priv, RXSTART, RXEND_INIT);
+		enc424j600_write_bits(priv, EIRL, BFC(EIRL), RXABTIF);
+		enc424j600_write_bits(priv, ECON1L, BFS(ECON1L), RXEN);
+		mutex_unlock(&priv->lock);
+		ndev->stats.rx_errors++;
+		return;
+	}
+
+	/* Read next packet pointer and rx status vector */
+	enc424j600_read_sram(priv, rsv, sizeof(rsv), priv->next_pk_ptr,
+			RXWINDOW);
+
+	next_packet = rsv[1];
+	next_packet <<= 8;
+	next_packet |= rsv[0];
+
+	len = rsv[3];
+	len <<= 8;
+	len |= rsv[2];
+
+	rxstat = rsv[5];
+	rxstat <<= 8;
+	rxstat |= rsv[4];
+
+	if (netif_msg_rx_status(priv))
+		enc424j600_dump_rsv(priv, __func__, next_packet, len, rxstat);
+
+	if (!RSV_GETBIT(rxstat, RSV_RXOK) || len > MAX_FRAMELEN) {
+		if (netif_msg_rx_err(priv))
+			dev_err(&ndev->dev, "Rx Error (%04x)\n", rxstat);
+		ndev->stats.rx_errors++;
+		if (RSV_GETBIT(rxstat, RSV_CRCERROR))
+			ndev->stats.rx_crc_errors++;
+		if (RSV_GETBIT(rxstat, RSV_LENCHECKERR))
+			ndev->stats.rx_frame_errors++;
+		if (len > MAX_FRAMELEN)
+			ndev->stats.rx_over_errors++;
+	} else {
+		skb = dev_alloc_skb(len + NET_IP_ALIGN);
+		if (!skb) {
+			if (netif_msg_rx_err(priv))
+				dev_err(&ndev->dev,
+					"out of memory for Rx'd frame\n");
+			ndev->stats.rx_dropped++;
+		} else {
+			skb->dev = ndev;
+			skb_reserve(skb, NET_IP_ALIGN);
+
+			/* copy the packet from the receive buffer */
+			enc424j600_read_sram(priv, skb_put(skb, len), len,
+					rx_packet_start(priv->next_pk_ptr),
+					RXWINDOW);
+
+			if (netif_msg_pktdata(priv))
+				dump_packet(__func__, skb->len, skb->data);
+			skb->protocol = eth_type_trans(skb, ndev);
+			/* update statistics */
+			ndev->stats.rx_packets++;
+			ndev->stats.rx_bytes += len;
+			netif_rx_ni(skb);
+		}
+	}
+	newrxtail = next_packet - 2;
+	if (next_packet == RXSTART)
+		newrxtail = SRAMSIZE - 2;
+
+	enc424j600_write_16b_sfr(priv, ERXTAILL, newrxtail);
+	/*
+	 * Move the RX read pointer to the start of the next
+	 * received packet.
+	 * This frees the memory we just read out
+	 */
+	erxrdpt = erxrdpt_workaround(next_packet, RXSTART, RXEND_INIT);
+	if (netif_msg_hw(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() ERXRDPT:0x%04x\n", __func__,
+				erxrdpt);
+
+	/*TODO: remove mutex_lock wherever not required */
+	mutex_lock(&priv->lock);
+	enc424j600_write_16b_sfr(priv, ERXRDPTL, erxrdpt);
+
+	priv->next_pk_ptr = next_packet;
+	enc424j600_read_8b_sfr(priv, ESTATL, &pkcnt);
+	enc424j600_read_16b_sfr(priv, ERXHEADL, &head);
+	enc424j600_read_16b_sfr(priv, ERXTAILL, &tail);
+	/* we are done with this packet, decrement the packet counter */
+	enc424j600_write_bits(priv, ECON1H, BFS(ECON1H), PKTDEC);
+
+	mutex_unlock(&priv->lock);
+}
+
+/*
+ * Access the PHY to determine link status
+ */
+static void enc424j600_check_link_status(struct enc424j600_net *priv)
+{
+	u8 estath;
+	u16 macon2;
+
+	enc424j600_read_8b_sfr(priv, ESTATH, &estath);
+	if (estath & PHYLNK) {
+		if (priv->autoneg) {
+			if (!enc424j600_wait_for_autoneg(priv)) {
+				if (estath & PHYDPX) {
+					printk(KERN_ALERT "Full Duplex");
+					enc424j600_read_16b_sfr(priv, MACON2L,
+							&macon2);
+					macon2 |= FULDPX;
+					enc424j600_write_16b_sfr(priv, MACON2L,
+							macon2);
+				}
+			} else	/*if timed out, disable autoneg and continue */
+				priv->autoneg = AUTONEG_DISABLE;
+		}
+		netif_carrier_on(priv->netdev);
+		if (netif_msg_ifup(priv))
+			dev_info(&(priv->netdev->dev), "link up\n");
+	} else {
+		if (netif_msg_ifdown(priv))
+			dev_info(&(priv->netdev->dev), "link down\n");
+		netif_carrier_off(priv->netdev);
+	}
+}
+
+static void enc424j600_tx_clear(struct enc424j600_net *priv, bool err)
+{
+	struct net_device *ndev = priv->netdev;
+
+	if (err)
+		ndev->stats.tx_errors++;
+	else
+		ndev->stats.tx_packets++;
+
+	if (priv->tx_skb) {
+		if (!err)
+			ndev->stats.tx_bytes += priv->tx_skb->len;
+		dev_kfree_skb(priv->tx_skb);
+		priv->tx_skb = NULL;
+	}
+
+	netif_wake_queue(ndev);
+}
+
+static int enc424j600_int_rx_abbort_handler(struct enc424j600_net *priv,
+		int loop)
+{
+	loop++;
+	if (netif_msg_intr(priv))
+		printk(KERN_DEBUG DRV_NAME ": intRXAbt(%d)\n", loop);
+	mutex_lock(&priv->lock);
+	priv->netdev->stats.rx_dropped++;
+	enc424j600_write_bits(priv, EIRL, BFC(EIRL), RXABTIF);
+	mutex_unlock(&priv->lock);
+
+	return loop;
+}
+
+static int enc424j600_int_link_handler(struct enc424j600_net *priv, int loop)
+{
+	loop++;
+	if (netif_msg_intr(priv))
+		printk(KERN_DEBUG DRV_NAME ": intLINK(%d)\n", loop);
+
+	/* we check more than is necessary here --
+	 * only PHYLNK would be needed. */
+	enc424j600_check_link_status(priv);
+
+	return loop;
+}
+
+static int enc424j600_int_tx_handler(struct enc424j600_net *priv, int loop)
+{
+	loop++;
+	if (netif_msg_intr(priv))
+		printk(KERN_DEBUG DRV_NAME ": intTX(%d)\n", loop);
+
+	mutex_lock(&priv->lock);
+	enc424j600_tx_clear(priv, false);
+	enc424j600_write_bits(priv, EIRL, BFC(EIRL), TXIF);
+	mutex_unlock(&priv->lock);
+
+	return loop;
+}
+
+static int enc424j600_int_tx_err_handler(struct enc424j600_net *priv, int loop)
+{
+	u8 etxstat;
+
+	loop++;
+	if (netif_msg_intr(priv))
+		printk(KERN_DEBUG DRV_NAME ": intTXErr(%d)\n", loop);
+
+	mutex_lock(&priv->lock);
+
+	enc424j600_read_8b_sfr(priv, ETXSTATH, &etxstat);
+
+	if (etxstat & LATECOL) {
+		if (netif_msg_tx_err(priv))
+			printk(KERN_DEBUG DRV_NAME
+					": Late collision TXErr (%d)\n",
+					priv->tx_retry_count);
+		if (priv->tx_retry_count++ < MAX_TX_RETRYCOUNT)
+			enc424j600_write_bits(priv, ECON1L, BFS(ECON1L), TXRTS);
+		else
+			enc424j600_tx_clear(priv, true);
+	} else if (etxstat & MAXCOL) {
+		if (netif_msg_tx_err(priv))
+			printk(KERN_DEBUG DRV_NAME ": Max collisions TXErr\n");
+		enc424j600_tx_clear(priv, true);
+	} else {
+		enc424j600_tx_clear(priv, true);
+	}
+
+	mutex_unlock(&priv->lock);
+
+	return loop;
+}
+
+static int enc424j600_int_received_packet_handler(struct enc424j600_net *priv)
+{
+	uint8_t pk_counter;
+	int ret;
+
+	enc424j600_read_8b_sfr(priv, ESTATL, &pk_counter);
+	if (pk_counter && netif_msg_intr(priv))
+		printk(KERN_DEBUG DRV_NAME ": intRX, pk_cnt: %d\n", pk_counter);
+	if (pk_counter > priv->max_pk_counter) {
+		/* update statistics */
+		priv->max_pk_counter = pk_counter;
+		if (netif_msg_rx_status(priv) && priv->max_pk_counter > 1)
+			printk(KERN_DEBUG DRV_NAME ": RX max_pk_cnt: %d\n",
+					priv->max_pk_counter);
+	}
+	ret = pk_counter;
+	while (pk_counter-- > 0)
+		enc424j600_hw_rx(priv->netdev);
+	return ret;
+}
+
+static void enc424j600_irq_work_handler(struct work_struct *work)
+{
+
+	struct enc424j600_net *priv =
+			container_of(work, struct enc424j600_net, irq_work);
+	int loop;
+
+	if (netif_msg_intr(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
+
+	/* disable further interrupts */
+	enc424j600_write_bits(priv, EIEH, BFC(EIEH), INTIE);
+
+	do {
+		u16 intflags;
+		enc424j600_read_16b_sfr(priv, EIRL, &intflags);
+		loop = 0;
+
+		/* LINK changed handler */
+		if ((intflags & LINKIF) != 0)
+			loop = enc424j600_int_link_handler(priv, loop);
+
+		/* TX complete handler */
+		if ((intflags & TXIF) != 0)
+			loop = enc424j600_int_tx_handler(priv, loop);
+
+		/* TX Error handler */
+		if ((intflags & TXABTIF) != 0) {
+			printk(KERN_ALERT "ABORTING TRANSMITTING PACKET");
+			loop = enc424j600_int_tx_err_handler(priv, loop);
+		}
+		/* RX Error handler */
+		if ((intflags & RXABTIF) != 0) {
+			printk(KERN_ALERT "ABORTING RECEIVED PACKET");
+			loop = enc424j600_int_rx_abbort_handler(priv, loop);
+		}
+		/* RX handler */
+		if ((intflags & PKTIF) != 0)
+			loop = enc424j600_int_received_packet_handler(priv);
+		enc424j600_write_bits(priv, EIRL, BFC(EIRL), intflags && 0xff);
+		enc424j600_write_bits(priv, EIRH, BFC(EIRH), intflags >> 8);
+	} while (loop);
+	/* re-enable interrupts */
+	enc424j600_write_bits(priv, EIEH, BFS(EIEH), INTIE);
+
+	if (netif_msg_intr(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() exit\n", __func__);
+}
+
+void locked_reg_bfset(struct enc424j600_net *priv, u8 addr, u8 mask)
+{
+	mutex_lock(&priv->lock);
+	enc424j600_write_bits(priv, addr, BFS(addr), mask);
+	mutex_unlock(&priv->lock);
+}
+
+/*
+ * Hardware transmit function.
+ * Fill the buffer memory and send the contents of the transmit buffer
+ * onto the network
+ */
+static void enc424j600_hw_tx(struct enc424j600_net *priv)
+{
+	if (!priv->tx_skb) {
+		enc424j600_tx_clear(priv, false);
+		return;
+	}
+
+	if (netif_msg_tx_queued(priv))
+		printk(KERN_DEBUG DRV_NAME ": Tx Packet Len:%d\n",
+		       priv->tx_skb->len);
+
+	if (netif_msg_pktdata(priv))
+		dump_packet(__func__, priv->tx_skb->len, priv->tx_skb->data);
+
+	enc424j600_write_sram(priv, priv->tx_skb->data, priv->tx_skb->len,
+		      TXSTART, GPWINDOW);
+
+	/* Set the tx pointer to start of general purpose SRAM area */
+	enc424j600_write_16b_sfr(priv, ETXSTL, TXSTART);
+
+	/* Write the transfer length */
+	enc424j600_write_16b_sfr(priv, ETXLENL, priv->tx_skb->len);
+
+	/* set TX request flag */
+	locked_reg_bfset(priv, ECON1L, TXRTS);
+}
+
+static int enc424j600_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct enc424j600_net *priv = netdev_priv(dev);
+
+	if (netif_msg_tx_queued(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
+
+	/* If some error occurs while trying to transmit this
+	 * packet, you should return '1' from this function.
+	 * In such a case you _may not_ do anything to the
+	 * SKB, it is still owned by the network queueing
+	 * layer when an error is returned. This means you
+	 * may not modify any SKB fields, you may not free
+	 * the SKB, etc.
+	 */
+	netif_stop_queue(dev);
+
+	/* save the timestamp */
+	priv->netdev->trans_start = jiffies;
+	/* Remember the skb for deferred processing */
+	priv->tx_skb = skb;
+	schedule_work(&priv->tx_work);
+
+	return NETDEV_TX_OK;
+}
+
+static void enc424j600_tx_work_handler(struct work_struct *work)
+{
+	struct enc424j600_net *priv =
+		container_of(work, struct enc424j600_net, tx_work);
+
+	/* actual delivery of data */
+	enc424j600_hw_tx(priv);
+}
+
+static irqreturn_t enc424j600_irq(int irq, void *dev_id)
+{
+	struct enc424j600_net *priv = dev_id;
+
+	/*
+	 * Can't do anything in interrupt context because we need to
+	 * block (spi_sync() is blocking) so fire of the interrupt
+	 * handling workqueue.
+	 * Remember that we access enc424j600 registers through SPI bus
+	 * via spi_sync() call.
+	 */
+	schedule_work(&priv->irq_work);
+
+	return IRQ_HANDLED;
+}
+
+static void enc424j600_tx_timeout(struct net_device *ndev)
+{
+	struct enc424j600_net *priv = netdev_priv(ndev);
+
+	if (netif_msg_timer(priv))
+		dev_err(&ndev->dev, DRV_NAME " tx timeout\n");
+
+	ndev->stats.tx_errors++;
+	/* can't restart safely under softirq */
+	schedule_work(&priv->restart_work);
+}
+
+/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+static int enc424j600_net_open(struct net_device *dev)
+{
+	struct enc424j600_net *priv = netdev_priv(dev);
+
+	if (netif_msg_drv(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
+
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		if (netif_msg_ifup(priv))
+			dev_err(&dev->dev, "invalid MAC address %pM\n",
+					dev->dev_addr);
+		return -EADDRNOTAVAIL;
+	}
+	/* Reset the hardware here (and take it out of low power mode) */
+	enc424j600_lowpower(priv, false);
+	enc424j600_hw_disable(priv);
+	if (!enc424j600_hw_init(priv)) {
+		if (netif_msg_ifup(priv))
+			dev_err(&dev->dev, "hw_reset() failed\n");
+		return -EINVAL;
+	}
+	/* Update the MAC address (in case user has changed it) */
+	enc424j600_set_hw_macaddr(dev);
+	/* Enable interrupts */
+	enc424j600_hw_enable(priv);
+	/* check link status */
+	enc424j600_check_link_status(priv);
+	/* We are now ready to accept transmit requests from
+	 * the queueing layer of the networking.
+	 */
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+/* The inverse routine to net_open(). */
+static int enc424j600_net_close(struct net_device *dev)
+{
+	struct enc424j600_net *priv = netdev_priv(dev);
+
+	if (netif_msg_drv(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
+
+	enc424j600_hw_disable(priv);
+	enc424j600_lowpower(priv, true);
+	netif_stop_queue(dev);
+
+	return 0;
+}
+
+/*
+ * Set or clear the multicast filter for this adapter
+ * num_addrs == -1 Promiscuous mode, receive all packets
+ * num_addrs == 0 Normal mode, filter out multicast packets
+ * num_addrs > 0 Multicast mode, receive normal and MC packets
+ */
+static void enc424j600_set_multicast_list(struct net_device *dev)
+{
+	struct enc424j600_net *priv = netdev_priv(dev);
+	int oldfilter = priv->rxfilter;
+
+	if (dev->flags & IFF_PROMISC) {
+		if (netif_msg_link(priv))
+			dev_info(&dev->dev, "promiscuous mode\n");
+		priv->rxfilter = RXFILTER_PROMISC;
+	} else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count) {
+		if (netif_msg_link(priv))
+			dev_info(&dev->dev, "%smulticast mode\n",
+				(dev->flags & IFF_ALLMULTI) ? "all-" : "");
+		priv->rxfilter = RXFILTER_MULTI;
+	} else {
+		if (netif_msg_link(priv))
+			dev_info(&dev->dev, "normal mode\n");
+		priv->rxfilter = RXFILTER_NORMAL;
+	}
+
+	if (oldfilter != priv->rxfilter)
+		schedule_work(&priv->setrx_work);
+}
+
+void locked_regb_write(struct enc424j600_net *priv, u8 address, u8 data)
+{
+	mutex_lock(&priv->lock);
+	enc424j600_write_8b_sfr(priv, address, data);
+	mutex_unlock(&priv->lock);
+}
+
+static void enc424j600_setrx_work_handler(struct work_struct *work)
+{
+	u16 macon1;
+	struct enc424j600_net *priv =
+			container_of(work, struct enc424j600_net, setrx_work);
+
+	if (priv->rxfilter == RXFILTER_PROMISC) {
+		if (netif_msg_drv(priv))
+			printk(KERN_DEBUG DRV_NAME ": promiscuous mode\n");
+		enc424j600_read_16b_sfr(priv, MACON1L, &macon1);
+		macon1 = macon1 | PASSALL;
+		enc424j600_write_16b_sfr(priv, MACON1L, macon1);
+		locked_regb_write(priv, ERXFCONL, UCEN | MCEN | NOTMEEN);
+	} else if (priv->rxfilter == RXFILTER_MULTI) {
+		if (netif_msg_drv(priv))
+			printk(KERN_DEBUG DRV_NAME ": multicast mode\n");
+		locked_regb_write(priv, ERXFCONL, UCEN | CRCEN | BCEN | MCEN);
+	} else {
+		if (netif_msg_drv(priv))
+			printk(KERN_DEBUG DRV_NAME ": normal mode\n");
+		locked_regb_write(priv, ERXFCONL, UCEN | CRCEN | BCEN);
+	}
+}
+
+static void enc424j600_restart_work_handler(struct work_struct *work)
+{
+	struct enc424j600_net *priv =
+			container_of(work, struct enc424j600_net, restart_work);
+	struct net_device *ndev = priv->netdev;
+	int ret;
+
+	rtnl_lock();
+	if (netif_running(ndev)) {
+		enc424j600_net_close(ndev);
+		ret = enc424j600_net_open(ndev);
+		if (unlikely(ret)) {
+			dev_info(&ndev->dev, " could not restart %d\n", ret);
+			dev_close(ndev);
+		}
+	}
+	rtnl_unlock();
+}
+
+/* ......................... ETHTOOL SUPPORT ........................... */
+static int enc424j600_get_regs_len(struct net_device *dev)
+{
+	return SFR_REG_COUNT;
+}
+
+static void
+enc424j600_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info,
+			dev_name(dev->dev.parent), sizeof(info->bus_info));
+}
+
+static int
+enc424j600_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct enc424j600_net *priv = netdev_priv(dev);
+
+	cmd->transceiver = XCVR_INTERNAL;
+	cmd->supported = SUPPORTED_10baseT_Half
+			| SUPPORTED_10baseT_Full
+			| SUPPORTED_100baseT_Half
+			| SUPPORTED_100baseT_Full
+			| SUPPORTED_TP;
+
+	cmd->speed = priv->speed100 ? SPEED_100 : SPEED_10;
+	cmd->duplex = priv->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+	cmd->port = PORT_TP;
+	cmd->autoneg = priv->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+
+	return 0;
+}
+
+static int
+enc424j600_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	return enc424j600_setlink(dev, cmd->autoneg, cmd->speed, cmd->duplex);
+}
+
+static u32 enc424j600_get_msglevel(struct net_device *dev)
+{
+	struct enc424j600_net *priv = netdev_priv(dev);
+
+	return priv->msg_enable;
+}
+
+static void enc424j600_set_msglevel(struct net_device *dev, u32 val)
+{
+	struct enc424j600_net *priv = netdev_priv(dev);
+
+	priv->msg_enable = val;
+}
+
+static void enc424j600_get_regs(struct net_device *dev,
+			struct ethtool_regs *regs, void *p)
+{
+	struct enc424j600_net *priv = netdev_priv(dev);
+	u8 *buff = p;
+	u8 addroffset;
+
+	regs->version = 1;
+	mutex_lock(&priv->lock);
+	for (addroffset = 0; addroffset < SFR_REG_COUNT; addroffset++) {
+		switch (addroffset) {
+			/*skip reading reserved regs */
+		case 0x4C:
+		case 0x4D:
+		case 0x4E:
+		case 0x4F:
+		case 0x50:
+		case 0x51:
+		case 0x81:
+		case 0x83:
+		case 0x85:
+		case 0x92:
+		case 0x93:
+		case 0x94:
+		case 0x95:
+		case 0x96:
+		case 0x97:
+		case 0x98:
+		case 0x99:
+		case 0x9A:
+		case 0x9B:
+		case 0x9C:
+		case 0x9D:
+		case 0x9E:
+		case 0x9F:
+			buff[addroffset] = 0;
+			break;
+		default:
+			buff[addroffset] = nolock_regb_read(priv, addroffset);
+			break;
+		}
+	}
+	mutex_unlock(&priv->lock);
+}
+
+static const struct ethtool_ops enc424j600_ethtool_ops = {
+	.get_settings = enc424j600_get_settings,
+	.set_settings = enc424j600_set_settings,
+	.get_drvinfo = enc424j600_get_drvinfo,
+	.get_msglevel = enc424j600_get_msglevel,
+	.set_msglevel = enc424j600_set_msglevel,
+	.get_regs_len = enc424j600_get_regs_len,
+	.get_regs = enc424j600_get_regs,
+};
+
+static int enc424j600_chipset_init(struct net_device *dev)
+{
+	struct enc424j600_net *priv = netdev_priv(dev);
+
+	enc424j600_get_hw_macaddr(dev);
+	return enc424j600_hw_init(priv);
+}
+
+static const struct net_device_ops enc424j600_netdev_ops = {
+	.ndo_open = enc424j600_net_open,
+	.ndo_stop = enc424j600_net_close,
+	.ndo_start_xmit = enc424j600_send_packet,
+	.ndo_set_multicast_list = enc424j600_set_multicast_list,
+	.ndo_set_mac_address = enc424j600_set_mac_address,
+	.ndo_tx_timeout = enc424j600_tx_timeout,
+	.ndo_change_mtu = eth_change_mtu,
+	.ndo_validate_addr = eth_validate_addr,
+};
+
+static int __devinit enc424j600_probe(struct spi_device *spi)
+{
+	struct net_device *dev;
+	struct enc424j600_net *priv;
+	int ret = 0;
+
+	if (netif_msg_drv(&debug))
+		dev_info(&spi->dev, DRV_NAME " Ethernet driver %s loaded\n",
+			DRV_VERSION);
+
+	dev = alloc_etherdev(sizeof(struct enc424j600_net));
+	if (!dev) {
+		if (netif_msg_drv(&debug))
+			dev_err(&spi->dev, DRV_NAME
+				": unable to alloc new ethernet\n");
+		ret = -ENOMEM;
+		goto error_alloc;
+	}
+	priv = netdev_priv(dev);
+
+	priv->netdev = dev;
+
+	priv->spi = spi;
+	priv->msg_enable = netif_msg_init(debug.msg_enable,
+					ENC424J600_MSG_DEFAULT);
+	mutex_init(&priv->lock);
+	INIT_WORK(&priv->tx_work, enc424j600_tx_work_handler);
+	INIT_WORK(&priv->setrx_work, enc424j600_setrx_work_handler);
+	INIT_WORK(&priv->irq_work, enc424j600_irq_work_handler);
+	INIT_WORK(&priv->restart_work, enc424j600_restart_work_handler);
+	dev_set_drvdata(&spi->dev, priv);
+	SET_NETDEV_DEV(dev, &spi->dev);
+	/*TODO: chip DMA features to be utilized */
+	/* If requested, allocate DMA buffers */
+	if (enc424j600_enable_dma) {
+		spi->dev.coherent_dma_mask = ~0;
+
+		/*
+		 * Minimum coherent DMA allocation is PAGE_SIZE, so allocate
+		 * that much and share it between Tx and Rx DMA buffers.
+		 */
+#if SPI_TRANSFER_BUF_LEN > PAGE_SIZE / 2
+#error "A problem in DMA buffer allocation"
+#endif
+		priv->spi_tx_buf = dma_alloc_coherent(&spi->dev,
+						      PAGE_SIZE,
+						      &priv->spi_tx_dma,
+						      GFP_DMA);
+
+		if (priv->spi_tx_buf) {
+			priv->spi_rx_buf = (u8 *) (priv->spi_tx_buf +
+							(PAGE_SIZE / 2));
+			priv->spi_rx_dma = (dma_addr_t) (priv->spi_tx_dma +
+							(PAGE_SIZE / 2));
+		} else {
+			/* Fall back to non-DMA */
+			enc424j600_enable_dma = 0;
+		}
+	}
+
+	/* Allocate non-DMA buffers */
+	if (!enc424j600_enable_dma) {
+		priv->spi_tx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
+		if (!priv->spi_tx_buf) {
+			ret = -ENOMEM;
+			goto error_tx_buf;
+		}
+		priv->spi_rx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);
+		if (!priv->spi_rx_buf) {
+			ret = -ENOMEM;
+			goto error_rx_buf;
+		}
+	}
+
+	if (!enc424j600_chipset_init(dev)) {
+		if (netif_msg_probe(priv))
+			dev_info(&spi->dev, DRV_NAME " chip not found\n");
+		ret = -EIO;
+		goto error_irq;
+	}
+
+	/* Board setup must set the relevant edge trigger type;
+	 * level triggers won't currently work.
+	 */
+	ret = request_irq(spi->irq, enc424j600_irq, 0, DRV_NAME, priv);
+	if (ret < 0) {
+		if (netif_msg_probe(priv))
+			dev_err(&spi->dev, DRV_NAME ": request irq %d failed "
+				"(ret = %d)\n", spi->irq, ret);
+		goto error_irq;
+	}
+
+	dev->if_port = IF_PORT_10BASET;
+	dev->irq = spi->irq;
+	dev->netdev_ops = &enc424j600_netdev_ops;
+	dev->watchdog_timeo = TX_TIMEOUT;
+	SET_ETHTOOL_OPS(dev, &enc424j600_ethtool_ops);
+
+	enc424j600_lowpower(priv, true);
+
+	ret = register_netdev(dev);
+	if (ret) {
+		if (netif_msg_probe(priv))
+			dev_err(&spi->dev, "register netdev " DRV_NAME
+				" failed (ret = %d)\n", ret);
+		goto error_register;
+	}
+	dev_info(&dev->dev, DRV_NAME " driver registered\n");
+
+	return ret;
+
+error_register:
+	free_irq(spi->irq, priv);
+error_irq:
+	free_netdev(dev);
+	if (!enc424j600_enable_dma)
+		kfree(priv->spi_rx_buf);
+error_rx_buf:
+	if (!enc424j600_enable_dma)
+		kfree(priv->spi_tx_buf);
+error_tx_buf:
+	if (enc424j600_enable_dma) {
+		dma_free_coherent(&spi->dev, PAGE_SIZE,
+				priv->spi_tx_buf, priv->spi_tx_dma);
+	}
+error_alloc:
+	return ret;
+}
+
+static int __devexit enc424j600_remove(struct spi_device *spi)
+{
+	struct enc424j600_net *priv = dev_get_drvdata(&spi->dev);
+
+	if (netif_msg_drv(priv))
+		printk(KERN_DEBUG DRV_NAME ": remove\n");
+
+	unregister_netdev(priv->netdev);
+	free_irq(spi->irq, priv);
+	free_netdev(priv->netdev);
+
+	return 0;
+}
+
+static struct spi_driver enc424j600_driver = {
+	.driver = {
+			.name = DRV_NAME,
+			.owner = THIS_MODULE,
+		},
+		.probe = enc424j600_probe,
+		.remove = __devexit_p(enc424j600_remove),
+};
+
+static int __init enc424j600_init(void)
+{
+	msec20_to_jiffies = msecs_to_jiffies(20);
+	/*autoneg works from 1600ms */
+	msec2000_to_jiffies = msecs_to_jiffies(2000);
+
+	return spi_register_driver(&enc424j600_driver);
+}
+
+module_init(enc424j600_init);
+
+static void __exit enc424j600_exit(void)
+{
+	spi_unregister_driver(&enc424j600_driver);
+}
+
+module_exit(enc424j600_exit);
+
+MODULE_DESCRIPTION(DRV_NAME " ethernet driver");
+MODULE_AUTHOR("Balaji Venkatachalam <balaji.v@thotakaa.com>");
+MODULE_LICENSE("GPL");
+module_param_named(debug, debug.msg_enable, int, 0);
+MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., ffff=all)");
+module_param(enc424j600_enable_dma, int, S_IRUGO);
+MODULE_PARM_DESC(enc424j600_enable_dma, "Enable SPI DMA. Default: 0 (Off)");
+MODULE_ALIAS("spi:" DRV_NAME);
+
diff -uprN -X a/Documentation/dontdiff a/drivers/net/enc424j600_hw.h
b/drivers/net/enc424j600_hw.h
--- a/drivers/net/enc424j600_hw.h	1970-01-01 05:30:00.000000000 +0530
+++ b/drivers/net/enc424j600_hw.h	2011-02-08 18:55:19.000000000 +0530
@@ -0,0 +1,460 @@
+/*
+* enc424j600_hw.h: Register definitions
+*
+*/
+
+#ifndef _ENC424J600_HW_H
+#define _ENC424J600_HW_H
+#define SFR_REG_COUNT	0xA0
+/*
+* ENC424J600 Control Registers
+* Control register definitions are a combination of address
+* and bank number
+* - Register address (bits 0-4)
+* - Bank number (bits 5-6)
+*/
+#define ADDR_MASK 0x1F
+#define BANK_MASK 0x60
+#define BANK_SHIFT 5
+
+/* All-bank registers */
+#define EUDASTL 0x16
+#define EUDASTH 0x17
+#define EUDANDL 0x18
+#define EUDANDH 0x19
+#define ESTATL 0x1A
+#define ESTATH 0x1B
+#define EIRL 0x1C
+#define EIRH 0x1D
+#define ECON1L 0x1E
+#define ECON1H 0x1F
+
+/* Bank 0 registers */
+#define ETXSTL (0x00 | 0x00)
+#define ETXSTH (0x01 | 0x00)
+#define ETXLENL (0x02 | 0x00)
+#define ETXLENH (0x03 | 0x00)
+#define ERXSTL (0x04 | 0x00)
+#define ERXSTH (0x05 | 0x00)
+#define ERXTAILL (0x06 | 0x00)
+#define ERXTAILH (0x07 | 0x00)
+#define ERXHEADL (0x08 | 0x00)
+#define ERXHEADH (0x09 | 0x00)
+#define EDMASTL (0x0A | 0x00)
+#define EDMASTH (0x0B | 0x00)
+#define EDMALENL (0x0C | 0x00)
+#define EDMALENH (0x0D | 0x00)
+#define EDMADSTL (0x0E | 0x00)
+#define EDMADSTH (0x0F | 0x00)
+#define EDMACSL (0x10 | 0x00)
+#define EDMACSH (0x11 | 0x00)
+#define ETXSTATL (0x12 | 0x00)
+#define ETXSTATH (0x13 | 0x00)
+#define ETXWIREL (0x14 | 0x00)
+#define ETXWIREH (0x15 | 0x00)
+
+/* Bank 1 registers */
+#define EHT1L (0x00 | 0x20)
+#define EHT1H (0x01 | 0x20)
+#define EHT2L (0x02 | 0x20)
+#define EHT2H (0x03 | 0x20)
+#define EHT3L (0x04 | 0x20)
+#define EHT3H (0x05 | 0x20)
+#define EHT4L (0x06 | 0x20)
+#define EHT4H (0x07 | 0x20)
+#define EPMM1L (0x08 | 0x20)
+#define EPMM1H (0x09 | 0x20)
+#define EPMM2L (0x0A | 0x20)
+#define EPMM2H (0x0B | 0x20)
+#define EPMM3L (0x0C | 0x20)
+#define EPMM3H (0x0D | 0x20)
+#define EPMM4L (0x0E | 0x20)
+#define EPMM4H (0x0F | 0x20)
+#define EPMCSL (0x10 | 0x20)
+#define EPMCSH (0x11 | 0x20)
+#define EPMOL (0x12 | 0x20)
+#define EPMOH (0x13 | 0x20)
+#define ERXFCONL (0x14 | 0x20)
+#define ERXFCONH (0x15 | 0x20)
+
+/* Bank 2 registers */
+#define MACON1L (0x00 | 0x40)
+#define MACON1H (0x01 | 0x40)
+#define MACON2L (0x02 | 0x40)
+#define MACON2H (0x03 | 0x40)
+#define MABBIPGL (0x04 | 0x40)
+#define MABBIPGH (0x05 | 0x40)
+#define MAIPGL (0x06 | 0x40)
+#define MAIPGH (0x07 | 0x40)
+#define MACLCONL (0x08 | 0x40)
+#define MACLCONH (0x09 | 0x40)
+#define MAMXFLL (0x0A | 0x40)
+#define MAMXFLH (0x0B | 0x40)
+#define MICMDL (0x12 | 0x40)
+#define MICMDH (0x13 | 0x40)
+#define MIREGADRL (0x14 | 0x40)
+#define MIREGADRH (0x15 | 0x40)
+
+/* Bank 3 registers */
+#define MAADR3L (0x00 | 0x60)
+#define MAADR3H (0x01 | 0x60)
+#define MAADR2L (0x02 | 0x60)
+#define MAADR2H (0x03 | 0x60)
+#define MAADR1L (0x04 | 0x60)
+#define MAADR1H (0x05 | 0x60)
+#define MIWRL (0x06 | 0x60)
+#define MIWRH (0x07 | 0x60)
+#define MIRDL (0x08 | 0x60)
+#define MIRDH (0x09 | 0x60)
+#define MISTATL (0x0A | 0x60)
+#define MISTATH (0x0B | 0x60)
+#define EPAUSL (0x0C | 0x60)
+#define EPAUSH (0x0D | 0x60)
+#define ECON2L (0x0E | 0x60)
+#define ECON2H (0x0F | 0x60)
+#define ERXWML (0x10 | 0x60)
+#define ERXWMH (0x11 | 0x60)
+#define EIEL (0x12 | 0x60)
+#define EIEH (0x13 | 0x60)
+#define EIDLEDL (0x14 | 0x60)
+#define EIDLEDH (0x15 | 0x60)
+
+/* Unbanked registers */
+#define EGPDATA (0x00 | 0x80)
+#define ERXDATA (0x02 | 0x80)
+#define EUDADATA (0x04 | 0x80)
+#define EGPRDPTL (0x06 | 0x80)
+#define EGPRDPTH (0x07 | 0x80)
+#define EGPWRPTL (0x08 | 0x80)
+#define EGPWRPTH (0x09 | 0x80)
+#define ERXRDPTL (0x0A | 0x80)
+#define ERXRDPTH (0x0B | 0x80)
+#define ERXWRPTL (0x0C | 0x80)
+#define ERXWRPTH (0x0D | 0x80)
+#define EUDARDPTL (0x0E | 0x80)
+#define EUDARDPTH (0x0F | 0x80)
+#define EUDAWRPTL (0x10 | 0x80)
+#define EUDAWRPTH (0x11 | 0x80)
+
+/* PHY registers */
+#define PHCON1 0x00
+#define PHSTAT1 0x01
+#define PHANA 0x04
+#define PHANLPA 0x05
+#define PHANE 0x06
+#define PHCON2 0x11
+#define PHSTAT2 0x1B
+#define PHSTAT3 0x1F
+
+/* Single-byte instructions */
+#define BXSEL(bank) (0xC0 + (bank & (BANK_MASK >> BANK_SHIFT)) * 2)
+/* Bank X Select */
+#define B0SEL 0xC0		/* Bank 0 Select */
+#define B1SEL 0xC2		/* Bank 1 Select */
+#define B2SEL 0xC4		/* Bank 2 Select */
+#define B3SEL 0xC6		/* Bank 3 Select */
+#define SETETHRST 0xCA		/* System Reset */
+#define FCDISABLE 0xE0		/* Flow Control Disable */
+#define FCSINGLE 0xE2		/* Flow Control Single */
+#define FCMULTIPLE 0xE4		/* Flow Control Multiple */
+#define FCCLEAR 0xE6		/* Flow Control Clear */
+#define SETPKTDEC 0xCC		/* Decrement Packet Counter */
+#define DMASTOP 0xD2		/* DMA Stop */
+#define DMACKSUM 0xD8		/* DMA Start Checksum */
+#define DMACKSUMS 0xDA		/* DMA Start Checksum with Seed */
+#define DMACOPY 0xDC		/* DMA Start Copy */
+#define DMACOPYS 0xDE		/* DMA Start Copy and Checksum with Seed */
+#define SETTXRTS 0xD4		/* Request Packet Transmission */
+#define ENABLERX 0xE8		/* Enable RX */
+#define DISABLERX 0xEA		/* Disable RX */
+#define SETEIE 0xEC		/* Enable Interrupts */
+#define CLREIE 0xEE		/* Disable Interrupts */
+
+/* Two byte instructions */
+#define RBSEL 0xC8		/* Read Bank Select */
+
+/* Three byte instructions */
+#define WGPRDPT 0x60		/* Write EGPRDPT */
+#define RGPRDPT 0x62		/* Read EGPRDPT */
+#define WRXRDPT 0x64		/* Write ERXRDPT */
+#define RRXRDPT 0x66		/* Read ERXRDPT */
+#define WUDARDPT 0x68		/* Write EUDARDPT */
+#define RUDARDPT 0x6A		/* Read EUDARDPT */
+#define WGPWRPT 0x6C		/* Write EGPWRPT */
+#define RGPWRPT 0x6E		/* Read EGPWRPT */
+#define WRXWRPT 0x70		/* Write ERXWRPT */
+#define RRXWRPT 0x72		/* Read ERXWRPT */
+#define WUDAWRPT 0x74		/* Write EUDAWRPT */
+#define RUDAWRPT 0x76		/* Read EUDAWRPT */
+
+/* n byte instructions */
+#define RCR(addr) (0x00 | (addr & ADDR_MASK))	/* Read Control Register */
+#define WCR(addr) (0x40 | (addr & ADDR_MASK))	/* Write Control Register */
+#define RCRU 0x20		/* Read Control Register Unbanked */
+#define WCRU 0x22		/* Write Control Register Unbanked */
+#define BFS(addr) (0x80 | (addr & ADDR_MASK))	/* Bit Field Set */
+#define BFC(addr) (0xA0 | (addr & ADDR_MASK))	/* Bit Field Clear */
+#define BFSU 0x24		/* Bit Field Set Unbanked */
+#define BFCU 0x26		/* Bit Field Clear Unbanked */
+#define RGPDATA 0x28		/* Read EGPDATA */
+#define WGPDATA 0x2A		/* Write EGPDATA */
+#define RRXDATA 0x2C		/* Read ERXDATA */
+#define WRXDATA 0x2E		/* Write ERXDATA */
+#define RUDADATA 0x30		/* Read EUDADATA */
+#define WUDADATA 0x32		/* Write EUDADATA */
+
+/* Register bit definitions */
+/* ESTATH */
+#define INT (1 << 7)
+#define FCIDLE (1 << 6)
+#define RXBUSY (1 << 5)
+#define CLKRDY (1 << 4)
+#define PHYDPX (1 << 2)
+#define PHYLNK (1 << 0)
+
+/* EIRH */
+/*for ease of use lets access it as a word*/
+#define CRYPTEN (1 << 15)
+#define MODEXIF (1 << 14)
+#define HASHIF (1 << 13)
+#define AESIF (1 << 12)
+#define LINKIF (1 << 11)
+
+/* EIRL */
+#define PKTIF (1 << 6)
+#define DMAIF (1 << 5)
+#define TXIF (1 << 3)
+#define TXABTIF (1 << 2)
+#define RXABTIF (1 << 1)
+#define PCFULIF (1 << 0)
+
+/* ECON1H */
+#define MODEXST (1 << 7)
+#define HASHEN (1 << 6)
+#define HASHOP (1 << 5)
+#define HASHLST (1 << 4)
+#define AESST (1 << 3)
+#define AESOP1 (1 << 2)
+#define AESOP0 (1 << 1)
+#define PKTDEC (1 << 0)
+
+/* ECON1L */
+#define FCOP1 (1 << 7)
+#define FCOP0 (1 << 6)
+#define DMAST (1 << 5)
+#define DMACPY (1 << 4)
+#define DMACSSD (1 << 3)
+#define DMANOCS (1 << 2)
+#define TXRTS (1 << 1)
+#define RXEN (1 << 0)
+
+/* ETXSTATH */
+#define LATECOL (1 << 2)
+#define MAXCOL (1 << 1)
+#define EXDEFER (1 << 0)
+
+/* ETXSTATL */
+#define ETXSTATL_DEFER (1 << 7)
+#define CRCBAD (1 << 4)
+#define COLCNT_MASK 0xF
+
+/* ERXFCONH */
+#define HTEN (1 << 7)
+#define MPEN (1 << 6)
+#define NOTPM (1 << 4)
+#define PMEN3 (1 << 3)
+#define PMEN2 (1 << 2)
+#define PMEN1 (1 << 1)
+#define PMEN0 (1 << 0)
+
+/* ERXFCONL */
+#define CRCEEN (1 << 7)
+#define CRCEN (1 << 6)
+#define RUNTEEN (1 << 5)
+#define RUNTEN (1 << 4)
+#define UCEN (1 << 3)
+#define NOTMEEN (1 << 2)
+#define MCEN (1 << 1)
+#define BCEN (1 << 0)
+/*no bytewise access*/
+/* MACON1L */
+#define LOOPBK (1 << 4)
+#define RXPAUS (1 << 2)
+#define PASSALL (1 << 1)
+
+/* MACON2 */
+#define MACON2_DEFER (1 << 14)
+#define BPEN (1 << 13)
+#define NOBKOFF (1 << 12)
+#define PADCFG2 (1 << 7)
+#define PADCFG1 (1 << 6)
+#define PADCFG0 (1 << 5)
+#define TXCRCEN (1 << 4)
+#define PHDREN (1 << 3)
+#define HFRMEN (1 << 2)
+#define FULDPX (1 << 0)
+
+/* MAIPG */
+/* value of the high byte is given by the reserved bits,
+* value of the low byte is recomended setting of the
+* IPG parameter.
+*/
+#define MAIPGH_VAL 0x0C
+#define MAIPGL_VAL 0x12
+
+/* MIREGADRH */
+#define MIREGADRH_VAL 0x01
+
+/* MIREGADRL */
+#define PHREG_MASK 0x1F
+
+/* MICMDL */
+#define MIISCAN (1 << 1)
+#define MIIRD (1 << 0)
+
+/* MISTATL */
+#define NVALID (1 << 2)
+#define SCAN (1 << 1)
+#define BUSY (1 << 0)
+
+/* ECON2H */
+#define ETHEN (1 << 7)
+#define STRCH (1 << 6)
+#define TXMAC (1 << 5)
+#define SHA1MD5 (1 << 4)
+#define COCON3 (1 << 3)
+#define COCON2 (1 << 2)
+#define COCON1 (1 << 1)
+#define COCON0 (1 << 0)
+
+/* ECON2L */
+#define AUTOFC (1 << 7)
+#define TXRST (1 << 6)
+#define RXRST (1 << 5)
+#define ETHRST (1 << 4)
+#define MODLEN1 (1 << 3)
+#define MODLEN0 (1 << 2)
+#define AESLEN1 (1 << 1)
+#define AESLEN0 (1 << 0)
+
+/* EIEH */
+#define INTIE (1 << 7)
+#define MODEXIE (1 << 6)
+#define HASHIE (1 << 5)
+#define AESIE (1 << 4)
+#define LINKIE (1 << 3)
+
+/* EIEL */
+#define PKTIE (1 << 6)
+#define DMAIE (1 << 5)
+#define TXIE (1 << 3)
+#define TXABTIE (1 << 2)
+#define RXABTIE (1 << 1)
+#define PCFULIE (1 << 0)
+
+/* EIDLEDH */
+#define LACFG3 (1 << 7)
+#define LACFG2 (1 << 6)
+#define LACFG1 (1 << 5)
+#define LACFG0 (1 << 4)
+#define LBCFG3 (1 << 3)
+#define LBCFG2 (1 << 2)
+#define LBCFG1 (1 << 1)
+#define LBCFG0 (1 << 0)
+
+/* EIDLEDL */
+#define DEVID_SHIFT 5
+#define DEVID_MASK (0x7 << DEVID_SHIFT)
+#define REVID_SHIFT 0
+#define REVID_MASK (0x1F << REVID_SHIFT)
+
+/* PHANA */
+/* Default value for PHY initialization*/
+#define PHANA_DEFAULT 0x05E1
+
+/* PHCON1 */
+#define PRST (1 << 15)
+#define PLOOPBK (1 << 14)
+#define SPD100 (1 << 13)
+#define ANEN (1 << 12)
+#define PSLEEP (1 << 11)
+#define RENEG (1 << 9)
+#define PFULDPX (1 << 8)
+
+/* PHSTAT */
+#define FULL100 (1 << 14)
+#define HALF100 (1 << 13)
+#define FULL10 (1 << 12)
+#define HALF10 (1 << 11)
+#define ANDONE (1 << 5)
+#define LRFAULT (1 << 4)
+#define ANABLE (1 << 3)
+#define LLSTAT (1 << 2)
+#define EXTREGS (1 << 0)
+
+#define EUDAST_TEST_VAL 0x1234
+
+#define TSV_SIZE 7
+
+#define ENC424J600_DEV_ID 0x1
+
+/* Configuration */
+
+/* Led is on when the link is present and driven low
+* temporarily when packet is TX'd or RX'd */
+#define LED_A_SETTINGS 0xC
+
+/* Led is on if the link is in 100 Mbps mode */
+#define LED_B_SETTINGS 0x8
+
+/* maximum ethernet frame length
+* Currently not used as a limit anywhere
+* (we're using the "huge frame enable" feature of
+* enc424j600). */
+#define MAX_FRAMELEN 1518
+
+/* Size in bytes of the receive buffer in enc424j600.
+* Must be word aligned (even).
+*/
+#define RX_BUFFER_SIZE (15 * MAX_FRAMELEN)
+
+/* Start of the general purpose area in sram */
+#define SRAM_GP_START 0x0
+
+/* SRAM size */
+#define SRAM_SIZE 0x6000
+
+/* Start of the receive buffer */
+#define ERXST_VAL (SRAM_SIZE - RX_BUFFER_SIZE)
+
+#define RSV_RXLONGEVDROPEV	16
+#define RSV_CARRIEREV		18
+#define RSV_CRCERROR		20
+#define RSV_LENCHECKERR		21
+#define RSV_LENOUTOFRANGE	22
+#define RSV_RXOK		23
+#define RSV_RXMULTICAST		24
+#define RSV_RXBROADCAST		25
+#define RSV_DRIBBLENIBBLE	26
+#define RSV_RXCONTROLFRAME	27
+#define RSV_RXPAUSEFRAME	28
+#define RSV_RXUNKNOWNOPCODE	29
+#define RSV_RXTYPEVLAN		30
+
+#define RSV_RUNTFILTERMATCH	31
+#define RSV_NOTMEFILTERMATCH	32
+#define RSV_HASHFILTERMATCH	33
+#define RSV_MAGICPKTFILTERMATCH	34
+#define RSV_PTRNMTCHFILTERMATCH	35
+#define RSV_UNICASTFILTERMATCH	36
+
+#define RSV_SIZE		8
+#define RSV_BITMASK(x)		(1 << ((x) - 16))
+#define RSV_GETBIT(x, y)	(((x) & RSV_BITMASK(y)) ? 1 : 0)
+
+/* Put RX buffer at 0 as suggested by the Errata datasheet */
+
+#define RXSTART_INIT		ERXST_VAL
+#define RXEND_INIT		0x5FFF
+
+#endif
diff -uprN -X a/Documentation/dontdiff a/drivers/net/Kconfig
b/drivers/net/Kconfig
--- a/drivers/net/Kconfig	2010-07-05 22:41:43.000000000 +0530
+++ b/drivers/net/Kconfig	2011-01-16 15:26:16.000000000 +0530
@@ -973,6 +973,16 @@ config ENC28J60_WRITEVERIFY
 	  Enable the verify after the buffer write useful for debugging purpose.
 	  If unsure, say N.

+config ENC424J600
+	tristate "ENC424J600 support"
+	depends on EXPERIMENTAL && SPI && NET_ETHERNET
+	select CRC32
+	---help---
+		Support for the Microchip EN424J600 ethernet chip.
+
+		To compile this driver as a module, choose M here. The module will be
+		called enc424j600.
+
 config ETHOC
 	tristate "OpenCores 10/100 Mbps Ethernet MAC support"
 	depends on NET_ETHERNET && HAS_IOMEM
diff -uprN -X a/Documentation/dontdiff a/drivers/net/Makefile
b/drivers/net/Makefile
--- a/drivers/net/Makefile	2010-07-05 22:41:43.000000000 +0530
+++ b/drivers/net/Makefile	2011-01-05 21:46:57.000000000 +0530
@@ -240,6 +240,7 @@ obj-$(CONFIG_PASEMI_MAC) += pasemi_mac_d
 pasemi_mac_driver-objs := pasemi_mac.o pasemi_mac_ethtool.o
 obj-$(CONFIG_MLX4_CORE) += mlx4/
 obj-$(CONFIG_ENC28J60) += enc28j60.o
+obj-$(CONFIG_ENC424J600) += enc424j600.o
 obj-$(CONFIG_ETHOC) += ethoc.o

 obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o

^ permalink raw reply

* Re: [PATCH] GRO: fix merging a paged skb after non-paged skbs
From: Ben Hutchings @ 2011-02-08 15:04 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Michal Schmidt, David Miller, netdev, linux-net-drivers
In-Reply-To: <20110208084928.GA27505@gondor.apana.org.au>

On Tue, 2011-02-08 at 19:49 +1100, Herbert Xu wrote:
> On Mon, Feb 07, 2011 at 08:39:20PM +0000, Ben Hutchings wrote:
> > 
> > That is indeed the case; commit da3bc07171dff957906cbe2ad5abb443eccf57c4
> > made the following deletions:
> > 
> > -       /* Both our generic-LRO and SFC-SSR support skb and page based
> > -        * allocation, but neither support switching from one to the
> > -        * other on the fly. If we spot that the allocation mode has
> > -        * changed, then flush the LRO state.
> > -        */
> > -       if (unlikely(channel->rx_alloc_pop_pages != (rx_buf->page != NULL))) {
> > -               efx_flush_lro(channel);
> > -               channel->rx_alloc_pop_pages = (rx_buf->page != NULL);
> > -       }
> 
> Oops, sorry about that.
> 
> How about changing skb_gro_receive to detect such switches and
> simply return an error, which should have the same effect as
> flushing that flow?

That would work, though it looks like Michal has managed to make it
tolerate switches.  (I haven't yet tested the result myself.)

Ben.

-- 
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply

* Re: [E1000-devel] [PATCH] fixing hw timestamping in igb
From: Anders Berggren @ 2011-02-08 15:25 UTC (permalink / raw)
  To: jeffrey.t.kirsher; +Cc: John Ronciak, e1000-devel, netdev
In-Reply-To: <1296775407.2698.10.camel@jtkirshe-MOBL1>

On Feb 4, 2011, at 12:23 AM, Jeff Kirsher wrote:

> Thanks Anders, I will add this patch to my queue of igb patches.

Another question which I asked John Ronciak earlier; is there any work on TX timestamping for IPv6? In 2.6.37 sock_tx_timestamp() is only called in IPv4 UDP (net/ipv4/udp.c) and raw sockets (net/packet/af_packet.c).

Would it be meaningful if I tried to add it to ipv6/ip6_output.c as Marcus D. Leech suggested in http://kerneltrap.org/mailarchive/linux-netdev/2009/11/10/6260604 and http://kerneltrap.org/mailarchive/linux-netdev/2009/11/11/6260643 

^ permalink raw reply

* Re
From: Mr Song Li @ 2011-02-08 15:40 UTC (permalink / raw)





My name is Mr. Song Li le; I have a business of $44.5m usd for you.
should you be interested please contact me directly on my personal e-mail
address;mrsonglile01@live.com



^ permalink raw reply

* Re: [PATCH] fixing hw timestamping in igb
From: Ronciak, John @ 2011-02-08 16:27 UTC (permalink / raw)
  To: Anders Berggren, Kirsher, Jeffrey T
  Cc: e1000-devel@lists.sourceforge.net, netdev@vger.kernel.org
In-Reply-To: <331E9D4A-6738-405A-8457-14858D1072DA@halon.se>

> -----Original Message-----
> From: Anders Berggren [mailto:anders@halon.se]
> Sent: Tuesday, February 08, 2011 7:25 AM
> To: Kirsher, Jeffrey T
> Cc: Ronciak, John; e1000-devel@lists.sourceforge.net;
> netdev@vger.kernel.org
> Subject: Re: [E1000-devel] [PATCH] fixing hw timestamping in igb
> 
> On Feb 4, 2011, at 12:23 AM, Jeff Kirsher wrote:
> 
> > Thanks Anders, I will add this patch to my queue of igb patches.
> 
> Another question which I asked John Ronciak earlier; is there any work
> on TX timestamping for IPv6? In 2.6.37 sock_tx_timestamp() is only
> called in IPv4 UDP (net/ipv4/udp.c) and raw sockets
> (net/packet/af_packet.c).
> 
> Would it be meaningful if I tried to add it to ipv6/ip6_output.c as
> Marcus D. Leech suggested in http://kerneltrap.org/mailarchive/linux-
> netdev/2009/11/10/6260604 and http://kerneltrap.org/mailarchive/linux-
> netdev/2009/11/11/6260643
Anders,

The question of IPv6 support for TX timestamping is still under discussion.  We are trying to understand the use case for it as well as how it would be used.  We have had no customers asking for this type of support (at least not yet).  If there is kernel work going on regarding it then maybe this needs to be looked at closer.

Other than being a science project, what is your use case for the TX timestamping in IPv6?

Cheers,
John

------------------------------------------------------------------------------
The ultimate all-in-one performance toolkit: Intel(R) Parallel Studio XE:
Pinpoint memory and threading errors before they happen.
Find and fix more than 250 security defects in the development cycle.
Locate bottlenecks in serial and parallel code that limit performance.
http://p.sf.net/sfu/intel-dev2devfeb
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel&#174; Ethernet, visit http://communities.intel.com/community/wired

^ permalink raw reply

* Re: [PATCH v2] xen network backend driver
From: Francois Romieu @ 2011-02-08 16:41 UTC (permalink / raw)
  To: Ian Campbell
  Cc: netdev@vger.kernel.org, xen-devel, Jeremy Fitzhardinge,
	Konrad Rzeszutek Wilk, Ben Hutchings, Herbert Xu
In-Reply-To: <1297160635.9149.21.camel@zakaz.uk.xensource.com>

Ian Campbell <Ian.Campbell@citrix.com> :
[...]
>       * Dropped the tasklet mode for the backend worker leaving only the
>         kthread mode. I will revisit the suggestion to use NAPI on the
>         driver side in the future, I think it's somewhat orthogonal to
>         the use of kthread here, but it seems likely to be a worthwhile
>         improvement either way. 

I have not dug into bind_interdomain_evtchn_to_irqhandler but I would
expect the kthread to go away once NAPI is plugged into xenvif_interrupt().

[...]
> diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
> new file mode 100644
> index 0000000..98a992d
> --- /dev/null
> +++ b/drivers/net/xen-netback/interface.c
> @@ -0,0 +1,550 @@
> +/*
> + * Network-device interface management.
> + *
> + * Copyright (c) 2004-2005, Keir Fraser
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation; or, when distributed
> + * separately from the Linux kernel or incorporated into other
> + * software packages, subject to the following license:
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this source file (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use, copy, modify,
> + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
> + * and to permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +#include "common.h"
> +
> +#include <linux/ethtool.h>
> +#include <linux/rtnetlink.h>
> +
> +#include <xen/events.h>
> +#include <asm/xen/hypercall.h>
> +
> +#define XENVIF_QUEUE_LENGTH 32
> +
> +void xenvif_get(struct xenvif *vif)
> +{
> +	atomic_inc(&vif->refcnt);
> +}
> +
> +void xenvif_put(struct xenvif *vif)
> +{
> +	if (atomic_dec_and_test(&vif->refcnt))
> +		wake_up(&vif->waiting_to_free);
> +}
> +
> +static int xenvif_max_required_rx_slots(struct xenvif *vif)
> +{
> +	int max = DIV_ROUND_UP(vif->dev->mtu, PAGE_SIZE);
> +
> +	if (vif->can_sg || vif->gso || vif->gso_prefix)
> +		max += MAX_SKB_FRAGS + 1; /* extra_info + frags */
> +
> +	return max;
> +}
> +
> +int xenvif_queue_full(struct xenvif *vif)
> +{
> +	RING_IDX peek   = vif->rx_req_cons_peek;
> +	RING_IDX needed = xenvif_max_required_rx_slots(vif);
> +
> +	return ((vif->rx.sring->req_prod - peek) < needed) ||
> +	       ((vif->rx.rsp_prod_pvt + XEN_NETIF_RX_RING_SIZE - peek) < needed);
> +}
> +
> +/*
> + * Implement our own carrier flag: the network stack's version causes delays
> + * when the carrier is re-enabled (in particular, dev_activate() may not
> + * immediately be called, which can cause packet loss; also the etherbridge
> + * can be rather lazy in activating its port).
> + */

I have found a netif_carrier_off(vif->dev) but no
netif_carrier_on(vif->dev). Did I overlook something ?

> +static void xenvif_carrier_on(struct xenvif *vif)
> +{
> +	vif->carrier = 1;
> +}
> +static void xenvif_carrier_off(struct xenvif *vif)
> +{
> +	vif->carrier = 0;
> +}
> +static int xenvif_carrier_ok(struct xenvif *vif)
> +{
> +	return vif->carrier;
> +}
> +
> +int xenvif_schedulable(struct xenvif *vif)
> +{
> +	return netif_running(vif->dev) && xenvif_carrier_ok(vif);
> +}
> +
> +static irqreturn_t xenvif_interrupt(int irq, void *dev_id)
> +{
> +	struct xenvif *vif = dev_id;
> +
> +	if (vif->netbk == NULL)
> +		return IRQ_NONE;
> +
> +	xen_netbk_schedule_xenvif(vif);
> +
> +	if (xenvif_schedulable(vif) && !xenvif_queue_full(vif))

This test appears three times along the code. Factor it out ?

> +		netif_wake_queue(vif->dev);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
> +{
> +	struct xenvif *vif = netdev_priv(dev);
> +
> +	BUG_ON(skb->dev != dev);
> +
> +	if (vif->netbk == NULL)

How is it supposed to happen ?

xenvif_open
	xenvif_up
		xen_netbk_add_xenvif
			netbk = &xen_netbk[min_group];

			vif->netbk = netbk;
	netif_start_queue

> +		goto drop;
> +
> +	/* Drop the packet if the target domain has no receive buffers. */
> +	if (unlikely(!xenvif_schedulable(vif) || xenvif_queue_full(vif)))
> +		goto drop;
> +
> +	/* Reserve ring slots for the worst-case number of fragments. */
> +	vif->rx_req_cons_peek += xen_netbk_count_skb_slots(vif, skb);
> +	xenvif_get(vif);
> +
> +	if (vif->can_queue && xenvif_queue_full(vif)) {
> +		vif->rx.sring->req_event = vif->rx_req_cons_peek +
> +			xenvif_max_required_rx_slots(vif);
> +		mb(); /* request notification /then/ check & stop the queue */
> +		if (xenvif_queue_full(vif))
> +			netif_stop_queue(dev);
> +	}
> +
> +	xen_netbk_queue_tx_skb(vif, skb);

Why not do the real work (xen_netbk_rx_action) here and avoid the skb list
lock ?  Batching ?

> +
> +	return 0;

NETDEV_TX_OK

> +
> + drop:
> +	vif->stats.tx_dropped++;
> +	dev_kfree_skb(skb);
> +	return 0;

NETDEV_TX_OK

> +}
> +
[...]
> +struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
> +			    unsigned int handle)
> +{
> +	int err = 0;

Useless init.

> +	struct net_device *dev;
> +	struct xenvif *vif;
> +	char name[IFNAMSIZ] = {};
> +
> +	snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
> +	dev = alloc_netdev(sizeof(struct xenvif), name, ether_setup);
> +	if (dev == NULL) {
> +		pr_debug("Could not allocate netdev\n");
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	SET_NETDEV_DEV(dev, parent);
> +
> +	vif = netdev_priv(dev);
> +	memset(vif, 0, sizeof(*vif));

Useless memset. It is kzalloced behind the scene.

> +	vif->domid  = domid;
> +	vif->handle = handle;
> +	vif->netbk  = NULL;
> +	vif->can_sg = 1;
> +	vif->csum = 1;
> +	atomic_set(&vif->refcnt, 1);
> +	init_waitqueue_head(&vif->waiting_to_free);
> +	vif->dev = dev;
> +	INIT_LIST_HEAD(&vif->list);
> +
> +	xenvif_carrier_off(vif);
> +
> +	vif->credit_bytes = vif->remaining_credit = ~0UL;
> +	vif->credit_usec  = 0UL;
> +	init_timer(&vif->credit_timeout);
> +	/* Initialize 'expires' now: it's used to track the credit window. */
> +	vif->credit_timeout.expires = jiffies;
> +
> +	dev->netdev_ops	= &xenvif_netdev_ops;
> +	xenvif_set_features(vif);
> +	SET_ETHTOOL_OPS(dev, &xenvif_ethtool_ops);
> +
> +	dev->tx_queue_len = XENVIF_QUEUE_LENGTH;
> +
> +	/*
> +	 * Initialise a dummy MAC address. We choose the numerically
> +	 * largest non-broadcast address to prevent the address getting
> +	 * stolen by an Ethernet bridge for STP purposes.
> +	 * (FE:FF:FF:FF:FF:FF)
> +	 */
> +	memset(dev->dev_addr, 0xFF, ETH_ALEN);
> +	dev->dev_addr[0] &= ~0x01;
> +
> +	rtnl_lock();
> +	err = register_netdevice(dev);
> +	rtnl_unlock();

register_netdev() will do the locking for you.

> +	if (err) {
> +		pr_debug("Could not register new net device %s: err=%d\n",
> +			 dev->name, err);
> +		free_netdev(dev);
> +		return ERR_PTR(err);
> +	}
> +
> +	pr_debug("Successfully created xenvif\n");
> +	return vif;
> +}
> +
[...]
> diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
> new file mode 100644
> index 0000000..fbddf3d
> --- /dev/null
> +++ b/drivers/net/xen-netback/netback.c
[...]
> +struct xen_netbk {
> +	wait_queue_head_t wq;
> +	struct task_struct *task;
> +
> +	struct sk_buff_head rx_queue;
> +	struct sk_buff_head tx_queue;
> +
> +	struct timer_list net_timer;
> +
> +	struct page *mmap_pages[MAX_PENDING_REQS];
> +
> +	pending_ring_idx_t pending_prod;
> +	pending_ring_idx_t pending_cons;
> +	struct list_head net_schedule_list;
> +
> +	/* Protect the net_schedule_list in netif. */
> +	spinlock_t net_schedule_list_lock;
> +
> +	atomic_t netfront_count;
> +
> +	struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
> +	struct gnttab_copy tx_copy_ops[MAX_PENDING_REQS];
> +
> +	u16 pending_ring[MAX_PENDING_REQS];

Group the [MAX_PENDING_REQS] arrays as a single array ?

> +
> +	/*
> +	 * Each head or fragment can be up to 4096 bytes. Given
> +	 * MAX_BUFFER_OFFSET of 4096 the worst case is that each
> +	 * head/fragment uses 2 copy operation.
> +	 */
> +	struct gnttab_copy grant_copy_op[2*XEN_NETIF_RX_RING_SIZE];
> +	unsigned char rx_notify[NR_IRQS];
> +	u16 notify_list[XEN_NETIF_RX_RING_SIZE];
> +	struct netbk_rx_meta meta[2*XEN_NETIF_RX_RING_SIZE];
> +};
> +
[...]
> +static int xen_netbk_kthread(void *data)
> +{
> +	struct xen_netbk *netbk = (struct xen_netbk *)data;

Useless cast.

> +	while (!kthread_should_stop()) {
> +		wait_event_interruptible(netbk->wq,
> +				rx_work_todo(netbk)
> +				|| tx_work_todo(netbk)
> +				|| kthread_should_stop());

Please put || at the end of the line.

[...]
> +static int __init netback_init(void)
> +{
> +	int i;
> +	int rc = 0;
> +	int group;
> +
> +	if (!xen_pv_domain())
> +		return -ENODEV;
> +
> +	xen_netbk_group_nr = num_online_cpus();
> +	xen_netbk = vmalloc(sizeof(struct xen_netbk) * xen_netbk_group_nr);
> +	if (!xen_netbk) {
> +		printk(KERN_ALERT "%s: out of memory\n", __func__);
> +		return -ENOMEM;
> +	}
> +	memset(xen_netbk, 0, sizeof(struct xen_netbk) * xen_netbk_group_nr);

vzalloc

> +
> +	for (group = 0; group < xen_netbk_group_nr; group++) {
> +		struct xen_netbk *netbk = &xen_netbk[group];
> +		skb_queue_head_init(&netbk->rx_queue);
> +		skb_queue_head_init(&netbk->tx_queue);
> +
> +		init_timer(&netbk->net_timer);
> +		netbk->net_timer.data = (unsigned long)netbk;
> +		netbk->net_timer.function = xen_netbk_alarm;
> +
> +		netbk->pending_cons = 0;
> +		netbk->pending_prod = MAX_PENDING_REQS;
> +		for (i = 0; i < MAX_PENDING_REQS; i++)
> +			netbk->pending_ring[i] = i;
> +
> +		init_waitqueue_head(&netbk->wq);
> +		netbk->task = kthread_create(xen_netbk_kthread,
> +					     (void *)netbk,
> +					     "netback/%u", group);
> +
> +		if (IS_ERR(netbk->task)) {
> +			printk(KERN_ALERT "kthread_run() fails at netback\n");
> +			del_timer(&netbk->net_timer);
> +			rc = PTR_ERR(netbk->task);
> +			goto failed_init;
> +		}
> +
> +		kthread_bind(netbk->task, group);
> +
> +		INIT_LIST_HEAD(&netbk->net_schedule_list);
> +
> +		spin_lock_init(&netbk->net_schedule_list_lock);
> +
> +		atomic_set(&netbk->netfront_count, 0);
> +
> +		wake_up_process(netbk->task);
> +	}
> +
> +	rc = xenvif_xenbus_init();
> +	if (rc)
> +		goto failed_init;
> +
> +	return 0;
> +
> +failed_init:
> +	for (i = 0; i < group; i++) {

	while (--group >= 0) ?

> +		struct xen_netbk *netbk = &xen_netbk[i];
> +		int j;
> +		for (j = 0; j < MAX_PENDING_REQS; j++) {
> +			if (netbk->mmap_pages[i])
                                              ^ j ?
> +				__free_page(netbk->mmap_pages[i]);
                                                              ^ j ?
> +		}


> +		del_timer(&netbk->net_timer);
> +		kthread_stop(netbk->task);
> +	}
> +	vfree(xen_netbk);
> +	return rc;
> +
> +}
> +

-- 
Ueimor

^ permalink raw reply

* [PATCH 0/2] CDC NCM errata updates
From: Alexey ORISHKO @ 2011-02-08 17:44 UTC (permalink / raw)
  To: davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	gregkh-l3A5Bk7waGM@public.gmane.org,
	yauheni.kaliuta-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org

Hi David,

Both patches can be applied to net-2.6 and net-next.
[PATCH 1/2] CDC NCM errata updates for cdc.h 
[PATCH 2/2] USB CDC NCM errata updates for cdc_ncm host driver

I don't know if the merge window is closed or not, but it would be
*really* good to get this patches merged to 2.6.38-rc branch due to
bug fixes included.

Best regards,
Alexey
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ 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