aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/dm9000.c
diff options
context:
space:
mode:
authorYeasah Pell <yeasah@comrex.com>2009-07-06 21:12:33 -0400
committerDavid S. Miller <davem@davemloft.net>2009-07-06 21:54:51 -0400
commit5dcc60b71886795965fd5029b5d9a9ba7b5a2c17 (patch)
tree5611d123e03d280bccce73f868451b0bd39dcbe8 /drivers/net/dm9000.c
parent482d804cb4b520b6e3134c959c968712ebcdea02 (diff)
dm9000: add checksum offload support
Add checksum offload support for DM9000A and DM9000B chips. v2 changes: added a local copy of ip_summed to save IO cycles in dm9000_send_packet v3 changes: trans_start updating is removed. Signed-off-by: Yeasah Pell <yeasah@comrex.com> Signed-off-by: Mike Rapoport <mike@compulab.co.il> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/dm9000.c')
-rw-r--r--drivers/net/dm9000.c107
1 files changed, 90 insertions, 17 deletions
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index ffd9edceb317..8603806be898 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -92,6 +92,7 @@ typedef struct board_info {
92 u16 tx_pkt_cnt; 92 u16 tx_pkt_cnt;
93 u16 queue_pkt_len; 93 u16 queue_pkt_len;
94 u16 queue_start_addr; 94 u16 queue_start_addr;
95 u16 queue_ip_summed;
95 u16 dbug_cnt; 96 u16 dbug_cnt;
96 u8 io_mode; /* 0:word, 2:byte */ 97 u8 io_mode; /* 0:word, 2:byte */
97 u8 phy_addr; 98 u8 phy_addr;
@@ -124,6 +125,10 @@ typedef struct board_info {
124 125
125 struct mii_if_info mii; 126 struct mii_if_info mii;
126 u32 msg_enable; 127 u32 msg_enable;
128
129 int rx_csum;
130 int can_csum;
131 int ip_summed;
127} board_info_t; 132} board_info_t;
128 133
129/* debug code */ 134/* debug code */
@@ -460,6 +465,40 @@ static int dm9000_nway_reset(struct net_device *dev)
460 return mii_nway_restart(&dm->mii); 465 return mii_nway_restart(&dm->mii);
461} 466}
462 467
468static uint32_t dm9000_get_rx_csum(struct net_device *dev)
469{
470 board_info_t *dm = to_dm9000_board(dev);
471 return dm->rx_csum;
472}
473
474static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data)
475{
476 board_info_t *dm = to_dm9000_board(dev);
477 unsigned long flags;
478
479 if (dm->can_csum) {
480 dm->rx_csum = data;
481
482 spin_lock_irqsave(&dm->lock, flags);
483 iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0);
484 spin_unlock_irqrestore(&dm->lock, flags);
485
486 return 0;
487 }
488
489 return -EOPNOTSUPP;
490}
491
492static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data)
493{
494 board_info_t *dm = to_dm9000_board(dev);
495 int ret = -EOPNOTSUPP;
496
497 if (dm->can_csum)
498 ret = ethtool_op_set_tx_csum(dev, data);
499 return ret;
500}
501
463static u32 dm9000_get_link(struct net_device *dev) 502static u32 dm9000_get_link(struct net_device *dev)
464{ 503{
465 board_info_t *dm = to_dm9000_board(dev); 504 board_info_t *dm = to_dm9000_board(dev);
@@ -540,6 +579,10 @@ static const struct ethtool_ops dm9000_ethtool_ops = {
540 .get_eeprom_len = dm9000_get_eeprom_len, 579 .get_eeprom_len = dm9000_get_eeprom_len,
541 .get_eeprom = dm9000_get_eeprom, 580 .get_eeprom = dm9000_get_eeprom,
542 .set_eeprom = dm9000_set_eeprom, 581 .set_eeprom = dm9000_set_eeprom,
582 .get_rx_csum = dm9000_get_rx_csum,
583 .set_rx_csum = dm9000_set_rx_csum,
584 .get_tx_csum = ethtool_op_get_tx_csum,
585 .set_tx_csum = dm9000_set_tx_csum,
543}; 586};
544 587
545static void dm9000_show_carrier(board_info_t *db, 588static void dm9000_show_carrier(board_info_t *db,
@@ -685,6 +728,9 @@ dm9000_init_dm9000(struct net_device *dev)
685 /* I/O mode */ 728 /* I/O mode */
686 db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ 729 db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */
687 730
731 /* Checksum mode */
732 dm9000_set_rx_csum(dev, db->rx_csum);
733
688 /* GPIO0 on pre-activate PHY */ 734 /* GPIO0 on pre-activate PHY */
689 iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */ 735 iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
690 iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ 736 iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */
@@ -743,6 +789,29 @@ static void dm9000_timeout(struct net_device *dev)
743 spin_unlock_irqrestore(&db->lock, flags); 789 spin_unlock_irqrestore(&db->lock, flags);
744} 790}
745 791
792static void dm9000_send_packet(struct net_device *dev,
793 int ip_summed,
794 u16 pkt_len)
795{
796 board_info_t *dm = to_dm9000_board(dev);
797
798 /* The DM9000 is not smart enough to leave fragmented packets alone. */
799 if (dm->ip_summed != ip_summed) {
800 if (ip_summed == CHECKSUM_NONE)
801 iow(dm, DM9000_TCCR, 0);
802 else
803 iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);
804 dm->ip_summed = ip_summed;
805 }
806
807 /* Set TX length to DM9000 */
808 iow(dm, DM9000_TXPLL, pkt_len);
809 iow(dm, DM9000_TXPLH, pkt_len >> 8);
810
811 /* Issue TX polling command */
812 iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
813}
814
746/* 815/*
747 * Hardware start transmission. 816 * Hardware start transmission.
748 * Send a packet to media from the upper layer. 817 * Send a packet to media from the upper layer.
@@ -769,17 +838,11 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
769 db->tx_pkt_cnt++; 838 db->tx_pkt_cnt++;
770 /* TX control: First packet immediately send, second packet queue */ 839 /* TX control: First packet immediately send, second packet queue */
771 if (db->tx_pkt_cnt == 1) { 840 if (db->tx_pkt_cnt == 1) {
772 /* Set TX length to DM9000 */ 841 dm9000_send_packet(dev, skb->ip_summed, skb->len);
773 iow(db, DM9000_TXPLL, skb->len);
774 iow(db, DM9000_TXPLH, skb->len >> 8);
775
776 /* Issue TX polling command */
777 iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
778
779 dev->trans_start = jiffies; /* save the time stamp */
780 } else { 842 } else {
781 /* Second packet */ 843 /* Second packet */
782 db->queue_pkt_len = skb->len; 844 db->queue_pkt_len = skb->len;
845 db->queue_ip_summed = skb->ip_summed;
783 netif_stop_queue(dev); 846 netif_stop_queue(dev);
784 } 847 }
785 848
@@ -809,12 +872,9 @@ static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
809 dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status); 872 dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);
810 873
811 /* Queue packet check & send */ 874 /* Queue packet check & send */
812 if (db->tx_pkt_cnt > 0) { 875 if (db->tx_pkt_cnt > 0)
813 iow(db, DM9000_TXPLL, db->queue_pkt_len); 876 dm9000_send_packet(dev, db->queue_ip_summed,
814 iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8); 877 db->queue_pkt_len);
815 iow(db, DM9000_TCR, TCR_TXREQ);
816 dev->trans_start = jiffies;
817 }
818 netif_wake_queue(dev); 878 netif_wake_queue(dev);
819 } 879 }
820} 880}
@@ -846,14 +906,14 @@ dm9000_rx(struct net_device *dev)
846 rxbyte = readb(db->io_data); 906 rxbyte = readb(db->io_data);
847 907
848 /* Status check: this byte must be 0 or 1 */ 908 /* Status check: this byte must be 0 or 1 */
849 if (rxbyte > DM9000_PKT_RDY) { 909 if (rxbyte & DM9000_PKT_ERR) {
850 dev_warn(db->dev, "status check fail: %d\n", rxbyte); 910 dev_warn(db->dev, "status check fail: %d\n", rxbyte);
851 iow(db, DM9000_RCR, 0x00); /* Stop Device */ 911 iow(db, DM9000_RCR, 0x00); /* Stop Device */
852 iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */ 912 iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */
853 return; 913 return;
854 } 914 }
855 915
856 if (rxbyte != DM9000_PKT_RDY) 916 if (!(rxbyte & DM9000_PKT_RDY))
857 return; 917 return;
858 918
859 /* A packet ready now & Get status/length */ 919 /* A packet ready now & Get status/length */
@@ -914,6 +974,12 @@ dm9000_rx(struct net_device *dev)
914 974
915 /* Pass to upper layer */ 975 /* Pass to upper layer */
916 skb->protocol = eth_type_trans(skb, dev); 976 skb->protocol = eth_type_trans(skb, dev);
977 if (db->rx_csum) {
978 if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
979 skb->ip_summed = CHECKSUM_UNNECESSARY;
980 else
981 skb->ip_summed = CHECKSUM_NONE;
982 }
917 netif_rx(skb); 983 netif_rx(skb);
918 dev->stats.rx_packets++; 984 dev->stats.rx_packets++;
919 985
@@ -922,7 +988,7 @@ dm9000_rx(struct net_device *dev)
922 988
923 (db->dumpblk)(db->io_data, RxLen); 989 (db->dumpblk)(db->io_data, RxLen);
924 } 990 }
925 } while (rxbyte == DM9000_PKT_RDY); 991 } while (rxbyte & DM9000_PKT_RDY);
926} 992}
927 993
928static irqreturn_t dm9000_interrupt(int irq, void *dev_id) 994static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
@@ -1349,6 +1415,13 @@ dm9000_probe(struct platform_device *pdev)
1349 db->type = TYPE_DM9000E; 1415 db->type = TYPE_DM9000E;
1350 } 1416 }
1351 1417
1418 /* dm9000a/b are capable of hardware checksum offload */
1419 if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) {
1420 db->can_csum = 1;
1421 db->rx_csum = 1;
1422 ndev->features |= NETIF_F_IP_CSUM;
1423 }
1424
1352 /* from this point we assume that we have found a DM9000 */ 1425 /* from this point we assume that we have found a DM9000 */
1353 1426
1354 /* driver system function */ 1427 /* driver system function */