diff options
author | Yeasah Pell <yeasah@comrex.com> | 2009-07-06 21:12:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-07-06 21:54:51 -0400 |
commit | 5dcc60b71886795965fd5029b5d9a9ba7b5a2c17 (patch) | |
tree | 5611d123e03d280bccce73f868451b0bd39dcbe8 /drivers | |
parent | 482d804cb4b520b6e3134c959c968712ebcdea02 (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')
-rw-r--r-- | drivers/net/dm9000.c | 107 | ||||
-rw-r--r-- | drivers/net/dm9000.h | 18 |
2 files changed, 108 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 | ||
468 | static 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 | |||
474 | static 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 | |||
492 | static 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 | |||
463 | static u32 dm9000_get_link(struct net_device *dev) | 502 | static 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 | ||
545 | static void dm9000_show_carrier(board_info_t *db, | 588 | static 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 | ||
792 | static 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 | ||
928 | static irqreturn_t dm9000_interrupt(int irq, void *dev_id) | 994 | static 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 */ |
diff --git a/drivers/net/dm9000.h b/drivers/net/dm9000.h index ba25cf541420..80817c2edfb3 100644 --- a/drivers/net/dm9000.h +++ b/drivers/net/dm9000.h | |||
@@ -45,6 +45,10 @@ | |||
45 | #define DM9000_CHIPR 0x2C | 45 | #define DM9000_CHIPR 0x2C |
46 | #define DM9000_SMCR 0x2F | 46 | #define DM9000_SMCR 0x2F |
47 | 47 | ||
48 | #define DM9000_ETXCSR 0x30 | ||
49 | #define DM9000_TCCR 0x31 | ||
50 | #define DM9000_RCSR 0x32 | ||
51 | |||
48 | #define CHIPR_DM9000A 0x19 | 52 | #define CHIPR_DM9000A 0x19 |
49 | #define CHIPR_DM9000B 0x1B | 53 | #define CHIPR_DM9000B 0x1B |
50 | 54 | ||
@@ -131,7 +135,21 @@ | |||
131 | 135 | ||
132 | #define GPCR_GEP_CNTL (1<<0) | 136 | #define GPCR_GEP_CNTL (1<<0) |
133 | 137 | ||
138 | #define TCCR_IP (1<<0) | ||
139 | #define TCCR_TCP (1<<1) | ||
140 | #define TCCR_UDP (1<<2) | ||
141 | |||
142 | #define RCSR_UDP_BAD (1<<7) | ||
143 | #define RCSR_TCP_BAD (1<<6) | ||
144 | #define RCSR_IP_BAD (1<<5) | ||
145 | #define RCSR_UDP (1<<4) | ||
146 | #define RCSR_TCP (1<<3) | ||
147 | #define RCSR_IP (1<<2) | ||
148 | #define RCSR_CSUM (1<<1) | ||
149 | #define RCSR_DISCARD (1<<0) | ||
150 | |||
134 | #define DM9000_PKT_RDY 0x01 /* Packet ready to receive */ | 151 | #define DM9000_PKT_RDY 0x01 /* Packet ready to receive */ |
152 | #define DM9000_PKT_ERR 0x02 | ||
135 | #define DM9000_PKT_MAX 1536 /* Received packet max size */ | 153 | #define DM9000_PKT_MAX 1536 /* Received packet max size */ |
136 | 154 | ||
137 | /* DM9000A / DM9000B definitions */ | 155 | /* DM9000A / DM9000B definitions */ |