diff options
Diffstat (limited to 'drivers/s390/net')
-rw-r--r-- | drivers/s390/net/Kconfig | 2 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core.h | 17 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 26 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l2_main.c | 173 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 189 |
5 files changed, 262 insertions, 145 deletions
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index 977bb4d4ed15..456b18743397 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig | |||
@@ -100,6 +100,6 @@ config QETH_IPV6 | |||
100 | 100 | ||
101 | config CCWGROUP | 101 | config CCWGROUP |
102 | tristate | 102 | tristate |
103 | default (LCS || CTCM || QETH) | 103 | default (LCS || CTCM || QETH || CLAW) |
104 | 104 | ||
105 | endmenu | 105 | endmenu |
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index d1257768be90..6be43eb126b4 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h | |||
@@ -676,6 +676,7 @@ enum qeth_discipline_id { | |||
676 | }; | 676 | }; |
677 | 677 | ||
678 | struct qeth_discipline { | 678 | struct qeth_discipline { |
679 | void (*start_poll)(struct ccw_device *, int, unsigned long); | ||
679 | qdio_handler_t *input_handler; | 680 | qdio_handler_t *input_handler; |
680 | qdio_handler_t *output_handler; | 681 | qdio_handler_t *output_handler; |
681 | int (*recover)(void *ptr); | 682 | int (*recover)(void *ptr); |
@@ -702,6 +703,16 @@ struct qeth_skb_data { | |||
702 | #define QETH_SKB_MAGIC 0x71657468 | 703 | #define QETH_SKB_MAGIC 0x71657468 |
703 | #define QETH_SIGA_CC2_RETRIES 3 | 704 | #define QETH_SIGA_CC2_RETRIES 3 |
704 | 705 | ||
706 | struct qeth_rx { | ||
707 | int b_count; | ||
708 | int b_index; | ||
709 | struct qdio_buffer_element *b_element; | ||
710 | int e_offset; | ||
711 | int qdio_err; | ||
712 | }; | ||
713 | |||
714 | #define QETH_NAPI_WEIGHT 128 | ||
715 | |||
705 | struct qeth_card { | 716 | struct qeth_card { |
706 | struct list_head list; | 717 | struct list_head list; |
707 | enum qeth_card_states state; | 718 | enum qeth_card_states state; |
@@ -749,6 +760,8 @@ struct qeth_card { | |||
749 | debug_info_t *debug; | 760 | debug_info_t *debug; |
750 | struct mutex conf_mutex; | 761 | struct mutex conf_mutex; |
751 | struct mutex discipline_mutex; | 762 | struct mutex discipline_mutex; |
763 | struct napi_struct napi; | ||
764 | struct qeth_rx rx; | ||
752 | }; | 765 | }; |
753 | 766 | ||
754 | struct qeth_card_list_struct { | 767 | struct qeth_card_list_struct { |
@@ -831,6 +844,10 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *, | |||
831 | struct qdio_buffer *, struct qdio_buffer_element **, int *, | 844 | struct qdio_buffer *, struct qdio_buffer_element **, int *, |
832 | struct qeth_hdr **); | 845 | struct qeth_hdr **); |
833 | void qeth_schedule_recovery(struct qeth_card *); | 846 | void qeth_schedule_recovery(struct qeth_card *); |
847 | void qeth_qdio_start_poll(struct ccw_device *, int, unsigned long); | ||
848 | void qeth_qdio_input_handler(struct ccw_device *, | ||
849 | unsigned int, unsigned int, int, | ||
850 | int, unsigned long); | ||
834 | void qeth_qdio_output_handler(struct ccw_device *, unsigned int, | 851 | void qeth_qdio_output_handler(struct ccw_device *, unsigned int, |
835 | int, int, int, unsigned long); | 852 | int, int, int, unsigned long); |
836 | void qeth_clear_ipacmd_list(struct qeth_card *); | 853 | void qeth_clear_ipacmd_list(struct qeth_card *); |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 3a5a18a0fc28..764267062601 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -2911,6 +2911,27 @@ static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) | |||
2911 | } | 2911 | } |
2912 | } | 2912 | } |
2913 | 2913 | ||
2914 | void qeth_qdio_start_poll(struct ccw_device *ccwdev, int queue, | ||
2915 | unsigned long card_ptr) | ||
2916 | { | ||
2917 | struct qeth_card *card = (struct qeth_card *)card_ptr; | ||
2918 | |||
2919 | if (card->dev) | ||
2920 | napi_schedule(&card->napi); | ||
2921 | } | ||
2922 | EXPORT_SYMBOL_GPL(qeth_qdio_start_poll); | ||
2923 | |||
2924 | void qeth_qdio_input_handler(struct ccw_device *ccwdev, unsigned int qdio_err, | ||
2925 | unsigned int queue, int first_element, int count, | ||
2926 | unsigned long card_ptr) | ||
2927 | { | ||
2928 | struct qeth_card *card = (struct qeth_card *)card_ptr; | ||
2929 | |||
2930 | if (qdio_err) | ||
2931 | qeth_schedule_recovery(card); | ||
2932 | } | ||
2933 | EXPORT_SYMBOL_GPL(qeth_qdio_input_handler); | ||
2934 | |||
2914 | void qeth_qdio_output_handler(struct ccw_device *ccwdev, | 2935 | void qeth_qdio_output_handler(struct ccw_device *ccwdev, |
2915 | unsigned int qdio_error, int __queue, int first_element, | 2936 | unsigned int qdio_error, int __queue, int first_element, |
2916 | int count, unsigned long card_ptr) | 2937 | int count, unsigned long card_ptr) |
@@ -3843,6 +3864,7 @@ static int qeth_qdio_establish(struct qeth_card *card) | |||
3843 | init_data.no_output_qs = card->qdio.no_out_queues; | 3864 | init_data.no_output_qs = card->qdio.no_out_queues; |
3844 | init_data.input_handler = card->discipline.input_handler; | 3865 | init_data.input_handler = card->discipline.input_handler; |
3845 | init_data.output_handler = card->discipline.output_handler; | 3866 | init_data.output_handler = card->discipline.output_handler; |
3867 | init_data.queue_start_poll = card->discipline.start_poll; | ||
3846 | init_data.int_parm = (unsigned long) card; | 3868 | init_data.int_parm = (unsigned long) card; |
3847 | init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; | 3869 | init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; |
3848 | init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; | 3870 | init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; |
@@ -4513,8 +4535,8 @@ static struct { | |||
4513 | /* 20 */{"queue 1 buffer usage"}, | 4535 | /* 20 */{"queue 1 buffer usage"}, |
4514 | {"queue 2 buffer usage"}, | 4536 | {"queue 2 buffer usage"}, |
4515 | {"queue 3 buffer usage"}, | 4537 | {"queue 3 buffer usage"}, |
4516 | {"rx handler time"}, | 4538 | {"rx poll time"}, |
4517 | {"rx handler count"}, | 4539 | {"rx poll count"}, |
4518 | {"rx do_QDIO time"}, | 4540 | {"rx do_QDIO time"}, |
4519 | {"rx do_QDIO count"}, | 4541 | {"rx do_QDIO count"}, |
4520 | {"tx handler time"}, | 4542 | {"tx handler time"}, |
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 830d63524d61..01c3c1f77879 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
@@ -407,29 +407,25 @@ static int qeth_l2_stop_card(struct qeth_card *card, int recovery_mode) | |||
407 | return rc; | 407 | return rc; |
408 | } | 408 | } |
409 | 409 | ||
410 | static void qeth_l2_process_inbound_buffer(struct qeth_card *card, | 410 | static int qeth_l2_process_inbound_buffer(struct qeth_card *card, |
411 | struct qeth_qdio_buffer *buf, int index) | 411 | int budget, int *done) |
412 | { | 412 | { |
413 | struct qdio_buffer_element *element; | 413 | int work_done = 0; |
414 | struct sk_buff *skb; | 414 | struct sk_buff *skb; |
415 | struct qeth_hdr *hdr; | 415 | struct qeth_hdr *hdr; |
416 | int offset; | ||
417 | unsigned int len; | 416 | unsigned int len; |
418 | 417 | ||
419 | /* get first element of current buffer */ | 418 | *done = 0; |
420 | element = (struct qdio_buffer_element *)&buf->buffer->element[0]; | 419 | BUG_ON(!budget); |
421 | offset = 0; | 420 | while (budget) { |
422 | if (card->options.performance_stats) | 421 | skb = qeth_core_get_next_skb(card, |
423 | card->perf_stats.bufs_rec++; | 422 | card->qdio.in_q->bufs[card->rx.b_index].buffer, |
424 | while ((skb = qeth_core_get_next_skb(card, buf->buffer, &element, | 423 | &card->rx.b_element, &card->rx.e_offset, &hdr); |
425 | &offset, &hdr))) { | 424 | if (!skb) { |
426 | skb->dev = card->dev; | 425 | *done = 1; |
427 | /* is device UP ? */ | 426 | break; |
428 | if (!(card->dev->flags & IFF_UP)) { | ||
429 | dev_kfree_skb_any(skb); | ||
430 | continue; | ||
431 | } | 427 | } |
432 | 428 | skb->dev = card->dev; | |
433 | switch (hdr->hdr.l2.id) { | 429 | switch (hdr->hdr.l2.id) { |
434 | case QETH_HEADER_TYPE_LAYER2: | 430 | case QETH_HEADER_TYPE_LAYER2: |
435 | skb->pkt_type = PACKET_HOST; | 431 | skb->pkt_type = PACKET_HOST; |
@@ -441,7 +437,7 @@ static void qeth_l2_process_inbound_buffer(struct qeth_card *card, | |||
441 | if (skb->protocol == htons(ETH_P_802_2)) | 437 | if (skb->protocol == htons(ETH_P_802_2)) |
442 | *((__u32 *)skb->cb) = ++card->seqno.pkt_seqno; | 438 | *((__u32 *)skb->cb) = ++card->seqno.pkt_seqno; |
443 | len = skb->len; | 439 | len = skb->len; |
444 | netif_rx(skb); | 440 | netif_receive_skb(skb); |
445 | break; | 441 | break; |
446 | case QETH_HEADER_TYPE_OSN: | 442 | case QETH_HEADER_TYPE_OSN: |
447 | if (card->info.type == QETH_CARD_TYPE_OSN) { | 443 | if (card->info.type == QETH_CARD_TYPE_OSN) { |
@@ -459,9 +455,87 @@ static void qeth_l2_process_inbound_buffer(struct qeth_card *card, | |||
459 | QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN); | 455 | QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN); |
460 | continue; | 456 | continue; |
461 | } | 457 | } |
458 | work_done++; | ||
459 | budget--; | ||
462 | card->stats.rx_packets++; | 460 | card->stats.rx_packets++; |
463 | card->stats.rx_bytes += len; | 461 | card->stats.rx_bytes += len; |
464 | } | 462 | } |
463 | return work_done; | ||
464 | } | ||
465 | |||
466 | static int qeth_l2_poll(struct napi_struct *napi, int budget) | ||
467 | { | ||
468 | struct qeth_card *card = container_of(napi, struct qeth_card, napi); | ||
469 | int work_done = 0; | ||
470 | struct qeth_qdio_buffer *buffer; | ||
471 | int done; | ||
472 | int new_budget = budget; | ||
473 | |||
474 | if (card->options.performance_stats) { | ||
475 | card->perf_stats.inbound_cnt++; | ||
476 | card->perf_stats.inbound_start_time = qeth_get_micros(); | ||
477 | } | ||
478 | |||
479 | while (1) { | ||
480 | if (!card->rx.b_count) { | ||
481 | card->rx.qdio_err = 0; | ||
482 | card->rx.b_count = qdio_get_next_buffers( | ||
483 | card->data.ccwdev, 0, &card->rx.b_index, | ||
484 | &card->rx.qdio_err); | ||
485 | if (card->rx.b_count <= 0) { | ||
486 | card->rx.b_count = 0; | ||
487 | break; | ||
488 | } | ||
489 | card->rx.b_element = | ||
490 | &card->qdio.in_q->bufs[card->rx.b_index] | ||
491 | .buffer->element[0]; | ||
492 | card->rx.e_offset = 0; | ||
493 | } | ||
494 | |||
495 | while (card->rx.b_count) { | ||
496 | buffer = &card->qdio.in_q->bufs[card->rx.b_index]; | ||
497 | if (!(card->rx.qdio_err && | ||
498 | qeth_check_qdio_errors(card, buffer->buffer, | ||
499 | card->rx.qdio_err, "qinerr"))) | ||
500 | work_done += qeth_l2_process_inbound_buffer( | ||
501 | card, new_budget, &done); | ||
502 | else | ||
503 | done = 1; | ||
504 | |||
505 | if (done) { | ||
506 | if (card->options.performance_stats) | ||
507 | card->perf_stats.bufs_rec++; | ||
508 | qeth_put_buffer_pool_entry(card, | ||
509 | buffer->pool_entry); | ||
510 | qeth_queue_input_buffer(card, card->rx.b_index); | ||
511 | card->rx.b_count--; | ||
512 | if (card->rx.b_count) { | ||
513 | card->rx.b_index = | ||
514 | (card->rx.b_index + 1) % | ||
515 | QDIO_MAX_BUFFERS_PER_Q; | ||
516 | card->rx.b_element = | ||
517 | &card->qdio.in_q | ||
518 | ->bufs[card->rx.b_index] | ||
519 | .buffer->element[0]; | ||
520 | card->rx.e_offset = 0; | ||
521 | } | ||
522 | } | ||
523 | |||
524 | if (work_done >= budget) | ||
525 | goto out; | ||
526 | else | ||
527 | new_budget = budget - work_done; | ||
528 | } | ||
529 | } | ||
530 | |||
531 | napi_complete(napi); | ||
532 | if (qdio_start_irq(card->data.ccwdev, 0)) | ||
533 | napi_schedule(&card->napi); | ||
534 | out: | ||
535 | if (card->options.performance_stats) | ||
536 | card->perf_stats.inbound_time += qeth_get_micros() - | ||
537 | card->perf_stats.inbound_start_time; | ||
538 | return work_done; | ||
465 | } | 539 | } |
466 | 540 | ||
467 | static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac, | 541 | static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac, |
@@ -755,49 +829,10 @@ tx_drop: | |||
755 | return NETDEV_TX_OK; | 829 | return NETDEV_TX_OK; |
756 | } | 830 | } |
757 | 831 | ||
758 | static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev, | ||
759 | unsigned int qdio_err, unsigned int queue, | ||
760 | int first_element, int count, unsigned long card_ptr) | ||
761 | { | ||
762 | struct net_device *net_dev; | ||
763 | struct qeth_card *card; | ||
764 | struct qeth_qdio_buffer *buffer; | ||
765 | int index; | ||
766 | int i; | ||
767 | |||
768 | card = (struct qeth_card *) card_ptr; | ||
769 | net_dev = card->dev; | ||
770 | if (card->options.performance_stats) { | ||
771 | card->perf_stats.inbound_cnt++; | ||
772 | card->perf_stats.inbound_start_time = qeth_get_micros(); | ||
773 | } | ||
774 | if (qdio_err & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) { | ||
775 | QETH_CARD_TEXT(card, 1, "qdinchk"); | ||
776 | QETH_CARD_TEXT_(card, 1, "%04X%04X", first_element, | ||
777 | count); | ||
778 | QETH_CARD_TEXT_(card, 1, "%04X", queue); | ||
779 | qeth_schedule_recovery(card); | ||
780 | return; | ||
781 | } | ||
782 | for (i = first_element; i < (first_element + count); ++i) { | ||
783 | index = i % QDIO_MAX_BUFFERS_PER_Q; | ||
784 | buffer = &card->qdio.in_q->bufs[index]; | ||
785 | if (!(qdio_err && | ||
786 | qeth_check_qdio_errors(card, buffer->buffer, qdio_err, | ||
787 | "qinerr"))) | ||
788 | qeth_l2_process_inbound_buffer(card, buffer, index); | ||
789 | /* clear buffer and give back to hardware */ | ||
790 | qeth_put_buffer_pool_entry(card, buffer->pool_entry); | ||
791 | qeth_queue_input_buffer(card, index); | ||
792 | } | ||
793 | if (card->options.performance_stats) | ||
794 | card->perf_stats.inbound_time += qeth_get_micros() - | ||
795 | card->perf_stats.inbound_start_time; | ||
796 | } | ||
797 | |||
798 | static int qeth_l2_open(struct net_device *dev) | 832 | static int qeth_l2_open(struct net_device *dev) |
799 | { | 833 | { |
800 | struct qeth_card *card = dev->ml_priv; | 834 | struct qeth_card *card = dev->ml_priv; |
835 | int rc = 0; | ||
801 | 836 | ||
802 | QETH_CARD_TEXT(card, 4, "qethopen"); | 837 | QETH_CARD_TEXT(card, 4, "qethopen"); |
803 | if (card->state != CARD_STATE_SOFTSETUP) | 838 | if (card->state != CARD_STATE_SOFTSETUP) |
@@ -814,18 +849,24 @@ static int qeth_l2_open(struct net_device *dev) | |||
814 | 849 | ||
815 | if (!card->lan_online && netif_carrier_ok(dev)) | 850 | if (!card->lan_online && netif_carrier_ok(dev)) |
816 | netif_carrier_off(dev); | 851 | netif_carrier_off(dev); |
817 | return 0; | 852 | if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) { |
853 | napi_enable(&card->napi); | ||
854 | napi_schedule(&card->napi); | ||
855 | } else | ||
856 | rc = -EIO; | ||
857 | return rc; | ||
818 | } | 858 | } |
819 | 859 | ||
820 | |||
821 | static int qeth_l2_stop(struct net_device *dev) | 860 | static int qeth_l2_stop(struct net_device *dev) |
822 | { | 861 | { |
823 | struct qeth_card *card = dev->ml_priv; | 862 | struct qeth_card *card = dev->ml_priv; |
824 | 863 | ||
825 | QETH_CARD_TEXT(card, 4, "qethstop"); | 864 | QETH_CARD_TEXT(card, 4, "qethstop"); |
826 | netif_tx_disable(dev); | 865 | netif_tx_disable(dev); |
827 | if (card->state == CARD_STATE_UP) | 866 | if (card->state == CARD_STATE_UP) { |
828 | card->state = CARD_STATE_SOFTSETUP; | 867 | card->state = CARD_STATE_SOFTSETUP; |
868 | napi_disable(&card->napi); | ||
869 | } | ||
829 | return 0; | 870 | return 0; |
830 | } | 871 | } |
831 | 872 | ||
@@ -836,8 +877,9 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev) | |||
836 | INIT_LIST_HEAD(&card->vid_list); | 877 | INIT_LIST_HEAD(&card->vid_list); |
837 | INIT_LIST_HEAD(&card->mc_list); | 878 | INIT_LIST_HEAD(&card->mc_list); |
838 | card->options.layer2 = 1; | 879 | card->options.layer2 = 1; |
880 | card->discipline.start_poll = qeth_qdio_start_poll; | ||
839 | card->discipline.input_handler = (qdio_handler_t *) | 881 | card->discipline.input_handler = (qdio_handler_t *) |
840 | qeth_l2_qdio_input_handler; | 882 | qeth_qdio_input_handler; |
841 | card->discipline.output_handler = (qdio_handler_t *) | 883 | card->discipline.output_handler = (qdio_handler_t *) |
842 | qeth_qdio_output_handler; | 884 | qeth_qdio_output_handler; |
843 | card->discipline.recover = qeth_l2_recover; | 885 | card->discipline.recover = qeth_l2_recover; |
@@ -923,6 +965,7 @@ static int qeth_l2_setup_netdev(struct qeth_card *card) | |||
923 | card->info.broadcast_capable = 1; | 965 | card->info.broadcast_capable = 1; |
924 | qeth_l2_request_initial_mac(card); | 966 | qeth_l2_request_initial_mac(card); |
925 | SET_NETDEV_DEV(card->dev, &card->gdev->dev); | 967 | SET_NETDEV_DEV(card->dev, &card->gdev->dev); |
968 | netif_napi_add(card->dev, &card->napi, qeth_l2_poll, QETH_NAPI_WEIGHT); | ||
926 | return register_netdev(card->dev); | 969 | return register_netdev(card->dev); |
927 | } | 970 | } |
928 | 971 | ||
@@ -955,6 +998,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
955 | qeth_l2_send_setmac(card, &card->dev->dev_addr[0]); | 998 | qeth_l2_send_setmac(card, &card->dev->dev_addr[0]); |
956 | 999 | ||
957 | card->state = CARD_STATE_HARDSETUP; | 1000 | card->state = CARD_STATE_HARDSETUP; |
1001 | memset(&card->rx, 0, sizeof(struct qeth_rx)); | ||
958 | qeth_print_status_message(card); | 1002 | qeth_print_status_message(card); |
959 | 1003 | ||
960 | /* softsetup */ | 1004 | /* softsetup */ |
@@ -1086,9 +1130,6 @@ static int qeth_l2_recover(void *ptr) | |||
1086 | card->use_hard_stop = 1; | 1130 | card->use_hard_stop = 1; |
1087 | __qeth_l2_set_offline(card->gdev, 1); | 1131 | __qeth_l2_set_offline(card->gdev, 1); |
1088 | rc = __qeth_l2_set_online(card->gdev, 1); | 1132 | rc = __qeth_l2_set_online(card->gdev, 1); |
1089 | /* don't run another scheduled recovery */ | ||
1090 | qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); | ||
1091 | qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); | ||
1092 | if (!rc) | 1133 | if (!rc) |
1093 | dev_info(&card->gdev->dev, | 1134 | dev_info(&card->gdev->dev, |
1094 | "Device successfully recovered!\n"); | 1135 | "Device successfully recovered!\n"); |
@@ -1099,6 +1140,8 @@ static int qeth_l2_recover(void *ptr) | |||
1099 | dev_warn(&card->gdev->dev, "The qeth device driver " | 1140 | dev_warn(&card->gdev->dev, "The qeth device driver " |
1100 | "failed to recover an error on the device\n"); | 1141 | "failed to recover an error on the device\n"); |
1101 | } | 1142 | } |
1143 | qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); | ||
1144 | qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); | ||
1102 | return 0; | 1145 | return 0; |
1103 | } | 1146 | } |
1104 | 1147 | ||
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index e22ae248f613..5b79f573bd93 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -103,12 +103,7 @@ int qeth_l3_string_to_ipaddr4(const char *buf, __u8 *addr) | |||
103 | 103 | ||
104 | void qeth_l3_ipaddr6_to_string(const __u8 *addr, char *buf) | 104 | void qeth_l3_ipaddr6_to_string(const __u8 *addr, char *buf) |
105 | { | 105 | { |
106 | sprintf(buf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x" | 106 | sprintf(buf, "%pI6", addr); |
107 | ":%02x%02x:%02x%02x:%02x%02x:%02x%02x", | ||
108 | addr[0], addr[1], addr[2], addr[3], | ||
109 | addr[4], addr[5], addr[6], addr[7], | ||
110 | addr[8], addr[9], addr[10], addr[11], | ||
111 | addr[12], addr[13], addr[14], addr[15]); | ||
112 | } | 107 | } |
113 | 108 | ||
114 | int qeth_l3_string_to_ipaddr6(const char *buf, __u8 *addr) | 109 | int qeth_l3_string_to_ipaddr6(const char *buf, __u8 *addr) |
@@ -2112,51 +2107,44 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, | |||
2112 | return vlan_id; | 2107 | return vlan_id; |
2113 | } | 2108 | } |
2114 | 2109 | ||
2115 | static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | 2110 | static int qeth_l3_process_inbound_buffer(struct qeth_card *card, |
2116 | struct qeth_qdio_buffer *buf, int index) | 2111 | int budget, int *done) |
2117 | { | 2112 | { |
2118 | struct qdio_buffer_element *element; | 2113 | int work_done = 0; |
2119 | struct sk_buff *skb; | 2114 | struct sk_buff *skb; |
2120 | struct qeth_hdr *hdr; | 2115 | struct qeth_hdr *hdr; |
2121 | int offset; | ||
2122 | __u16 vlan_tag = 0; | 2116 | __u16 vlan_tag = 0; |
2123 | unsigned int len; | 2117 | unsigned int len; |
2124 | /* get first element of current buffer */ | ||
2125 | element = (struct qdio_buffer_element *)&buf->buffer->element[0]; | ||
2126 | offset = 0; | ||
2127 | if (card->options.performance_stats) | ||
2128 | card->perf_stats.bufs_rec++; | ||
2129 | while ((skb = qeth_core_get_next_skb(card, buf->buffer, &element, | ||
2130 | &offset, &hdr))) { | ||
2131 | skb->dev = card->dev; | ||
2132 | /* is device UP ? */ | ||
2133 | if (!(card->dev->flags & IFF_UP)) { | ||
2134 | dev_kfree_skb_any(skb); | ||
2135 | continue; | ||
2136 | } | ||
2137 | 2118 | ||
2119 | *done = 0; | ||
2120 | BUG_ON(!budget); | ||
2121 | while (budget) { | ||
2122 | skb = qeth_core_get_next_skb(card, | ||
2123 | card->qdio.in_q->bufs[card->rx.b_index].buffer, | ||
2124 | &card->rx.b_element, &card->rx.e_offset, &hdr); | ||
2125 | if (!skb) { | ||
2126 | *done = 1; | ||
2127 | break; | ||
2128 | } | ||
2129 | skb->dev = card->dev; | ||
2138 | switch (hdr->hdr.l3.id) { | 2130 | switch (hdr->hdr.l3.id) { |
2139 | case QETH_HEADER_TYPE_LAYER3: | 2131 | case QETH_HEADER_TYPE_LAYER3: |
2140 | vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr); | 2132 | vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr); |
2141 | len = skb->len; | 2133 | len = skb->len; |
2142 | if (vlan_tag && !card->options.sniffer) | 2134 | if (vlan_tag && !card->options.sniffer) |
2143 | if (card->vlangrp) | 2135 | if (card->vlangrp) |
2144 | vlan_hwaccel_rx(skb, card->vlangrp, | 2136 | vlan_gro_receive(&card->napi, |
2145 | vlan_tag); | 2137 | card->vlangrp, vlan_tag, skb); |
2146 | else { | 2138 | else { |
2147 | dev_kfree_skb_any(skb); | 2139 | dev_kfree_skb_any(skb); |
2148 | continue; | 2140 | continue; |
2149 | } | 2141 | } |
2150 | else | 2142 | else |
2151 | netif_rx(skb); | 2143 | napi_gro_receive(&card->napi, skb); |
2152 | break; | 2144 | break; |
2153 | case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */ | 2145 | case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */ |
2154 | skb->pkt_type = PACKET_HOST; | 2146 | skb->pkt_type = PACKET_HOST; |
2155 | skb->protocol = eth_type_trans(skb, skb->dev); | 2147 | skb->protocol = eth_type_trans(skb, skb->dev); |
2156 | if (card->options.checksum_type == NO_CHECKSUMMING) | ||
2157 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
2158 | else | ||
2159 | skb->ip_summed = CHECKSUM_NONE; | ||
2160 | len = skb->len; | 2148 | len = skb->len; |
2161 | netif_receive_skb(skb); | 2149 | netif_receive_skb(skb); |
2162 | break; | 2150 | break; |
@@ -2166,10 +2154,87 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | |||
2166 | QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN); | 2154 | QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN); |
2167 | continue; | 2155 | continue; |
2168 | } | 2156 | } |
2169 | 2157 | work_done++; | |
2158 | budget--; | ||
2170 | card->stats.rx_packets++; | 2159 | card->stats.rx_packets++; |
2171 | card->stats.rx_bytes += len; | 2160 | card->stats.rx_bytes += len; |
2172 | } | 2161 | } |
2162 | return work_done; | ||
2163 | } | ||
2164 | |||
2165 | static int qeth_l3_poll(struct napi_struct *napi, int budget) | ||
2166 | { | ||
2167 | struct qeth_card *card = container_of(napi, struct qeth_card, napi); | ||
2168 | int work_done = 0; | ||
2169 | struct qeth_qdio_buffer *buffer; | ||
2170 | int done; | ||
2171 | int new_budget = budget; | ||
2172 | |||
2173 | if (card->options.performance_stats) { | ||
2174 | card->perf_stats.inbound_cnt++; | ||
2175 | card->perf_stats.inbound_start_time = qeth_get_micros(); | ||
2176 | } | ||
2177 | |||
2178 | while (1) { | ||
2179 | if (!card->rx.b_count) { | ||
2180 | card->rx.qdio_err = 0; | ||
2181 | card->rx.b_count = qdio_get_next_buffers( | ||
2182 | card->data.ccwdev, 0, &card->rx.b_index, | ||
2183 | &card->rx.qdio_err); | ||
2184 | if (card->rx.b_count <= 0) { | ||
2185 | card->rx.b_count = 0; | ||
2186 | break; | ||
2187 | } | ||
2188 | card->rx.b_element = | ||
2189 | &card->qdio.in_q->bufs[card->rx.b_index] | ||
2190 | .buffer->element[0]; | ||
2191 | card->rx.e_offset = 0; | ||
2192 | } | ||
2193 | |||
2194 | while (card->rx.b_count) { | ||
2195 | buffer = &card->qdio.in_q->bufs[card->rx.b_index]; | ||
2196 | if (!(card->rx.qdio_err && | ||
2197 | qeth_check_qdio_errors(card, buffer->buffer, | ||
2198 | card->rx.qdio_err, "qinerr"))) | ||
2199 | work_done += qeth_l3_process_inbound_buffer( | ||
2200 | card, new_budget, &done); | ||
2201 | else | ||
2202 | done = 1; | ||
2203 | |||
2204 | if (done) { | ||
2205 | if (card->options.performance_stats) | ||
2206 | card->perf_stats.bufs_rec++; | ||
2207 | qeth_put_buffer_pool_entry(card, | ||
2208 | buffer->pool_entry); | ||
2209 | qeth_queue_input_buffer(card, card->rx.b_index); | ||
2210 | card->rx.b_count--; | ||
2211 | if (card->rx.b_count) { | ||
2212 | card->rx.b_index = | ||
2213 | (card->rx.b_index + 1) % | ||
2214 | QDIO_MAX_BUFFERS_PER_Q; | ||
2215 | card->rx.b_element = | ||
2216 | &card->qdio.in_q | ||
2217 | ->bufs[card->rx.b_index] | ||
2218 | .buffer->element[0]; | ||
2219 | card->rx.e_offset = 0; | ||
2220 | } | ||
2221 | } | ||
2222 | |||
2223 | if (work_done >= budget) | ||
2224 | goto out; | ||
2225 | else | ||
2226 | new_budget = budget - work_done; | ||
2227 | } | ||
2228 | } | ||
2229 | |||
2230 | napi_complete(napi); | ||
2231 | if (qdio_start_irq(card->data.ccwdev, 0)) | ||
2232 | napi_schedule(&card->napi); | ||
2233 | out: | ||
2234 | if (card->options.performance_stats) | ||
2235 | card->perf_stats.inbound_time += qeth_get_micros() - | ||
2236 | card->perf_stats.inbound_start_time; | ||
2237 | return work_done; | ||
2173 | } | 2238 | } |
2174 | 2239 | ||
2175 | static int qeth_l3_verify_vlan_dev(struct net_device *dev, | 2240 | static int qeth_l3_verify_vlan_dev(struct net_device *dev, |
@@ -3103,6 +3168,7 @@ tx_drop: | |||
3103 | static int qeth_l3_open(struct net_device *dev) | 3168 | static int qeth_l3_open(struct net_device *dev) |
3104 | { | 3169 | { |
3105 | struct qeth_card *card = dev->ml_priv; | 3170 | struct qeth_card *card = dev->ml_priv; |
3171 | int rc = 0; | ||
3106 | 3172 | ||
3107 | QETH_CARD_TEXT(card, 4, "qethopen"); | 3173 | QETH_CARD_TEXT(card, 4, "qethopen"); |
3108 | if (card->state != CARD_STATE_SOFTSETUP) | 3174 | if (card->state != CARD_STATE_SOFTSETUP) |
@@ -3113,7 +3179,12 @@ static int qeth_l3_open(struct net_device *dev) | |||
3113 | 3179 | ||
3114 | if (!card->lan_online && netif_carrier_ok(dev)) | 3180 | if (!card->lan_online && netif_carrier_ok(dev)) |
3115 | netif_carrier_off(dev); | 3181 | netif_carrier_off(dev); |
3116 | return 0; | 3182 | if (qdio_stop_irq(card->data.ccwdev, 0) >= 0) { |
3183 | napi_enable(&card->napi); | ||
3184 | napi_schedule(&card->napi); | ||
3185 | } else | ||
3186 | rc = -EIO; | ||
3187 | return rc; | ||
3117 | } | 3188 | } |
3118 | 3189 | ||
3119 | static int qeth_l3_stop(struct net_device *dev) | 3190 | static int qeth_l3_stop(struct net_device *dev) |
@@ -3122,8 +3193,10 @@ static int qeth_l3_stop(struct net_device *dev) | |||
3122 | 3193 | ||
3123 | QETH_CARD_TEXT(card, 4, "qethstop"); | 3194 | QETH_CARD_TEXT(card, 4, "qethstop"); |
3124 | netif_tx_disable(dev); | 3195 | netif_tx_disable(dev); |
3125 | if (card->state == CARD_STATE_UP) | 3196 | if (card->state == CARD_STATE_UP) { |
3126 | card->state = CARD_STATE_SOFTSETUP; | 3197 | card->state = CARD_STATE_SOFTSETUP; |
3198 | napi_disable(&card->napi); | ||
3199 | } | ||
3127 | return 0; | 3200 | return 0; |
3128 | } | 3201 | } |
3129 | 3202 | ||
@@ -3293,57 +3366,19 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) | |||
3293 | card->dev->gso_max_size = 15 * PAGE_SIZE; | 3366 | card->dev->gso_max_size = 15 * PAGE_SIZE; |
3294 | 3367 | ||
3295 | SET_NETDEV_DEV(card->dev, &card->gdev->dev); | 3368 | SET_NETDEV_DEV(card->dev, &card->gdev->dev); |
3369 | netif_napi_add(card->dev, &card->napi, qeth_l3_poll, QETH_NAPI_WEIGHT); | ||
3296 | return register_netdev(card->dev); | 3370 | return register_netdev(card->dev); |
3297 | } | 3371 | } |
3298 | 3372 | ||
3299 | static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev, | ||
3300 | unsigned int qdio_err, unsigned int queue, int first_element, | ||
3301 | int count, unsigned long card_ptr) | ||
3302 | { | ||
3303 | struct net_device *net_dev; | ||
3304 | struct qeth_card *card; | ||
3305 | struct qeth_qdio_buffer *buffer; | ||
3306 | int index; | ||
3307 | int i; | ||
3308 | |||
3309 | card = (struct qeth_card *) card_ptr; | ||
3310 | net_dev = card->dev; | ||
3311 | if (card->options.performance_stats) { | ||
3312 | card->perf_stats.inbound_cnt++; | ||
3313 | card->perf_stats.inbound_start_time = qeth_get_micros(); | ||
3314 | } | ||
3315 | if (qdio_err & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) { | ||
3316 | QETH_CARD_TEXT(card, 1, "qdinchk"); | ||
3317 | QETH_CARD_TEXT_(card, 1, "%04X%04X", | ||
3318 | first_element, count); | ||
3319 | QETH_CARD_TEXT_(card, 1, "%04X", queue); | ||
3320 | qeth_schedule_recovery(card); | ||
3321 | return; | ||
3322 | } | ||
3323 | for (i = first_element; i < (first_element + count); ++i) { | ||
3324 | index = i % QDIO_MAX_BUFFERS_PER_Q; | ||
3325 | buffer = &card->qdio.in_q->bufs[index]; | ||
3326 | if (!(qdio_err && | ||
3327 | qeth_check_qdio_errors(card, buffer->buffer, | ||
3328 | qdio_err, "qinerr"))) | ||
3329 | qeth_l3_process_inbound_buffer(card, buffer, index); | ||
3330 | /* clear buffer and give back to hardware */ | ||
3331 | qeth_put_buffer_pool_entry(card, buffer->pool_entry); | ||
3332 | qeth_queue_input_buffer(card, index); | ||
3333 | } | ||
3334 | if (card->options.performance_stats) | ||
3335 | card->perf_stats.inbound_time += qeth_get_micros() - | ||
3336 | card->perf_stats.inbound_start_time; | ||
3337 | } | ||
3338 | |||
3339 | static int qeth_l3_probe_device(struct ccwgroup_device *gdev) | 3373 | static int qeth_l3_probe_device(struct ccwgroup_device *gdev) |
3340 | { | 3374 | { |
3341 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | 3375 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); |
3342 | 3376 | ||
3343 | qeth_l3_create_device_attributes(&gdev->dev); | 3377 | qeth_l3_create_device_attributes(&gdev->dev); |
3344 | card->options.layer2 = 0; | 3378 | card->options.layer2 = 0; |
3379 | card->discipline.start_poll = qeth_qdio_start_poll; | ||
3345 | card->discipline.input_handler = (qdio_handler_t *) | 3380 | card->discipline.input_handler = (qdio_handler_t *) |
3346 | qeth_l3_qdio_input_handler; | 3381 | qeth_qdio_input_handler; |
3347 | card->discipline.output_handler = (qdio_handler_t *) | 3382 | card->discipline.output_handler = (qdio_handler_t *) |
3348 | qeth_qdio_output_handler; | 3383 | qeth_qdio_output_handler; |
3349 | card->discipline.recover = qeth_l3_recover; | 3384 | card->discipline.recover = qeth_l3_recover; |
@@ -3402,6 +3437,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
3402 | } | 3437 | } |
3403 | 3438 | ||
3404 | card->state = CARD_STATE_HARDSETUP; | 3439 | card->state = CARD_STATE_HARDSETUP; |
3440 | memset(&card->rx, 0, sizeof(struct qeth_rx)); | ||
3405 | qeth_print_status_message(card); | 3441 | qeth_print_status_message(card); |
3406 | 3442 | ||
3407 | /* softsetup */ | 3443 | /* softsetup */ |
@@ -3538,9 +3574,6 @@ static int qeth_l3_recover(void *ptr) | |||
3538 | card->use_hard_stop = 1; | 3574 | card->use_hard_stop = 1; |
3539 | __qeth_l3_set_offline(card->gdev, 1); | 3575 | __qeth_l3_set_offline(card->gdev, 1); |
3540 | rc = __qeth_l3_set_online(card->gdev, 1); | 3576 | rc = __qeth_l3_set_online(card->gdev, 1); |
3541 | /* don't run another scheduled recovery */ | ||
3542 | qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); | ||
3543 | qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); | ||
3544 | if (!rc) | 3577 | if (!rc) |
3545 | dev_info(&card->gdev->dev, | 3578 | dev_info(&card->gdev->dev, |
3546 | "Device successfully recovered!\n"); | 3579 | "Device successfully recovered!\n"); |
@@ -3551,6 +3584,8 @@ static int qeth_l3_recover(void *ptr) | |||
3551 | dev_warn(&card->gdev->dev, "The qeth device driver " | 3584 | dev_warn(&card->gdev->dev, "The qeth device driver " |
3552 | "failed to recover an error on the device\n"); | 3585 | "failed to recover an error on the device\n"); |
3553 | } | 3586 | } |
3587 | qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); | ||
3588 | qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); | ||
3554 | return 0; | 3589 | return 0; |
3555 | } | 3590 | } |
3556 | 3591 | ||