Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Yeasah Pell and committed by
David S. Miller
5dcc60b7 482d804c

+108 -17
+90 -17
drivers/net/dm9000.c
··· 92 92 u16 tx_pkt_cnt; 93 93 u16 queue_pkt_len; 94 94 u16 queue_start_addr; 95 + u16 queue_ip_summed; 95 96 u16 dbug_cnt; 96 97 u8 io_mode; /* 0:word, 2:byte */ 97 98 u8 phy_addr; ··· 125 124 126 125 struct mii_if_info mii; 127 126 u32 msg_enable; 127 + 128 + int rx_csum; 129 + int can_csum; 130 + int ip_summed; 128 131 } board_info_t; 129 132 130 133 /* debug code */ ··· 465 460 return mii_nway_restart(&dm->mii); 466 461 } 467 462 463 + static uint32_t dm9000_get_rx_csum(struct net_device *dev) 464 + { 465 + board_info_t *dm = to_dm9000_board(dev); 466 + return dm->rx_csum; 467 + } 468 + 469 + static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data) 470 + { 471 + board_info_t *dm = to_dm9000_board(dev); 472 + unsigned long flags; 473 + 474 + if (dm->can_csum) { 475 + dm->rx_csum = data; 476 + 477 + spin_lock_irqsave(&dm->lock, flags); 478 + iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0); 479 + spin_unlock_irqrestore(&dm->lock, flags); 480 + 481 + return 0; 482 + } 483 + 484 + return -EOPNOTSUPP; 485 + } 486 + 487 + static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data) 488 + { 489 + board_info_t *dm = to_dm9000_board(dev); 490 + int ret = -EOPNOTSUPP; 491 + 492 + if (dm->can_csum) 493 + ret = ethtool_op_set_tx_csum(dev, data); 494 + return ret; 495 + } 496 + 468 497 static u32 dm9000_get_link(struct net_device *dev) 469 498 { 470 499 board_info_t *dm = to_dm9000_board(dev); ··· 579 540 .get_eeprom_len = dm9000_get_eeprom_len, 580 541 .get_eeprom = dm9000_get_eeprom, 581 542 .set_eeprom = dm9000_set_eeprom, 543 + .get_rx_csum = dm9000_get_rx_csum, 544 + .set_rx_csum = dm9000_set_rx_csum, 545 + .get_tx_csum = ethtool_op_get_tx_csum, 546 + .set_tx_csum = dm9000_set_tx_csum, 582 547 }; 583 548 584 549 static void dm9000_show_carrier(board_info_t *db, ··· 728 685 /* I/O mode */ 729 686 db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ 730 687 688 + /* Checksum mode */ 689 + dm9000_set_rx_csum(dev, db->rx_csum); 690 + 731 691 /* GPIO0 on pre-activate PHY */ 732 692 iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */ 733 693 iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ ··· 789 743 spin_unlock_irqrestore(&db->lock, flags); 790 744 } 791 745 746 + static void dm9000_send_packet(struct net_device *dev, 747 + int ip_summed, 748 + u16 pkt_len) 749 + { 750 + board_info_t *dm = to_dm9000_board(dev); 751 + 752 + /* The DM9000 is not smart enough to leave fragmented packets alone. */ 753 + if (dm->ip_summed != ip_summed) { 754 + if (ip_summed == CHECKSUM_NONE) 755 + iow(dm, DM9000_TCCR, 0); 756 + else 757 + iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP); 758 + dm->ip_summed = ip_summed; 759 + } 760 + 761 + /* Set TX length to DM9000 */ 762 + iow(dm, DM9000_TXPLL, pkt_len); 763 + iow(dm, DM9000_TXPLH, pkt_len >> 8); 764 + 765 + /* Issue TX polling command */ 766 + iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ 767 + } 768 + 792 769 /* 793 770 * Hardware start transmission. 794 771 * Send a packet to media from the upper layer. ··· 838 769 db->tx_pkt_cnt++; 839 770 /* TX control: First packet immediately send, second packet queue */ 840 771 if (db->tx_pkt_cnt == 1) { 841 - /* Set TX length to DM9000 */ 842 - iow(db, DM9000_TXPLL, skb->len); 843 - iow(db, DM9000_TXPLH, skb->len >> 8); 844 - 845 - /* Issue TX polling command */ 846 - iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ 847 - 848 - dev->trans_start = jiffies; /* save the time stamp */ 772 + dm9000_send_packet(dev, skb->ip_summed, skb->len); 849 773 } else { 850 774 /* Second packet */ 851 775 db->queue_pkt_len = skb->len; 776 + db->queue_ip_summed = skb->ip_summed; 852 777 netif_stop_queue(dev); 853 778 } 854 779 ··· 872 809 dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status); 873 810 874 811 /* Queue packet check & send */ 875 - if (db->tx_pkt_cnt > 0) { 876 - iow(db, DM9000_TXPLL, db->queue_pkt_len); 877 - iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8); 878 - iow(db, DM9000_TCR, TCR_TXREQ); 879 - dev->trans_start = jiffies; 880 - } 812 + if (db->tx_pkt_cnt > 0) 813 + dm9000_send_packet(dev, db->queue_ip_summed, 814 + db->queue_pkt_len); 881 815 netif_wake_queue(dev); 882 816 } 883 817 } ··· 906 846 rxbyte = readb(db->io_data); 907 847 908 848 /* Status check: this byte must be 0 or 1 */ 909 - if (rxbyte > DM9000_PKT_RDY) { 849 + if (rxbyte & DM9000_PKT_ERR) { 910 850 dev_warn(db->dev, "status check fail: %d\n", rxbyte); 911 851 iow(db, DM9000_RCR, 0x00); /* Stop Device */ 912 852 iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */ 913 853 return; 914 854 } 915 855 916 - if (rxbyte != DM9000_PKT_RDY) 856 + if (!(rxbyte & DM9000_PKT_RDY)) 917 857 return; 918 858 919 859 /* A packet ready now & Get status/length */ ··· 974 914 975 915 /* Pass to upper layer */ 976 916 skb->protocol = eth_type_trans(skb, dev); 917 + if (db->rx_csum) { 918 + if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0) 919 + skb->ip_summed = CHECKSUM_UNNECESSARY; 920 + else 921 + skb->ip_summed = CHECKSUM_NONE; 922 + } 977 923 netif_rx(skb); 978 924 dev->stats.rx_packets++; 979 925 ··· 988 922 989 923 (db->dumpblk)(db->io_data, RxLen); 990 924 } 991 - } while (rxbyte == DM9000_PKT_RDY); 925 + } while (rxbyte & DM9000_PKT_RDY); 992 926 } 993 927 994 928 static irqreturn_t dm9000_interrupt(int irq, void *dev_id) ··· 1413 1347 default: 1414 1348 dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val); 1415 1349 db->type = TYPE_DM9000E; 1350 + } 1351 + 1352 + /* dm9000a/b are capable of hardware checksum offload */ 1353 + if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) { 1354 + db->can_csum = 1; 1355 + db->rx_csum = 1; 1356 + ndev->features |= NETIF_F_IP_CSUM; 1416 1357 } 1417 1358 1418 1359 /* from this point we assume that we have found a DM9000 */
+18
drivers/net/dm9000.h
··· 45 45 #define DM9000_CHIPR 0x2C 46 46 #define DM9000_SMCR 0x2F 47 47 48 + #define DM9000_ETXCSR 0x30 49 + #define DM9000_TCCR 0x31 50 + #define DM9000_RCSR 0x32 51 + 48 52 #define CHIPR_DM9000A 0x19 49 53 #define CHIPR_DM9000B 0x1B 50 54 ··· 135 131 136 132 #define GPCR_GEP_CNTL (1<<0) 137 133 134 + #define TCCR_IP (1<<0) 135 + #define TCCR_TCP (1<<1) 136 + #define TCCR_UDP (1<<2) 137 + 138 + #define RCSR_UDP_BAD (1<<7) 139 + #define RCSR_TCP_BAD (1<<6) 140 + #define RCSR_IP_BAD (1<<5) 141 + #define RCSR_UDP (1<<4) 142 + #define RCSR_TCP (1<<3) 143 + #define RCSR_IP (1<<2) 144 + #define RCSR_CSUM (1<<1) 145 + #define RCSR_DISCARD (1<<0) 146 + 138 147 #define DM9000_PKT_RDY 0x01 /* Packet ready to receive */ 148 + #define DM9000_PKT_ERR 0x02 139 149 #define DM9000_PKT_MAX 1536 /* Received packet max size */ 140 150 141 151 /* DM9000A / DM9000B definitions */