* Re: [PATCH] sky2: fix receive length error in mixed non-VLAN/VLAN traffic
From: Stephen Hemminger @ 2012-04-28 3:05 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: Niccolò Belli, netdev
In-Reply-To: <20120427200310.60325fb1@nehalam.linuxnetplumber.net>
On Fri, 27 Apr 2012 20:03:10 -0700
Stephen Hemminger <shemminger@vyatta.com> wrote:
> Bug: The VLAN bit of the MAC RX Status Word is unreliable in several older
> supported chips. Sometimes the VLAN bit is not set for valid VLAN packets
> and also sometimes the VLAN bit is set for non-VLAN packets that came after
> a VLAN packet. This results in a receive length error when VLAN hardware
> tagging is enabled.
>
> Fix: The driver uses only VLAN information included in VLAN status list elements,
> that signals that the VLAN tag field is valid. It must ignore the VLAN bit in the
> MAC RX Status Word. An additional variable set when evaluating the VLAN opcodes
> is used to indicate that the received packet is a VLAN packet and a packet length
> correction (subtraction of VLAN header length) must be done.
>
> This is an alternative to Mirko's patch that relies on the new method of
> encoding VLAN tag, and therefore means extra code can be removed.
>
> Testing: Tested with regular and VLAN traffic on 88E8056, but this chip
> does not have the bug, just proves that the alternative method of handling
> VLAN tag will work.
>
> Reported-by: Mirko Lindner <mlindner@marvell.com>
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
>
This doesn't work. Furthur testing just crapped out with lots
of rx length errors in mixed vlan/non-vlan traffic case.
^ permalink raw reply
* [PATCH] sky2: fix receive length error in mixed non-VLAN/VLAN traffic
From: Stephen Hemminger @ 2012-04-28 3:03 UTC (permalink / raw)
To: Niccolò Belli; +Cc: netdev
In-Reply-To: <4F9B2641.9070209@linuxsystems.it>
Bug: The VLAN bit of the MAC RX Status Word is unreliable in several older
supported chips. Sometimes the VLAN bit is not set for valid VLAN packets
and also sometimes the VLAN bit is set for non-VLAN packets that came after
a VLAN packet. This results in a receive length error when VLAN hardware
tagging is enabled.
Fix: The driver uses only VLAN information included in VLAN status list elements,
that signals that the VLAN tag field is valid. It must ignore the VLAN bit in the
MAC RX Status Word. An additional variable set when evaluating the VLAN opcodes
is used to indicate that the received packet is a VLAN packet and a packet length
correction (subtraction of VLAN header length) must be done.
This is an alternative to Mirko's patch that relies on the new method of
encoding VLAN tag, and therefore means extra code can be removed.
Testing: Tested with regular and VLAN traffic on 88E8056, but this chip
does not have the bug, just proves that the alternative method of handling
VLAN tag will work.
Reported-by: Mirko Lindner <mlindner@marvell.com>
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
This version is built and tested against net-next (3.4-rc4)
--- a/drivers/net/ethernet/marvell/sky2.c 2012-04-27 19:37:31.891137630 -0700
+++ b/drivers/net/ethernet/marvell/sky2.c 2012-04-27 19:42:54.242757283 -0700
@@ -2568,6 +2568,14 @@ nobuf:
return NULL;
}
+/* Apply vlan tag to the current Rx skb */
+static inline void sky2_rx_tag(struct sky2_port *sky2, u16 tag)
+{
+ struct rx_ring_info *re = sky2->rx_ring + sky2->rx_next;
+
+ __vlan_hwaccel_put_tag(re->skb, be16_to_cpu(tag));
+}
+
/*
* Receive one packet.
* For larger packets, get new buffer.
@@ -2580,7 +2588,7 @@ static struct sk_buff *sky2_receive(stru
struct sk_buff *skb = NULL;
u16 count = (status & GMR_FS_LEN) >> 16;
- if (status & GMR_FS_VLAN)
+ if (vlan_tx_tag_present(re->skb))
count -= VLAN_HLEN; /* Account for vlan tag */
netif_printk(sky2, rx_status, KERN_DEBUG, dev,
@@ -2646,12 +2654,9 @@ static inline void sky2_tx_done(struct n
}
}
-static inline void sky2_skb_rx(const struct sky2_port *sky2,
- u32 status, struct sk_buff *skb)
+static inline void sky2_skb_rx(struct sky2_port *sky2,
+ struct sk_buff *skb)
{
- if (status & GMR_FS_VLAN)
- __vlan_hwaccel_put_tag(skb, be16_to_cpu(sky2->rx_tag));
-
if (skb->ip_summed == CHECKSUM_NONE)
netif_receive_skb(skb);
else
@@ -2764,7 +2769,7 @@ static int sky2_status_intr(struct sky2_
skb->protocol = eth_type_trans(skb, dev);
- sky2_skb_rx(sky2, status, skb);
+ sky2_skb_rx(sky2, skb);
/* Stop after net poll weight */
if (++work_done >= to_do)
@@ -2772,11 +2777,11 @@ static int sky2_status_intr(struct sky2_
break;
case OP_RXVLAN:
- sky2->rx_tag = length;
+ sky2_rx_tag(sky2, length);
break;
case OP_RXCHKSVLAN:
- sky2->rx_tag = length;
+ sky2_rx_tag(sky2, length);
/* fall through */
case OP_RXCHKS:
if (likely(dev->features & NETIF_F_RXCSUM))
--- a/drivers/net/ethernet/marvell/sky2.h 2012-04-27 19:37:31.891137630 -0700
+++ b/drivers/net/ethernet/marvell/sky2.h 2012-04-27 19:41:01.857495110 -0700
@@ -2241,7 +2241,6 @@ struct sky2_port {
u16 rx_pending;
u16 rx_data_size;
u16 rx_nfrags;
- u16 rx_tag;
struct {
unsigned long last;
^ permalink raw reply
* Re: [RFT] sky2: fix status length check on older chips
From: Stephen Hemminger @ 2012-04-28 2:46 UTC (permalink / raw)
To: Niccolò Belli; +Cc: netdev
In-Reply-To: <4F9B2641.9070209@linuxsystems.it>
Are you using VLAN's? the whole problem report only applies if using VLAN
on old hardware.
^ permalink raw reply
* Re: [PATCH 01/10] atl1c: add workaround for issue of bit INTX-disable for MSI interrupt
From: Luis R. Rodriguez @ 2012-04-28 2:05 UTC (permalink / raw)
To: xiong; +Cc: davem, netdev, linux-kernel, qca-linux-team, nic-devel
In-Reply-To: <1335578325-21326-2-git-send-email-xiong@qca.qualcomm.com>
On Sat, Apr 28, 2012 at 09:58:36AM +0800, xiong wrote:
> All supported devices have one issue that msi interrupt doesn't assert
> if pci command register bit (PCI_COMMAND_INTX_DISABLE) is set.
> Add workaround in drivers/pci/quirks.c
>
> Signed-off-by: xiong <xiong@qca.qualcomm.com>
> ---
> drivers/pci/quirks.c | 12 ++++++++++++
> 1 files changed, 12 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
> index 4bf7102..953ec3f 100644
> --- a/drivers/pci/quirks.c
> +++ b/drivers/pci/quirks.c
> @@ -2626,6 +2626,18 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4374,
> DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4375,
> quirk_msi_intx_disable_bug);
>
> +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1062,
> + quirk_msi_intx_disable_bug);
> +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1063,
> + quirk_msi_intx_disable_bug);
> +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x2060,
> + quirk_msi_intx_disable_bug);
> +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x2062,
> + quirk_msi_intx_disable_bug);
> +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1073,
> + quirk_msi_intx_disable_bug);
> +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1083,
> + quirk_msi_intx_disable_bug);
> #endif /* CONFIG_PCI_MSI */
Xiong -- just a heads up, I think to backport these then you can
send me patches for compat-wireless to do the work around itself on
the driver on a patch under patches/ you can say create a
58-drivers-pci-quirks.patch which pathces your driver there.
Luis
^ permalink raw reply
* [PATCH 10/10] atl1c: remove PHY polling from atl1c_change_mtu
From: xiong @ 2012-04-28 1:58 UTC (permalink / raw)
To: davem, netdev, linux-kernel; +Cc: qca-linux-team, nic-devel, xiong
In-Reply-To: <1335578325-21326-1-git-send-email-xiong@qca.qualcomm.com>
PHY polling code for FPGA is considered in every MDIO R/W API.
no need to add additional code to atl1c_change_mtu.
Signed-off-by: xiong <xiong@qca.qualcomm.com>
Tested-by: David Liu <dwliu@qca.qaulcomm.com>
---
drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 8 --------
1 files changed, 0 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 1cdd898..86630a5 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -553,14 +553,6 @@ static int atl1c_change_mtu(struct net_device *netdev, int new_mtu)
netdev_update_features(netdev);
atl1c_up(adapter);
clear_bit(__AT_RESETTING, &adapter->flags);
- if (adapter->hw.ctrl_flags & ATL1C_FPGA_VERSION) {
- u32 phy_data;
-
- AT_READ_REG(&adapter->hw, 0x1414, &phy_data);
- phy_data |= 0x10000000;
- AT_WRITE_REG(&adapter->hw, 0x1414, phy_data);
- }
-
}
return 0;
}
--
1.7.7
^ permalink raw reply related
* [PATCH 07/10] atl1c: cancel task when interface closed
From: xiong @ 2012-04-28 1:58 UTC (permalink / raw)
To: davem, netdev, linux-kernel; +Cc: qca-linux-team, nic-devel, xiong
In-Reply-To: <1335578325-21326-1-git-send-email-xiong@qca.qualcomm.com>
common_task might be running while close routine is called,
wait/cancel it.
Signed-off-by: xiong <xiong@qca.qualcomm.com>
Tested-by: Liu David <dwliu@qca.qualcomm.com>
---
drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 8fee1fc..e082901 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -330,6 +330,9 @@ static void atl1c_common_task(struct work_struct *work)
adapter = container_of(work, struct atl1c_adapter, common_task);
netdev = adapter->netdev;
+ if (test_bit(__AT_DOWN, &adapter->flags))
+ return;
+
if (test_and_clear_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event)) {
netif_device_detach(netdev);
atl1c_down(adapter);
@@ -2313,6 +2316,8 @@ static int atl1c_close(struct net_device *netdev)
struct atl1c_adapter *adapter = netdev_priv(netdev);
WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
+ set_bit(__AT_DOWN, &adapter->flags);
+ cancel_work_sync(&adapter->common_task);
atl1c_down(adapter);
atl1c_free_ring_resources(adapter);
return 0;
--
1.7.7
^ permalink raw reply related
* [PATCH 02/10] atl1c: add PHY link event(up/down) patch
From: xiong @ 2012-04-28 1:58 UTC (permalink / raw)
To: davem, netdev, linux-kernel; +Cc: qca-linux-team, nic-devel, xiong
In-Reply-To: <1335578325-21326-1-git-send-email-xiong@qca.qualcomm.com>
On some platforms the PHY settings need to change depending on the
cable link status to get better stability.
Signed-off-by: xiong <xiong@qca.qualcomm.com>
Tested-by: Liu David <dwliu@qca.qualcomm.com>
---
drivers/net/ethernet/atheros/atl1c/atl1c.h | 1 +
drivers/net/ethernet/atheros/atl1c/atl1c_hw.c | 37 +++++++++++++++
drivers/net/ethernet/atheros/atl1c/atl1c_hw.h | 1 +
drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 55 +++++++++++++++++++++++
4 files changed, 94 insertions(+), 0 deletions(-)
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c.h b/drivers/net/ethernet/atheros/atl1c/atl1c.h
index acc2956..b2bf324 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c.h
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c.h
@@ -436,6 +436,7 @@ struct atl1c_hw {
bool phy_configured;
bool re_autoneg;
bool emi_ca;
+ bool msi_lnkpatch; /* link patch for specific platforms */
};
/*
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
index 07f017f..209c179 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
@@ -848,3 +848,40 @@ int atl1c_power_saving(struct atl1c_hw *hw, u32 wufc)
return 0;
}
+
+
+/* configure phy after Link change Event */
+void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed)
+{
+ u16 phy_val;
+ bool adj_thresh = false;
+
+ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2 ||
+ hw->nic_type == athr_l1d || hw->nic_type == athr_l1d_2)
+ adj_thresh = true;
+
+ if (link_speed != SPEED_0) { /* link up */
+ /* az with brcm, half-amp */
+ if (hw->nic_type == athr_l1d_2) {
+ atl1c_read_phy_ext(hw, MIIEXT_PCS, MIIEXT_CLDCTRL6,
+ &phy_val);
+ phy_val = FIELD_GETX(phy_val, CLDCTRL6_CAB_LEN);
+ phy_val = phy_val > CLDCTRL6_CAB_LEN_SHORT ?
+ AZ_ANADECT_LONG : AZ_ANADECT_DEF;
+ atl1c_write_phy_dbg(hw, MIIDBG_AZ_ANADECT, phy_val);
+ }
+ /* threshold adjust */
+ if (adj_thresh && link_speed == SPEED_100 && hw->msi_lnkpatch) {
+ atl1c_write_phy_dbg(hw, MIIDBG_MSE16DB, L1D_MSE16DB_UP);
+ atl1c_write_phy_dbg(hw, MIIDBG_SYSMODCTRL,
+ L1D_SYSMODCTRL_IECHOADJ_DEF);
+ }
+ } else { /* link down */
+ if (adj_thresh && hw->msi_lnkpatch) {
+ atl1c_write_phy_dbg(hw, MIIDBG_SYSMODCTRL,
+ SYSMODCTRL_IECHOADJ_DEF);
+ atl1c_write_phy_dbg(hw, MIIDBG_MSE16DB,
+ L1D_MSE16DB_DOWN);
+ }
+ }
+}
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
index 0adb341..ea3f520 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
@@ -63,6 +63,7 @@ int atl1c_write_phy_ext(struct atl1c_hw *hw, u8 dev_addr,
u16 reg_addr, u16 phy_data);
int atl1c_read_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data);
int atl1c_write_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 phy_data);
+void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed);
/* hw-ids */
#define PCI_DEVICE_ID_ATTANSIC_L2C 0x1062
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 25b7b00..50df437 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -258,6 +258,7 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
if (netif_msg_hw(adapter))
dev_warn(&pdev->dev, "stop mac failed\n");
atl1c_set_aspm(hw, SPEED_0);
+ atl1c_post_phy_linkchg(hw, SPEED_0);
netif_carrier_off(netdev);
netif_stop_queue(netdev);
} else {
@@ -274,6 +275,7 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
adapter->link_speed = speed;
adapter->link_duplex = duplex;
atl1c_set_aspm(hw, speed);
+ atl1c_post_phy_linkchg(hw, speed);
atl1c_start_mac(adapter);
if (netif_msg_link(adapter))
dev_info(&pdev->dev,
@@ -697,6 +699,57 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
hw->link_cap_flags |= ATL1C_LINK_CAP_1000M;
return 0;
}
+
+struct atl1c_platform_patch {
+ u16 pci_vid;
+ u16 pci_did;
+ u8 pci_revid;
+ u16 subsystem_vid;
+ u16 subsystem_did;
+ u32 patch_flag;
+#define ATL1C_LINK_PATCH 0x1
+};
+static struct atl1c_platform_patch plats[] = {
+{0x1969, 0x2060, 0xC1, 0x1019, 0x8152, 0x1},
+{0x1969, 0x2060, 0xC1, 0x1019, 0x2060, 0x1},
+{0x1969, 0x2060, 0xC1, 0x1019, 0xE000, 0x1},
+{0x1969, 0x2062, 0xC0, 0x1019, 0x8152, 0x1},
+{0x1969, 0x2062, 0xC0, 0x1019, 0x2062, 0x1},
+{0x1969, 0x2062, 0xC0, 0x1458, 0xE000, 0x1},
+{0x1969, 0x2062, 0xC1, 0x1019, 0x8152, 0x1},
+{0x1969, 0x2062, 0xC1, 0x1019, 0x2062, 0x1},
+{0x1969, 0x2062, 0xC1, 0x1458, 0xE000, 0x1},
+{0x1969, 0x2062, 0xC1, 0x1565, 0x2802, 0x1},
+{0x1969, 0x2062, 0xC1, 0x1565, 0x2801, 0x1},
+{0x1969, 0x1073, 0xC0, 0x1019, 0x8151, 0x1},
+{0x1969, 0x1073, 0xC0, 0x1019, 0x1073, 0x1},
+{0x1969, 0x1073, 0xC0, 0x1458, 0xE000, 0x1},
+{0x1969, 0x1083, 0xC0, 0x1458, 0xE000, 0x1},
+{0x1969, 0x1083, 0xC0, 0x1019, 0x8151, 0x1},
+{0x1969, 0x1083, 0xC0, 0x1019, 0x1083, 0x1},
+{0x1969, 0x1083, 0xC0, 0x1462, 0x7680, 0x1},
+{0x1969, 0x1083, 0xC0, 0x1565, 0x2803, 0x1},
+{0},
+};
+
+static void __devinit atl1c_patch_assign(struct atl1c_hw *hw)
+{
+ int i = 0;
+
+ hw->msi_lnkpatch = false;
+
+ while (plats[i].pci_vid != 0) {
+ if (plats[i].pci_vid == hw->vendor_id &&
+ plats[i].pci_did == hw->device_id &&
+ plats[i].pci_revid == hw->revision_id &&
+ plats[i].subsystem_vid == hw->subsystem_vendor_id &&
+ plats[i].subsystem_did == hw->subsystem_id) {
+ if (plats[i].patch_flag & ATL1C_LINK_PATCH)
+ hw->msi_lnkpatch = true;
+ }
+ i++;
+ }
+}
/*
* atl1c_sw_init - Initialize general software structures (struct atl1c_adapter)
* @adapter: board private structure to initialize
@@ -732,6 +785,8 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter)
dev_err(&pdev->dev, "set mac function pointers failed\n");
return -1;
}
+ atl1c_patch_assign(hw);
+
hw->intr_mask = IMR_NORMAL_MASK;
hw->phy_configured = false;
hw->preamble_len = 7;
--
1.7.7
^ permalink raw reply related
* [PATCH 01/10] atl1c: add workaround for issue of bit INTX-disable for MSI interrupt
From: xiong @ 2012-04-28 1:58 UTC (permalink / raw)
To: davem, netdev, linux-kernel; +Cc: qca-linux-team, nic-devel, xiong
In-Reply-To: <1335578325-21326-1-git-send-email-xiong@qca.qualcomm.com>
All supported devices have one issue that msi interrupt doesn't assert
if pci command register bit (PCI_COMMAND_INTX_DISABLE) is set.
Add workaround in drivers/pci/quirks.c
Signed-off-by: xiong <xiong@qca.qualcomm.com>
---
drivers/pci/quirks.c | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 4bf7102..953ec3f 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -2626,6 +2626,18 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4374,
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4375,
quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1062,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1063,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x2060,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x2062,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1073,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1083,
+ quirk_msi_intx_disable_bug);
#endif /* CONFIG_PCI_MSI */
/* Allow manual resource allocation for PCI hotplug bridges
--
1.7.7
^ permalink raw reply related
* [PATCH 09/10] atl1c: Disable L0S when no cable link
From: xiong @ 2012-04-28 1:58 UTC (permalink / raw)
To: davem, netdev, linux-kernel; +Cc: qca-linux-team, nic-devel, xiong
In-Reply-To: <1335578325-21326-1-git-send-email-xiong@qca.qualcomm.com>
L0S might be unstable if no cable link, only enable it when link up.
Signed-off-by: xiong <xiong@qca.qualcomm.com>
Tested-by: Liu David <dwliu@qca.qualcomm.com>
---
drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index f410d84..1cdd898 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -1328,7 +1328,7 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, u16 link_speed)
}
/* L0S/L1 enable */
- if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT)
+ if ((hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT) && link_speed != SPEED_0)
pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN | PM_CTRL_MAC_ASPM_CHK;
if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT)
pm_ctrl_data |= PM_CTRL_ASPM_L1_EN | PM_CTRL_MAC_ASPM_CHK;
--
1.7.7
^ permalink raw reply related
* [PATCH 08/10] atl1c: do MAC-reset when PHY link down
From: xiong @ 2012-04-28 1:58 UTC (permalink / raw)
To: davem, netdev, linux-kernel; +Cc: qca-linux-team, nic-devel, xiong
In-Reply-To: <1335578325-21326-1-git-send-email-xiong@qca.qualcomm.com>
There may be tx-skbs still pending in HW when PHY link down.
Reset MAC will make the DMA engine go to the start point.
and release all pending skbs.
Note: Reset MAC will clear any interrupt status and mask.
Signed-off-by: xiong <xiong@qca.qualcomm.com>
Tested-by: Liu David <dwliu@qca.qualcomm.com>
---
drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 74 ++++++++++++++--------
1 files changed, 47 insertions(+), 27 deletions(-)
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index e082901..f410d84 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -60,6 +60,10 @@ static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter,
int *work_done, int work_to_do);
static int atl1c_up(struct atl1c_adapter *adapter);
static void atl1c_down(struct atl1c_adapter *adapter);
+static int atl1c_reset_mac(struct atl1c_hw *hw);
+static void atl1c_reset_dma_ring(struct atl1c_adapter *adapter);
+static int atl1c_configure(struct atl1c_adapter *adapter);
+static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter);
static const u16 atl1c_pay_load_size[] = {
128, 256, 512, 1024, 2048, 4096,
@@ -256,14 +260,16 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
if ((phy_data & BMSR_LSTATUS) == 0) {
/* link down */
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
hw->hibernate = true;
- if (atl1c_stop_mac(hw) != 0)
+ if (atl1c_reset_mac(hw) != 0)
if (netif_msg_hw(adapter))
- dev_warn(&pdev->dev, "stop mac failed\n");
+ dev_warn(&pdev->dev, "reset mac failed\n");
atl1c_set_aspm(hw, SPEED_0);
atl1c_post_phy_linkchg(hw, SPEED_0);
- netif_carrier_off(netdev);
- netif_stop_queue(netdev);
+ atl1c_reset_dma_ring(adapter);
+ atl1c_configure(adapter);
} else {
/* Link Up */
hw->hibernate = false;
@@ -341,8 +347,11 @@ static void atl1c_common_task(struct work_struct *work)
}
if (test_and_clear_bit(ATL1C_WORK_EVENT_LINK_CHANGE,
- &adapter->work_event))
+ &adapter->work_event)) {
+ atl1c_irq_disable(adapter);
atl1c_check_link_status(adapter);
+ atl1c_irq_enable(adapter);
+ }
}
@@ -1232,9 +1241,6 @@ static int atl1c_reset_mac(struct atl1c_hw *hw)
struct pci_dev *pdev = adapter->pdev;
u32 ctrl_data = 0;
- AT_WRITE_REG(hw, REG_IMR, 0);
- AT_WRITE_REG(hw, REG_ISR, ISR_DIS_INT);
-
atl1c_stop_mac(hw);
/*
* Issue Soft Reset to the MAC. This will reset the chip's
@@ -1373,7 +1379,7 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, u16 link_speed)
*
* Configure the Tx /Rx unit of the MAC after a reset.
*/
-static int atl1c_configure(struct atl1c_adapter *adapter)
+static int atl1c_configure_mac(struct atl1c_adapter *adapter)
{
struct atl1c_hw *hw = &adapter->hw;
u32 master_ctrl_data = 0;
@@ -1436,6 +1442,25 @@ static int atl1c_configure(struct atl1c_adapter *adapter)
return 0;
}
+static int atl1c_configure(struct atl1c_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int num;
+
+ atl1c_init_ring_ptrs(adapter);
+ atl1c_set_multi(netdev);
+ atl1c_restore_vlan(adapter);
+
+ num = atl1c_alloc_rx_buffer(adapter);
+ if (unlikely(num == 0))
+ return -ENOMEM;
+
+ if (atl1c_configure_mac(adapter))
+ return -EIO;
+
+ return 0;
+}
+
static void atl1c_update_hw_stats(struct atl1c_adapter *adapter)
{
u16 hw_reg_addr = 0;
@@ -2196,41 +2221,38 @@ static int atl1c_request_irq(struct atl1c_adapter *adapter)
return err;
}
+
+static void atl1c_reset_dma_ring(struct atl1c_adapter *adapter)
+{
+ /* release tx-pending skbs and reset tx/rx ring index */
+ atl1c_clean_tx_ring(adapter, atl1c_trans_normal);
+ atl1c_clean_tx_ring(adapter, atl1c_trans_high);
+ atl1c_clean_rx_ring(adapter);
+}
+
static int atl1c_up(struct atl1c_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- int num;
int err;
netif_carrier_off(netdev);
- atl1c_init_ring_ptrs(adapter);
- atl1c_set_multi(netdev);
- atl1c_restore_vlan(adapter);
- num = atl1c_alloc_rx_buffer(adapter);
- if (unlikely(num == 0)) {
- err = -ENOMEM;
- goto err_alloc_rx;
- }
-
- if (atl1c_configure(adapter)) {
- err = -EIO;
+ err = atl1c_configure(adapter);
+ if (unlikely(err))
goto err_up;
- }
err = atl1c_request_irq(adapter);
if (unlikely(err))
goto err_up;
+ atl1c_check_link_status(adapter);
clear_bit(__AT_DOWN, &adapter->flags);
napi_enable(&adapter->napi);
atl1c_irq_enable(adapter);
- atl1c_check_link_status(adapter);
netif_start_queue(netdev);
return err;
err_up:
-err_alloc_rx:
atl1c_clean_rx_ring(adapter);
return err;
}
@@ -2256,9 +2278,7 @@ static void atl1c_down(struct atl1c_adapter *adapter)
adapter->link_speed = SPEED_0;
adapter->link_duplex = -1;
- atl1c_clean_tx_ring(adapter, atl1c_trans_normal);
- atl1c_clean_tx_ring(adapter, atl1c_trans_high);
- atl1c_clean_rx_ring(adapter);
+ atl1c_reset_dma_ring(adapter);
}
/*
--
1.7.7
^ permalink raw reply related
* [PATCH 06/10] atl1c: enlarge L1 response waiting timer
From: xiong @ 2012-04-28 1:58 UTC (permalink / raw)
To: davem, netdev, linux-kernel; +Cc: qca-linux-team, nic-devel, xiong
In-Reply-To: <1335578325-21326-1-git-send-email-xiong@qca.qualcomm.com>
The hardware incorrectly process L0S/L1 entrance if the chipset/root
response after specific/shorter timer and cause system hang.
Enlarge the timeout value to avoid this issue.
Signed-off-by: xiong <xiong@qca.qualcomm.com>
Tested-by: Liu David <dwliu@qca.qualcomm.com>
---
drivers/net/ethernet/atheros/atl1c/atl1c_hw.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
index 21a5bc1..17d935b 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
@@ -157,7 +157,7 @@ void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed);
#define PM_CTRL_PM_REQ_TIMER_MASK 0xFUL
#define PM_CTRL_PM_REQ_TIMER_SHIFT 20 /* pm_request_l1 time > @
* ->L0s not L1 */
-#define PM_CTRL_PM_REQ_TO_DEF 0xC
+#define PM_CTRL_PM_REQ_TO_DEF 0xF
#define PMCTRL_TXL1_AFTER_L0S BIT(19) /* l1dv2.0+ */
#define L1D_PMCTRL_L1_ENTRY_TM_MASK 7UL /* l1dv2.0+, 3bits */
#define L1D_PMCTRL_L1_ENTRY_TM_SHIFT 16
--
1.7.7
^ permalink raw reply related
* [PATCH 05/10] atl1c: refine mac address related code
From: xiong @ 2012-04-28 1:58 UTC (permalink / raw)
To: davem, netdev, linux-kernel; +Cc: qca-linux-team, nic-devel, xiong
In-Reply-To: <1335578325-21326-1-git-send-email-xiong@qca.qualcomm.com>
On some platform with EEPROM/OTP existing, the BIOS could overwrite
a new MAC address for the NIC. so, the permanent mac address should
be from BIOS. the address is restored when driver removing.
Voltage raising isn't applicable for l1d.
Replace swab32 with htonl for big/little endian platform.
related Registers are refined as well.
Signed-off-by: xiong <xiong@qca.qualcomm.com>
Tested-by: Liu David <dwliu@qca.qualcomm.com>
---
drivers/net/ethernet/atheros/atl1c/atl1c_hw.c | 93 ++++++++++-------------
drivers/net/ethernet/atheros/atl1c/atl1c_hw.h | 32 +++-----
drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 6 +-
3 files changed, 57 insertions(+), 74 deletions(-)
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
index 2522685..ff9c738 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
@@ -43,7 +43,7 @@ int atl1c_check_eeprom_exist(struct atl1c_hw *hw)
return 0;
}
-void atl1c_hw_set_mac_addr(struct atl1c_hw *hw)
+void atl1c_hw_set_mac_addr(struct atl1c_hw *hw, u8 *mac_addr)
{
u32 value;
/*
@@ -51,33 +51,48 @@ void atl1c_hw_set_mac_addr(struct atl1c_hw *hw)
* 0: 6AF600DC 1: 000B
* low dword
*/
- value = (((u32)hw->mac_addr[2]) << 24) |
- (((u32)hw->mac_addr[3]) << 16) |
- (((u32)hw->mac_addr[4]) << 8) |
- (((u32)hw->mac_addr[5])) ;
+ value = mac_addr[2] << 24 |
+ mac_addr[3] << 16 |
+ mac_addr[4] << 8 |
+ mac_addr[5];
AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value);
/* hight dword */
- value = (((u32)hw->mac_addr[0]) << 8) |
- (((u32)hw->mac_addr[1])) ;
+ value = mac_addr[0] << 8 |
+ mac_addr[1];
AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value);
}
+/* read mac address from hardware register */
+static bool atl1c_read_current_addr(struct atl1c_hw *hw, u8 *eth_addr)
+{
+ u32 addr[2];
+
+ AT_READ_REG(hw, REG_MAC_STA_ADDR, &addr[0]);
+ AT_READ_REG(hw, REG_MAC_STA_ADDR + 4, &addr[1]);
+
+ *(u32 *) ð_addr[2] = htonl(addr[0]);
+ *(u16 *) ð_addr[0] = htons((u16)addr[1]);
+
+ return is_valid_ether_addr(eth_addr);
+}
+
/*
* atl1c_get_permanent_address
* return 0 if get valid mac address,
*/
static int atl1c_get_permanent_address(struct atl1c_hw *hw)
{
- u32 addr[2];
u32 i;
u32 otp_ctrl_data;
u32 twsi_ctrl_data;
- u8 eth_addr[ETH_ALEN];
u16 phy_data;
bool raise_vol = false;
+ /* MAC-address from BIOS is the 1st priority */
+ if (atl1c_read_current_addr(hw, hw->perm_mac_addr))
+ return 0;
+
/* init */
- addr[0] = addr[1] = 0;
AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
if (atl1c_check_eeprom_exist(hw)) {
if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) {
@@ -89,21 +104,14 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
msleep(1);
}
}
-
- if (hw->nic_type == athr_l2c_b ||
- hw->nic_type == athr_l2c_b2 ||
- hw->nic_type == athr_l1d) {
- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
- if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
- goto out;
- phy_data &= 0xFF7F;
- atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
-
- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
- if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
- goto out;
- phy_data |= 0x8;
- atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
+ /* raise voltage temporally for l2cb */
+ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2) {
+ atl1c_read_phy_dbg(hw, MIIDBG_ANACTRL, &phy_data);
+ phy_data &= ~ANACTRL_HB_EN;
+ atl1c_write_phy_dbg(hw, MIIDBG_ANACTRL, phy_data);
+ atl1c_read_phy_dbg(hw, MIIDBG_VOLT_CTRL, &phy_data);
+ phy_data |= VOLT_CTRL_SWLOWEST;
+ atl1c_write_phy_dbg(hw, MIIDBG_VOLT_CTRL, phy_data);
udelay(20);
raise_vol = true;
}
@@ -127,37 +135,18 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
msleep(1);
}
if (raise_vol) {
- if (hw->nic_type == athr_l2c_b ||
- hw->nic_type == athr_l2c_b2 ||
- hw->nic_type == athr_l1d ||
- hw->nic_type == athr_l1d_2) {
- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
- if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
- goto out;
- phy_data |= 0x80;
- atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
-
- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
- if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
- goto out;
- phy_data &= 0xFFF7;
- atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
- udelay(20);
- }
+ atl1c_read_phy_dbg(hw, MIIDBG_ANACTRL, &phy_data);
+ phy_data |= ANACTRL_HB_EN;
+ atl1c_write_phy_dbg(hw, MIIDBG_ANACTRL, phy_data);
+ atl1c_read_phy_dbg(hw, MIIDBG_VOLT_CTRL, &phy_data);
+ phy_data &= ~VOLT_CTRL_SWLOWEST;
+ atl1c_write_phy_dbg(hw, MIIDBG_VOLT_CTRL, phy_data);
+ udelay(20);
}
- /* maybe MAC-address is from BIOS */
- AT_READ_REG(hw, REG_MAC_STA_ADDR, &addr[0]);
- AT_READ_REG(hw, REG_MAC_STA_ADDR + 4, &addr[1]);
- *(u32 *) ð_addr[2] = swab32(addr[0]);
- *(u16 *) ð_addr[0] = swab16(*(u16 *)&addr[1]);
-
- if (is_valid_ether_addr(eth_addr)) {
- memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
+ if (atl1c_read_current_addr(hw, hw->perm_mac_addr))
return 0;
- }
-out:
return -1;
}
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
index ea3f520..21a5bc1 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h
@@ -36,7 +36,7 @@ struct atl1c_hw;
/* function prototype */
void atl1c_phy_disable(struct atl1c_hw *hw);
-void atl1c_hw_set_mac_addr(struct atl1c_hw *hw);
+void atl1c_hw_set_mac_addr(struct atl1c_hw *hw, u8 *mac_addr);
int atl1c_phy_reset(struct atl1c_hw *hw);
int atl1c_read_mac_addr(struct atl1c_hw *hw);
int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex);
@@ -94,25 +94,17 @@ void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed);
#define REG_DEV_SERIAL_NUM_EN_SHIFT 1
#define REG_TWSI_CTRL 0x218
+#define TWSI_CTLR_FREQ_MASK 0x3UL
+#define TWSI_CTRL_FREQ_SHIFT 24
+#define TWSI_CTRL_FREQ_100K 0
+#define TWSI_CTRL_FREQ_200K 1
+#define TWSI_CTRL_FREQ_300K 2
+#define TWSI_CTRL_FREQ_400K 3
+#define TWSI_CTRL_LD_EXIST BIT(23)
+#define TWSI_CTRL_HW_LDSTAT BIT(12) /* 0:finish,1:in progress */
+#define TWSI_CTRL_SW_LDSTART BIT(11)
#define TWSI_CTRL_LD_OFFSET_MASK 0xFF
#define TWSI_CTRL_LD_OFFSET_SHIFT 0
-#define TWSI_CTRL_LD_SLV_ADDR_MASK 0x7
-#define TWSI_CTRL_LD_SLV_ADDR_SHIFT 8
-#define TWSI_CTRL_SW_LDSTART 0x800
-#define TWSI_CTRL_HW_LDSTART 0x1000
-#define TWSI_CTRL_SMB_SLV_ADDR_MASK 0x7F
-#define TWSI_CTRL_SMB_SLV_ADDR_SHIFT 15
-#define TWSI_CTRL_LD_EXIST 0x400000
-#define TWSI_CTRL_READ_FREQ_SEL_MASK 0x3
-#define TWSI_CTRL_READ_FREQ_SEL_SHIFT 23
-#define TWSI_CTRL_FREQ_SEL_100K 0
-#define TWSI_CTRL_FREQ_SEL_200K 1
-#define TWSI_CTRL_FREQ_SEL_300K 2
-#define TWSI_CTRL_FREQ_SEL_400K 3
-#define TWSI_CTRL_SMB_SLV_ADDR
-#define TWSI_CTRL_WRITE_FREQ_SEL_MASK 0x3
-#define TWSI_CTRL_WRITE_FREQ_SEL_SHIFT 24
-
#define REG_PCIE_DEV_MISC_CTRL 0x21C
#define PCIE_DEV_MISC_EXT_PIPE 0x2
@@ -135,7 +127,7 @@ void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed);
#define L2CB1_PCIE_PHYMISC2_CDR_BW 3
#define REG_TWSI_DEBUG 0x1108
-#define TWSI_DEBUG_DEV_EXIST 0x20000000
+#define TWSI_DEBUG_DEV_EXIST BIT(29)
#define REG_DMA_DBG 0x1114
#define DMA_DBG_VENDOR_MSG BIT(0)
@@ -151,7 +143,7 @@ void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed);
#define REG_EEPROM_DATA_LO 0x12C4
#define REG_OTP_CTRL 0x12F0
-#define OTP_CTRL_CLK_EN 0x0002
+#define OTP_CTRL_CLK_EN BIT(1)
#define REG_PM_CTRL 0x12F8
#define PM_CTRL_HOTRST BIT(31)
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 6552913..8fee1fc 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -463,7 +463,7 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p)
memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
- atl1c_hw_set_mac_addr(&adapter->hw);
+ atl1c_hw_set_mac_addr(&adapter->hw, adapter->hw.mac_addr);
return 0;
}
@@ -2536,7 +2536,7 @@ static int __devinit atl1c_probe(struct pci_dev *pdev,
dev_dbg(&pdev->dev, "mac address : %pM\n",
adapter->hw.mac_addr);
- atl1c_hw_set_mac_addr(&adapter->hw);
+ atl1c_hw_set_mac_addr(&adapter->hw, adapter->hw.mac_addr);
INIT_WORK(&adapter->common_task, atl1c_common_task);
adapter->work_event = 0;
err = register_netdev(netdev);
@@ -2580,6 +2580,8 @@ static void __devexit atl1c_remove(struct pci_dev *pdev)
struct atl1c_adapter *adapter = netdev_priv(netdev);
unregister_netdev(netdev);
+ /* restore permanent address */
+ atl1c_hw_set_mac_addr(&adapter->hw, adapter->hw.perm_mac_addr);
atl1c_phy_disable(&adapter->hw);
iounmap(adapter->hw.hw_addr);
--
1.7.7
^ permalink raw reply related
* [PATCH 04/10] atl1c: remove code of closing register writable attribution
From: xiong @ 2012-04-28 1:58 UTC (permalink / raw)
To: davem, netdev, linux-kernel; +Cc: qca-linux-team, nic-devel, xiong
In-Reply-To: <1335578325-21326-1-git-send-email-xiong@qca.qualcomm.com>
The Close-action is done by atl1c_reset_pcie, remove it from
atl1c_get_permanent_address.
Signed-off-by: xiong <xiong@qca.qualcomm.com>
Tested-by: Liu David <dwliu@qca.qualcomm.com>
---
drivers/net/ethernet/atheros/atl1c/atl1c_hw.c | 6 ------
1 files changed, 0 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
index 49f433e..2522685 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
@@ -72,7 +72,6 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
u32 i;
u32 otp_ctrl_data;
u32 twsi_ctrl_data;
- u32 ltssm_ctrl_data;
u8 eth_addr[ETH_ALEN];
u16 phy_data;
bool raise_vol = false;
@@ -108,11 +107,6 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
udelay(20);
raise_vol = true;
}
- /* close open bit of ReadOnly*/
- AT_READ_REG(hw, REG_LTSSM_ID_CTRL, <ssm_ctrl_data);
- ltssm_ctrl_data &= ~LTSSM_ID_EN_WRO;
- AT_WRITE_REG(hw, REG_LTSSM_ID_CTRL, ltssm_ctrl_data);
-
AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
--
1.7.7
^ permalink raw reply related
* [PATCH 03/10] atl1c: clear WoL status when reset pcie
From: xiong @ 2012-04-28 1:58 UTC (permalink / raw)
To: davem, netdev, linux-kernel; +Cc: qca-linux-team, nic-devel, xiong
In-Reply-To: <1335578325-21326-1-git-send-email-xiong@qca.qualcomm.com>
WoL status is read-clear and should be cleared when in S0
status.
putting it in atl1c_reset_pcie is more suitable than
in atl1c_get_permanent_address.
Signed-off-by: xiong <xiong@qca.qualcomm.com>
Tested-by: Liu David <dwliu@qca.qualcomm.com>
---
drivers/net/ethernet/atheros/atl1c/atl1c_hw.c | 5 -----
drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 3 +++
2 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
index 209c179..49f433e 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
@@ -73,7 +73,6 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
u32 otp_ctrl_data;
u32 twsi_ctrl_data;
u32 ltssm_ctrl_data;
- u32 wol_data;
u8 eth_addr[ETH_ALEN];
u16 phy_data;
bool raise_vol = false;
@@ -114,10 +113,6 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
ltssm_ctrl_data &= ~LTSSM_ID_EN_WRO;
AT_WRITE_REG(hw, REG_LTSSM_ID_CTRL, ltssm_ctrl_data);
- /* clear any WOL settings */
- AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
- AT_READ_REG(hw, REG_WOL_CTRL, &wol_data);
-
AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 50df437..6552913 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -133,6 +133,9 @@ static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag)
*/
pci_enable_wake(pdev, PCI_D3hot, 0);
pci_enable_wake(pdev, PCI_D3cold, 0);
+ /* wol sts read-clear */
+ AT_READ_REG(hw, REG_WOL_CTRL, &data);
+ AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
/*
* Mask some pcie error bits
--
1.7.7
^ permalink raw reply related
* [PATCH 00/10] atl1c: update hardware settings - v4
From: xiong @ 2012-04-28 1:58 UTC (permalink / raw)
To: davem, netdev, linux-kernel; +Cc: qca-linux-team, nic-devel, xiong
This update contains a serial of patches, most of them are hardware
settings related. register definitions are refined (or removed if
meaningless) for each patch.
This is the last patch set.
The patches have addressed all sparse and checkpatch warnings.
Following NICs are tested:
AR8131/AR8132/AR8151A/AR8152A/AR8152B
Test item includes:
build/install/uninstall/dhcp/ping/iperf/wol/reboot/etc.
xiong (10):
atl1c: add workaround for issue of bit INTX-disable for MSI interrupt
atl1c: add PHY link event(up/down) patch
atl1c: clear WoL status when reset pcie
atl1c: remove code of closing register writable attribution
atl1c: refine mac address related code
atl1c: enlarge L1 response waiting timer
atl1c: cancel task when interface closed
atl1c: do MAC-reset when PHY link down
atl1c: Disable L0S when no cable link
atl1c: remove PHY polling from atl1c_change_mtu
drivers/net/ethernet/atheros/atl1c/atl1c.h | 1 +
drivers/net/ethernet/atheros/atl1c/atl1c_hw.c | 141 ++++++++++++---------
drivers/net/ethernet/atheros/atl1c/atl1c_hw.h | 35 ++---
drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 153 +++++++++++++++++------
drivers/pci/quirks.c | 12 ++
5 files changed, 220 insertions(+), 122 deletions(-)
--
1.7.7
^ permalink raw reply
* RE: [PATCH net-next 2/5] be2net: Fix to allow setting of debug levels in the firmware.
From: Somnath.Kotur @ 2012-04-28 1:23 UTC (permalink / raw)
To: Somnath.Kotur, bhutchings; +Cc: netdev
In-Reply-To: <3367B80B08154D42A3B2BC708B5D41F6440F8979D6@EXMAIL.ad.emulex.com>
Ben,
Could you pls respond to my replies inline.
Thanks
Somnath
> -----Original Message-----
> From: netdev-owner@vger.kernel.org [mailto:netdev-
> owner@vger.kernel.org] On Behalf Of Somnath.Kotur@Emulex.Com
> Sent: Friday, April 27, 2012 12:16 PM
> To: bhutchings@solarflare.com
> Cc: netdev@vger.kernel.org
> Subject: RE: [PATCH net-next 2/5] be2net: Fix to allow setting of debug levels
> in the firmware.
>
> > > This operation is intended for controlling logging by the driver,
> > > and the flags
> > are defined in <linux/netdevice.h>. (Not exported to userland yet,
> > but ethtool knows their names.)
> >
> > If your firmware supports some kind of logging then it may be
> > reasonable to have this control both driver and firmware, but not *just*
> the firmware.
> Thanks for your comments Ben.
>
> Currently the driver logs only a very few critical errors/warnings; so we felt it
> might be an overkill to define driver log levels.
> On the other hand, the F/W has extensive logging and tracing facility and the
> ethtool 'msglevel' option seemed like a reasonable method for controlling
> the logging level.
>
> >
> > You should also implement the get_msglevel operation at the same time.
>
> Yes you are correct. We will implement the get_msglevel and re-post the
> patch.
> >
> > Ben.
> >
>
> Thanks
> Som
> N r y b X ǧv ^ ){.n + z ^ ) w*jg \x1e ݢj/ z ޖ 2 ޙ & )ߡ a \x7f \x1e G h \x0f j:+v
> w ٥
^ permalink raw reply
* Re: [PATCH 1/4 net-next] net: allow skb->head to be a page fragment
From: Alexander Duyck @ 2012-04-28 0:27 UTC (permalink / raw)
To: Eric Dumazet
Cc: David Miller, netdev, Ilpo Järvinen, Neal Cardwell,
Tom Herbert, Maciej Żenczykowski, Jeff Kirsher,
Ben Hutchings, Matt Carlson, Michael Chan, Herbert Xu
In-Reply-To: <1335522818.2775.227.camel@edumazet-glaptop>
On 04/27/2012 03:33 AM, Eric Dumazet wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> skb->head is currently allocated from kmalloc(). This is convenient but
> has the drawback the data cannot be converted to a page fragment if
> needed.
>
> We have three spots were it hurts :
>
> 1) GRO aggregation
>
> When a linear skb must be appended to another skb, GRO uses the
> frag_list fallback, very inefficient since we keep all struct sk_buff
> around. So drivers enabling GRO but delivering linear skbs to network
> stack aren't enabling full GRO power.
>
> 2) splice(socket -> pipe).
>
> We must copy the linear part to a page fragment.
> This kind of defeats splice() purpose (zero copy claim)
>
> 3) TCP coalescing.
>
> Recently introduced, this permits to group several contiguous segments
> into a single skb. This shortens queue lengths and save kernel memory,
> and greatly reduce probabilities of TCP collapses. This coalescing
> doesnt work on linear skbs (or we would need to copy data, this would be
> too slow)
>
> Given all these issues, the following patch introduces the possibility
> of having skb->head be a fragment in itself. We use a new skb flag,
> skb->head_frag to carry this information.
>
> build_skb() is changed to accept a frag_size argument. Drivers willing
> to provide a page fragment instead of kmalloc() data will set a non zero
> value, set to the fragment size.
>
> Then, on situations we need to convert the skb head to a frag in itself,
> we can check if skb->head_frag is set and avoid the copies or various
> fallbacks we have.
>
> This means drivers currently using frags could be updated to avoid the
> current skb->head allocation and reduce their memory footprint (aka skb
> truesize). (thats 512 or 1024 bytes saved per skb). This also makes
> bpf/netfilter faster since the 'first frag' will be part of skb linear
> part, no need to copy data.
[...]
> diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> index 2342a72..effa75d 100644
> --- a/net/core/skbuff.c
> +++ b/net/core/skbuff.c
> @@ -245,6 +245,7 @@ EXPORT_SYMBOL(__alloc_skb);
> /**
> * build_skb - build a network buffer
> * @data: data buffer provided by caller
> + * @frag_size: size of fragment, or 0 if head was kmalloced
> *
> * Allocate a new &sk_buff. Caller provides space holding head and
> * skb_shared_info. @data must have been allocated by kmalloc()
> @@ -258,20 +259,21 @@ EXPORT_SYMBOL(__alloc_skb);
> * before giving packet to stack.
> * RX rings only contains data buffers, not full skbs.
> */
> -struct sk_buff *build_skb(void *data)
> +struct sk_buff *build_skb(void *data, unsigned int frag_size)
> {
> struct skb_shared_info *shinfo;
> struct sk_buff *skb;
> - unsigned int size;
> + unsigned int size = frag_size ? : ksize(data);
>
> skb = kmem_cache_alloc(skbuff_head_cache, GFP_ATOMIC);
> if (!skb)
> return NULL;
>
> - size = ksize(data) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
> + size -= SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
>
> memset(skb, 0, offsetof(struct sk_buff, tail));
> skb->truesize = SKB_TRUESIZE(size);
> + skb->head_frag = frag_size != 0;
> atomic_set(&skb->users, 1);
> skb->head = data;
> skb->data = data;
This doesn't seem right to me. You are only counting the piece of the
page that got filled with data and the piece that will get overwritten
with the shared info. What about the rest of the page? It looks like
in the tg3 patch you have the driver using a half page. Based on this
function I suspect the resultant truesize would be something like 64 +
256 + 320 for an ack. Shouldn't your truesize in that case be 2048 + 256?
Thanks,
Alex
^ permalink raw reply
* Re: [RFT] sky2: fix status length check on older chips
From: Niccolò Belli @ 2012-04-27 23:05 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20120427135514.48b03ce8@nehalam.linuxnetplumber.net>
It doesn't compile against 3.4-rc4:
CC [M] drivers/net/ethernet/intel/e1000e/param.o
CC [M] drivers/net/ethernet/marvell/sky2.o
CC [M] drivers/net/ethernet/intel/e1000e/ethtool.o
CC [M] net/sunrpc/svc_xprt.o
drivers/net/ethernet/marvell/sky2.c: In function ‘sky2_status_intr’:
drivers/net/ethernet/marvell/sky2.c:2769:4: warning: passing argument 2
of ‘sky2_skb_rx’ makes pointer from integer without a cast
drivers/net/ethernet/marvell/sky2.c:2649:20: note: expected ‘struct
sk_buff *’ but argument is of type ‘u32’
drivers/net/ethernet/marvell/sky2.c:2769:4: error: too many arguments to
function ‘sky2_skb_rx’
drivers/net/ethernet/marvell/sky2.c:2649:20: note: declared here
make[4]: *** [drivers/net/ethernet/marvell/sky2.o] Errore 1
make[3]: *** [drivers/net/ethernet/marvell] Errore 2
make[3]: *** Attesa dei processi non terminati....
CC [M] net/sunrpc/backchannel_rqst.o
CC [M] drivers/net/ethernet/intel/e1000e/netdev.o
Niccolò
^ permalink raw reply
* Re: [PATCH] mwl8k: Add 0x2a02 PCI device-id (Marvell 88W8361)
From: Sedat Dilek @ 2012-04-27 21:53 UTC (permalink / raw)
To: Lennert Buytenhek
Cc: John W. Linville, linux-wireless, netdev, linux-kernel, lautriv,
Jim Cromie
In-Reply-To: <20120427185809.GZ3157@wantstofly.org>
[-- Attachment #1: Type: text/plain, Size: 6523 bytes --]
On Fri, Apr 27, 2012 at 8:58 PM, Lennert Buytenhek
<buytenh@wantstofly.org> wrote:
> On Fri, Apr 27, 2012 at 03:29:26PM +0200, Sedat Dilek wrote:
>
>> >>> >> >> >> Are you planning to or even working on support (for) 8361 devices?
>> >>> >> >> >
>> >>> >> >> > I don't have any such plans, and I don't know of anyone who does.
>> >>> >> >>
>> >>> >> >> Does 8361 require firmware support?
>> >>> >> >
>> >>> >> > What do you mean by that?
>> >>> >>
>> >>> >> IIRC ath5k for example needs no external firmware file.
>> >>> >
>> >>> > The 8361 requires firmware to be loaded into it before it'll do
>> >>> > anything useful.
>> >>> >
>> >>> >
>> >>> >> >> Does a firmware file exist (name?)?
>> >>> >> >
>> >>> >> > There's firmware for the 8361 out there, however, that version of
>> >>> >> > the firmware implements a firmware API that is different from the
>> >>> >> > one that mwl8k currently implements.
>> >>> >> >
>> >>> >> > You could add 8361 support to mwl8k, but then you'd have to go over
>> >>> >> > all the firmware command invocations in mwl8k and make sure that they
>> >>> >> > will work on the 8361 firmware that you're trying to support as well.
>> >>> >>
>> >>> >> Without having a 8361 this will be even harder to walk through.
>> >>> >>
>> >>> >> Anyway, thanks for your detailed explanations.
>> >>> >>
>> >>> >> What's the alternative for such affected users?
>> >>> >> Use ndis-wrapper?
>> >>> >
>> >>> > I'm not sure. I've never tried to get a 8361 work under Linux.
>> >>>
>> >>> Just found on [1] this same wrong patch in [2] :-).
>> >>> Dunno if [3] worked and from where they have stolen fw-files.
>> >>>
>> >>> - Sedat -
>> >>>
>> >>> [1] https://dev.openwrt.org/ticket/7209
>> >>> [2] https://dev.openwrt.org/attachment/ticket/7209/mwl8k_fix_pci_id.patch
>> >>> [3] https://dev.openwrt.org/attachment/ticket/7209/mwl8k_8361p.patch
>> >>
>> >> I doubt that [3] is really all that's needed to make it work. But if
>> >> there's someone for whom it works, I'd like them to run some tests on
>> >> mwl8k + [3] on 88w8361p.
>> >
>> > Just asked lautriv to do so (he will do against linux-3.3.3), lets' see.
>> > Also, I refreshed and adapted a bit the instructions (see attachment).
>> >
>> > - Sedat -
>>
>> [ CC Jim Cromie ]
>>
>> Now, with extracted firmware files renamed & copied to
>> /lib/firmware/mwl8k/ and applied patch (see attachment) against
>> Linux-3.4-rc4+ I am seeing with modinfo:
>>
>> $ sudo modinfo mwl8k
>> filename:
>> /lib/modules/3.4.0-rc4-5-generic/kernel/drivers/net/wireless/mwl8k.ko
>> license: GPL
>> author: Lennert Buytenhek <buytenh@marvell.com>
>> version: 0.13
>> description: Marvell TOPDOG(R) 802.11 Wireless Network Driver
>> firmware: mwl8k/fmimage_8366_ap-2.fw
>> firmware: mwl8k/fmimage_8366.fw
>> firmware: mwl8k/helper_8366.fw
>> firmware: mwl8k/fmimage_8687.fw
>> firmware: mwl8k/helper_8687.fw
>> firmware: mwl8k/fmimage_8363.fw
>> firmware: mwl8k/helper_8363.fw
>> firmware: mwl8k/fmimage_8361p.fw
>> firmware: mwl8k/helper_8361p.fw
>> srcversion: 9E1479A05C8D67E6AE90746
>> alias: pci:v000011ABd00002A43sv*sd*bc*sc*i*
>> alias: pci:v000011ABd00002A40sv*sd*bc*sc*i*
>> alias: pci:v000011ABd00002A30sv*sd*bc*sc*i*
>> alias: pci:v000011ABd00002A2Bsv*sd*bc*sc*i*
>> alias: pci:v000011ABd00002A24sv*sd*bc*sc*i*
>> alias: pci:v000011ABd00002A0Csv*sd*bc*sc*i*
>> alias: pci:v000011ABd00002A0Asv*sd*bc*sc*i*
>> alias: pci:v000011ABd00002A02sv*sd*bc*sc*i* <--- 8361P:
>> 0x2a02 PCI device-id
>> depends: mac80211,cfg80211
>> vermagic: 3.4.0-rc4-5-generic SMP mod_unload modversions
>> parm: ap_mode_default:Set to 1 to make ap mode the default
>> instead of sta mode (bool)
>>
>> $ ls -l /lib/firmware/mwl8k/
>> insgesamt 456
>> -rw-r--r-- 1 root root 75848 Apr 27 13:49 fmimage_8361p.fw <---
>> 8361P: Firmware image
>> -rw-r--r-- 1 root root 101780 Mär 19 19:32 fmimage_8366_ap-1.fw
>> -rw-r--r-- 1 root root 101976 Mär 19 19:32 fmimage_8366_ap-2.fw
>> -rw-r--r-- 1 root root 96664 Mär 19 19:32 fmimage_8366.fw
>> -rw-r--r-- 1 root root 73252 Feb 23 20:07 fmimage_8687.fw
>> -rw-r--r-- 1 root root 2476 Apr 27 13:49 helper_8361p.fw <--- 8361P:
>> Helper image
>> -rw-r--r-- 1 root root 2476 Mär 19 19:32 helper_8366.fw
>> -rw-r--r-- 1 root root 2476 Feb 23 20:07 helper_8687.fw
>>
>> As said... ***compile-tested*** only here.
>
> Which doesn't say much at all, but..
>
As already pointed out, no Marwell WLAN hardware here. Marvell comics
of course :-).
>
>> I had a short query with lautriv on #linux-wireless this afternoon:
>> * mwl8k kernel-module was autoloaded
>> * wlan0 interface got fired up
>> * ESSID was accepted
>> * logs reported 802.11bgn support is active
>> * (he tested on Linux-3.3.3)
>>
>> With WPA/WPA2 lautriv had some problems as his installation was
>> missing wpasupplicant.
>> He setup a classic /etc/network/interfaces.
>> After resetting his router mwl8k worked nicely.
>>
>> Unfortunately, he was on the run and promised me to send logs and do
>> more testing this evening.
>
> ..but this is pretty interesting. I thought that the only available
> 8361p firmware used an incompatible firmware API, and I didn't know
> of the existence of an apparently compatible firmware.
>
>
>> So, Lennert if you want more testing - What? How? etc.
>
> For one, the output of 'iw phy', please.
>
> Also, does monitor mode work? Do you get plausible channel/rxpower
> values in tcpdump in monitor mode?
>
> Are there any messages in the syslog about failing commands?
>
>
> thanks,
> Lennert
On 1st sight, logs look fine:
[21:52:52] <lautriv> [ 6.050967] ieee80211 phy0: 88w8361p v4,
00173f3bdde3, STA firmware 2.1.4.25
But WLAN connection is not that fast and stable as lautriv reports
(several abnormalities were observed).
I requested a tarball which includes:
* dmesg (Linux-3.3.3)
* e_n_a (/etc/network/interfaces)
* ifconfig output
* iwconfig output
* iw_phy output
* ps_axu (WPA) output
lautriv will be so kind to be around on #linux-wireless/Freenode the
next days (UTC+2: German/Swiss local-time).
Just ping him.
Hope you have fun, together!
- Sedat -
[-- Attachment #2: 8361p.tar.xz --]
[-- Type: application/octet-stream, Size: 10076 bytes --]
^ permalink raw reply
* Re: [PATCH V2 1/2] bonding support for IPv6 transmit hashing
From: John @ 2012-04-27 21:21 UTC (permalink / raw)
To: Jay Vosburgh; +Cc: netdev
In-Reply-To: <22560.1335307907@death.nxdomain>
Thanks Jay. It was against Linux 3.3.0. I will update my patch and re-post.
John
On 4/24/2012 3:51 PM, Jay Vosburgh wrote:
> John<linux@8192.net> wrote:
>
> In principle, I think this is a good idea, but the patch has
> some (mostly style) issues, and does not apply to net-next (you don't
> say what tree it is based on).
>
> Can you address the comments noted below, and repost against the
> current net-next?
>
^ permalink raw reply
* Re: [PATCH][RFC] bonding: delete migrated IP addresses from the rlb hash table
From: Jiri Bohac @ 2012-04-27 21:03 UTC (permalink / raw)
To: Jay Vosburgh; +Cc: Jiri Bohac, Andy Gospodarek, netdev
In-Reply-To: <19845.1335471502@death.nxdomain>
On Thu, Apr 26, 2012 at 01:18:22PM -0700, Jay Vosburgh wrote:
> >On Wed, Mar 07, 2012 at 05:02:16PM +0100, Jiri Bohac wrote:
> >> I think it would be better to also
> >> store the source (server) MAC address in struct client_info and
> >> only flush the hash table entries if the MAC address from the
> >> incoming APR packet and the source MAC address stored in the hash
> >> table differ.
>
> Just to make sure I understand: the additional check you propose
> (beyond a check that the IP source address is not locally in use) is for
> the purpose of minimizing unnecessary flushes, by insuring that the
> address really has moved. Correct?
No. There is no check whether the IP source address is local.
The check looks if the IP source address is stored in the rlb
hash table as ip_src. Could be a result of using the IP address
locally, or by other hosts bridged with the bonding master.
And the additional check that prevents unnecessarry flushes
(caused by ARP packets sent out from the bond being looped back
by a switch) is a check for the MAC address in the ARP packet.
If the MAC address is different from the MAC address stored in
the rlb hash table, it means the host with IP address ip_src does
no longer use mac_src and we must not send out client updates
with this ip_src/mac_src combination.
If the MAC address in the ARP packet is equal to the mac_src, it
could mean two things:
- the IP address has not moved and is still used locally or
bridged to the bonding master; we received this packet because
a switch looped it back to another slave of the bond
- the IP address has actually moved, but the MAC address remained
the same (think of a virtual machine migration, keeping the
virtual NIC's MAC address). We don't mind keeping the
corresponding rlb entry, because the ip/mac combination is
still valid and will not polute ARP caches with invalid
information.
> I'm going to give this a spin this afternoon, but just skimming
> through it, I'm still not that thrilled about the "forward" and
> "reverse" terminology applying to "hash by dst" and "hash by src"; why
> not just call 'em "dst_next" and "src_next", et al, and cut out the
> middle man?
How about these naming changes - patch below:
next -> used_next
prev -> used_prev
rx_hashtbl_head -> rx_hashtbl_used_head
the currect linked list is _not_ a list of hash table
entries with colliding ip_dst. It's a list of entries that are
being used; its purpose is to avoid walking the whole hash table
when looking for used entries;
reverse_next -> src_next
reverse_prev -> src_prev
reverse_first -> src_first
I also renamed some of the functions, e.g.
rlb_src_unlink/rlb_src_link instead of
rlb_delete_table_entry_reverse/rlb_set_reverse_entry
because they actually link the existing entries to the
corresponding linked list.
Signed-off-by: Jiri Bohac <jbohac@suse.cz>
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 9abfde4..a7809ae 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -84,6 +84,9 @@ static inline struct arp_pkt *arp_pkt(const struct sk_buff *skb)
/* Forward declaration */
static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]);
+static void rlb_purge_src_ip(struct bonding *bond, struct arp_pkt *arp);
+static void rlb_src_unlink(struct bonding *bond, u32 index);
+static void rlb_src_link(struct bonding *bond, u32 ip_src_hash, u32 ip_dst_hash);
static inline u8 _simple_hash(const u8 *hash_start, int hash_size)
{
@@ -364,6 +367,17 @@ static void rlb_arp_recv(struct sk_buff *skb, struct bonding *bond,
return;
}
+ /* We received an ARP from arp->ip_src.
+ * We might have used this IP address previously (on the bonding host
+ * itself or on a system that is bridged together with the bond).
+ * However, if arp->mac_src is different than what is stored in
+ * rx_hashtbl, some other host is now using the IP and we must prevent
+ * sending out client updates with this IP address and the old MAC address.
+ * Clean up all hash table entries that have this address as ip_src but
+ * have a dirrerent mac_src.
+ */
+ rlb_purge_src_ip(bond, arp);
+
if (arp->op_code == htons(ARPOP_REPLY)) {
/* update rx hash table for this ARP */
rlb_update_entry_from_arp(bond, arp);
@@ -440,9 +454,9 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave)
_lock_rx_hashtbl_bh(bond);
rx_hash_table = bond_info->rx_hashtbl;
- index = bond_info->rx_hashtbl_head;
+ index = bond_info->rx_hashtbl_used_head;
for (; index != RLB_NULL_INDEX; index = next_index) {
- next_index = rx_hash_table[index].next;
+ next_index = rx_hash_table[index].used_next;
if (rx_hash_table[index].slave == slave) {
struct slave *assigned_slave = rlb_next_rx_slave(bond);
@@ -527,8 +541,8 @@ static void rlb_update_rx_clients(struct bonding *bond)
_lock_rx_hashtbl_bh(bond);
- hash_index = bond_info->rx_hashtbl_head;
- for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
+ hash_index = bond_info->rx_hashtbl_used_head;
+ for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]);
if (client_info->ntt) {
rlb_update_client(client_info);
@@ -556,8 +570,8 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla
_lock_rx_hashtbl_bh(bond);
- hash_index = bond_info->rx_hashtbl_head;
- for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
+ hash_index = bond_info->rx_hashtbl_used_head;
+ for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]);
if ((client_info->slave == slave) &&
@@ -586,8 +600,8 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip)
_lock_rx_hashtbl(bond);
- hash_index = bond_info->rx_hashtbl_head;
- for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
+ hash_index = bond_info->rx_hashtbl_used_head;
+ for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]);
if (!client_info->slave) {
@@ -633,6 +647,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
/* update mac address from arp */
memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN);
}
+ memcpy(client_info->mac_src, arp->mac_src, ETH_ALEN);
assigned_slave = client_info->slave;
if (assigned_slave) {
@@ -655,6 +670,13 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
assigned_slave = rlb_next_rx_slave(bond);
if (assigned_slave) {
+ if (!(client_info->assigned && client_info->ip_src == arp->ip_src)) {
+ /* ip_src is going to be updated, fix the src hash list */
+ u32 hash_src = _simple_hash((u8 *)&arp->ip_src, sizeof(arp->ip_src));
+ rlb_src_unlink(bond, hash_index);
+ rlb_src_link(bond, hash_src, hash_index);
+ }
+
client_info->ip_src = arp->ip_src;
client_info->ip_dst = arp->ip_dst;
/* arp->mac_dst is broadcast for arp reqeusts.
@@ -662,6 +684,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
* upon receiving an arp reply.
*/
memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN);
+ memcpy(client_info->mac_src, arp->mac_src, ETH_ALEN);
client_info->slave = assigned_slave;
if (compare_ether_addr_64bits(client_info->mac_dst, mac_bcast)) {
@@ -677,11 +700,11 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
}
if (!client_info->assigned) {
- u32 prev_tbl_head = bond_info->rx_hashtbl_head;
- bond_info->rx_hashtbl_head = hash_index;
- client_info->next = prev_tbl_head;
+ u32 prev_tbl_head = bond_info->rx_hashtbl_used_head;
+ bond_info->rx_hashtbl_used_head = hash_index;
+ client_info->used_next = prev_tbl_head;
if (prev_tbl_head != RLB_NULL_INDEX) {
- bond_info->rx_hashtbl[prev_tbl_head].prev =
+ bond_info->rx_hashtbl[prev_tbl_head].used_prev =
hash_index;
}
client_info->assigned = 1;
@@ -748,8 +771,8 @@ static void rlb_rebalance(struct bonding *bond)
_lock_rx_hashtbl_bh(bond);
ntt = 0;
- hash_index = bond_info->rx_hashtbl_head;
- for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
+ hash_index = bond_info->rx_hashtbl_used_head;
+ for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]);
assigned_slave = rlb_next_rx_slave(bond);
if (assigned_slave && (client_info->slave != assigned_slave)) {
@@ -767,11 +790,113 @@ static void rlb_rebalance(struct bonding *bond)
}
/* Caller must hold rx_hashtbl lock */
+static void rlb_init_table_entry_dst(struct rlb_client_info *entry)
+{
+ entry->used_next = RLB_NULL_INDEX;
+ entry->used_prev = RLB_NULL_INDEX;
+ entry->assigned = 0;
+ entry->slave = NULL;
+ entry->tag = 0;
+}
+static void rlb_init_table_entry_src(struct rlb_client_info *entry)
+{
+ entry->src_first = RLB_NULL_INDEX;
+ entry->src_prev = RLB_NULL_INDEX;
+ entry->src_next = RLB_NULL_INDEX;
+}
+
static void rlb_init_table_entry(struct rlb_client_info *entry)
{
memset(entry, 0, sizeof(struct rlb_client_info));
- entry->next = RLB_NULL_INDEX;
- entry->prev = RLB_NULL_INDEX;
+ rlb_init_table_entry_dst(entry);
+ rlb_init_table_entry_src(entry);
+}
+
+static void rlb_delete_table_entry_dst(struct bonding *bond, u32 index)
+{
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+ u32 next_index = bond_info->rx_hashtbl[index].used_next;
+ u32 prev_index = bond_info->rx_hashtbl[index].used_prev;
+
+ if (index == bond_info->rx_hashtbl_used_head)
+ bond_info->rx_hashtbl_used_head = next_index;
+ if (prev_index != RLB_NULL_INDEX)
+ bond_info->rx_hashtbl[prev_index].used_next = next_index;
+ if (next_index != RLB_NULL_INDEX)
+ bond_info->rx_hashtbl[next_index].used_prev = prev_index;
+}
+
+/* unlink a rlb hash table entry from the src list */
+static void rlb_src_unlink(struct bonding *bond, u32 index)
+{
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+ u32 next_index = bond_info->rx_hashtbl[index].src_next;
+ u32 prev_index = bond_info->rx_hashtbl[index].src_prev;
+
+ bond_info->rx_hashtbl[index].src_next = RLB_NULL_INDEX;
+ bond_info->rx_hashtbl[index].src_prev = RLB_NULL_INDEX;
+
+ if (next_index != RLB_NULL_INDEX)
+ bond_info->rx_hashtbl[next_index].src_prev = prev_index;
+
+ if (prev_index == RLB_NULL_INDEX)
+ return;
+
+ /* is prev_index pointing to the head of this list? */
+ if (bond_info->rx_hashtbl[prev_index].src_first == index)
+ bond_info->rx_hashtbl[prev_index].src_first = next_index;
+ else
+ bond_info->rx_hashtbl[prev_index].src_next = next_index;
+
+}
+
+static void rlb_delete_table_entry(struct bonding *bond, u32 index)
+{
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+ struct rlb_client_info *entry = &(bond_info->rx_hashtbl[index]);
+
+ rlb_delete_table_entry_dst(bond, index);
+ rlb_init_table_entry_dst(entry);
+
+ rlb_src_unlink(bond, index);
+}
+
+/* add the rx_hashtbl[ip_dst_hash] entry to the list
+ * of entries with identical ip_src_hash
+ */
+static void rlb_src_link(struct bonding *bond, u32 ip_src_hash, u32 ip_dst_hash)
+{
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+ u32 next;
+
+ bond_info->rx_hashtbl[ip_dst_hash].src_prev = ip_src_hash;
+ next = bond_info->rx_hashtbl[ip_src_hash].src_first;
+ bond_info->rx_hashtbl[ip_dst_hash].src_next = next;
+ if (next != RLB_NULL_INDEX)
+ bond_info->rx_hashtbl[next].src_prev = ip_dst_hash;
+ bond_info->rx_hashtbl[ip_src_hash].src_first = ip_dst_hash;
+}
+
+/* deletes all rx_hashtbl entries with arp->ip_src if their mac_src does
+ * not match arp->mac_src */
+static void rlb_purge_src_ip(struct bonding *bond, struct arp_pkt *arp)
+{
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+ u32 ip_src_hash = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src));
+ u32 index;
+
+ _lock_rx_hashtbl_bh(bond);
+
+ index = bond_info->rx_hashtbl[ip_src_hash].src_first;
+ while (index != RLB_NULL_INDEX) {
+ struct rlb_client_info *entry = &(bond_info->rx_hashtbl[index]);
+ u32 next_index = entry->src_next;
+ if (entry->ip_src == arp->ip_src &&
+ compare_ether_addr_64bits(arp->mac_src, entry->mac_src))
+ rlb_delete_table_entry(bond, index);
+ index = next_index;
+ }
+ _unlock_rx_hashtbl_bh(bond);
}
static int rlb_initialize(struct bonding *bond)
@@ -789,7 +914,7 @@ static int rlb_initialize(struct bonding *bond)
bond_info->rx_hashtbl = new_hashtbl;
- bond_info->rx_hashtbl_head = RLB_NULL_INDEX;
+ bond_info->rx_hashtbl_used_head = RLB_NULL_INDEX;
for (i = 0; i < RLB_HASH_TABLE_SIZE; i++) {
rlb_init_table_entry(bond_info->rx_hashtbl + i);
@@ -811,7 +936,7 @@ static void rlb_deinitialize(struct bonding *bond)
kfree(bond_info->rx_hashtbl);
bond_info->rx_hashtbl = NULL;
- bond_info->rx_hashtbl_head = RLB_NULL_INDEX;
+ bond_info->rx_hashtbl_used_head = RLB_NULL_INDEX;
_unlock_rx_hashtbl_bh(bond);
}
@@ -823,25 +948,13 @@ static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
_lock_rx_hashtbl_bh(bond);
- curr_index = bond_info->rx_hashtbl_head;
+ curr_index = bond_info->rx_hashtbl_used_head;
while (curr_index != RLB_NULL_INDEX) {
struct rlb_client_info *curr = &(bond_info->rx_hashtbl[curr_index]);
- u32 next_index = bond_info->rx_hashtbl[curr_index].next;
- u32 prev_index = bond_info->rx_hashtbl[curr_index].prev;
-
- if (curr->tag && (curr->vlan_id == vlan_id)) {
- if (curr_index == bond_info->rx_hashtbl_head) {
- bond_info->rx_hashtbl_head = next_index;
- }
- if (prev_index != RLB_NULL_INDEX) {
- bond_info->rx_hashtbl[prev_index].next = next_index;
- }
- if (next_index != RLB_NULL_INDEX) {
- bond_info->rx_hashtbl[next_index].prev = prev_index;
- }
+ u32 next_index = bond_info->rx_hashtbl[curr_index].used_next;
- rlb_init_table_entry(curr);
- }
+ if (curr->tag && (curr->vlan_id == vlan_id))
+ rlb_delete_table_entry(bond, curr_index);
curr_index = next_index;
}
diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h
index 90f140a..1fbc938 100644
--- a/drivers/net/bonding/bond_alb.h
+++ b/drivers/net/bonding/bond_alb.h
@@ -100,9 +100,18 @@ struct tlb_client_info {
struct rlb_client_info {
__be32 ip_src; /* the server IP address */
__be32 ip_dst; /* the client IP address */
+ u8 mac_src[ETH_ALEN]; /* the server MAC address */
u8 mac_dst[ETH_ALEN]; /* the client MAC address */
- u32 next; /* The next Hash table entry index */
- u32 prev; /* The previous Hash table entry index */
+
+ /* list of used hash table entries, starting at rx_hashtbl_used_head */
+ u32 used_next;
+ u32 used_prev;
+
+ /* ip_src based hashing */
+ u32 src_next; /* next entry with same hash(ip_src) */
+ u32 src_prev; /* prev entry with same hash(ip_src) */
+ u32 src_first; /* first entry with hash(ip_src) == this entry's index */
+
u8 assigned; /* checking whether this entry is assigned */
u8 ntt; /* flag - need to transmit client info */
struct slave *slave; /* the slave assigned to this client */
@@ -131,7 +140,7 @@ struct alb_bond_info {
int rlb_enabled;
struct rlb_client_info *rx_hashtbl; /* Receive hash table */
spinlock_t rx_hashtbl_lock;
- u32 rx_hashtbl_head;
+ u32 rx_hashtbl_used_head;
u8 rx_ntt; /* flag - need to transmit
* to all rx clients
*/
diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c
index 3680aa2..a570843 100644
--- a/drivers/net/bonding/bond_debugfs.c
+++ b/drivers/net/bonding/bond_debugfs.c
@@ -31,8 +31,8 @@ static int bond_debug_rlb_hash_show(struct seq_file *m, void *v)
spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
- hash_index = bond_info->rx_hashtbl_head;
- for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
+ hash_index = bond_info->rx_hashtbl_used_head;
+ for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]);
seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n",
&client_info->ip_src,
--
Jiri Bohac <jbohac@suse.cz>
SUSE Labs, SUSE CZ
^ permalink raw reply related
* Re: [RFT] sky2: fix status length check on older chips
From: Stephen Hemminger @ 2012-04-27 20:55 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: Niccolò Belli, netdev
In-Reply-To: <20120427134127.6d536a96@nehalam.linuxnetplumber.net>
Mirko and I were working on a related issue, here is his fix.
I proposed a similar alternative, but he was unavailable to test it,
and therefore was still pending. Does this fix your problem?
Resend with missing bits.
The cleaner alternative is to not use the boolean flag, but instead
put tag on skb directly (eliminating rx_tag and rx_vlan from
data structure).
=================
From: From: Mirko Lindner <mlindner@marvell.com>
Bug: The VLAN bit of the MAC RX Status Word is unreliable in several older
supported chips. Sometimes the VLAN bit is not set for valid VLAN packets
and also sometimes the VLAN bit is set for non-VLAN packets that came after
a VLAN packet. This results in a receive length error when VLAN hardware
tagging is enabled.
Fix: The driver uses only VLAN information included in VLAN status list elements,
that signals that the VLAN tag field is valid. It must ignore the VLAN bit in the
MAC RX Status Word. An additional variable set when evaluating the VLAN opcodes
is used to indicate that the received packet is a VLAN packet and a packet length
correction (subtraction of VLAN header length) must be done.
Signed-off-by: Mirko Lindner <mlindner@marvell.com>
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
--- a/drivers/net/ethernet/marvell/sky2.c 2012-04-18 23:44:40.637276647 -0700
+++ b/drivers/net/ethernet/marvell/sky2.c 2012-04-27 13:52:06.154756866 -0700
@@ -2580,7 +2580,7 @@ static struct sk_buff *sky2_receive(stru
struct sk_buff *skb = NULL;
u16 count = (status & GMR_FS_LEN) >> 16;
- if (status & GMR_FS_VLAN)
+ if (sky2->rx_vlan)
count -= VLAN_HLEN; /* Account for vlan tag */
netif_printk(sky2, rx_status, KERN_DEBUG, dev,
@@ -2646,11 +2646,13 @@ static inline void sky2_tx_done(struct n
}
}
-static inline void sky2_skb_rx(const struct sky2_port *sky2,
- u32 status, struct sk_buff *skb)
+static inline void sky2_skb_rx(struct sky2_port *sky2,
+ struct sk_buff *skb)
{
- if (status & GMR_FS_VLAN)
+ if (sky2->rx_vlan) {
__vlan_hwaccel_put_tag(skb, be16_to_cpu(sky2->rx_tag));
+ sky2->rx_vlan = 0;
+ }
if (skb->ip_summed == CHECKSUM_NONE)
netif_receive_skb(skb);
@@ -2772,10 +2774,12 @@ static int sky2_status_intr(struct sky2_
break;
case OP_RXVLAN:
+ sky2->rx_vlan = 1;
sky2->rx_tag = length;
break;
case OP_RXCHKSVLAN:
+ sky2->rx_vlan = 1;
sky2->rx_tag = length;
/* fall through */
case OP_RXCHKS:
--- a/drivers/net/ethernet/marvell/sky2.h 2012-02-13 09:23:53.642447236 -0800
+++ b/drivers/net/ethernet/marvell/sky2.h 2012-04-27 13:36:07.487834432 -0700
@@ -2242,6 +2242,7 @@ struct sky2_port {
u16 rx_data_size;
u16 rx_nfrags;
u16 rx_tag;
+ u8 rx_vlan;
struct {
unsigned long last;
^ permalink raw reply
* Re: [RFT] sky2: fix status length check on older chips
From: David Miller @ 2012-04-27 20:48 UTC (permalink / raw)
To: shemminger; +Cc: darkbasic, netdev
In-Reply-To: <20120427134127.6d536a96@nehalam.linuxnetplumber.net>
From: Stephen Hemminger <shemminger@vyatta.com>
Date: Fri, 27 Apr 2012 13:41:27 -0700
> Mirko and I were working on a related issue, here is his fix.
> I proposed a similar alternative, but he was unavailable to test it,
> and therefore was still pending. Does this fix your problem?
Nothing sets ->rx_vlan in that patch.
^ permalink raw reply
* [RFT] sky2: fix status length check on older chips
From: Stephen Hemminger @ 2012-04-27 20:41 UTC (permalink / raw)
To: Niccolò Belli; +Cc: netdev
In-Reply-To: <4F9AFE4E.8010108@linuxsystems.it>
Mirko and I were working on a related issue, here is his fix.
I proposed a similar alternative, but he was unavailable to test it,
and therefore was still pending. Does this fix your problem?
=================
From: From: Mirko Lindner <mlindner@marvell.com>
Bug: The VLAN bit of the MAC RX Status Word is unreliable in several older
supported chips. Sometimes the VLAN bit is not set for valid VLAN packets
and also sometimes the VLAN bit is set for non-VLAN packets that came after
a VLAN packet. This results in a receive length error when VLAN hardware
tagging is enabled.
Fix: The driver uses only VLAN information included in VLAN status list elements,
that signals that the VLAN tag field is valid. It must ignore the VLAN bit in the
MAC RX Status Word. An additional variable set when evaluating the VLAN opcodes
is used to indicate that the received packet is a VLAN packet and a packet length
correction (subtraction of VLAN header length) must be done.
Signed-off-by: Mirko Lindner <mlindner@marvell.com>
--- a/drivers/net/ethernet/marvell/sky2.c 2012-04-18 23:44:40.637276647 -0700
+++ b/drivers/net/ethernet/marvell/sky2.c 2012-04-27 13:36:07.487834432 -0700
@@ -2580,7 +2580,7 @@ static struct sk_buff *sky2_receive(stru
struct sk_buff *skb = NULL;
u16 count = (status & GMR_FS_LEN) >> 16;
- if (status & GMR_FS_VLAN)
+ if (sky2->rx_vlan)
count -= VLAN_HLEN; /* Account for vlan tag */
netif_printk(sky2, rx_status, KERN_DEBUG, dev,
@@ -2646,11 +2646,13 @@ static inline void sky2_tx_done(struct n
}
}
-static inline void sky2_skb_rx(const struct sky2_port *sky2,
- u32 status, struct sk_buff *skb)
+static inline void sky2_skb_rx(struct sky2_port *sky2,
+ struct sk_buff *skb)
{
- if (status & GMR_FS_VLAN)
+ if (sky2->rx_vlan) {
__vlan_hwaccel_put_tag(skb, be16_to_cpu(sky2->rx_tag));
+ sky2->rx_vlan = 0;
+ }
if (skb->ip_summed == CHECKSUM_NONE)
netif_receive_skb(skb);
--- a/drivers/net/ethernet/marvell/sky2.h 2012-02-13 09:23:53.642447236 -0800
+++ b/drivers/net/ethernet/marvell/sky2.h 2012-04-27 13:36:07.487834432 -0700
@@ -2242,6 +2242,7 @@ struct sky2_port {
u16 rx_data_size;
u16 rx_nfrags;
u16 rx_tag;
+ u8 rx_vlan;
struct {
unsigned long last;
^ permalink raw reply
* sky2 still badly broken
From: Niccolò Belli @ 2012-04-27 20:15 UTC (permalink / raw)
To: netdev
dmesg is full of
[ 1464.914044] sky2 0000:06:00.0: eth0: rx error, status 0x5220002
length 1314
[ 1465.005628] sky2 0000:06:00.0: eth0: rx error, status 0x7ffc0001
length 532
[ 1465.204459] sky2 0000:06:00.0: eth0: rx error, status 0x7ffc0001
length 532
[ 1465.825909] sky2 0000:06:00.0: eth0: rx error, status 0x7ffc0001
length 532
[ 1468.715858] net_ratelimit: 3 callbacks suppressed
[ 1468.715865] sky2 0000:06:00.0: eth0: rx error, status 0x7ffc0001
length 532
dhcp does not work (after a few minutes it does not renew the ip)
while under heavy load the card resets and I have to unload and reload
the module
also transfer rate is VERY low.
lowering the mtu does help a bit, but it doesn't make miracles...
kernel 3.4.0-rc4
06:00.0 Ethernet controller: Marvell Technology Group Ltd. 88E8055 PCI-E
Gigabit Ethernet Controller (rev 13)
http://forums.gentoo.org/viewtopic-t-487018-start-0-postdays-0-postorder-asc-highlight-.html
Thanks,
Niccolò
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox