diff options
Diffstat (limited to 'drivers/s390/net/qeth_l2_main.c')
-rw-r--r-- | drivers/s390/net/qeth_l2_main.c | 173 |
1 files changed, 108 insertions, 65 deletions
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 | ||