[PATCH] sk98lin: allow ethtool checksum on/off per port

Allow control of checksumming parameters via ethtool.

Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
diff --git a/drivers/net/sk98lin/h/skdrv2nd.h b/drivers/net/sk98lin/h/skdrv2nd.h
index 9bdfde8..0ebafc8 100644
--- a/drivers/net/sk98lin/h/skdrv2nd.h
+++ b/drivers/net/sk98lin/h/skdrv2nd.h
@@ -297,6 +297,7 @@
 	RXD		*pRxdRingTail;	/* Tail of Rx rings */
 	RXD		*pRxdRingPrev;	/* descriptor given to BMU previously */
 	int		RxdRingFree;	/* # of free entrys */
+	int		RxCsum;		/* use receive checksum hardware */
 	spinlock_t	RxDesRingLock;	/* serialize descriptor accesses */
 	int		RxFillLimit;	/* limit for buffers in ring */
 	SK_IOC		HwAddr;		/* bmu registers address */
diff --git a/drivers/net/sk98lin/skethtool.c b/drivers/net/sk98lin/skethtool.c
index b71769a..4265ed9 100644
--- a/drivers/net/sk98lin/skethtool.c
+++ b/drivers/net/sk98lin/skethtool.c
@@ -539,6 +539,48 @@
         return ret ? -EIO : 0;
 }
 
+/* Only Yukon supports checksum offload. */
+static int setScatterGather(struct net_device *dev, u32 data)
+{
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
+		return -EOPNOTSUPP;
+	return ethtool_op_set_sg(dev, data);
+}
+
+static int setTxCsum(struct net_device *dev, u32 data)
+{
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
+		return -EOPNOTSUPP;
+
+	return ethtool_op_set_tx_csum(dev, data);
+}
+
+static u32 getRxCsum(struct net_device *dev)
+{
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+
+	return pAC->RxPort[pNet->PortNr].RxCsum;
+}
+
+static int setRxCsum(struct net_device *dev, u32 data)
+{
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
+		return -EOPNOTSUPP;
+
+	pAC->RxPort[pNet->PortNr].RxCsum = data != 0;
+	return 0;
+}
+
 struct ethtool_ops SkGeEthtoolOps = {
 	.get_settings		= getSettings,
 	.set_settings		= setSettings,
@@ -551,4 +593,10 @@
 	.set_pauseparam		= setPauseParams,
 	.get_link		= ethtool_op_get_link,
 	.get_perm_addr		= ethtool_op_get_perm_addr,
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= setScatterGather,
+	.get_tx_csum		= ethtool_op_get_tx_csum,
+	.set_tx_csum		= setTxCsum,
+	.get_rx_csum		= getRxCsum,
+	.set_rx_csum		= setRxCsum,
 };
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index 107c5d9..02143fa 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -2189,13 +2189,10 @@
 			skb_put(pMsg, FrameLength);
 		} /* frame > SK_COPY_TRESHOLD */
 
-#ifdef USE_SK_RX_CHECKSUM
-		pMsg->csum = pRxd->TcpSums;
-		pMsg->ip_summed = CHECKSUM_HW;
-#else
-		pMsg->ip_summed = CHECKSUM_NONE;
-#endif
-
+		if (pRxPort->RxCsum) {
+			pMsg->csum = pRxd->TcpSums;
+			pMsg->ip_summed = CHECKSUM_HW;
+		}
 
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV,	1,("V"));
 		ForRlmt = SK_RLMT_RX_PROTOCOL;
@@ -4149,6 +4146,7 @@
 			Flags);
 		break;
 	case SK_DRV_NET_UP:	 /* SK_U32 PortIdx */
+	{	struct net_device *dev = pAC->dev[Param.Para32[0]];
 		/* action list 5 */
 		FromPort = Param.Para32[0];
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
@@ -4232,22 +4230,12 @@
 			printk("    irq moderation:  disabled\n");
 
 
-#ifdef SK_ZEROCOPY
-		if (pAC->ChipsetType)
-#ifdef USE_SK_TX_CHECKSUM
-			printk("    scatter-gather:  enabled\n");
-#else
-			printk("    tx-checksum:     disabled\n");
-#endif
-		else
-			printk("    scatter-gather:  disabled\n");
-#else
-			printk("    scatter-gather:  disabled\n");
-#endif
-
-#ifndef USE_SK_RX_CHECKSUM
-			printk("    rx-checksum:     disabled\n");
-#endif
+		printk("    scatter-gather:  %s\n",
+		       (dev->features & NETIF_F_SG) ? "enabled" : "disabled");
+		printk("    tx-checksum:     %s\n",
+		       (dev->features & NETIF_F_IP_CSUM) ? "enabled" : "disabled");
+		printk("    rx-checksum:     %s\n",
+		       pAC->RxPort[Param.Para32[0]].RxCsum ? "enabled" : "disabled");
 
 		} else {
                         DoPrintInterfaceChange = SK_TRUE;
@@ -4262,9 +4250,9 @@
 		}
 
 		/* Inform the world that link protocol is up. */
-		netif_carrier_on(pAC->dev[Param.Para32[0]]);
-
+		netif_carrier_on(dev);
 		break;
+	}
 	case SK_DRV_NET_DOWN:	 /* SK_U32 Reason */
 		/* action list 7 */
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
@@ -4871,15 +4859,18 @@
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps);
 
-#ifdef SK_ZEROCOPY
-#ifdef USE_SK_TX_CHECKSUM
+	/* Use only if yukon hardware */
 	if (pAC->ChipsetType) {
-		/* Use only if yukon hardware */
-		/* SK and ZEROCOPY - fly baby... */
-		dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+#ifdef USE_SK_TX_CHECKSUM
+		dev->features |= NETIF_F_IP_CSUM;
+#endif
+#ifdef SK_ZEROCOPY
+		dev->features |= NETIF_F_SG;
+#endif
+#ifdef USE_SK_RX_CHECKSUM
+		pAC->RxPort[0].RxCsum = 1;
+#endif
 	}
-#endif
-#endif
 
 	pAC->Index = boards_found++;
 
@@ -4944,14 +4935,17 @@
 		SET_NETDEV_DEV(dev, &pdev->dev);
 		SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps);
 
-#ifdef SK_ZEROCOPY
-#ifdef USE_SK_TX_CHECKSUM
 		if (pAC->ChipsetType) {
-			/* SG and ZEROCOPY - fly baby... */
-			dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+#ifdef USE_SK_TX_CHECKSUM
+			dev->features |= NETIF_F_IP_CSUM;
+#endif
+#ifdef SK_ZEROCOPY
+			dev->features |= NETIF_F_SG;
+#endif
+#ifdef USE_SK_RX_CHECKSUM
+			pAC->RxPort[1].RxCsum = 1;
+#endif
 		}
-#endif
-#endif
 
 		if (register_netdev(dev)) {
 			printk(KERN_ERR "sk98lin: Could not register device for seconf port.\n");