From f022ae62dd84425192b27100dcf907019f654d02 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 3 Jan 2014 10:09:11 -0800 Subject: [PATCH 1/5] tg3: Refactor __tg3_set_mac_addr() so that individual MAC address filter entries can be set. Signed-off-by: Michael Chan Signed-off-by: Nithin Nayak Sujir Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 35 ++++++++++++++++++----------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index a8def93f6b6b..80d55bf699ba 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -3948,32 +3948,41 @@ static int tg3_load_tso_firmware(struct tg3 *tp) return 0; } +/* tp->lock is held. */ +static void __tg3_set_one_mac_addr(struct tg3 *tp, u8 *mac_addr, int index) +{ + u32 addr_high, addr_low; + + addr_high = ((mac_addr[0] << 8) | mac_addr[1]); + addr_low = ((mac_addr[2] << 24) | (mac_addr[3] << 16) | + (mac_addr[4] << 8) | mac_addr[5]); + + if (index < 4) { + tw32(MAC_ADDR_0_HIGH + (index * 8), addr_high); + tw32(MAC_ADDR_0_LOW + (index * 8), addr_low); + } else { + index -= 4; + tw32(MAC_EXTADDR_0_HIGH + (index * 8), addr_high); + tw32(MAC_EXTADDR_0_LOW + (index * 8), addr_low); + } +} /* tp->lock is held. */ static void __tg3_set_mac_addr(struct tg3 *tp, bool skip_mac_1) { - u32 addr_high, addr_low; + u32 addr_high; int i; - addr_high = ((tp->dev->dev_addr[0] << 8) | - tp->dev->dev_addr[1]); - addr_low = ((tp->dev->dev_addr[2] << 24) | - (tp->dev->dev_addr[3] << 16) | - (tp->dev->dev_addr[4] << 8) | - (tp->dev->dev_addr[5] << 0)); for (i = 0; i < 4; i++) { if (i == 1 && skip_mac_1) continue; - tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high); - tw32(MAC_ADDR_0_LOW + (i * 8), addr_low); + __tg3_set_one_mac_addr(tp, tp->dev->dev_addr, i); } if (tg3_asic_rev(tp) == ASIC_REV_5703 || tg3_asic_rev(tp) == ASIC_REV_5704) { - for (i = 0; i < 12; i++) { - tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high); - tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low); - } + for (i = 4; i < 16; i++) + __tg3_set_one_mac_addr(tp, tp->dev->dev_addr, i); } addr_high = (tp->dev->dev_addr[0] + From e565eec31d9d5b1024311564f6536162df951de4 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 3 Jan 2014 10:09:12 -0800 Subject: [PATCH 2/5] tg3: Add unicast filtering support. Up to 3 additional unicast addresses can be added to the perfect match filter table. Signed-off-by: Michael Chan Signed-off-by: Nithin Nayak Sujir Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 80d55bf699ba..c3b12de0b918 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -208,6 +209,9 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits) #define TG3_RAW_IP_ALIGN 2 +#define TG3_MAX_UCAST_ADDR(tp) (tg3_flag((tp), ENABLE_ASF) ? 2 : 3) +#define TG3_UCAST_ADDR_IDX(tp) (tg3_flag((tp), ENABLE_ASF) ? 2 : 1) + #define TG3_FW_UPDATE_TIMEOUT_SEC 5 #define TG3_FW_UPDATE_FREQ_SEC (TG3_FW_UPDATE_TIMEOUT_SEC / 2) @@ -9198,6 +9202,7 @@ static int tg3_chip_reset(struct tg3 *tp) static void tg3_get_nstats(struct tg3 *, struct rtnl_link_stats64 *); static void tg3_get_estats(struct tg3 *, struct tg3_ethtool_stats *); +static void __tg3_set_rx_mode(struct net_device *); /* tp->lock is held. */ static int tg3_halt(struct tg3 *tp, int kind, bool silent) @@ -9258,6 +9263,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p) } spin_lock_bh(&tp->lock); __tg3_set_mac_addr(tp, skip_mac_1); + __tg3_set_rx_mode(dev); spin_unlock_bh(&tp->lock); return err; @@ -9646,6 +9652,20 @@ static void __tg3_set_rx_mode(struct net_device *dev) tw32(MAC_HASH_REG_3, mc_filter[3]); } + if (netdev_uc_count(dev) > TG3_MAX_UCAST_ADDR(tp)) { + rx_mode |= RX_MODE_PROMISC; + } else if (!(dev->flags & IFF_PROMISC)) { + /* Add all entries into to the mac addr filter list */ + int i = 0; + struct netdev_hw_addr *ha; + + netdev_for_each_uc_addr(ha, dev) { + __tg3_set_one_mac_addr(tp, ha->addr, + i + TG3_UCAST_ADDR_IDX(tp)); + i++; + } + } + if (rx_mode != tp->rx_mode) { tp->rx_mode = rx_mode; tw32_f(MAC_RX_MODE, rx_mode); @@ -17620,6 +17640,7 @@ static int tg3_init_one(struct pci_dev *pdev, features |= NETIF_F_LOOPBACK; dev->hw_features |= features; + dev->priv_flags |= IFF_UNICAST_FLT; if (tg3_chip_rev_id(tp) == CHIPREV_ID_5705_A1 && !tg3_flag(tp, TSO_CAPABLE) && From f82995b65c44f353358179f4e2745cf967e00b31 Mon Sep 17 00:00:00 2001 From: Nithin Sujir Date: Fri, 3 Jan 2014 10:09:13 -0800 Subject: [PATCH 3/5] tg3: Set the MAC clock to the fastest speed during boot code load On the 5717, 5718 and 5719 devices, the bootcode runs slower when any port doesn't have a link due to clock speed slowing down as part of the link-aware feature. This leads to the driver timing out waiting for the bootcode signature. This patch overrides the clock policy to the highest frequency just before reset and restores it after the bootcode is up. Signed-off-by: Nithin Nayak Sujir Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 55 ++++++++++++++++++++++++++--- drivers/net/ethernet/broadcom/tg3.h | 3 ++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index c3b12de0b918..7bc8449af262 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -8941,6 +8941,49 @@ static void tg3_restore_pci_state(struct tg3 *tp) } } +static void tg3_override_clk(struct tg3 *tp) +{ + u32 val; + + switch (tg3_asic_rev(tp)) { + case ASIC_REV_5717: + val = tr32(TG3_CPMU_CLCK_ORIDE_ENABLE); + tw32(TG3_CPMU_CLCK_ORIDE_ENABLE, val | + TG3_CPMU_MAC_ORIDE_ENABLE); + break; + + case ASIC_REV_5719: + case ASIC_REV_5720: + tw32(TG3_CPMU_CLCK_ORIDE, CPMU_CLCK_ORIDE_MAC_ORIDE_EN); + break; + + default: + return; + } +} + +static void tg3_restore_clk(struct tg3 *tp) +{ + u32 val; + + switch (tg3_asic_rev(tp)) { + case ASIC_REV_5717: + val = tr32(TG3_CPMU_CLCK_ORIDE_ENABLE); + tw32(TG3_CPMU_CLCK_ORIDE_ENABLE, + val & ~TG3_CPMU_MAC_ORIDE_ENABLE); + break; + + case ASIC_REV_5719: + case ASIC_REV_5720: + val = tr32(TG3_CPMU_CLCK_ORIDE); + tw32(TG3_CPMU_CLCK_ORIDE, val & ~CPMU_CLCK_ORIDE_MAC_ORIDE_EN); + break; + + default: + return; + } +} + /* tp->lock is held. */ static int tg3_chip_reset(struct tg3 *tp) { @@ -9029,6 +9072,13 @@ static int tg3_chip_reset(struct tg3 *tp) tr32(GRC_VCPU_EXT_CTRL) & ~GRC_VCPU_EXT_CTRL_HALT_CPU); } + /* Set the clock to the highest frequency to avoid timeouts. With link + * aware mode, the clock speed could be slow and bootcode does not + * complete within the expected time. Override the clock to allow the + * bootcode to finish sooner and then restore it. + */ + tg3_override_clk(tp); + /* Manage gphy power for all CPMU absent PCIe devices. */ if (tg3_flag(tp, 5705_PLUS) && !tg3_flag(tp, CPMU_PRESENT)) val |= GRC_MISC_CFG_KEEP_GPHY_POWER; @@ -9167,10 +9217,7 @@ static int tg3_chip_reset(struct tg3 *tp) tw32(0x7c00, val | (1 << 25)); } - if (tg3_asic_rev(tp) == ASIC_REV_5720) { - val = tr32(TG3_CPMU_CLCK_ORIDE); - tw32(TG3_CPMU_CLCK_ORIDE, val & ~CPMU_CLCK_ORIDE_MAC_ORIDE_EN); - } + tg3_restore_clk(tp); /* Reprobe ASF enable state. */ tg3_flag_clear(tp, ENABLE_ASF); diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index e4da9d7834ce..9e31eccc250b 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -1146,6 +1146,9 @@ #define TG3_CPMU_CLCK_ORIDE 0x00003624 #define CPMU_CLCK_ORIDE_MAC_ORIDE_EN 0x80000000 +#define TG3_CPMU_CLCK_ORIDE_ENABLE 0x00003628 +#define TG3_CPMU_MAC_ORIDE_ENABLE (1 << 13) + #define TG3_CPMU_STATUS 0x0000362c #define TG3_CPMU_STATUS_FMSK_5717 0x20000000 #define TG3_CPMU_STATUS_FMSK_5719 0xc0000000 From 1743b83c86b5dc525463a1bc9c701b4d9e428c5b Mon Sep 17 00:00:00 2001 From: Nithin Sujir Date: Fri, 3 Jan 2014 10:09:14 -0800 Subject: [PATCH 4/5] tg3: Poll cpmu link state on APE + ASF enabled devices On ASF enabled devices where the mgmt firmware runs on the application processing engine, there is a race between the tg3 driver processing a link change event and the ASF firmware clearing the link changed bit in the EMAC status register. This leads to link notifications to the driver sometimes getting lost. Poll the CPMU link state as a backup for the normal interrupt path update if ASF is enabled. Signed-off-by: Nithin Nayak Sujir Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 10 ++++++++++ drivers/net/ethernet/broadcom/tg3.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 7bc8449af262..8f43c6755911 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -10960,6 +10960,13 @@ static void tg3_timer(unsigned long __opaque) } else if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) && tg3_flag(tp, 5780_CLASS)) { tg3_serdes_parallel_detect(tp); + } else if (tg3_flag(tp, POLL_CPMU_LINK)) { + u32 cpmu = tr32(TG3_CPMU_STATUS); + bool link_up = !((cpmu & TG3_CPMU_STATUS_LINK_MASK) == + TG3_CPMU_STATUS_LINK_MASK); + + if (link_up != tp->link_up) + tg3_setup_phy(tp, false); } tp->timer_counter = tp->timer_multiplier; @@ -16766,6 +16773,9 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) else tg3_flag_clear(tp, POLL_SERDES); + if (tg3_flag(tp, ENABLE_APE) && tg3_flag(tp, ENABLE_ASF)) + tg3_flag_set(tp, POLL_CPMU_LINK); + tp->rx_offset = NET_SKB_PAD + NET_IP_ALIGN; tp->rx_copy_thresh = TG3_RX_COPY_THRESHOLD; if (tg3_asic_rev(tp) == ASIC_REV_5701 && diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index 9e31eccc250b..ef472385bce4 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -1153,6 +1153,7 @@ #define TG3_CPMU_STATUS_FMSK_5717 0x20000000 #define TG3_CPMU_STATUS_FMSK_5719 0xc0000000 #define TG3_CPMU_STATUS_FSHFT_5719 30 +#define TG3_CPMU_STATUS_LINK_MASK 0x180000 #define TG3_CPMU_CLCK_STAT 0x00003630 #define CPMU_CLCK_STAT_MAC_CLCK_MASK 0x001f0000 @@ -3020,6 +3021,7 @@ enum TG3_FLAGS { TG3_FLAG_ENABLE_ASF, TG3_FLAG_ASPM_WORKAROUND, TG3_FLAG_POLL_SERDES, + TG3_FLAG_POLL_CPMU_LINK, TG3_FLAG_MBOX_WRITE_REORDER, TG3_FLAG_PCIX_TARGET_HWBUG, TG3_FLAG_WOL_SPEED_100MB, From 20170e774729008e9d37d4ccba28b9e5a567e196 Mon Sep 17 00:00:00 2001 From: Nithin Sujir Date: Fri, 3 Jan 2014 10:09:15 -0800 Subject: [PATCH 5/5] tg3: Update version to 3.136 Signed-off-by: Michael Chan Signed-off-by: Nithin Nayak Sujir Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 8f43c6755911..d88ef551dfcd 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -95,10 +95,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits) #define DRV_MODULE_NAME "tg3" #define TG3_MAJ_NUM 3 -#define TG3_MIN_NUM 135 +#define TG3_MIN_NUM 136 #define DRV_MODULE_VERSION \ __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM) -#define DRV_MODULE_RELDATE "Nov 14, 2013" +#define DRV_MODULE_RELDATE "Jan 03, 2014" #define RESET_KIND_SHUTDOWN 0 #define RESET_KIND_INIT 1