diff options
Diffstat (limited to 'drivers/s390/net/qeth_l3_main.c')
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 108 |
1 files changed, 79 insertions, 29 deletions
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index fc6ca1da8b98..61adae21a464 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -54,16 +54,16 @@ int qeth_l3_set_large_send(struct qeth_card *card, if (card->options.large_send == QETH_LARGE_SEND_TSO) { if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) { card->dev->features |= NETIF_F_TSO | NETIF_F_SG | - NETIF_F_HW_CSUM; + NETIF_F_IP_CSUM; } else { card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | - NETIF_F_HW_CSUM); + NETIF_F_IP_CSUM); card->options.large_send = QETH_LARGE_SEND_NO; rc = -EOPNOTSUPP; } } else { card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | - NETIF_F_HW_CSUM); + NETIF_F_IP_CSUM); card->options.large_send = QETH_LARGE_SEND_NO; } return rc; @@ -1108,6 +1108,13 @@ static int qeth_l3_default_setassparms_cb(struct qeth_card *card, card->info.csum_mask = cmd->data.setassparms.data.flags_32bit; QETH_DBF_TEXT_(TRACE, 3, "csum:%d", card->info.csum_mask); } + if (cmd->data.setassparms.hdr.assist_no == IPA_OUTBOUND_CHECKSUM && + cmd->data.setassparms.hdr.command_code == IPA_CMD_ASS_START) { + card->info.tx_csum_mask = + cmd->data.setassparms.data.flags_32bit; + QETH_DBF_TEXT_(TRACE, 3, "tcsu:%d", card->info.tx_csum_mask); + } + return 0; } @@ -1536,6 +1543,28 @@ static int qeth_l3_start_ipa_checksum(struct qeth_card *card) return rc; } +static int qeth_l3_start_ipa_tx_checksum(struct qeth_card *card) +{ + int rc = 0; + + if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) + return rc; + rc = qeth_l3_send_simple_setassparms(card, IPA_OUTBOUND_CHECKSUM, + IPA_CMD_ASS_START, 0); + if (rc) + goto err_out; + rc = qeth_l3_send_simple_setassparms(card, IPA_OUTBOUND_CHECKSUM, + IPA_CMD_ASS_ENABLE, card->info.tx_csum_mask); + if (rc) + goto err_out; + dev_info(&card->gdev->dev, "HW TX Checksumming enabled\n"); + return rc; +err_out: + dev_warn(&card->gdev->dev, "Enabling HW TX checksumming for %s " + "failed, using SW TX checksumming\n", QETH_CARD_IFNAME(card)); + return rc; +} + static int qeth_l3_start_ipa_tso(struct qeth_card *card) { int rc; @@ -1578,6 +1607,7 @@ static int qeth_l3_start_ipassists(struct qeth_card *card) qeth_l3_start_ipa_ipv6(card); /* go on*/ qeth_l3_start_ipa_broadcast(card); /* go on*/ qeth_l3_start_ipa_checksum(card); /* go on*/ + qeth_l3_start_ipa_tx_checksum(card); qeth_l3_start_ipa_tso(card); /* go on*/ return 0; } @@ -1929,7 +1959,7 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card, in6_dev = in6_dev_get(vlan_group_get_device(card->vlangrp, vid)); if (!in6_dev) return; - for (ifa = in6_dev->addr_list; ifa; ifa = ifa->lst_next) { + list_for_each_entry(ifa, &in6_dev->addr_list, if_list) { addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6); if (addr) { memcpy(&addr->u.a6.addr, &ifa->addr, @@ -2681,7 +2711,8 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) rc = qeth_snmp_command(card, rq->ifr_ifru.ifru_data); break; case SIOC_QETH_GET_CARD_TYPE: - if ((card->info.type == QETH_CARD_TYPE_OSAE) && + if ((card->info.type == QETH_CARD_TYPE_OSD || + card->info.type == QETH_CARD_TYPE_OSX) && !card->info.guestlan) return 1; return 0; @@ -2817,6 +2848,21 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, } } +static inline void qeth_l3_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.l3.ext_flags |= QETH_HDR_EXT_UDP; + hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ; + if (card->options.performance_stats) + card->perf_stats.tx_csum++; +} + static void qeth_tso_fill_header(struct qeth_card *card, struct qeth_hdr *qhdr, struct sk_buff *skb) { @@ -2852,21 +2898,6 @@ static void qeth_tso_fill_header(struct qeth_card *card, } } -static void qeth_tx_csum(struct sk_buff *skb) -{ - __wsum csum; - int offset; - - skb_set_transport_header(skb, skb->csum_start - skb_headroom(skb)); - offset = skb->csum_start - skb_headroom(skb); - BUG_ON(offset >= skb_headlen(skb)); - csum = skb_checksum(skb, offset, skb->len - offset, 0); - - offset += skb->csum_offset; - BUG_ON(offset + sizeof(__sum16) > skb_headlen(skb)); - *(__sum16 *)(skb->data + offset) = csum_fold(csum); -} - static inline int qeth_l3_tso_elements(struct sk_buff *skb) { unsigned long tcpd = (unsigned long)tcp_hdr(skb) + @@ -2923,12 +2954,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb_is_gso(skb)) large_send = card->options.large_send; - else - if (skb->ip_summed == CHECKSUM_PARTIAL) { - qeth_tx_csum(skb); - if (card->options.performance_stats) - card->perf_stats.tx_csum++; - } if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && (skb_shinfo(skb)->nr_frags == 0)) { @@ -3007,6 +3032,9 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) cast_type); hdr->hdr.l3.length = new_skb->len - data_offset; } + + if (skb->ip_summed == CHECKSUM_PARTIAL) + qeth_l3_hdr_csum(card, hdr, new_skb); } elems = qeth_get_elements_no(card, (void *)hdr, new_skb, @@ -3132,10 +3160,25 @@ static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) return rc; } +static int qeth_l3_ethtool_set_tx_csum(struct net_device *dev, u32 data) +{ + struct qeth_card *card = dev->ml_priv; + + if (data) { + if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) + dev->features |= NETIF_F_IP_CSUM; + else + return -EPERM; + } else + dev->features &= ~NETIF_F_IP_CSUM; + + return 0; +} + static const struct ethtool_ops qeth_l3_ethtool_ops = { .get_link = ethtool_op_get_link, .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, + .set_tx_csum = qeth_l3_ethtool_set_tx_csum, .get_rx_csum = qeth_l3_ethtool_get_rx_csum, .set_rx_csum = qeth_l3_ethtool_set_rx_csum, .get_sg = ethtool_op_get_sg, @@ -3206,7 +3249,8 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = { static int qeth_l3_setup_netdev(struct qeth_card *card) { - if (card->info.type == QETH_CARD_TYPE_OSAE) { + if (card->info.type == QETH_CARD_TYPE_OSD || + card->info.type == QETH_CARD_TYPE_OSX) { if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) || (card->info.link_type == QETH_LINK_TYPE_HSTR)) { #ifdef CONFIG_TR @@ -3336,6 +3380,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) enum qeth_card_states recover_flag; BUG_ON(!card); + mutex_lock(&card->conf_mutex); QETH_DBF_TEXT(SETUP, 2, "setonlin"); QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); @@ -3367,7 +3412,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) dev_warn(&card->gdev->dev, "The LAN is offline\n"); card->lan_online = 0; - return 0; + goto out; } rc = -ENODEV; goto out_remove; @@ -3414,6 +3459,8 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) } /* let user_space know that device is online */ kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE); +out: + mutex_unlock(&card->conf_mutex); return 0; out_remove: card->use_hard_stop = 1; @@ -3425,6 +3472,7 @@ out_remove: card->state = CARD_STATE_RECOVER; else card->state = CARD_STATE_DOWN; + mutex_unlock(&card->conf_mutex); return rc; } @@ -3440,6 +3488,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev, int rc = 0, rc2 = 0, rc3 = 0; enum qeth_card_states recover_flag; + mutex_lock(&card->conf_mutex); QETH_DBF_TEXT(SETUP, 3, "setoffl"); QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *)); @@ -3458,6 +3507,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev, card->state = CARD_STATE_RECOVER; /* let user_space know that device is offline */ kobject_uevent(&cgdev->dev.kobj, KOBJ_CHANGE); + mutex_unlock(&card->conf_mutex); return 0; } |