Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
[cascardo/linux.git] / drivers / s390 / net / qeth_l3_main.c
index fc6ca1d..61adae2 100644 (file)
@@ -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;
 }