Documentation/networking/dom.txt | 16 ++-- drivers/net/igb/e1000_mac.c | 2 +- drivers/net/igb/igb_ethtool.c | 191 ++++++++++++++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_common.c | 2 + drivers/net/ixgbe/ixgbe_ethtool.c | 205 ++++++++++++++++++++++++++++++++++++- drivers/net/ixgbe/ixgbe_main.c | 32 ++++++- drivers/net/ixgbe/ixgbe_phy.c | 12 ++- include/linux/ethtool.h | 49 +++++++++ include/net/dom.h | 38 ++++---- net/core/ethtool.c | 18 ++++ net/core/pktgen.c | 58 ++++++++++- 11 files changed, 586 insertions(+), 37 deletions(-) diff --git a/Documentation/networking/dom.txt b/Documentation/networking/dom.txt index ff255b4..4bf24de 100644 --- a/Documentation/networking/dom.txt +++ b/Documentation/networking/dom.txt @@ -2,11 +2,11 @@ Diagnostic Monitoring Interface Monitoring also called DOM is a specification for optical transceivers to allow link and other diagnostics related to the transceiver's to standardized and communicated. For communication the I2C bus is used. The SFF specifications is available at ftp://ftp.seagate.com/ -Specification is generic and should work for many types of optical modules +Specification is generic and should work for many types of optical modules as GBIC, SFP, SFp+, XFP etc -In short DOM spec adds a memory page where the diagnostics's is kept (address -0xA2 bytes 66 to 105) but there are lot's of option's and variants. For example +In short DOM spec adds a memory page where the diagnostics's is kept (address +0xA2 bytes 66 to 105) but there are lot's of option's and variants. For example alarm and warnings are optional. See example below. Not all SFP's (SFP is for GIGE) have DOM support normally long range supports @@ -21,7 +21,7 @@ include/linux/ethtool.h # adds ETHTOOL_GPHYDIAG And drivers hooks exists currently in igb and ixgbe driver -Usage example: ethtool -D eth5 +Usage example: ethtool -D eth5 Ext-Calbr: Avr RX-Power: Alarm & Warn: RX_LOS: Wavelength: 1310 nm Alarms, warnings in beginning of line, Ie. AH = Alarm High, WL == Warn Low etc @@ -32,10 +32,10 @@ ALWL TX-pwr: -5.9 dBm ( 0.26 mW) Thresh: Lo: -4.0/-2.0 Hi: 7.0/8.2 dBm AHWH RX-pwr: -5.0 dBm ( 0.31 mW) Thresh: Lo: -35.2/-28.0 Hi: -8.2/-6.0 dBm -First line shows the options supported by the module. As we see this module -supports Alarms and warnings as a consequence thresholds are printed. As example -RX-pwr: -35.2 < no_alarm < -6.0 dBm and -28.0 < no_warning < -8.2 dBm. (dBm yields -1 mW == 0 dBm) +First line shows the options supported by the module. As we see this module +supports Alarms and warnings as a consequence thresholds are printed. As example +RX-pwr: -35.2 < no_alarm < -6.0 dBm and -28.0 < no_warning < -8.2 dBm. (dBm yields +1 mW == 0 dBm) In the example above we see both warnings for both TX-pwr (low) and RX-Pwr high. The Rx side would need some attenuation. diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 2ad358a..cc4c675 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -678,7 +678,7 @@ static s32 igb_set_default_fc(struct e1000_hw *hw) NVM_WORD0F_ASM_DIR) hw->fc.requested_mode = e1000_fc_tx_pause; else - hw->fc.requested_mode = e1000_fc_full; + hw->fc.requested_mode = e1000_fc_none; //e1000_fc_full; out: return ret_val; diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index ac9d527..63a297d 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include "igb.h" @@ -2063,6 +2064,195 @@ static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) } } +static s32 read_phy_diag(struct e1000_hw *hw, u8 page, u8 offset, u16 *data) +{ + u32 i, i2ccmd = 0; + + if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) { + hw_dbg("DOM Register Address %u is out of range\n", offset); + return -E1000_ERR_PARAM; + } + + /* + * Set up Op-code, Phy Address, and register address in the I2CCMD + * register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + + i2ccmd = (E1000_I2CCMD_OPCODE_READ) | + (page << E1000_I2CCMD_PHY_ADDR_SHIFT) | + (offset << E1000_I2CCMD_REG_ADDR_SHIFT); + + wr32(E1000_I2CCMD, i2ccmd); + + /* Poll the ready bit to see if the I2C read completed */ + for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) { + udelay(50); + i2ccmd = rd32(E1000_I2CCMD); + //printk("DATA i2ccmd=0x%x\n", i2ccmd); + if (i2ccmd & E1000_I2CCMD_READY) + break; + } + if (!(i2ccmd & E1000_I2CCMD_READY)) { + hw_dbg("I2CCMD Read did not complete\n"); + return -E1000_ERR_PHY; + } + if (i2ccmd & E1000_I2CCMD_ERROR) { + hw_dbg("I2CCMD Error bit set\n"); + return -E1000_ERR_PHY; + } + + /* Need to byte-swap the 16-bit value. */ + *data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00); + return 0; +} + +static s32 read_phy_diag_u32(struct e1000_hw *hw, u8 page, u8 offset, u32 *data) +{ + u16 p1; + u16 p2; + s32 res; + + res = read_phy_diag(hw, page, offset, &p1); + if (res) + goto out; + + res = read_phy_diag(hw, page, offset + 2, &p2); + if (res) + goto out; + + *data = ((u32)p1) << 16 | p2; + +out: + return res; +} + +struct reg_offset { + int reg; + size_t offset; +}; + +#define REG_OFFSET(a, b) \ + { .reg = a, .offset = offsetof(struct ethtool_phy_diag, b) } + +int igb_get_phy_diag(struct net_device *netdev, struct ethtool_phy_diag *pd) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + int res; + u8 type, eo; + int i; + + static const struct reg_offset basic[] = { + REG_OFFSET(DOM_A2_TEMP, temp), + REG_OFFSET(DOM_A2_TEMP_SLOPE, temp_slope), + REG_OFFSET(DOM_A2_TEMP_OFFSET, temp_offset), + REG_OFFSET(DOM_A2_VCC, vcc), + REG_OFFSET(DOM_A2_VCC_SLOPE, vcc_slope), + REG_OFFSET(DOM_A2_VCC_OFFSET, vcc_offset), + REG_OFFSET(DOM_A2_TX_BIAS, tx_bias), + REG_OFFSET(DOM_A2_TX_I_SLOPE, tx_bias_slope), + REG_OFFSET(DOM_A2_TX_I_OFFSET, tx_bias_offset), + REG_OFFSET(DOM_A2_TX_PWR, tx_pwr), + REG_OFFSET(DOM_A2_TX_PWR_SLOPE, tx_pwr_slope), + REG_OFFSET(DOM_A2_TX_PWR_OFFSET, tx_pwr_offset), + REG_OFFSET(DOM_A2_RX_PWR, rx_pwr), + }; + + static const struct reg_offset power[] = { + REG_OFFSET(DOM_A2_RX_PWR_0, rx_pwr_cal[0]), + REG_OFFSET(DOM_A2_RX_PWR_1, rx_pwr_cal[1]), + REG_OFFSET(DOM_A2_RX_PWR_2, rx_pwr_cal[2]), + REG_OFFSET(DOM_A2_RX_PWR_3, rx_pwr_cal[3]), + REG_OFFSET(DOM_A2_RX_PWR_4, rx_pwr_cal[4]), + }; + + static const struct reg_offset aw[] = { + REG_OFFSET(DOM_A2_TEMP_AHT, temp_aht), + REG_OFFSET(DOM_A2_TEMP_ALT, temp_alt), + REG_OFFSET(DOM_A2_TEMP_WHT, temp_wht), + REG_OFFSET(DOM_A2_TEMP_WLT, temp_wlt), + REG_OFFSET(DOM_A2_VCC_AHT, vcc_aht), + REG_OFFSET(DOM_A2_VCC_ALT, vcc_alt), + REG_OFFSET(DOM_A2_VCC_WHT, vcc_wht), + REG_OFFSET(DOM_A2_VCC_WLT, vcc_wlt), + REG_OFFSET(DOM_A2_TX_BIAS_AHT, tx_bias_aht), + REG_OFFSET(DOM_A2_TX_BIAS_ALT, tx_bias_alt), + REG_OFFSET(DOM_A2_TX_BIAS_WHT, tx_bias_wht), + REG_OFFSET(DOM_A2_TX_BIAS_WLT, tx_bias_wlt), + REG_OFFSET(DOM_A2_TX_PWR_AHT, tx_pwr_aht), + REG_OFFSET(DOM_A2_TX_PWR_ALT, tx_pwr_alt), + REG_OFFSET(DOM_A2_TX_PWR_WHT, tx_pwr_wht), + REG_OFFSET(DOM_A2_TX_PWR_WLT, tx_pwr_wlt), + REG_OFFSET(DOM_A2_RX_PWR_AHT, rx_pwr_aht), + REG_OFFSET(DOM_A2_RX_PWR_ALT, rx_pwr_alt), + REG_OFFSET(DOM_A2_RX_PWR_WHT, rx_pwr_wht), + REG_OFFSET(DOM_A2_RX_PWR_WLT, rx_pwr_wlt), + }; + + res = read_phy_diag(hw, 0x0, DOM_A0_DOM_TYPE, &pd->type); + if (res) + goto out; + + type = pd->type >> 8; + + if ((~type & DOM_TYPE_DOM) || (type & DOM_TYPE_LEGAGY_DOM)) + goto out; + + if (type & DOM_TYPE_ADDR_CHNGE) { + hw_dbg("DOM module not supported (Address change)\n"); + goto out; + } + + eo = pd->type & 0xFF; + + res = read_phy_diag(hw, 0x0, DOM_A0_WAVELENGTH, &pd->wavelength); + if (res) + goto out; + + /* If supported. Read alarms and Warnings first*/ + if (eo & DOM_EO_AW) { + res = read_phy_diag(hw, 0x1, DOM_A2_ALARM, &pd->alarm); + if (res) + goto out; + res = read_phy_diag(hw, 0x1, DOM_A2_WARNING, &pd->warning); + if (res) + goto out; + } + + /* Basic diag */ + + for (i = 0; i < ARRAY_SIZE(basic); i++) { + res = read_phy_diag(hw, 0x1, basic[i].reg, + (u16 *)((char *)pd + basic[i].offset)); + if (res) + goto out; + } + + /* Power */ + + for (i = 0; i < ARRAY_SIZE(power); i++) { + res = read_phy_diag_u32(hw, 0x1, power[i].reg, + (u32 *)((char *)pd + power[i].offset)); + if (res) + goto out; + } + + /* Thresholds for Alarms and Warnings */ + + if (eo & DOM_EO_AW) { + for (i = 0; i < ARRAY_SIZE(aw); i++) { + res = read_phy_diag(hw, 0x1, aw[i].reg, + (u16 *)((char *)pd + aw[i].offset)); + if (res) + goto out; + } + } + +out: + return res; +} + static const struct ethtool_ops igb_ethtool_ops = { .get_settings = igb_get_settings, .set_settings = igb_set_settings, @@ -2097,6 +2287,7 @@ static const struct ethtool_ops igb_ethtool_ops = { .get_ethtool_stats = igb_get_ethtool_stats, .get_coalesce = igb_get_coalesce, .set_coalesce = igb_set_coalesce, + .get_phy_diag = igb_get_phy_diag, }; void igb_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 40ff120..25c6676 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -1927,6 +1927,8 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) if (hw->fc.requested_mode == ixgbe_fc_default) hw->fc.requested_mode = ixgbe_fc_full; + hw->fc.requested_mode = ixgbe_fc_none; + /* * Set up the 1G flow control advertisement registers so the HW will be * able to do fc autoneg once the cable is plugged in. If we end up diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 74f04e1..40056de 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -34,9 +34,11 @@ #include #include #include +#include #include "ixgbe.h" - +#include "ixgbe_phy.h" +#include "ixgbe_common.h" #define IXGBE_ALL_RAR_ENTRIES 16 @@ -2105,6 +2107,206 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data) } +static s32 read_phy_diag_dump(struct ixgbe_hw *hw, u8 page) +{ + s32 status; + u8 hi; + u8 i; + + for(i=0; i < 93; i++) { + hi = 0; + status = ixgbe_read_i2c_byte_generic(hw, i, page, &hi); + + if (status) + break; + + printk("page=%d offset=%d data=%2X\n", page, i, hi); + + } + return status; +} + +static s32 read_phy_diag(struct ixgbe_hw *hw, u8 page, u8 offset, u16 *data) +{ + s32 status; + u8 hi, lo; + hi = 0; lo = 0; + + status = ixgbe_read_i2c_byte_generic(hw, offset, page, &hi); + if (status) + goto out; + + status = ixgbe_read_i2c_byte_generic(hw, offset+1, page, &lo); + if (status) + goto out; + + *data = (((u16)hi) << 8) | lo; +out: + printk("read_phy_diag: status=%d page=%d offset=%d data=%4X\n", + status, page, offset, *data); + + return status; +} + +static s32 read_phy_diag_u32(struct ixgbe_hw *hw, u8 page, u8 offset, u32 *data) +{ + u16 p1; + u16 p2; + s32 res; + + res = read_phy_diag(hw, page, offset, &p1); + if (res) + goto out; + + res = read_phy_diag(hw, page, offset+1, &p2); + if (res) + goto out; + + *data = ((u32)p1) << 16 | p2; + +out: + printk("u32_read_phy_diag: res=%d page=%d offset=%d date=%4X\n", + res, page, offset, *data); + return res; +} + +struct reg_offset { + int reg; + size_t offset; +}; + +#define REG_OFFSET(a, b) \ + { .reg = a, .offset = offsetof(struct ethtool_phy_diag, b) } + +int ixgb_get_phy_diag(struct net_device *netdev, struct ethtool_phy_diag *pd) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + int res; + u8 type, eo; + int i; + + static const struct reg_offset basic[] = { + REG_OFFSET(DOM_A2_TEMP, temp), + REG_OFFSET(DOM_A2_TEMP_SLOPE, temp_slope), + REG_OFFSET(DOM_A2_TEMP_OFFSET, temp_offset), + REG_OFFSET(DOM_A2_VCC, vcc), + REG_OFFSET(DOM_A2_VCC_SLOPE, vcc_slope), + REG_OFFSET(DOM_A2_VCC_OFFSET, vcc_offset), + REG_OFFSET(DOM_A2_TX_BIAS, tx_bias), + REG_OFFSET(DOM_A2_TX_I_SLOPE, tx_bias_slope), + REG_OFFSET(DOM_A2_TX_I_OFFSET, tx_bias_offset), + REG_OFFSET(DOM_A2_TX_PWR, tx_pwr), + REG_OFFSET(DOM_A2_TX_PWR_SLOPE, tx_pwr_slope), + REG_OFFSET(DOM_A2_TX_PWR_OFFSET, tx_pwr_offset), + REG_OFFSET(DOM_A2_RX_PWR, rx_pwr), + }; + + static const struct reg_offset power[] = { + REG_OFFSET(DOM_A2_RX_PWR_0, rx_pwr_cal[0]), + REG_OFFSET(DOM_A2_RX_PWR_1, rx_pwr_cal[1]), + REG_OFFSET(DOM_A2_RX_PWR_2, rx_pwr_cal[2]), + REG_OFFSET(DOM_A2_RX_PWR_3, rx_pwr_cal[3]), + REG_OFFSET(DOM_A2_RX_PWR_4, rx_pwr_cal[4]), + }; + + static const struct reg_offset aw[] = { + REG_OFFSET(DOM_A2_TEMP_AHT, temp_aht), + REG_OFFSET(DOM_A2_TEMP_ALT, temp_alt), + REG_OFFSET(DOM_A2_TEMP_WHT, temp_wht), + REG_OFFSET(DOM_A2_TEMP_WLT, temp_wlt), + REG_OFFSET(DOM_A2_VCC_AHT, vcc_aht), + REG_OFFSET(DOM_A2_VCC_ALT, vcc_alt), + REG_OFFSET(DOM_A2_VCC_WHT, vcc_wht), + REG_OFFSET(DOM_A2_VCC_WLT, vcc_wlt), + REG_OFFSET(DOM_A2_TX_BIAS_AHT, tx_bias_aht), + REG_OFFSET(DOM_A2_TX_BIAS_ALT, tx_bias_alt), + REG_OFFSET(DOM_A2_TX_BIAS_WHT, tx_bias_wht), + REG_OFFSET(DOM_A2_TX_BIAS_WLT, tx_bias_wlt), + REG_OFFSET(DOM_A2_TX_PWR_AHT, tx_pwr_aht), + REG_OFFSET(DOM_A2_TX_PWR_ALT, tx_pwr_alt), + REG_OFFSET(DOM_A2_TX_PWR_WHT, tx_pwr_wht), + REG_OFFSET(DOM_A2_TX_PWR_WLT, tx_pwr_wlt), + REG_OFFSET(DOM_A2_RX_PWR_AHT, rx_pwr_aht), + REG_OFFSET(DOM_A2_RX_PWR_ALT, rx_pwr_alt), + REG_OFFSET(DOM_A2_RX_PWR_WHT, rx_pwr_wht), + REG_OFFSET(DOM_A2_RX_PWR_WLT, rx_pwr_wlt), + }; + + + // read_phy_diag_dump(hw, 0xA0); + //return res; + + + res = read_phy_diag(hw, 0xA0, DOM_A0_DOM_TYPE, &pd->type); + if (res) + goto out; + + + type = pd->type >> 8; + + printk("ixgbe_get_phy_diag: type=0x%X\n", pd->type); + + if ((~type & DOM_TYPE_DOM) || (type & DOM_TYPE_LEGAGY_DOM)) + goto out; + + if (type & DOM_TYPE_ADDR_CHNGE) { + hw_dbg(hw, "DOM module not supported (Address change)\n"); + goto out; + } + + eo = pd->type & 0xFF; + + res = read_phy_diag(hw, 0xA0, DOM_A0_WAVELENGTH, &pd->wavelength); + if (res) + goto out; + + + /* If supported. Read alarms and Warnings first*/ + if (eo & DOM_EO_AW) { + res = read_phy_diag(hw, 0xA2, DOM_A2_ALARM, &pd->alarm); + if (res) + goto out; + + res = read_phy_diag(hw, 0xA2, DOM_A2_WARNING, &pd->warning); + if (res) + goto out; + } + + /* Basic diag */ + + for (i = 0; i < ARRAY_SIZE(basic); i++) { + res = read_phy_diag(hw, 0xA2, basic[i].reg, + (u16 *)((char *)pd + basic[i].offset)); + if (res) + goto out; + } + + + /* Power */ + + for (i = 0; i < ARRAY_SIZE(power); i++) { + res = read_phy_diag_u32(hw, 0xA2, power[i].reg, + (u32 *)((char *)pd + power[i].offset)); + if (res) + goto out; + } + + /* Thresholds for Alarms and Warnings */ + + if (eo & DOM_EO_AW) { + for (i = 0; i < ARRAY_SIZE(aw); i++) { + res = read_phy_diag(hw, 0xA2, aw[i].reg, + (u16 *)((char *)pd + aw[i].offset)); + if (res) + goto out; + } + } + +out: + return res; +} + static const struct ethtool_ops ixgbe_ethtool_ops = { .get_settings = ixgbe_get_settings, .set_settings = ixgbe_set_settings, @@ -2140,6 +2342,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = { .set_coalesce = ixgbe_set_coalesce, .get_flags = ethtool_op_get_flags, .set_flags = ixgbe_set_flags, + .get_phy_diag = ixgb_get_phy_diag, }; void ixgbe_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index ebcec30..e12c857 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -2224,9 +2224,9 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { /* Fill out redirection table */ - for (i = 0, j = 0; i < 128; i++, j++) { + for (i = 0, j = 0; i < 128; i++, j++) { // J = 1 if (j == adapter->ring_feature[RING_F_RSS].indices) - j = 0; + j = 0; //j = 1 /* reta = 4-byte sliding window of * 0x00..(indices-1)(indices-1)00..etc. */ reta = (reta << 8) | (j * 0x11); @@ -5156,6 +5156,32 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, writel(i, adapter->hw.hw_addr + tx_ring->tail); } +static void ixgbe_atr_set_fdir_policy(struct sk_buff *skb, int *queue) +{ + /* Right now, we support IPv4 only */ + struct tcphdr *th; + struct iphdr *iph = ip_hdr(skb); + + /* check our local fdir policy's yet only TCP */ + if(iph->protocol == IPPROTO_TCP) { + th = tcp_hdr(skb); + //printk("3 queue=%d proto=%d p-source=%d p-dest=%d\n", *queue, iph->protocol, ntohs(th->source), ntohs(th->dest) ); + + if( th->dest == htons(22) || + th->dest == htons(179) || + th->source == htons(22) || + th->source == htons(179) ) { + *queue = 0; + return; + } + } + if( *queue == 0) { + /* Remap others */ + *queue = 1; // For now + return; + } +} + static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb, int queue, u32 tx_flags) { @@ -5197,6 +5223,8 @@ static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb, ixgbe_atr_set_src_ipv4_82599(&atr_input, dst_ipv4_addr); ixgbe_atr_set_dst_ipv4_82599(&atr_input, src_ipv4_addr); + ///ixgbe_atr_set_fdir_policy(skb, &queue); + /* This assumes the Rx queue and Tx queue are bound to the same CPU */ ixgbe_fdir_add_signature_filter_82599(&adapter->hw, &atr_input, queue); } diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 9ecad17..d20ad15 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -676,14 +676,19 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) goto out; } + hw->phy.type = ixgbe_phy_sfp_intel; + /* This is guaranteed to be 82599, no need to check for NULL */ hw->mac.ops.get_device_caps(hw, &enforce_sfp); - if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) { + // if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) { + if (0) { + printk("APA1: %d\n", hw->phy.type); /* Make sure we're a supported PHY type */ if (hw->phy.type == ixgbe_phy_sfp_intel) { status = 0; } else { hw_dbg(hw, "SFP+ module not supported\n"); + printk("APA2: %d\n", hw->phy.type); hw->phy.type = ixgbe_phy_sfp_unsupported; status = IXGBE_ERR_SFP_NOT_SUPPORTED; } @@ -861,6 +866,11 @@ fail: } while (retry < max_retry); + printk("s32 ixgbe_read_i2c_byte_generic "); + printk("hw=%p offset=%d, addr=%d, data=%4X\n", + hw, byte_offset, dev_addr, *data); + + return status; } diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index edd03b7..4e45a94 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -272,6 +272,53 @@ struct ethtool_stats { __u64 data[0]; }; +/* Diagmostic Monitoring Interface Data -- DOM */ +struct ethtool_phy_diag { + __u32 cmd; + /* A0 page */ + __u16 type; + __u16 wavelength; + /* A2 page */ + __u16 alarm; + __u16 warning; + __s16 temp; + __u16 temp_slope; + __s16 temp_offset; + __u16 vcc; + __u16 vcc_slope; + __s16 vcc_offset; + __u16 tx_bias; + __u16 tx_bias_slope; + __s16 tx_bias_offset; + __u16 tx_pwr; + __u16 tx_pwr_slope; + __s16 tx_pwr_offset; + __u16 rx_pwr; + __u32 rx_pwr_cal[5]; + + /* Thresholds */ + __s16 temp_alt; + __s16 temp_aht; + __s16 temp_wlt; + __s16 temp_wht; + __u16 vcc_alt; + __u16 vcc_aht; + __u16 vcc_wlt; + __u16 vcc_wht; + __u16 tx_bias_alt; + __u16 tx_bias_aht; + __u16 tx_bias_wlt; + __u16 tx_bias_wht; + __u16 tx_pwr_alt; + __u16 tx_pwr_aht; + __u16 tx_pwr_wlt; + __u16 tx_pwr_wht; + __u16 rx_pwr_alt; + __u16 rx_pwr_aht; + __u16 rx_pwr_wlt; + __u16 rx_pwr_wht; +}; + struct ethtool_perm_addr { __u32 cmd; /* ETHTOOL_GPERMADDR */ __u32 size; @@ -499,6 +546,7 @@ struct ethtool_ops { int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *); int (*flash_device)(struct net_device *, struct ethtool_flash *); int (*reset)(struct net_device *, u32 *); + int (*get_phy_diag)(struct net_device *, struct ethtool_phy_diag *); }; #endif /* __KERNEL__ */ @@ -557,6 +605,7 @@ struct ethtool_ops { #define ETHTOOL_SRXCLSRLINS 0x00000032 /* Insert RX classification rule */ #define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */ #define ETHTOOL_RESET 0x00000034 /* Reset hardware */ +#define ETHTOOL_GPHYDIAG 0x00000035 /* Get PHY diagnostics */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff --git a/include/net/dom.h b/include/net/dom.h index 4c118a9..61540c3 100644 --- a/include/net/dom.h +++ b/include/net/dom.h @@ -1,12 +1,12 @@ #ifndef _LINUX_DOM_H #define _LINUX_DOM_H -/* - Diagnostic Monitoring Interface for Optical Tranceivers +/* + Diagnostic Monitoring Interface for Optical Tranceivers SFF-8472 v. 10.4 (Jan 2009) ftp://ftp.seagate.com/sff/SFF-8472.PDF - Licensce GPL. Copyright Robert Olsson robert@herjulf.net + Licensce GPL. Copyright Robert Olsson robert@herjulf.net */ #define DOM_A0_IDENTIFIER 0 @@ -83,27 +83,27 @@ #define DOM_A2_ALARM 112 /* 2 bytes */ #define DOM_TYPE_TEMP_AH (1<<7) /* Temp alarm high */ #define DOM_TYPE_TEMP_AL (1<<6) /* low */ -#define DOM_TYPE_VCC_AH (1<<5) -#define DOM_TYPE_VCC_AL (1<<4) -#define DOM_TYPE_TX_BIAS_AH (1<<3) -#define DOM_TYPE_TX_BIAS_AL (1<<2) -#define DOM_TYPE_TX_PWR_AH (1<<1) -#define DOM_TYPE_TX_PWR_AL (1<<0) +#define DOM_TYPE_VCC_AH (1<<5) +#define DOM_TYPE_VCC_AL (1<<4) +#define DOM_TYPE_TX_BIAS_AH (1<<3) +#define DOM_TYPE_TX_BIAS_AL (1<<2) +#define DOM_TYPE_TX_PWR_AH (1<<1) +#define DOM_TYPE_TX_PWR_AL (1<<0) /* Next byte 113 */ -#define DOM_TYPE_RX_PWR_AH (1<<7) -#define DOM_TYPE_RX_PWR_AL (1<<6) +#define DOM_TYPE_RX_PWR_AH (1<<7) +#define DOM_TYPE_RX_PWR_AL (1<<6) #define DOM_A2_WARNING 116 /* 2 bytes */ #define DOM_TYPE_TEMP_WH (1<<7) /* Temp warning high */ #define DOM_TYPE_TEMP_WL (1<<6) /* low */ -#define DOM_TYPE_VCC_WH (1<<5) -#define DOM_TYPE_VCC_WL (1<<4) -#define DOM_TYPE_TX_BIAS_WH (1<<3) -#define DOM_TYPE_TX_BIAS_WL (1<<2) -#define DOM_TYPE_TX_PWR_WH (1<<1) -#define DOM_TYPE_TX_PWR_WL (1<<0) +#define DOM_TYPE_VCC_WH (1<<5) +#define DOM_TYPE_VCC_WL (1<<4) +#define DOM_TYPE_TX_BIAS_WH (1<<3) +#define DOM_TYPE_TX_BIAS_WL (1<<2) +#define DOM_TYPE_TX_PWR_WH (1<<1) +#define DOM_TYPE_TX_PWR_WL (1<<0) /* Next byte 117 */ -#define DOM_TYPE_RX_PWR_WH (1<<7) -#define DOM_TYPE_RX_PWR_WL (1<<6) +#define DOM_TYPE_RX_PWR_WH (1<<7) +#define DOM_TYPE_RX_PWR_WL (1<<6) #endif /* _LINUX_DOM_H */ diff --git a/net/core/ethtool.c b/net/core/ethtool.c index d8aee58..756434a 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -893,6 +893,21 @@ static int ethtool_flash_device(struct net_device *dev, char __user *useraddr) return dev->ethtool_ops->flash_device(dev, &efl); } +static int ethtool_phy_diag(struct net_device *dev, void __user *useraddr) +{ + struct ethtool_phy_diag pd; + + if (!dev->ethtool_ops->get_phy_diag) + return -EOPNOTSUPP; + + dev->ethtool_ops->get_phy_diag(dev, &pd); /* FIXME */ + + if (copy_to_user(useraddr, &pd, sizeof(pd))) + return -EFAULT; + + return 0; +} + /* The main entry point in this file. Called from net/core/dev.c */ int dev_ethtool(struct net *net, struct ifreq *ifr) @@ -1112,6 +1127,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_RESET: rc = ethtool_reset(dev, useraddr); break; + case ETHTOOL_GPHYDIAG: + rc = ethtool_phy_diag(dev, useraddr); + break; default: rc = -EOPNOTSUPP; } diff --git a/net/core/pktgen.c b/net/core/pktgen.c index d38470a..72a3b6d 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -169,7 +169,7 @@ #include #include /* do_div */ -#define VERSION "2.72" +#define VERSION "2.73" #define IP_NAME_SZ 32 #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */ #define MPLS_STACK_BOTTOM htonl(0x00000100) @@ -190,6 +190,7 @@ #define F_IPSEC_ON (1<<12) /* ipsec on for flows */ #define F_QUEUE_MAP_RND (1<<13) /* queue map Random */ #define F_QUEUE_MAP_CPU (1<<14) /* queue map mirrors smp_processor_id() */ +#define F_NODE (1<<15) /* Node memory alloc*/ /* Thread control flag bits */ #define T_STOP (1<<0) /* Stop run */ @@ -372,6 +373,7 @@ struct pktgen_dev { u16 queue_map_min; u16 queue_map_max; + int node; /* Memory node */ #ifdef CONFIG_XFRM __u8 ipsmode; /* IPSEC mode (config) */ @@ -607,6 +609,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v) if (pkt_dev->traffic_class) seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class); + if (pkt_dev->node >= 0) + seq_printf(seq, " node: %d\n", pkt_dev->node); + seq_printf(seq, " Flags: "); if (pkt_dev->flags & F_IPV6) @@ -660,6 +665,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v) if (pkt_dev->flags & F_SVID_RND) seq_printf(seq, "SVID_RND "); + if (pkt_dev->flags & F_NODE) + seq_printf(seq, "NODE_ALLOC "); + seq_puts(seq, "\n"); /* not really stopped, more like last-running-at */ @@ -1074,6 +1082,21 @@ static ssize_t pktgen_if_write(struct file *file, pkt_dev->dst_mac_count); return count; } + if (!strcmp(name, "node")) { + len = num_arg(&user_buffer[i], 10, &value); + if (len < 0) + return len; + + i += len; + + if(node_possible(value)) { + pkt_dev->node = value; + sprintf(pg_result, "OK: node=%d", pkt_dev->node); + } + else + sprintf(pg_result, "ERROR: node not possible"); + return count; + } if (!strcmp(name, "flag")) { char f[32]; memset(f, 0, 32); @@ -1166,12 +1189,18 @@ static ssize_t pktgen_if_write(struct file *file, else if (strcmp(f, "!IPV6") == 0) pkt_dev->flags &= ~F_IPV6; + else if (strcmp(f, "NODE_ALLOC") == 0) + pkt_dev->flags |= F_NODE; + + else if (strcmp(f, "!NODE_ALLOC") == 0) + pkt_dev->flags &= ~F_NODE; + else { sprintf(pg_result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", f, "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " - "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC\n"); + "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC, NODE_ALLOC\n"); return count; } sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); @@ -2571,9 +2600,27 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, mod_cur_headers(pkt_dev); datalen = (odev->hard_header_len + 16) & ~0xf; - skb = __netdev_alloc_skb(odev, - pkt_dev->cur_pkt_size + 64 - + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT); + + if(pkt_dev->flags & F_NODE) { + int node; + + if(pkt_dev->node >= 0) + node = pkt_dev->node; + else + node = numa_node_id(); + + skb = __alloc_skb(NET_SKB_PAD + pkt_dev->cur_pkt_size + 64 + + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT, 0, node); + if (likely(skb)) { + skb_reserve(skb, NET_SKB_PAD); + skb->dev = odev; + } + } + else + skb = __netdev_alloc_skb(odev, + pkt_dev->cur_pkt_size + 64 + + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT); + if (!skb) { sprintf(pkt_dev->result, "No memory"); return NULL; @@ -3658,6 +3705,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) pkt_dev->svlan_p = 0; pkt_dev->svlan_cfi = 0; pkt_dev->svlan_id = 0xffff; + pkt_dev->node = -1; err = pktgen_setup_dev(pkt_dev, ifname); if (err)