qeth: add layer 2 RX/TX checksum offloading
Checksum offloading for send and receive is already supported for layer 3 (IP layer). This patch adds support for RX and TX hardware checksum offloading for layer 2 (MAC layer). The hardware calculates the checksum for IP UDP and TCP packets. This patch moves the hardware checksum offloading setup to the set of common functions in qeth_core_main.c. Layer 2 and layer 3 now simply call the same common functions. Also note that TX checksum offloading is always enabled. The device driver relies on the TCP/IP stack to make use of this feature. Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com> Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com> Reviewed-by: Eugene Crosser <Eugene.Crosser@ru.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
239ff408dd
commit
4d7def2a12
@@ -252,6 +252,23 @@ static inline int qeth_l2_get_cast_type(struct qeth_card *card,
|
||||
return RTN_UNSPEC;
|
||||
}
|
||||
|
||||
static inline void qeth_l2_hdr_csum(struct qeth_card *card,
|
||||
struct qeth_hdr *hdr, struct sk_buff *skb)
|
||||
{
|
||||
struct iphdr *iph = ip_hdr(skb);
|
||||
|
||||
/* tcph->check contains already the pseudo hdr checksum
|
||||
* so just set the header flags
|
||||
*/
|
||||
if (iph->protocol == IPPROTO_UDP)
|
||||
hdr->hdr.l2.flags[1] |= QETH_HDR_EXT_UDP;
|
||||
hdr->hdr.l2.flags[1] |= QETH_HDR_EXT_CSUM_TRANSP_REQ |
|
||||
QETH_HDR_EXT_CSUM_HDR_REQ;
|
||||
iph->check = 0;
|
||||
if (card->options.performance_stats)
|
||||
card->perf_stats.tx_csum++;
|
||||
}
|
||||
|
||||
static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
|
||||
struct sk_buff *skb, int cast_type)
|
||||
{
|
||||
@@ -390,6 +407,38 @@ static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static netdev_features_t qeth_l2_fix_features(struct net_device *dev,
|
||||
netdev_features_t features)
|
||||
{
|
||||
struct qeth_card *card = dev->ml_priv;
|
||||
|
||||
QETH_DBF_TEXT(SETUP, 2, "fixfeat");
|
||||
if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
|
||||
features &= ~NETIF_F_IP_CSUM;
|
||||
if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM))
|
||||
features &= ~NETIF_F_RXCSUM;
|
||||
QETH_DBF_HEX(SETUP, 2, &features, sizeof(features));
|
||||
return features;
|
||||
}
|
||||
|
||||
static int qeth_l2_set_features(struct net_device *dev,
|
||||
netdev_features_t features)
|
||||
{
|
||||
struct qeth_card *card = dev->ml_priv;
|
||||
netdev_features_t changed = dev->features ^ features;
|
||||
|
||||
QETH_DBF_TEXT(SETUP, 2, "setfeat");
|
||||
QETH_DBF_HEX(SETUP, 2, &features, sizeof(features));
|
||||
|
||||
if (card->state == CARD_STATE_DOWN ||
|
||||
card->state == CARD_STATE_RECOVER)
|
||||
return 0;
|
||||
|
||||
if (!(changed & NETIF_F_RXCSUM))
|
||||
return 0;
|
||||
return qeth_set_rx_csum(card, features & NETIF_F_RXCSUM ? 1 : 0);
|
||||
}
|
||||
|
||||
static void qeth_l2_stop_card(struct qeth_card *card, int recovery_mode)
|
||||
{
|
||||
QETH_DBF_TEXT(SETUP , 2, "stopcard");
|
||||
@@ -450,7 +499,15 @@ static int qeth_l2_process_inbound_buffer(struct qeth_card *card,
|
||||
case QETH_HEADER_TYPE_LAYER2:
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
skb->protocol = eth_type_trans(skb, skb->dev);
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
if ((card->dev->features & NETIF_F_RXCSUM)
|
||||
&& ((hdr->hdr.l2.flags[1] &
|
||||
(QETH_HDR_EXT_CSUM_HDR_REQ |
|
||||
QETH_HDR_EXT_CSUM_TRANSP_REQ)) ==
|
||||
(QETH_HDR_EXT_CSUM_HDR_REQ |
|
||||
QETH_HDR_EXT_CSUM_TRANSP_REQ)))
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
else
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
if (skb->protocol == htons(ETH_P_802_2))
|
||||
*((__u32 *)skb->cb) = ++card->seqno.pkt_seqno;
|
||||
len = skb->len;
|
||||
@@ -803,6 +860,8 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
sizeof(struct qeth_hdr));
|
||||
skb_set_mac_header(new_skb, sizeof(struct qeth_hdr));
|
||||
qeth_l2_fill_header(card, hdr, new_skb, cast_type);
|
||||
if (new_skb->ip_summed == CHECKSUM_PARTIAL)
|
||||
qeth_l2_hdr_csum(card, hdr, new_skb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,6 +1027,8 @@ static const struct net_device_ops qeth_l2_netdev_ops = {
|
||||
.ndo_vlan_rx_add_vid = qeth_l2_vlan_rx_add_vid,
|
||||
.ndo_vlan_rx_kill_vid = qeth_l2_vlan_rx_kill_vid,
|
||||
.ndo_tx_timeout = qeth_tx_timeout,
|
||||
.ndo_fix_features = qeth_l2_fix_features,
|
||||
.ndo_set_features = qeth_l2_set_features
|
||||
};
|
||||
|
||||
static int qeth_l2_setup_netdev(struct qeth_card *card)
|
||||
@@ -997,6 +1058,11 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
|
||||
(card->info.type != QETH_CARD_TYPE_OSN) ?
|
||||
&qeth_l2_ethtool_ops : &qeth_l2_osn_ops;
|
||||
card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
|
||||
if (card->info.type == QETH_CARD_TYPE_OSD && !card->info.guestlan) {
|
||||
card->dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
|
||||
/* Turn on RX offloading per default */
|
||||
card->dev->features |= NETIF_F_RXCSUM;
|
||||
}
|
||||
card->info.broadcast_capable = 1;
|
||||
qeth_l2_request_initial_mac(card);
|
||||
SET_NETDEV_DEV(card->dev, &card->gdev->dev);
|
||||
@@ -1004,6 +1070,17 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
|
||||
return register_netdev(card->dev);
|
||||
}
|
||||
|
||||
static int qeth_l2_start_ipassists(struct qeth_card *card)
|
||||
{
|
||||
/* configure isolation level */
|
||||
if (qeth_set_access_ctrl_online(card, 0))
|
||||
return -ENODEV;
|
||||
if (qeth_is_supported(card, IPA_INBOUND_CHECKSUM))
|
||||
qeth_set_rx_csum(card, 1);
|
||||
qeth_start_ipa_tx_checksum(card);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
|
||||
{
|
||||
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
|
||||
@@ -1069,12 +1146,8 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
|
||||
contin:
|
||||
if ((card->info.type == QETH_CARD_TYPE_OSD) ||
|
||||
(card->info.type == QETH_CARD_TYPE_OSX)) {
|
||||
/* configure isolation level */
|
||||
rc = qeth_set_access_ctrl_online(card, 0);
|
||||
if (rc) {
|
||||
rc = -ENODEV;
|
||||
if (qeth_l2_start_ipassists(card))
|
||||
goto out_remove;
|
||||
}
|
||||
}
|
||||
|
||||
if (card->info.type != QETH_CARD_TYPE_OSN &&
|
||||
@@ -1453,7 +1526,7 @@ static void qeth_bridge_emit_host_event(struct qeth_card *card,
|
||||
}
|
||||
if (code & IPA_ADDR_CHANGE_CODE_MACADDR) {
|
||||
snprintf(str[i], sizeof(str[i]), "MAC=%pM",
|
||||
addr_lnid->mac);
|
||||
addr_lnid->mac);
|
||||
env[i] = str[i]; i++;
|
||||
}
|
||||
snprintf(str[i], sizeof(str[i]), "NTOK_BUSID=%x.%x.%04x",
|
||||
|
Reference in New Issue
Block a user