enum qeth_header_ids {
        QETH_HEADER_TYPE_LAYER3 = 0x01,
        QETH_HEADER_TYPE_LAYER2 = 0x02,
-       QETH_HEADER_TYPE_TSO    = 0x03,
+       QETH_HEADER_TYPE_L3_TSO = 0x03,
        QETH_HEADER_TYPE_OSN    = 0x04,
+       QETH_HEADER_TYPE_L2_TSO = 0x06,
 };
 /* flags for qeth_hdr.ext_flags */
 #define QETH_HDR_EXT_VLAN_FRAME       0x01
 
                                struct sk_buff *skb, int ipv, int cast_type,
                                unsigned int data_len)
 {
-       struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb);
+       struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
 
-       hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2;
        hdr->hdr.l2.pkt_length = data_len;
 
-       if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], ipv);
-               if (card->options.performance_stats)
-                       card->perf_stats.tx_csum++;
+       if (skb_is_gso(skb)) {
+               hdr->hdr.l2.id = QETH_HEADER_TYPE_L2_TSO;
+       } else {
+               hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2;
+               if (skb->ip_summed == CHECKSUM_PARTIAL) {
+                       qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], ipv);
+                       if (card->options.performance_stats)
+                               card->perf_stats.tx_csum++;
+               }
        }
 
        /* set byte byte 3 to casting flags */
                card->dev->hw_features |= NETIF_F_RXCSUM;
                card->dev->vlan_features |= NETIF_F_RXCSUM;
        }
+       if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
+               card->dev->hw_features |= NETIF_F_TSO;
+               card->dev->vlan_features |= NETIF_F_TSO;
+       }
+       if (qeth_is_supported6(card, IPA_OUTBOUND_TSO)) {
+               card->dev->hw_features |= NETIF_F_TSO6;
+               card->dev->vlan_features |= NETIF_F_TSO6;
+       }
+
+       if (card->dev->hw_features & (NETIF_F_TSO | NETIF_F_TSO6)) {
+               card->dev->needed_headroom = sizeof(struct qeth_hdr_tso);
+               netif_set_gso_max_size(card->dev,
+                                      PAGE_SIZE * (QDIO_MAX_ELEMENTS_PER_BUFFER - 1));
+       }
 
        qeth_l2_request_initial_mac(card);
        netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT);