diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index b7b0eb104430..dd6379809c74 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -885,6 +885,7 @@ struct vf_info { unsigned int tx_rate; bool pf_set_mac; u16 vlan; + int link_state; }; enum { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 1754ff794360..45093a620c3f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -2740,6 +2740,7 @@ static int cxgb4_mgmt_get_vf_config(struct net_device *dev, ivi->min_tx_rate = 0; ether_addr_copy(ivi->mac, vfinfo->vf_mac_addr); ivi->vlan = vfinfo->vlan; + ivi->linkstate = vfinfo->link_state; return 0; } @@ -2879,6 +2880,49 @@ static int cxgb4_mgmt_set_vf_vlan(struct net_device *dev, int vf, ret, (vlan ? "setting" : "clearing"), adap->pf, vf); return ret; } + +static int cxgb4_mgmt_set_vf_link_state(struct net_device *dev, int vf, + int link) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + u32 param, val; + int ret = 0; + + if (vf >= adap->num_vfs) + return -EINVAL; + + switch (link) { + case IFLA_VF_LINK_STATE_AUTO: + val = FW_VF_LINK_STATE_AUTO; + break; + + case IFLA_VF_LINK_STATE_ENABLE: + val = FW_VF_LINK_STATE_ENABLE; + break; + + case IFLA_VF_LINK_STATE_DISABLE: + val = FW_VF_LINK_STATE_DISABLE; + break; + + default: + return -EINVAL; + } + + param = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_PFVF) | + FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_PFVF_LINK_STATE)); + ret = t4_set_params(adap, adap->mbox, adap->pf, vf + 1, 1, + ¶m, &val); + if (ret) { + dev_err(adap->pdev_dev, + "Error %d in setting PF %d VF %d link state\n", + ret, adap->pf, vf); + return -EINVAL; + } + + adap->vfinfo[vf].link_state = link; + return ret; +} #endif /* CONFIG_PCI_IOV */ static int cxgb_set_mac_addr(struct net_device *dev, void *p) @@ -3294,12 +3338,13 @@ static const struct net_device_ops cxgb4_netdev_ops = { #ifdef CONFIG_PCI_IOV static const struct net_device_ops cxgb4_mgmt_netdev_ops = { - .ndo_open = cxgb4_mgmt_open, - .ndo_set_vf_mac = cxgb4_mgmt_set_vf_mac, - .ndo_get_vf_config = cxgb4_mgmt_get_vf_config, - .ndo_set_vf_rate = cxgb4_mgmt_set_vf_rate, - .ndo_get_phys_port_id = cxgb4_mgmt_get_phys_port_id, - .ndo_set_vf_vlan = cxgb4_mgmt_set_vf_vlan, + .ndo_open = cxgb4_mgmt_open, + .ndo_set_vf_mac = cxgb4_mgmt_set_vf_mac, + .ndo_get_vf_config = cxgb4_mgmt_get_vf_config, + .ndo_set_vf_rate = cxgb4_mgmt_set_vf_rate, + .ndo_get_phys_port_id = cxgb4_mgmt_get_phys_port_id, + .ndo_set_vf_vlan = cxgb4_mgmt_set_vf_vlan, + .ndo_set_vf_link_state = cxgb4_mgmt_set_vf_link_state, }; #endif diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 631f1663f4e0..b2a618e72fcf 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -1312,6 +1312,14 @@ enum fw_params_param_pfvf { FW_PARAMS_PARAM_PFVF_RAWF_END = 0x37, FW_PARAMS_PARAM_PFVF_NCRYPTO_LOOKASIDE = 0x39, FW_PARAMS_PARAM_PFVF_PORT_CAPS32 = 0x3A, + FW_PARAMS_PARAM_PFVF_LINK_STATE = 0x40, +}; + +/* Virtual link state as seen by the specified VF */ +enum vf_link_states { + FW_VF_LINK_STATE_AUTO = 0x00, + FW_VF_LINK_STATE_ENABLE = 0x01, + FW_VF_LINK_STATE_DISABLE = 0x02, }; /* diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index 6b2754a574d6..62fd1250ff7e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -155,6 +155,8 @@ void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok) const char *fc; const struct port_info *pi = netdev_priv(dev); + netif_carrier_on(dev); + switch (pi->link_cfg.speed) { case 100: s = "100Mbps"; @@ -200,6 +202,7 @@ void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok) netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s, fc); } else { + netif_carrier_off(dev); netdev_info(dev, "link down\n"); } } @@ -339,16 +342,6 @@ static int link_start(struct net_device *dev) if (ret == 0) ret = t4vf_enable_pi(pi->adapter, pi, true, true); - /* The Virtual Interfaces are connected to an internal switch on the - * chip which allows VIs attached to the same port to talk to each - * other even when the port link is down. As a result, we generally - * want to always report a VI's link as being "up", provided there are - * no errors in enabling vi. - */ - - if (ret == 0) - netif_carrier_on(dev); - return ret; }