diff options
Diffstat (limited to 'drivers/s390/net/qeth_l3_main.c')
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 144 |
1 files changed, 98 insertions, 46 deletions
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 073b6d35491..fd1b6ed3721 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -41,6 +41,32 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *, | |||
41 | static int __qeth_l3_set_online(struct ccwgroup_device *, int); | 41 | static int __qeth_l3_set_online(struct ccwgroup_device *, int); |
42 | static int __qeth_l3_set_offline(struct ccwgroup_device *, int); | 42 | static int __qeth_l3_set_offline(struct ccwgroup_device *, int); |
43 | 43 | ||
44 | int qeth_l3_set_large_send(struct qeth_card *card, | ||
45 | enum qeth_large_send_types type) | ||
46 | { | ||
47 | int rc = 0; | ||
48 | |||
49 | card->options.large_send = type; | ||
50 | if (card->dev == NULL) | ||
51 | return 0; | ||
52 | |||
53 | if (card->options.large_send == QETH_LARGE_SEND_TSO) { | ||
54 | if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) { | ||
55 | card->dev->features |= NETIF_F_TSO | NETIF_F_SG | | ||
56 | NETIF_F_HW_CSUM; | ||
57 | } else { | ||
58 | card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | | ||
59 | NETIF_F_HW_CSUM); | ||
60 | card->options.large_send = QETH_LARGE_SEND_NO; | ||
61 | rc = -EOPNOTSUPP; | ||
62 | } | ||
63 | } else { | ||
64 | card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | | ||
65 | NETIF_F_HW_CSUM); | ||
66 | card->options.large_send = QETH_LARGE_SEND_NO; | ||
67 | } | ||
68 | return rc; | ||
69 | } | ||
44 | 70 | ||
45 | static int qeth_l3_isxdigit(char *buf) | 71 | static int qeth_l3_isxdigit(char *buf) |
46 | { | 72 | { |
@@ -1439,6 +1465,35 @@ static int qeth_l3_send_checksum_command(struct qeth_card *card) | |||
1439 | return 0; | 1465 | return 0; |
1440 | } | 1466 | } |
1441 | 1467 | ||
1468 | int qeth_l3_set_rx_csum(struct qeth_card *card, | ||
1469 | enum qeth_checksum_types csum_type) | ||
1470 | { | ||
1471 | int rc = 0; | ||
1472 | |||
1473 | if (card->options.checksum_type == HW_CHECKSUMMING) { | ||
1474 | if ((csum_type != HW_CHECKSUMMING) && | ||
1475 | (card->state != CARD_STATE_DOWN)) { | ||
1476 | rc = qeth_l3_send_simple_setassparms(card, | ||
1477 | IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0); | ||
1478 | if (rc) | ||
1479 | return -EIO; | ||
1480 | } | ||
1481 | } else { | ||
1482 | if (csum_type == HW_CHECKSUMMING) { | ||
1483 | if (card->state != CARD_STATE_DOWN) { | ||
1484 | if (!qeth_is_supported(card, | ||
1485 | IPA_INBOUND_CHECKSUM)) | ||
1486 | return -EPERM; | ||
1487 | rc = qeth_l3_send_checksum_command(card); | ||
1488 | if (rc) | ||
1489 | return -EIO; | ||
1490 | } | ||
1491 | } | ||
1492 | } | ||
1493 | card->options.checksum_type = csum_type; | ||
1494 | return rc; | ||
1495 | } | ||
1496 | |||
1442 | static int qeth_l3_start_ipa_checksum(struct qeth_card *card) | 1497 | static int qeth_l3_start_ipa_checksum(struct qeth_card *card) |
1443 | { | 1498 | { |
1444 | int rc = 0; | 1499 | int rc = 0; |
@@ -1506,6 +1561,8 @@ static int qeth_l3_start_ipa_tso(struct qeth_card *card) | |||
1506 | static int qeth_l3_start_ipassists(struct qeth_card *card) | 1561 | static int qeth_l3_start_ipassists(struct qeth_card *card) |
1507 | { | 1562 | { |
1508 | QETH_DBF_TEXT(TRACE, 3, "strtipas"); | 1563 | QETH_DBF_TEXT(TRACE, 3, "strtipas"); |
1564 | |||
1565 | qeth_set_access_ctrl_online(card); /* go on*/ | ||
1509 | qeth_l3_start_ipa_arp_processing(card); /* go on*/ | 1566 | qeth_l3_start_ipa_arp_processing(card); /* go on*/ |
1510 | qeth_l3_start_ipa_ip_fragmentation(card); /* go on*/ | 1567 | qeth_l3_start_ipa_ip_fragmentation(card); /* go on*/ |
1511 | qeth_l3_start_ipa_source_mac(card); /* go on*/ | 1568 | qeth_l3_start_ipa_source_mac(card); /* go on*/ |
@@ -2684,6 +2741,24 @@ static void qeth_tx_csum(struct sk_buff *skb) | |||
2684 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); | 2741 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); |
2685 | } | 2742 | } |
2686 | 2743 | ||
2744 | static inline int qeth_l3_tso_elements(struct sk_buff *skb) | ||
2745 | { | ||
2746 | unsigned long tcpd = (unsigned long)tcp_hdr(skb) + | ||
2747 | tcp_hdr(skb)->doff * 4; | ||
2748 | int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data); | ||
2749 | int elements = PFN_UP(tcpd + tcpd_len) - PFN_DOWN(tcpd); | ||
2750 | elements += skb_shinfo(skb)->nr_frags; | ||
2751 | return elements; | ||
2752 | } | ||
2753 | |||
2754 | static inline int qeth_l3_tso_check(struct sk_buff *skb) | ||
2755 | { | ||
2756 | int len = ((unsigned long)tcp_hdr(skb) + tcp_hdr(skb)->doff * 4) - | ||
2757 | (unsigned long)skb->data; | ||
2758 | return (((unsigned long)skb->data & PAGE_MASK) != | ||
2759 | (((unsigned long)skb->data + len) & PAGE_MASK)); | ||
2760 | } | ||
2761 | |||
2687 | static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | 2762 | static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) |
2688 | { | 2763 | { |
2689 | int rc; | 2764 | int rc; |
@@ -2777,16 +2852,21 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2777 | /* fix hardware limitation: as long as we do not have sbal | 2852 | /* fix hardware limitation: as long as we do not have sbal |
2778 | * chaining we can not send long frag lists | 2853 | * chaining we can not send long frag lists |
2779 | */ | 2854 | */ |
2780 | if ((large_send == QETH_LARGE_SEND_TSO) && | 2855 | if (large_send == QETH_LARGE_SEND_TSO) { |
2781 | ((skb_shinfo(new_skb)->nr_frags + 2) > 16)) { | 2856 | if (qeth_l3_tso_elements(new_skb) + 1 > 16) { |
2782 | if (skb_linearize(new_skb)) | 2857 | if (skb_linearize(new_skb)) |
2783 | goto tx_drop; | 2858 | goto tx_drop; |
2859 | if (card->options.performance_stats) | ||
2860 | card->perf_stats.tx_lin++; | ||
2861 | } | ||
2784 | } | 2862 | } |
2785 | 2863 | ||
2786 | if ((large_send == QETH_LARGE_SEND_TSO) && | 2864 | if ((large_send == QETH_LARGE_SEND_TSO) && |
2787 | (cast_type == RTN_UNSPEC)) { | 2865 | (cast_type == RTN_UNSPEC)) { |
2788 | hdr = (struct qeth_hdr *)skb_push(new_skb, | 2866 | hdr = (struct qeth_hdr *)skb_push(new_skb, |
2789 | sizeof(struct qeth_hdr_tso)); | 2867 | sizeof(struct qeth_hdr_tso)); |
2868 | if (qeth_l3_tso_check(new_skb)) | ||
2869 | QETH_DBF_MESSAGE(2, "tso skb misaligned\n"); | ||
2790 | memset(hdr, 0, sizeof(struct qeth_hdr_tso)); | 2870 | memset(hdr, 0, sizeof(struct qeth_hdr_tso)); |
2791 | qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); | 2871 | qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); |
2792 | qeth_tso_fill_header(card, hdr, new_skb); | 2872 | qeth_tso_fill_header(card, hdr, new_skb); |
@@ -2903,46 +2983,28 @@ static u32 qeth_l3_ethtool_get_rx_csum(struct net_device *dev) | |||
2903 | static int qeth_l3_ethtool_set_rx_csum(struct net_device *dev, u32 data) | 2983 | static int qeth_l3_ethtool_set_rx_csum(struct net_device *dev, u32 data) |
2904 | { | 2984 | { |
2905 | struct qeth_card *card = dev->ml_priv; | 2985 | struct qeth_card *card = dev->ml_priv; |
2906 | enum qeth_card_states old_state; | ||
2907 | enum qeth_checksum_types csum_type; | 2986 | enum qeth_checksum_types csum_type; |
2908 | 2987 | ||
2909 | if ((card->state != CARD_STATE_UP) && | ||
2910 | (card->state != CARD_STATE_DOWN)) | ||
2911 | return -EPERM; | ||
2912 | |||
2913 | if (data) | 2988 | if (data) |
2914 | csum_type = HW_CHECKSUMMING; | 2989 | csum_type = HW_CHECKSUMMING; |
2915 | else | 2990 | else |
2916 | csum_type = SW_CHECKSUMMING; | 2991 | csum_type = SW_CHECKSUMMING; |
2917 | 2992 | ||
2918 | if (card->options.checksum_type != csum_type) { | 2993 | return qeth_l3_set_rx_csum(card, csum_type); |
2919 | old_state = card->state; | ||
2920 | if (card->state == CARD_STATE_UP) | ||
2921 | __qeth_l3_set_offline(card->gdev, 1); | ||
2922 | card->options.checksum_type = csum_type; | ||
2923 | if (old_state == CARD_STATE_UP) | ||
2924 | __qeth_l3_set_online(card->gdev, 1); | ||
2925 | } | ||
2926 | return 0; | ||
2927 | } | 2994 | } |
2928 | 2995 | ||
2929 | static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) | 2996 | static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) |
2930 | { | 2997 | { |
2931 | struct qeth_card *card = dev->ml_priv; | 2998 | struct qeth_card *card = dev->ml_priv; |
2999 | int rc = 0; | ||
2932 | 3000 | ||
2933 | if (data) { | 3001 | if (data) { |
2934 | if (card->options.large_send == QETH_LARGE_SEND_NO) { | 3002 | rc = qeth_l3_set_large_send(card, QETH_LARGE_SEND_TSO); |
2935 | if (card->info.type == QETH_CARD_TYPE_IQD) | ||
2936 | return -EPERM; | ||
2937 | else | ||
2938 | card->options.large_send = QETH_LARGE_SEND_TSO; | ||
2939 | dev->features |= NETIF_F_TSO; | ||
2940 | } | ||
2941 | } else { | 3003 | } else { |
2942 | dev->features &= ~NETIF_F_TSO; | 3004 | dev->features &= ~NETIF_F_TSO; |
2943 | card->options.large_send = QETH_LARGE_SEND_NO; | 3005 | card->options.large_send = QETH_LARGE_SEND_NO; |
2944 | } | 3006 | } |
2945 | return 0; | 3007 | return rc; |
2946 | } | 3008 | } |
2947 | 3009 | ||
2948 | static const struct ethtool_ops qeth_l3_ethtool_ops = { | 3010 | static const struct ethtool_ops qeth_l3_ethtool_ops = { |
@@ -2957,7 +3019,7 @@ static const struct ethtool_ops qeth_l3_ethtool_ops = { | |||
2957 | .set_tso = qeth_l3_ethtool_set_tso, | 3019 | .set_tso = qeth_l3_ethtool_set_tso, |
2958 | .get_strings = qeth_core_get_strings, | 3020 | .get_strings = qeth_core_get_strings, |
2959 | .get_ethtool_stats = qeth_core_get_ethtool_stats, | 3021 | .get_ethtool_stats = qeth_core_get_ethtool_stats, |
2960 | .get_stats_count = qeth_core_get_stats_count, | 3022 | .get_sset_count = qeth_core_get_sset_count, |
2961 | .get_drvinfo = qeth_core_get_drvinfo, | 3023 | .get_drvinfo = qeth_core_get_drvinfo, |
2962 | .get_settings = qeth_core_ethtool_get_settings, | 3024 | .get_settings = qeth_core_ethtool_get_settings, |
2963 | }; | 3025 | }; |
@@ -3058,6 +3120,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) | |||
3058 | NETIF_F_HW_VLAN_RX | | 3120 | NETIF_F_HW_VLAN_RX | |
3059 | NETIF_F_HW_VLAN_FILTER; | 3121 | NETIF_F_HW_VLAN_FILTER; |
3060 | card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | 3122 | card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; |
3123 | card->dev->gso_max_size = 15 * PAGE_SIZE; | ||
3061 | 3124 | ||
3062 | SET_NETDEV_DEV(card->dev, &card->gdev->dev); | 3125 | SET_NETDEV_DEV(card->dev, &card->gdev->dev); |
3063 | return register_netdev(card->dev); | 3126 | return register_netdev(card->dev); |
@@ -3154,32 +3217,19 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
3154 | qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1); | 3217 | qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1); |
3155 | 3218 | ||
3156 | recover_flag = card->state; | 3219 | recover_flag = card->state; |
3157 | rc = ccw_device_set_online(CARD_RDEV(card)); | ||
3158 | if (rc) { | ||
3159 | QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); | ||
3160 | return -EIO; | ||
3161 | } | ||
3162 | rc = ccw_device_set_online(CARD_WDEV(card)); | ||
3163 | if (rc) { | ||
3164 | QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); | ||
3165 | return -EIO; | ||
3166 | } | ||
3167 | rc = ccw_device_set_online(CARD_DDEV(card)); | ||
3168 | if (rc) { | ||
3169 | QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); | ||
3170 | return -EIO; | ||
3171 | } | ||
3172 | |||
3173 | rc = qeth_core_hardsetup_card(card); | 3220 | rc = qeth_core_hardsetup_card(card); |
3174 | if (rc) { | 3221 | if (rc) { |
3175 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); | 3222 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); |
3223 | rc = -ENODEV; | ||
3176 | goto out_remove; | 3224 | goto out_remove; |
3177 | } | 3225 | } |
3178 | 3226 | ||
3179 | qeth_l3_query_ipassists(card, QETH_PROT_IPV4); | 3227 | qeth_l3_query_ipassists(card, QETH_PROT_IPV4); |
3180 | 3228 | ||
3181 | if (!card->dev && qeth_l3_setup_netdev(card)) | 3229 | if (!card->dev && qeth_l3_setup_netdev(card)) { |
3230 | rc = -ENODEV; | ||
3182 | goto out_remove; | 3231 | goto out_remove; |
3232 | } | ||
3183 | 3233 | ||
3184 | card->state = CARD_STATE_HARDSETUP; | 3234 | card->state = CARD_STATE_HARDSETUP; |
3185 | qeth_print_status_message(card); | 3235 | qeth_print_status_message(card); |
@@ -3196,10 +3246,11 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
3196 | card->lan_online = 0; | 3246 | card->lan_online = 0; |
3197 | return 0; | 3247 | return 0; |
3198 | } | 3248 | } |
3249 | rc = -ENODEV; | ||
3199 | goto out_remove; | 3250 | goto out_remove; |
3200 | } else | 3251 | } else |
3201 | card->lan_online = 1; | 3252 | card->lan_online = 1; |
3202 | qeth_set_large_send(card, card->options.large_send); | 3253 | qeth_l3_set_large_send(card, card->options.large_send); |
3203 | 3254 | ||
3204 | rc = qeth_l3_setadapter_parms(card); | 3255 | rc = qeth_l3_setadapter_parms(card); |
3205 | if (rc) | 3256 | if (rc) |
@@ -3218,6 +3269,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
3218 | rc = qeth_init_qdio_queues(card); | 3269 | rc = qeth_init_qdio_queues(card); |
3219 | if (rc) { | 3270 | if (rc) { |
3220 | QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); | 3271 | QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); |
3272 | rc = -ENODEV; | ||
3221 | goto out_remove; | 3273 | goto out_remove; |
3222 | } | 3274 | } |
3223 | card->state = CARD_STATE_SOFTSETUP; | 3275 | card->state = CARD_STATE_SOFTSETUP; |
@@ -3248,7 +3300,7 @@ out_remove: | |||
3248 | card->state = CARD_STATE_RECOVER; | 3300 | card->state = CARD_STATE_RECOVER; |
3249 | else | 3301 | else |
3250 | card->state = CARD_STATE_DOWN; | 3302 | card->state = CARD_STATE_DOWN; |
3251 | return -ENODEV; | 3303 | return rc; |
3252 | } | 3304 | } |
3253 | 3305 | ||
3254 | static int qeth_l3_set_online(struct ccwgroup_device *gdev) | 3306 | static int qeth_l3_set_online(struct ccwgroup_device *gdev) |