diff options
Diffstat (limited to 'drivers/net/qlcnic/qlcnic_ethtool.c')
-rw-r--r-- | drivers/net/qlcnic/qlcnic_ethtool.c | 100 |
1 files changed, 80 insertions, 20 deletions
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 3bd514ec7e8f..e294b825bac5 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -69,8 +69,6 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = { QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)}, {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure), QLC_OFF(stats.skb_alloc_failure)}, - {"null skb", - QLC_SIZEOF(stats.null_skb), QLC_OFF(stats.null_skb)}, {"null rxbuf", QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)}, {"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error), @@ -101,7 +99,7 @@ static const u32 diag_registers[] = { CRB_XG_STATE_P3, CRB_FW_CAPABILITIES_1, ISR_INT_STATE_REG, - QLCNIC_CRB_DEV_REF_COUNT, + QLCNIC_CRB_DRV_ACTIVE, QLCNIC_CRB_DEV_STATE, QLCNIC_CRB_DRV_STATE, QLCNIC_CRB_DRV_SCRATCH, @@ -350,7 +348,7 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) for (i = 0; diag_registers[i] != -1; i++) regs_buff[i] = QLCRD32(adapter, diag_registers[i]); - if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) return; regs_buff[i++] = 0xFFEFCDAB; /* Marker btw regs and ring count*/ @@ -580,8 +578,12 @@ qlcnic_set_pauseparam(struct net_device *netdev, } QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val); } else if (adapter->ahw.port_type == QLCNIC_XGBE) { + if (!pause->rx_pause || pause->autoneg) + return -EOPNOTSUPP; + if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS)) return -EIO; + val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL); if (port == 0) { if (pause->tx_pause) @@ -676,6 +678,12 @@ static int qlcnic_loopback_test(struct net_device *netdev) int max_sds_rings = adapter->max_sds_rings; int ret; + if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) { + dev_warn(&adapter->pdev->dev, "Loopback test not supported" + "for non privilege function\n"); + return 0; + } + if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) return -EIO; @@ -715,7 +723,8 @@ static int qlcnic_irq_test(struct net_device *netdev) adapter->diag_cnt = 0; ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func, - QLCHAL_VERSION, adapter->portnum, 0, 0, 0x00000011); + adapter->fw_hal_version, adapter->portnum, + 0, 0, 0x00000011); if (ret) goto done; @@ -738,6 +747,14 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, { memset(data, 0, sizeof(u64) * QLCNIC_TEST_LEN); + data[0] = qlcnic_reg_test(dev); + if (data[0]) + eth_test->flags |= ETH_TEST_FL_FAILED; + + data[1] = (u64) qlcnic_test_link(dev); + if (data[1]) + eth_test->flags |= ETH_TEST_FL_FAILED; + if (eth_test->flags == ETH_TEST_FL_OFFLINE) { data[2] = qlcnic_irq_test(dev); if (data[2]) @@ -748,15 +765,6 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, eth_test->flags |= ETH_TEST_FL_FAILED; } - - data[0] = qlcnic_reg_test(dev); - if (data[0]) - eth_test->flags |= ETH_TEST_FL_FAILED; - - /* link test */ - data[1] = (u64) qlcnic_test_link(dev); - if (data[1]) - eth_test->flags |= ETH_TEST_FL_FAILED; } static void @@ -796,6 +804,20 @@ qlcnic_get_ethtool_stats(struct net_device *dev, } } +static int qlcnic_set_tx_csum(struct net_device *dev, u32 data) +{ + struct qlcnic_adapter *adapter = netdev_priv(dev); + + if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) + return -EOPNOTSUPP; + if (data) + dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); + else + dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); + + return 0; + +} static u32 qlcnic_get_tx_csum(struct net_device *dev) { return dev->features & NETIF_F_IP_CSUM; @@ -810,7 +832,23 @@ static u32 qlcnic_get_rx_csum(struct net_device *dev) static int qlcnic_set_rx_csum(struct net_device *dev, u32 data) { struct qlcnic_adapter *adapter = netdev_priv(dev); + + if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) + return -EOPNOTSUPP; + if (!!data) { + adapter->rx_csum = !!data; + return 0; + } + + if (adapter->flags & QLCNIC_LRO_ENABLED) { + if (qlcnic_config_hw_lro(adapter, QLCNIC_LRO_DISABLED)) + return -EIO; + + dev->features &= ~NETIF_F_LRO; + qlcnic_send_lro_cleanup(adapter); + } adapter->rx_csum = !!data; + dev_info(&adapter->pdev->dev, "disabling LRO as rx_csum is off\n"); return 0; } @@ -821,6 +859,9 @@ static u32 qlcnic_get_tso(struct net_device *dev) static int qlcnic_set_tso(struct net_device *dev, u32 data) { + struct qlcnic_adapter *adapter = netdev_priv(dev); + if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO)) + return -EOPNOTSUPP; if (data) dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); else @@ -834,7 +875,10 @@ static int qlcnic_blink_led(struct net_device *dev, u32 val) struct qlcnic_adapter *adapter = netdev_priv(dev); int ret; - ret = qlcnic_config_led(adapter, 1, 0xf); + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) + return -EIO; + + ret = adapter->nic_ops->config_led(adapter, 1, 0xf); if (ret) { dev_err(&adapter->pdev->dev, "Failed to set LED blink state.\n"); @@ -843,7 +887,7 @@ static int qlcnic_blink_led(struct net_device *dev, u32 val) msleep_interruptible(val * 1000); - ret = qlcnic_config_led(adapter, 0, 0xf); + ret = adapter->nic_ops->config_led(adapter, 0, 0xf); if (ret) { dev_err(&adapter->pdev->dev, "Failed to reset LED blink state.\n"); @@ -905,7 +949,7 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev, { struct qlcnic_adapter *adapter = netdev_priv(netdev); - if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC) + if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) return -EINVAL; /* @@ -981,12 +1025,28 @@ static int qlcnic_set_flags(struct net_device *netdev, u32 data) struct qlcnic_adapter *adapter = netdev_priv(netdev); int hw_lro; + if (data & ~ETH_FLAG_LRO) + return -EINVAL; + if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)) return -EINVAL; - ethtool_op_set_flags(netdev, data); + if (!adapter->rx_csum) { + dev_info(&adapter->pdev->dev, "rx csum is off, " + "cannot toggle lro\n"); + return -EINVAL; + } + + if ((data & ETH_FLAG_LRO) && (adapter->flags & QLCNIC_LRO_ENABLED)) + return 0; - hw_lro = (data & ETH_FLAG_LRO) ? QLCNIC_LRO_ENABLED : 0; + if (data & ETH_FLAG_LRO) { + hw_lro = QLCNIC_LRO_ENABLED; + netdev->features |= NETIF_F_LRO; + } else { + hw_lro = 0; + netdev->features &= ~NETIF_F_LRO; + } if (qlcnic_config_hw_lro(adapter, hw_lro)) return -EIO; @@ -1026,7 +1086,7 @@ const struct ethtool_ops qlcnic_ethtool_ops = { .get_pauseparam = qlcnic_get_pauseparam, .set_pauseparam = qlcnic_set_pauseparam, .get_tx_csum = qlcnic_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, + .set_tx_csum = qlcnic_set_tx_csum, .set_sg = ethtool_op_set_sg, .get_tso = qlcnic_get_tso, .set_tso = qlcnic_set_tso, |