diff options
Diffstat (limited to 'drivers/net/enic/enic_main.c')
| -rw-r--r-- | drivers/net/enic/enic_main.c | 274 | 
1 files changed, 59 insertions, 215 deletions
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 8b9cad5e971..3d99b0f1a23 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -45,6 +45,7 @@  #include "enic_res.h"  #include "enic.h"  #include "enic_dev.h" +#include "enic_pp.h"  #define ENIC_NOTIFY_TIMER_PERIOD	(2 * HZ)  #define WQ_ENET_MAX_DESC_LEN		(1 << WQ_ENET_LEN_BITS) @@ -179,10 +180,10 @@ static int enic_get_settings(struct net_device *netdev,  	ecmd->transceiver = XCVR_EXTERNAL;  	if (netif_carrier_ok(netdev)) { -		ecmd->speed = vnic_dev_port_speed(enic->vdev); +		ethtool_cmd_speed_set(ecmd, vnic_dev_port_speed(enic->vdev));  		ecmd->duplex = DUPLEX_FULL;  	} else { -		ecmd->speed = -1; +		ethtool_cmd_speed_set(ecmd, -1);  		ecmd->duplex = -1;  	} @@ -250,56 +251,6 @@ static void enic_get_ethtool_stats(struct net_device *netdev,  		*(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].offset];  } -static u32 enic_get_rx_csum(struct net_device *netdev) -{ -	struct enic *enic = netdev_priv(netdev); -	return enic->csum_rx_enabled; -} - -static int enic_set_rx_csum(struct net_device *netdev, u32 data) -{ -	struct enic *enic = netdev_priv(netdev); - -	if (data && !ENIC_SETTING(enic, RXCSUM)) -		return -EINVAL; - -	enic->csum_rx_enabled = !!data; - -	return 0; -} - -static int enic_set_tx_csum(struct net_device *netdev, u32 data) -{ -	struct enic *enic = netdev_priv(netdev); - -	if (data && !ENIC_SETTING(enic, TXCSUM)) -		return -EINVAL; - -	if (data) -		netdev->features |= NETIF_F_HW_CSUM; -	else -		netdev->features &= ~NETIF_F_HW_CSUM; - -	return 0; -} - -static int enic_set_tso(struct net_device *netdev, u32 data) -{ -	struct enic *enic = netdev_priv(netdev); - -	if (data && !ENIC_SETTING(enic, TSO)) -		return -EINVAL; - -	if (data) -		netdev->features |= -			NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN; -	else -		netdev->features &= -			~(NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN); - -	return 0; -} -  static u32 enic_get_msglevel(struct net_device *netdev)  {  	struct enic *enic = netdev_priv(netdev); @@ -387,17 +338,8 @@ static const struct ethtool_ops enic_ethtool_ops = {  	.get_strings = enic_get_strings,  	.get_sset_count = enic_get_sset_count,  	.get_ethtool_stats = enic_get_ethtool_stats, -	.get_rx_csum = enic_get_rx_csum, -	.set_rx_csum = enic_set_rx_csum, -	.get_tx_csum = ethtool_op_get_tx_csum, -	.set_tx_csum = enic_set_tx_csum, -	.get_sg = ethtool_op_get_sg, -	.set_sg = ethtool_op_set_sg, -	.get_tso = ethtool_op_get_tso, -	.set_tso = enic_set_tso,  	.get_coalesce = enic_get_coalesce,  	.set_coalesce = enic_set_coalesce, -	.get_flags = ethtool_op_get_flags,  };  static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) @@ -874,7 +816,7 @@ static struct net_device_stats *enic_get_stats(struct net_device *netdev)  	return net_stats;  } -static void enic_reset_addr_lists(struct enic *enic) +void enic_reset_addr_lists(struct enic *enic)  {  	enic->mc_count = 0;  	enic->uc_count = 0; @@ -1112,157 +1054,77 @@ static int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)  		return -EINVAL;  } -static int enic_set_port_profile(struct enic *enic, u8 *mac) -{ -	struct vic_provinfo *vp; -	u8 oui[3] = VIC_PROVINFO_CISCO_OUI; -	u16 os_type = VIC_GENERIC_PROV_OS_TYPE_LINUX; -	char uuid_str[38]; -	char client_mac_str[18]; -	u8 *client_mac; -	int err; - -	err = enic_vnic_dev_deinit(enic); -	if (err) -		return err; - -	enic_reset_addr_lists(enic); - -	switch (enic->pp.request) { - -	case PORT_REQUEST_ASSOCIATE: - -		if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name)) -			return -EINVAL; - -		if (!is_valid_ether_addr(mac)) -			return -EADDRNOTAVAIL; - -		vp = vic_provinfo_alloc(GFP_KERNEL, oui, -			VIC_PROVINFO_GENERIC_TYPE); -		if (!vp) -			return -ENOMEM; - -		vic_provinfo_add_tlv(vp, -			VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR, -			strlen(enic->pp.name) + 1, enic->pp.name); - -		if (!is_zero_ether_addr(enic->pp.mac_addr)) -			client_mac = enic->pp.mac_addr; -		else -			client_mac = mac; - -		vic_provinfo_add_tlv(vp, -			VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR, -			ETH_ALEN, client_mac); - -		sprintf(client_mac_str, "%pM", client_mac); -		vic_provinfo_add_tlv(vp, -			VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR, -			sizeof(client_mac_str), client_mac_str); - -		if (enic->pp.set & ENIC_SET_INSTANCE) { -			sprintf(uuid_str, "%pUB", enic->pp.instance_uuid); -			vic_provinfo_add_tlv(vp, -				VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR, -				sizeof(uuid_str), uuid_str); -		} - -		if (enic->pp.set & ENIC_SET_HOST) { -			sprintf(uuid_str, "%pUB", enic->pp.host_uuid); -			vic_provinfo_add_tlv(vp, -				VIC_GENERIC_PROV_TLV_HOST_UUID_STR, -				sizeof(uuid_str), uuid_str); -		} - -		os_type = htons(os_type); -		vic_provinfo_add_tlv(vp, -			VIC_GENERIC_PROV_TLV_OS_TYPE, -			sizeof(os_type), &os_type); - -		err = enic_dev_init_prov(enic, vp); -		vic_provinfo_free(vp); -		if (err) -			return err; -		break; - -	case PORT_REQUEST_DISASSOCIATE: -		break; - -	default: -		return -EINVAL; -	} - -	/* Set flag to indicate that the port assoc/disassoc -	 * request has been sent out to fw -	 */ -	enic->pp.set |= ENIC_PORT_REQUEST_APPLIED; - -	return 0; -} -  static int enic_set_vf_port(struct net_device *netdev, int vf,  	struct nlattr *port[])  {  	struct enic *enic = netdev_priv(netdev); -	struct enic_port_profile new_pp; -	int err = 0; +	struct enic_port_profile prev_pp; +	int err = 0, restore_pp = 1; + +	/* don't support VFs, yet */ +	if (vf != PORT_SELF_VF) +		return -EOPNOTSUPP; + +	if (!port[IFLA_PORT_REQUEST]) +		return -EOPNOTSUPP; -	memset(&new_pp, 0, sizeof(new_pp)); +	memcpy(&prev_pp, &enic->pp, sizeof(enic->pp)); +	memset(&enic->pp, 0, sizeof(enic->pp)); -	if (port[IFLA_PORT_REQUEST]) { -		new_pp.set |= ENIC_SET_REQUEST; -		new_pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]); -	} +	enic->pp.set |= ENIC_SET_REQUEST; +	enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]);  	if (port[IFLA_PORT_PROFILE]) { -		new_pp.set |= ENIC_SET_NAME; -		memcpy(new_pp.name, nla_data(port[IFLA_PORT_PROFILE]), +		enic->pp.set |= ENIC_SET_NAME; +		memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]),  			PORT_PROFILE_MAX);  	}  	if (port[IFLA_PORT_INSTANCE_UUID]) { -		new_pp.set |= ENIC_SET_INSTANCE; -		memcpy(new_pp.instance_uuid, +		enic->pp.set |= ENIC_SET_INSTANCE; +		memcpy(enic->pp.instance_uuid,  			nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX);  	}  	if (port[IFLA_PORT_HOST_UUID]) { -		new_pp.set |= ENIC_SET_HOST; -		memcpy(new_pp.host_uuid, +		enic->pp.set |= ENIC_SET_HOST; +		memcpy(enic->pp.host_uuid,  			nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX);  	} -	/* don't support VFs, yet */ -	if (vf != PORT_SELF_VF) -		return -EOPNOTSUPP; - -	if (!(new_pp.set & ENIC_SET_REQUEST)) -		return -EOPNOTSUPP; - -	if (new_pp.request == PORT_REQUEST_ASSOCIATE) { -		/* Special case handling */ -		if (!is_zero_ether_addr(enic->pp.vf_mac)) -			memcpy(new_pp.mac_addr, enic->pp.vf_mac, ETH_ALEN); +	/* Special case handling: mac came from IFLA_VF_MAC */ +	if (!is_zero_ether_addr(prev_pp.vf_mac)) +		memcpy(enic->pp.mac_addr, prev_pp.vf_mac, ETH_ALEN);  		if (is_zero_ether_addr(netdev->dev_addr))  			random_ether_addr(netdev->dev_addr); -	} -	memcpy(&enic->pp, &new_pp, sizeof(struct enic_port_profile)); +	err = enic_process_set_pp_request(enic, &prev_pp, &restore_pp); +	if (err) { +		if (restore_pp) { +			/* Things are still the way they were: Implicit +			 * DISASSOCIATE failed +			 */ +			memcpy(&enic->pp, &prev_pp, sizeof(enic->pp)); +		} else { +			memset(&enic->pp, 0, sizeof(enic->pp)); +			memset(netdev->dev_addr, 0, ETH_ALEN); +		} +	} else { +		/* Set flag to indicate that the port assoc/disassoc +		 * request has been sent out to fw +		 */ +		enic->pp.set |= ENIC_PORT_REQUEST_APPLIED; -	err = enic_set_port_profile(enic, netdev->dev_addr); -	if (err) -		goto set_port_profile_cleanup; +		/* If DISASSOCIATE, clean up all assigned/saved macaddresses */ +		if (enic->pp.request == PORT_REQUEST_DISASSOCIATE) { +			memset(enic->pp.mac_addr, 0, ETH_ALEN); +			memset(netdev->dev_addr, 0, ETH_ALEN); +		} +	} -set_port_profile_cleanup:  	memset(enic->pp.vf_mac, 0, ETH_ALEN); -	if (err || enic->pp.request == PORT_REQUEST_DISASSOCIATE) { -		memset(netdev->dev_addr, 0, ETH_ALEN); -		memset(enic->pp.mac_addr, 0, ETH_ALEN); -	} -  	return err;  } @@ -1270,34 +1132,15 @@ static int enic_get_vf_port(struct net_device *netdev, int vf,  	struct sk_buff *skb)  {  	struct enic *enic = netdev_priv(netdev); -	int err, error, done;  	u16 response = PORT_PROFILE_RESPONSE_SUCCESS; +	int err;  	if (!(enic->pp.set & ENIC_PORT_REQUEST_APPLIED))  		return -ENODATA; -	err = enic_dev_init_done(enic, &done, &error); +	err = enic_process_get_pp_request(enic, enic->pp.request, &response);  	if (err) -		error = err; - -	switch (error) { -	case ERR_SUCCESS: -		if (!done) -			response = PORT_PROFILE_RESPONSE_INPROGRESS; -		break; -	case ERR_EINVAL: -		response = PORT_PROFILE_RESPONSE_INVALID; -		break; -	case ERR_EBADSTATE: -		response = PORT_PROFILE_RESPONSE_BADSTATE; -		break; -	case ERR_ENOMEM: -		response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES; -		break; -	default: -		response = PORT_PROFILE_RESPONSE_ERROR; -		break; -	} +		return err;  	NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request);  	NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response); @@ -1407,7 +1250,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,  		skb_put(skb, bytes_written);  		skb->protocol = eth_type_trans(skb, netdev); -		if (enic->csum_rx_enabled && !csum_not_calc) { +		if ((netdev->features & NETIF_F_RXCSUM) && !csum_not_calc) {  			skb->csum = htons(checksum);  			skb->ip_summed = CHECKSUM_COMPLETE;  		} @@ -2536,17 +2379,18 @@ static int __devinit enic_probe(struct pci_dev *pdev,  		dev_info(dev, "loopback tag=0x%04x\n", enic->loop_tag);  	}  	if (ENIC_SETTING(enic, TXCSUM)) -		netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; +		netdev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM;  	if (ENIC_SETTING(enic, TSO)) -		netdev->features |= NETIF_F_TSO | +		netdev->hw_features |= NETIF_F_TSO |  			NETIF_F_TSO6 | NETIF_F_TSO_ECN; -	if (ENIC_SETTING(enic, LRO)) -		netdev->features |= NETIF_F_GRO; +	if (ENIC_SETTING(enic, RXCSUM)) +		netdev->hw_features |= NETIF_F_RXCSUM; + +	netdev->features |= netdev->hw_features; +  	if (using_dac)  		netdev->features |= NETIF_F_HIGHDMA; -	enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM); -  	err = register_netdev(netdev);  	if (err) {  		dev_err(dev, "Cannot register net device, aborting\n");  |