]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/s390/net/qeth_core_main.c
Merge branch 'smp-hotplug-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / drivers / s390 / net / qeth_core_main.c
index 9806ee046fa557e8681f0a964b4fadc38532dc5a..7dba6c8537a16c18e550f311361b3bdf6231bd38 100644 (file)
@@ -1464,8 +1464,6 @@ static int qeth_setup_card(struct qeth_card *card)
        card->thread_allowed_mask = 0;
        card->thread_running_mask = 0;
        INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread);
-       INIT_LIST_HEAD(&card->ip_list);
-       INIT_LIST_HEAD(card->ip_tbd_list);
        INIT_LIST_HEAD(&card->cmd_waiter_list);
        init_waitqueue_head(&card->wait_q);
        /* initial options */
@@ -1500,11 +1498,6 @@ static struct qeth_card *qeth_alloc_card(void)
        if (!card)
                goto out;
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
-       card->ip_tbd_list = kzalloc(sizeof(struct list_head), GFP_KERNEL);
-       if (!card->ip_tbd_list) {
-               QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
-               goto out_card;
-       }
        if (qeth_setup_channel(&card->read))
                goto out_ip;
        if (qeth_setup_channel(&card->write))
@@ -1517,8 +1510,6 @@ static struct qeth_card *qeth_alloc_card(void)
 out_channel:
        qeth_clean_channel(&card->read);
 out_ip:
-       kfree(card->ip_tbd_list);
-out_card:
        kfree(card);
 out:
        return NULL;
@@ -3757,6 +3748,14 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
 }
 EXPORT_SYMBOL_GPL(qeth_qdio_output_handler);
 
+/* We cannot use outbound queue 3 for unicast packets on HiperSockets */
+static inline int qeth_cut_iqd_prio(struct qeth_card *card, int queue_num)
+{
+       if ((card->info.type == QETH_CARD_TYPE_IQD) && (queue_num == 3))
+               return 2;
+       return queue_num;
+}
+
 /**
  * Note: Function assumes that we have 4 outbound queues.
  */
@@ -3784,9 +3783,9 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
                        return card->qdio.default_out_queue;
                }
                if (card->qdio.do_prio_queueing == QETH_PRIO_Q_ING_PREC)
-                       return ~tos >> 6 & 3;
+                       return qeth_cut_iqd_prio(card, ~tos >> 6 & 3);
                if (tos & IPTOS_MINCOST)
-                       return 3;
+                       return qeth_cut_iqd_prio(card, 3);
                if (tos & IPTOS_RELIABILITY)
                        return 2;
                if (tos & IPTOS_THROUGHPUT)
@@ -3797,11 +3796,12 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
        case QETH_PRIO_Q_ING_SKB:
                if (skb->priority > 5)
                        return 0;
-               return ~skb->priority >> 1 & 3;
+               return qeth_cut_iqd_prio(card, ~skb->priority >> 1 & 3);
        case QETH_PRIO_Q_ING_VLAN:
                tci = &((struct ethhdr *)skb->data)->h_proto;
                if (*tci == ETH_P_8021Q)
-                       return ~*(tci + 1) >> (VLAN_PRIO_SHIFT + 1) & 3;
+                       return qeth_cut_iqd_prio(card, ~*(tci + 1) >>
+                       (VLAN_PRIO_SHIFT + 1) & 3);
                break;
        default:
                break;
@@ -4980,7 +4980,6 @@ static void qeth_core_free_card(struct qeth_card *card)
        qeth_clean_channel(&card->write);
        if (card->dev)
                free_netdev(card->dev);
-       kfree(card->ip_tbd_list);
        qeth_free_qdio_buffers(card);
        unregister_service_level(&card->qeth_service_level);
        kfree(card);
@@ -5278,8 +5277,8 @@ no_mem:
 }
 EXPORT_SYMBOL_GPL(qeth_core_get_next_skb);
 
-static int qeth_setassparms_cb(struct qeth_card *card,
-                              struct qeth_reply *reply, unsigned long data)
+int qeth_setassparms_cb(struct qeth_card *card,
+                       struct qeth_reply *reply, unsigned long data)
 {
        struct qeth_ipa_cmd *cmd;
 
@@ -5307,6 +5306,7 @@ static int qeth_setassparms_cb(struct qeth_card *card,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(qeth_setassparms_cb);
 
 struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *card,
                                                 enum qeth_ipa_funcs ipa_func,
@@ -6063,74 +6063,136 @@ int qeth_core_ethtool_get_settings(struct net_device *netdev,
 }
 EXPORT_SYMBOL_GPL(qeth_core_ethtool_get_settings);
 
-static int qeth_send_checksum_command(struct qeth_card *card)
+static int qeth_send_checksum_on(struct qeth_card *card, int cstype)
 {
+       long rxtx_arg;
        int rc;
 
-       rc = qeth_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM,
-                                         IPA_CMD_ASS_START, 0);
+       rc = qeth_send_simple_setassparms(card, cstype, IPA_CMD_ASS_START, 0);
        if (rc) {
-               dev_warn(&card->gdev->dev, "Starting HW checksumming for %s "
-                       "failed, using SW checksumming\n",
-                       QETH_CARD_IFNAME(card));
+               dev_warn(&card->gdev->dev,
+                        "Starting HW checksumming for %s failed, using SW checksumming\n",
+                        QETH_CARD_IFNAME(card));
                return rc;
        }
-       rc = qeth_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM,
-                                         IPA_CMD_ASS_ENABLE,
-                                         card->info.csum_mask);
+       rxtx_arg = (cstype == IPA_OUTBOUND_CHECKSUM) ? card->info.tx_csum_mask
+                                                    : card->info.csum_mask;
+       rc = qeth_send_simple_setassparms(card, cstype, IPA_CMD_ASS_ENABLE,
+                                         rxtx_arg);
        if (rc) {
-               dev_warn(&card->gdev->dev, "Enabling HW checksumming for %s "
-                       "failed, using SW checksumming\n",
-                       QETH_CARD_IFNAME(card));
+               dev_warn(&card->gdev->dev,
+                        "Enabling HW checksumming for %s failed, using SW checksumming\n",
+                        QETH_CARD_IFNAME(card));
                return rc;
        }
+
+       dev_info(&card->gdev->dev, "HW Checksumming (%sbound) enabled\n",
+                cstype == IPA_INBOUND_CHECKSUM ? "in" : "out");
        return 0;
 }
 
-int qeth_set_rx_csum(struct qeth_card *card, int on)
+static int qeth_set_ipa_csum(struct qeth_card *card, int on, int cstype)
 {
        int rc;
 
        if (on) {
-               rc = qeth_send_checksum_command(card);
+               rc = qeth_send_checksum_on(card, cstype);
                if (rc)
                        return -EIO;
-               dev_info(&card->gdev->dev,
-                       "HW Checksumming (inbound) enabled\n");
        } else {
-               rc = qeth_send_simple_setassparms(card,
-                       IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0);
+               rc = qeth_send_simple_setassparms(card, cstype,
+                                                 IPA_CMD_ASS_STOP, 0);
                if (rc)
                        return -EIO;
        }
        return 0;
 }
-EXPORT_SYMBOL_GPL(qeth_set_rx_csum);
 
-int qeth_start_ipa_tx_checksum(struct qeth_card *card)
+static int qeth_set_ipa_tso(struct qeth_card *card, int on)
 {
-       int rc = 0;
+       int rc;
 
-       if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
-               return rc;
-       rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_CHECKSUM,
-                                         IPA_CMD_ASS_START, 0);
-       if (rc)
-               goto err_out;
-       rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_CHECKSUM,
-                                         IPA_CMD_ASS_ENABLE,
-                                         card->info.tx_csum_mask);
-       if (rc)
-               goto err_out;
+       QETH_CARD_TEXT(card, 3, "sttso");
 
-       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));
+       if (on) {
+               rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_TSO,
+                                                 IPA_CMD_ASS_START, 0);
+               if (rc) {
+                       dev_warn(&card->gdev->dev,
+                                "Starting outbound TCP segmentation offload for %s failed\n",
+                                QETH_CARD_IFNAME(card));
+                       return -EIO;
+               }
+               dev_info(&card->gdev->dev, "Outbound TSO enabled\n");
+       } else {
+               rc = qeth_send_simple_setassparms(card, IPA_OUTBOUND_TSO,
+                                                 IPA_CMD_ASS_STOP, 0);
+       }
        return rc;
 }
-EXPORT_SYMBOL_GPL(qeth_start_ipa_tx_checksum);
+
+int qeth_set_features(struct net_device *dev, netdev_features_t features)
+{
+       struct qeth_card *card = dev->ml_priv;
+       netdev_features_t changed = dev->features ^ features;
+       int rc = 0;
+
+       QETH_DBF_TEXT(SETUP, 2, "setfeat");
+       QETH_DBF_HEX(SETUP, 2, &features, sizeof(features));
+
+       if ((changed & NETIF_F_IP_CSUM)) {
+               rc = qeth_set_ipa_csum(card,
+                                      features & NETIF_F_IP_CSUM ? 1 : 0,
+                                      IPA_OUTBOUND_CHECKSUM);
+               if (rc)
+                       changed ^= NETIF_F_IP_CSUM;
+       }
+       if ((changed & NETIF_F_RXCSUM)) {
+               rc = qeth_set_ipa_csum(card,
+                                       features & NETIF_F_RXCSUM ? 1 : 0,
+                                       IPA_INBOUND_CHECKSUM);
+               if (rc)
+                       changed ^= NETIF_F_RXCSUM;
+       }
+       if ((changed & NETIF_F_TSO)) {
+               rc = qeth_set_ipa_tso(card, features & NETIF_F_TSO ? 1 : 0);
+               if (rc)
+                       changed ^= NETIF_F_TSO;
+       }
+
+       /* everything changed successfully? */
+       if ((dev->features ^ features) == changed)
+               return 0;
+       /* something went wrong. save changed features and return error */
+       dev->features ^= changed;
+       return -EIO;
+}
+EXPORT_SYMBOL_GPL(qeth_set_features);
+
+netdev_features_t qeth_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;
+       if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
+               features &= ~NETIF_F_TSO;
+               dev_info(&card->gdev->dev, "Outbound TSO not supported on %s\n",
+                        QETH_CARD_IFNAME(card));
+       }
+       /* if the card isn't up, remove features that require hw changes */
+       if (card->state == CARD_STATE_DOWN ||
+           card->state == CARD_STATE_RECOVER)
+               features = features & ~(NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
+                                       NETIF_F_TSO);
+       QETH_DBF_HEX(SETUP, 2, &features, sizeof(features));
+       return features;
+}
+EXPORT_SYMBOL_GPL(qeth_fix_features);
 
 static int __init qeth_core_init(void)
 {