diff options
author | Brian King <brking@linux.vnet.ibm.com> | 2007-08-17 10:16:31 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:50:43 -0400 |
commit | 5fc7e01cb77132f96e171a37f9f792270b1603f6 (patch) | |
tree | 44c4e1926a803ef1e53f5a1985f976ba6dd35171 | |
parent | f4ff28720f45354573dcf4e0eb5a2dc5452cb3e1 (diff) |
ibmveth: Implement ethtool hooks to enable/disable checksum offload
This patch adds the appropriate ethtool hooks to allow for enabling/disabling
of hypervisor assisted checksum offload for TCP.
Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/net/ibmveth.c | 125 | ||||
-rw-r--r-- | drivers/net/ibmveth.h | 1 |
2 files changed, 124 insertions, 2 deletions
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 9353890dcda0..9c16928e20ed 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c | |||
@@ -652,12 +652,132 @@ static u32 netdev_get_link(struct net_device *dev) { | |||
652 | return 1; | 652 | return 1; |
653 | } | 653 | } |
654 | 654 | ||
655 | static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data) | ||
656 | { | ||
657 | struct ibmveth_adapter *adapter = dev->priv; | ||
658 | |||
659 | if (data) | ||
660 | adapter->rx_csum = 1; | ||
661 | else { | ||
662 | /* | ||
663 | * Since the ibmveth firmware interface does not have the concept of | ||
664 | * separate tx/rx checksum offload enable, if rx checksum is disabled | ||
665 | * we also have to disable tx checksum offload. Once we disable rx | ||
666 | * checksum offload, we are no longer allowed to send tx buffers that | ||
667 | * are not properly checksummed. | ||
668 | */ | ||
669 | adapter->rx_csum = 0; | ||
670 | dev->features &= ~NETIF_F_IP_CSUM; | ||
671 | } | ||
672 | } | ||
673 | |||
674 | static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data) | ||
675 | { | ||
676 | struct ibmveth_adapter *adapter = dev->priv; | ||
677 | |||
678 | if (data) { | ||
679 | dev->features |= NETIF_F_IP_CSUM; | ||
680 | adapter->rx_csum = 1; | ||
681 | } else | ||
682 | dev->features &= ~NETIF_F_IP_CSUM; | ||
683 | } | ||
684 | |||
685 | static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, | ||
686 | void (*done) (struct net_device *, u32)) | ||
687 | { | ||
688 | struct ibmveth_adapter *adapter = dev->priv; | ||
689 | union ibmveth_illan_attributes set_attr, clr_attr, ret_attr; | ||
690 | long ret; | ||
691 | int rc1 = 0, rc2 = 0; | ||
692 | int restart = 0; | ||
693 | |||
694 | if (netif_running(dev)) { | ||
695 | restart = 1; | ||
696 | adapter->pool_config = 1; | ||
697 | ibmveth_close(dev); | ||
698 | adapter->pool_config = 0; | ||
699 | } | ||
700 | |||
701 | set_attr.desc = 0; | ||
702 | clr_attr.desc = 0; | ||
703 | |||
704 | if (data) | ||
705 | set_attr.fields.tcp_csum_offload_ipv4 = 1; | ||
706 | else | ||
707 | clr_attr.fields.tcp_csum_offload_ipv4 = 1; | ||
708 | |||
709 | ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr.desc); | ||
710 | |||
711 | if (ret == H_SUCCESS && !ret_attr.fields.active_trunk && | ||
712 | !ret_attr.fields.trunk_priority && | ||
713 | ret_attr.fields.csum_offload_padded_pkt_support) { | ||
714 | ret = h_illan_attributes(adapter->vdev->unit_address, clr_attr.desc, | ||
715 | set_attr.desc, &ret_attr.desc); | ||
716 | |||
717 | if (ret != H_SUCCESS) { | ||
718 | rc1 = -EIO; | ||
719 | ibmveth_error_printk("unable to change checksum offload settings." | ||
720 | " %d rc=%ld\n", data, ret); | ||
721 | |||
722 | ret = h_illan_attributes(adapter->vdev->unit_address, | ||
723 | set_attr.desc, clr_attr.desc, &ret_attr.desc); | ||
724 | } else | ||
725 | done(dev, data); | ||
726 | } else { | ||
727 | rc1 = -EIO; | ||
728 | ibmveth_error_printk("unable to change checksum offload settings." | ||
729 | " %d rc=%ld ret_attr=%lx\n", data, ret, ret_attr.desc); | ||
730 | } | ||
731 | |||
732 | if (restart) | ||
733 | rc2 = ibmveth_open(dev); | ||
734 | |||
735 | return rc1 ? rc1 : rc2; | ||
736 | } | ||
737 | |||
738 | static int ibmveth_set_rx_csum(struct net_device *dev, u32 data) | ||
739 | { | ||
740 | struct ibmveth_adapter *adapter = dev->priv; | ||
741 | |||
742 | if ((data && adapter->rx_csum) || (!data && !adapter->rx_csum)) | ||
743 | return 0; | ||
744 | |||
745 | return ibmveth_set_csum_offload(dev, data, ibmveth_set_rx_csum_flags); | ||
746 | } | ||
747 | |||
748 | static int ibmveth_set_tx_csum(struct net_device *dev, u32 data) | ||
749 | { | ||
750 | struct ibmveth_adapter *adapter = dev->priv; | ||
751 | int rc = 0; | ||
752 | |||
753 | if (data && (dev->features & NETIF_F_IP_CSUM)) | ||
754 | return 0; | ||
755 | if (!data && !(dev->features & NETIF_F_IP_CSUM)) | ||
756 | return 0; | ||
757 | |||
758 | if (data && !adapter->rx_csum) | ||
759 | rc = ibmveth_set_csum_offload(dev, data, ibmveth_set_tx_csum_flags); | ||
760 | else | ||
761 | ibmveth_set_tx_csum_flags(dev, data); | ||
762 | |||
763 | return rc; | ||
764 | } | ||
765 | |||
766 | static u32 ibmveth_get_rx_csum(struct net_device *dev) | ||
767 | { | ||
768 | struct ibmveth_adapter *adapter = dev->priv; | ||
769 | return adapter->rx_csum; | ||
770 | } | ||
771 | |||
655 | static const struct ethtool_ops netdev_ethtool_ops = { | 772 | static const struct ethtool_ops netdev_ethtool_ops = { |
656 | .get_drvinfo = netdev_get_drvinfo, | 773 | .get_drvinfo = netdev_get_drvinfo, |
657 | .get_settings = netdev_get_settings, | 774 | .get_settings = netdev_get_settings, |
658 | .get_link = netdev_get_link, | 775 | .get_link = netdev_get_link, |
659 | .get_sg = ethtool_op_get_sg, | 776 | .get_sg = ethtool_op_get_sg, |
660 | .get_tx_csum = ethtool_op_get_tx_csum, | 777 | .get_tx_csum = ethtool_op_get_tx_csum, |
778 | .set_tx_csum = ibmveth_set_tx_csum, | ||
779 | .get_rx_csum = ibmveth_get_rx_csum, | ||
780 | .set_rx_csum = ibmveth_set_rx_csum, | ||
661 | }; | 781 | }; |
662 | 782 | ||
663 | static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | 783 | static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
@@ -1103,9 +1223,10 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ | |||
1103 | ret = h_illan_attributes(dev->unit_address, 0, set_attr.desc, | 1223 | ret = h_illan_attributes(dev->unit_address, 0, set_attr.desc, |
1104 | &ret_attr.desc); | 1224 | &ret_attr.desc); |
1105 | 1225 | ||
1106 | if (ret == H_SUCCESS) | 1226 | if (ret == H_SUCCESS) { |
1227 | adapter->rx_csum = 1; | ||
1107 | netdev->features |= NETIF_F_IP_CSUM; | 1228 | netdev->features |= NETIF_F_IP_CSUM; |
1108 | else | 1229 | } else |
1109 | ret = h_illan_attributes(dev->unit_address, set_attr.desc, | 1230 | ret = h_illan_attributes(dev->unit_address, set_attr.desc, |
1110 | 0, &ret_attr.desc); | 1231 | 0, &ret_attr.desc); |
1111 | } | 1232 | } |
diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index 3f10f0f4447a..43b068d9a558 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h | |||
@@ -138,6 +138,7 @@ struct ibmveth_adapter { | |||
138 | struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools]; | 138 | struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools]; |
139 | struct ibmveth_rx_q rx_queue; | 139 | struct ibmveth_rx_q rx_queue; |
140 | int pool_config; | 140 | int pool_config; |
141 | int rx_csum; | ||
141 | 142 | ||
142 | /* adapter specific stats */ | 143 | /* adapter specific stats */ |
143 | u64 replenish_task_cycles; | 144 | u64 replenish_task_cycles; |