diff options
| -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 | 182 |
4 files changed, 260 insertions, 138 deletions
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 561bdc881e92..5b79f573bd93 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
| @@ -2107,51 +2107,44 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, | |||
| 2107 | return vlan_id; | 2107 | return vlan_id; |
| 2108 | } | 2108 | } |
| 2109 | 2109 | ||
| 2110 | static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | 2110 | static int qeth_l3_process_inbound_buffer(struct qeth_card *card, |
| 2111 | struct qeth_qdio_buffer *buf, int index) | 2111 | int budget, int *done) |
| 2112 | { | 2112 | { |
| 2113 | struct qdio_buffer_element *element; | 2113 | int work_done = 0; |
| 2114 | struct sk_buff *skb; | 2114 | struct sk_buff *skb; |
| 2115 | struct qeth_hdr *hdr; | 2115 | struct qeth_hdr *hdr; |
| 2116 | int offset; | ||
| 2117 | __u16 vlan_tag = 0; | 2116 | __u16 vlan_tag = 0; |
| 2118 | unsigned int len; | 2117 | unsigned int len; |
| 2119 | /* get first element of current buffer */ | ||
| 2120 | element = (struct qdio_buffer_element *)&buf->buffer->element[0]; | ||
| 2121 | offset = 0; | ||
| 2122 | if (card->options.performance_stats) | ||
| 2123 | card->perf_stats.bufs_rec++; | ||
| 2124 | while ((skb = qeth_core_get_next_skb(card, buf->buffer, &element, | ||
| 2125 | &offset, &hdr))) { | ||
| 2126 | skb->dev = card->dev; | ||
| 2127 | /* is device UP ? */ | ||
| 2128 | if (!(card->dev->flags & IFF_UP)) { | ||
| 2129 | dev_kfree_skb_any(skb); | ||
| 2130 | continue; | ||
| 2131 | } | ||
| 2132 | 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; | ||
| 2133 | switch (hdr->hdr.l3.id) { | 2130 | switch (hdr->hdr.l3.id) { |
| 2134 | case QETH_HEADER_TYPE_LAYER3: | 2131 | case QETH_HEADER_TYPE_LAYER3: |
| 2135 | vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr); | 2132 | vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr); |
| 2136 | len = skb->len; | 2133 | len = skb->len; |
| 2137 | if (vlan_tag && !card->options.sniffer) | 2134 | if (vlan_tag && !card->options.sniffer) |
| 2138 | if (card->vlangrp) | 2135 | if (card->vlangrp) |
| 2139 | vlan_hwaccel_rx(skb, card->vlangrp, | 2136 | vlan_gro_receive(&card->napi, |
| 2140 | vlan_tag); | 2137 | card->vlangrp, vlan_tag, skb); |
| 2141 | else { | 2138 | else { |
| 2142 | dev_kfree_skb_any(skb); | 2139 | dev_kfree_skb_any(skb); |
| 2143 | continue; | 2140 | continue; |
| 2144 | } | 2141 | } |
| 2145 | else | 2142 | else |
| 2146 | netif_rx(skb); | 2143 | napi_gro_receive(&card->napi, skb); |
| 2147 | break; | 2144 | break; |
| 2148 | case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */ | 2145 | case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */ |
| 2149 | skb->pkt_type = PACKET_HOST; | 2146 | skb->pkt_type = PACKET_HOST; |
| 2150 | skb->protocol = eth_type_trans(skb, skb->dev); | 2147 | skb->protocol = eth_type_trans(skb, skb->dev); |
| 2151 | if (card->options.checksum_type == NO_CHECKSUMMING) | ||
| 2152 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 2153 | else | ||
| 2154 | skb->ip_summed = CHECKSUM_NONE; | ||
| 2155 | len = skb->len; | 2148 | len = skb->len; |
| 2156 | netif_receive_skb(skb); | 2149 | netif_receive_skb(skb); |
| 2157 | break; | 2150 | break; |
| @@ -2161,10 +2154,87 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | |||
| 2161 | QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN); | 2154 | QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN); |
| 2162 | continue; | 2155 | continue; |
| 2163 | } | 2156 | } |
| 2164 | 2157 | work_done++; | |
| 2158 | budget--; | ||
| 2165 | card->stats.rx_packets++; | 2159 | card->stats.rx_packets++; |
| 2166 | card->stats.rx_bytes += len; | 2160 | card->stats.rx_bytes += len; |
| 2167 | } | 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; | ||
| 2168 | } | 2238 | } |
| 2169 | 2239 | ||
| 2170 | static int qeth_l3_verify_vlan_dev(struct net_device *dev, | 2240 | static int qeth_l3_verify_vlan_dev(struct net_device *dev, |
| @@ -3098,6 +3168,7 @@ tx_drop: | |||
| 3098 | static int qeth_l3_open(struct net_device *dev) | 3168 | static int qeth_l3_open(struct net_device *dev) |
| 3099 | { | 3169 | { |
| 3100 | struct qeth_card *card = dev->ml_priv; | 3170 | struct qeth_card *card = dev->ml_priv; |
| 3171 | int rc = 0; | ||
| 3101 | 3172 | ||
| 3102 | QETH_CARD_TEXT(card, 4, "qethopen"); | 3173 | QETH_CARD_TEXT(card, 4, "qethopen"); |
| 3103 | if (card->state != CARD_STATE_SOFTSETUP) | 3174 | if (card->state != CARD_STATE_SOFTSETUP) |
| @@ -3108,7 +3179,12 @@ static int qeth_l3_open(struct net_device *dev) | |||
| 3108 | 3179 | ||
| 3109 | if (!card->lan_online && netif_carrier_ok(dev)) | 3180 | if (!card->lan_online && netif_carrier_ok(dev)) |
| 3110 | netif_carrier_off(dev); | 3181 | netif_carrier_off(dev); |
| 3111 | 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; | ||
| 3112 | } | 3188 | } |
| 3113 | 3189 | ||
| 3114 | static int qeth_l3_stop(struct net_device *dev) | 3190 | static int qeth_l3_stop(struct net_device *dev) |
| @@ -3117,8 +3193,10 @@ static int qeth_l3_stop(struct net_device *dev) | |||
| 3117 | 3193 | ||
| 3118 | QETH_CARD_TEXT(card, 4, "qethstop"); | 3194 | QETH_CARD_TEXT(card, 4, "qethstop"); |
| 3119 | netif_tx_disable(dev); | 3195 | netif_tx_disable(dev); |
| 3120 | if (card->state == CARD_STATE_UP) | 3196 | if (card->state == CARD_STATE_UP) { |
| 3121 | card->state = CARD_STATE_SOFTSETUP; | 3197 | card->state = CARD_STATE_SOFTSETUP; |
| 3198 | napi_disable(&card->napi); | ||
| 3199 | } | ||
| 3122 | return 0; | 3200 | return 0; |
| 3123 | } | 3201 | } |
| 3124 | 3202 | ||
| @@ -3288,57 +3366,19 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) | |||
| 3288 | card->dev->gso_max_size = 15 * PAGE_SIZE; | 3366 | card->dev->gso_max_size = 15 * PAGE_SIZE; |
| 3289 | 3367 | ||
| 3290 | 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); | ||
| 3291 | return register_netdev(card->dev); | 3370 | return register_netdev(card->dev); |
| 3292 | } | 3371 | } |
| 3293 | 3372 | ||
| 3294 | static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev, | ||
| 3295 | unsigned int qdio_err, unsigned int queue, int first_element, | ||
| 3296 | int count, unsigned long card_ptr) | ||
| 3297 | { | ||
| 3298 | struct net_device *net_dev; | ||
| 3299 | struct qeth_card *card; | ||
| 3300 | struct qeth_qdio_buffer *buffer; | ||
| 3301 | int index; | ||
| 3302 | int i; | ||
| 3303 | |||
| 3304 | card = (struct qeth_card *) card_ptr; | ||
| 3305 | net_dev = card->dev; | ||
| 3306 | if (card->options.performance_stats) { | ||
| 3307 | card->perf_stats.inbound_cnt++; | ||
| 3308 | card->perf_stats.inbound_start_time = qeth_get_micros(); | ||
| 3309 | } | ||
| 3310 | if (qdio_err & QDIO_ERROR_ACTIVATE_CHECK_CONDITION) { | ||
| 3311 | QETH_CARD_TEXT(card, 1, "qdinchk"); | ||
| 3312 | QETH_CARD_TEXT_(card, 1, "%04X%04X", | ||
| 3313 | first_element, count); | ||
| 3314 | QETH_CARD_TEXT_(card, 1, "%04X", queue); | ||
| 3315 | qeth_schedule_recovery(card); | ||
| 3316 | return; | ||
| 3317 | } | ||
| 3318 | for (i = first_element; i < (first_element + count); ++i) { | ||
| 3319 | index = i % QDIO_MAX_BUFFERS_PER_Q; | ||
| 3320 | buffer = &card->qdio.in_q->bufs[index]; | ||
| 3321 | if (!(qdio_err && | ||
| 3322 | qeth_check_qdio_errors(card, buffer->buffer, | ||
| 3323 | qdio_err, "qinerr"))) | ||
| 3324 | qeth_l3_process_inbound_buffer(card, buffer, index); | ||
| 3325 | /* clear buffer and give back to hardware */ | ||
| 3326 | qeth_put_buffer_pool_entry(card, buffer->pool_entry); | ||
| 3327 | qeth_queue_input_buffer(card, index); | ||
| 3328 | } | ||
| 3329 | if (card->options.performance_stats) | ||
| 3330 | card->perf_stats.inbound_time += qeth_get_micros() - | ||
| 3331 | card->perf_stats.inbound_start_time; | ||
| 3332 | } | ||
| 3333 | |||
| 3334 | static int qeth_l3_probe_device(struct ccwgroup_device *gdev) | 3373 | static int qeth_l3_probe_device(struct ccwgroup_device *gdev) |
| 3335 | { | 3374 | { |
| 3336 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | 3375 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); |
| 3337 | 3376 | ||
| 3338 | qeth_l3_create_device_attributes(&gdev->dev); | 3377 | qeth_l3_create_device_attributes(&gdev->dev); |
| 3339 | card->options.layer2 = 0; | 3378 | card->options.layer2 = 0; |
| 3379 | card->discipline.start_poll = qeth_qdio_start_poll; | ||
| 3340 | card->discipline.input_handler = (qdio_handler_t *) | 3380 | card->discipline.input_handler = (qdio_handler_t *) |
| 3341 | qeth_l3_qdio_input_handler; | 3381 | qeth_qdio_input_handler; |
| 3342 | card->discipline.output_handler = (qdio_handler_t *) | 3382 | card->discipline.output_handler = (qdio_handler_t *) |
| 3343 | qeth_qdio_output_handler; | 3383 | qeth_qdio_output_handler; |
| 3344 | card->discipline.recover = qeth_l3_recover; | 3384 | card->discipline.recover = qeth_l3_recover; |
| @@ -3397,6 +3437,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
| 3397 | } | 3437 | } |
| 3398 | 3438 | ||
| 3399 | card->state = CARD_STATE_HARDSETUP; | 3439 | card->state = CARD_STATE_HARDSETUP; |
| 3440 | memset(&card->rx, 0, sizeof(struct qeth_rx)); | ||
| 3400 | qeth_print_status_message(card); | 3441 | qeth_print_status_message(card); |
| 3401 | 3442 | ||
| 3402 | /* softsetup */ | 3443 | /* softsetup */ |
| @@ -3533,9 +3574,6 @@ static int qeth_l3_recover(void *ptr) | |||
| 3533 | card->use_hard_stop = 1; | 3574 | card->use_hard_stop = 1; |
| 3534 | __qeth_l3_set_offline(card->gdev, 1); | 3575 | __qeth_l3_set_offline(card->gdev, 1); |
| 3535 | rc = __qeth_l3_set_online(card->gdev, 1); | 3576 | rc = __qeth_l3_set_online(card->gdev, 1); |
| 3536 | /* don't run another scheduled recovery */ | ||
| 3537 | qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); | ||
| 3538 | qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); | ||
| 3539 | if (!rc) | 3577 | if (!rc) |
| 3540 | dev_info(&card->gdev->dev, | 3578 | dev_info(&card->gdev->dev, |
| 3541 | "Device successfully recovered!\n"); | 3579 | "Device successfully recovered!\n"); |
| @@ -3546,6 +3584,8 @@ static int qeth_l3_recover(void *ptr) | |||
| 3546 | dev_warn(&card->gdev->dev, "The qeth device driver " | 3584 | dev_warn(&card->gdev->dev, "The qeth device driver " |
| 3547 | "failed to recover an error on the device\n"); | 3585 | "failed to recover an error on the device\n"); |
| 3548 | } | 3586 | } |
| 3587 | qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); | ||
| 3588 | qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); | ||
| 3549 | return 0; | 3589 | return 0; |
| 3550 | } | 3590 | } |
| 3551 | 3591 | ||
