Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

[PATCH] s390: qeth driver fixes [4/6]

[PATCH 7/9] s390: qeth driver fixes [4/6]

From: Frank Pavlic <fpavlic@de.ibm.com>
- fix kernel crash due to race,
set card->state to SOFTSETUP after
card and card->dev are initialized properly.
- remove CONFIG_QETH_PERF_STATS, use sysfs attribute instead,
as we want to have the ability to turn on/off the
statistics at runtime.

Signed-off-by: Frank Pavlic <fpavlic@de.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>

authored by

Frank Pavlic and committed by
Jeff Garzik
09d2d38a f7b65d70

+128 -108
-9
drivers/s390/net/Kconfig
··· 92 92 If CONFIG_QETH is switched on, this option will include IEEE 93 93 802.1q VLAN support in the qeth device driver. 94 94 95 - config QETH_PERF_STATS 96 - bool "Performance statistics in /proc" 97 - depends on QETH 98 - help 99 - When switched on, this option will add a file in the proc-fs 100 - (/proc/qeth_perf_stats) containing performance statistics. It 101 - may slightly impact performance, so this is only recommended for 102 - internal tuning of the device driver. 103 - 104 95 config CCWGROUP 105 96 tristate 106 97 default (LCS || CTC || QETH)
+4 -6
drivers/s390/net/qeth.h
··· 176 176 /** 177 177 * card stuff 178 178 */ 179 - #ifdef CONFIG_QETH_PERF_STATS 180 179 struct qeth_perf_stats { 181 180 unsigned int bufs_rec; 182 181 unsigned int bufs_sent; ··· 210 211 unsigned int large_send_cnt; 211 212 unsigned int sg_skbs_sent; 212 213 unsigned int sg_frags_sent; 214 + /* initial values when measuring starts */ 215 + unsigned long initial_rx_packets; 216 + unsigned long initial_tx_packets; 213 217 }; 214 - #endif /* CONFIG_QETH_PERF_STATS */ 215 218 216 219 /* Routing stuff */ 217 220 struct qeth_routing_info { ··· 768 767 int fake_ll; 769 768 int layer2; 770 769 enum qeth_large_send_types large_send; 770 + int performance_stats; 771 771 }; 772 772 773 773 /* ··· 821 819 struct list_head cmd_waiter_list; 822 820 /* QDIO buffer handling */ 823 821 struct qeth_qdio_info qdio; 824 - #ifdef CONFIG_QETH_PERF_STATS 825 822 struct qeth_perf_stats perf_stats; 826 - #endif /* CONFIG_QETH_PERF_STATS */ 827 823 int use_hard_stop; 828 824 int (*orig_hard_header)(struct sk_buff *,struct net_device *, 829 825 unsigned short,void *,void *,unsigned); ··· 1049 1049 } 1050 1050 } 1051 1051 1052 - #ifdef CONFIG_QETH_PERF_STATS 1053 1052 static inline int 1054 1053 qeth_get_micros(void) 1055 1054 { 1056 1055 return (int) (get_clock() >> 12); 1057 1056 } 1058 - #endif 1059 1057 1060 1058 static inline int 1061 1059 qeth_get_qdio_q_format(struct qeth_card *card)
+2 -3
drivers/s390/net/qeth_eddp.c
··· 179 179 flush_cnt++; 180 180 } 181 181 } else { 182 - #ifdef CONFIG_QETH_PERF_STATS 183 - queue->card->perf_stats.skbs_sent_pack++; 184 - #endif 182 + if (queue->card->options.performance_stats) 183 + queue->card->perf_stats.skbs_sent_pack++; 185 184 QETH_DBF_TEXT(trace, 6, "fillbfpa"); 186 185 if (buf->next_element_to_fill >= 187 186 QETH_MAX_BUFFER_ELEMENTS(queue->card)) {
+69 -78
drivers/s390/net/qeth_main.c
··· 1073 1073 card->options.layer2 = 1; 1074 1074 else 1075 1075 card->options.layer2 = 0; 1076 + card->options.performance_stats = 1; 1076 1077 } 1077 1078 1078 1079 /** ··· 2565 2564 /* get first element of current buffer */ 2566 2565 element = (struct qdio_buffer_element *)&buf->buffer->element[0]; 2567 2566 offset = 0; 2568 - #ifdef CONFIG_QETH_PERF_STATS 2569 - card->perf_stats.bufs_rec++; 2570 - #endif 2567 + if (card->options.performance_stats) 2568 + card->perf_stats.bufs_rec++; 2571 2569 while((skb = qeth_get_next_skb(card, buf->buffer, &element, 2572 2570 &offset, &hdr))) { 2573 2571 skb->dev = card->dev; ··· 2623 2623 { 2624 2624 struct qeth_buffer_pool_entry *pool_entry; 2625 2625 int i; 2626 - 2626 + 2627 2627 pool_entry = qeth_get_buffer_pool_entry(card); 2628 2628 /* 2629 2629 * since the buffer is accessed only from the input_tasklet ··· 2697 2697 * 'index') un-requeued -> this buffer is the first buffer that 2698 2698 * will be requeued the next time 2699 2699 */ 2700 - #ifdef CONFIG_QETH_PERF_STATS 2701 - card->perf_stats.inbound_do_qdio_cnt++; 2702 - card->perf_stats.inbound_do_qdio_start_time = qeth_get_micros(); 2703 - #endif 2700 + if (card->options.performance_stats) { 2701 + card->perf_stats.inbound_do_qdio_cnt++; 2702 + card->perf_stats.inbound_do_qdio_start_time = 2703 + qeth_get_micros(); 2704 + } 2704 2705 rc = do_QDIO(CARD_DDEV(card), 2705 2706 QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT, 2706 2707 0, queue->next_buf_to_init, count, NULL); 2707 - #ifdef CONFIG_QETH_PERF_STATS 2708 - card->perf_stats.inbound_do_qdio_time += qeth_get_micros() - 2709 - card->perf_stats.inbound_do_qdio_start_time; 2710 - #endif 2708 + if (card->options.performance_stats) 2709 + card->perf_stats.inbound_do_qdio_time += 2710 + qeth_get_micros() - 2711 + card->perf_stats.inbound_do_qdio_start_time; 2711 2712 if (rc){ 2712 2713 PRINT_WARN("qeth_queue_input_buffer's do_QDIO " 2713 2714 "return %i (device %s).\n", ··· 2744 2743 QETH_DBF_TEXT(trace, 6, "qdinput"); 2745 2744 card = (struct qeth_card *) card_ptr; 2746 2745 net_dev = card->dev; 2747 - #ifdef CONFIG_QETH_PERF_STATS 2748 - card->perf_stats.inbound_cnt++; 2749 - card->perf_stats.inbound_start_time = qeth_get_micros(); 2750 - #endif 2746 + if (card->options.performance_stats) { 2747 + card->perf_stats.inbound_cnt++; 2748 + card->perf_stats.inbound_start_time = qeth_get_micros(); 2749 + } 2751 2750 if (status & QDIO_STATUS_LOOK_FOR_ERROR) { 2752 2751 if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION){ 2753 2752 QETH_DBF_TEXT(trace, 1,"qdinchk"); ··· 2769 2768 qeth_put_buffer_pool_entry(card, buffer->pool_entry); 2770 2769 qeth_queue_input_buffer(card, index); 2771 2770 } 2772 - #ifdef CONFIG_QETH_PERF_STATS 2773 - card->perf_stats.inbound_time += qeth_get_micros() - 2774 - card->perf_stats.inbound_start_time; 2775 - #endif 2771 + if (card->options.performance_stats) 2772 + card->perf_stats.inbound_time += qeth_get_micros() - 2773 + card->perf_stats.inbound_start_time; 2776 2774 } 2777 2775 2778 2776 static inline int ··· 2861 2861 } 2862 2862 2863 2863 queue->card->dev->trans_start = jiffies; 2864 - #ifdef CONFIG_QETH_PERF_STATS 2865 - queue->card->perf_stats.outbound_do_qdio_cnt++; 2866 - queue->card->perf_stats.outbound_do_qdio_start_time = qeth_get_micros(); 2867 - #endif 2864 + if (queue->card->options.performance_stats) { 2865 + queue->card->perf_stats.outbound_do_qdio_cnt++; 2866 + queue->card->perf_stats.outbound_do_qdio_start_time = 2867 + qeth_get_micros(); 2868 + } 2868 2869 if (under_int) 2869 2870 rc = do_QDIO(CARD_DDEV(queue->card), 2870 2871 QDIO_FLAG_SYNC_OUTPUT | QDIO_FLAG_UNDER_INTERRUPT, ··· 2873 2872 else 2874 2873 rc = do_QDIO(CARD_DDEV(queue->card), QDIO_FLAG_SYNC_OUTPUT, 2875 2874 queue->queue_no, index, count, NULL); 2876 - #ifdef CONFIG_QETH_PERF_STATS 2877 - queue->card->perf_stats.outbound_do_qdio_time += qeth_get_micros() - 2878 - queue->card->perf_stats.outbound_do_qdio_start_time; 2879 - #endif 2875 + if (queue->card->options.performance_stats) 2876 + queue->card->perf_stats.outbound_do_qdio_time += 2877 + qeth_get_micros() - 2878 + queue->card->perf_stats.outbound_do_qdio_start_time; 2880 2879 if (rc){ 2881 2880 QETH_DBF_TEXT(trace, 2, "flushbuf"); 2882 2881 QETH_DBF_TEXT_(trace, 2, " err%d", rc); ··· 2888 2887 return; 2889 2888 } 2890 2889 atomic_add(count, &queue->used_buffers); 2891 - #ifdef CONFIG_QETH_PERF_STATS 2892 - queue->card->perf_stats.bufs_sent += count; 2893 - #endif 2890 + if (queue->card->options.performance_stats) 2891 + queue->card->perf_stats.bufs_sent += count; 2894 2892 } 2895 2893 2896 2894 /* ··· 2904 2904 >= QETH_HIGH_WATERMARK_PACK){ 2905 2905 /* switch non-PACKING -> PACKING */ 2906 2906 QETH_DBF_TEXT(trace, 6, "np->pack"); 2907 - #ifdef CONFIG_QETH_PERF_STATS 2908 - queue->card->perf_stats.sc_dp_p++; 2909 - #endif 2907 + if (queue->card->options.performance_stats) 2908 + queue->card->perf_stats.sc_dp_p++; 2910 2909 queue->do_pack = 1; 2911 2910 } 2912 2911 } ··· 2928 2929 <= QETH_LOW_WATERMARK_PACK) { 2929 2930 /* switch PACKING -> non-PACKING */ 2930 2931 QETH_DBF_TEXT(trace, 6, "pack->np"); 2931 - #ifdef CONFIG_QETH_PERF_STATS 2932 - queue->card->perf_stats.sc_p_dp++; 2933 - #endif 2932 + if (queue->card->options.performance_stats) 2933 + queue->card->perf_stats.sc_p_dp++; 2934 2934 queue->do_pack = 0; 2935 2935 /* flush packing buffers */ 2936 2936 buffer = &queue->bufs[queue->next_buf_to_fill]; ··· 2941 2943 queue->next_buf_to_fill = 2942 2944 (queue->next_buf_to_fill + 1) % 2943 2945 QDIO_MAX_BUFFERS_PER_Q; 2944 - } 2946 + } 2945 2947 } 2946 2948 } 2947 2949 return flush_count; ··· 2997 2999 !atomic_read(&queue->set_pci_flags_count)) 2998 3000 flush_cnt += 2999 3001 qeth_flush_buffers_on_no_pci(queue); 3000 - #ifdef CONFIG_QETH_PERF_STATS 3001 - if (q_was_packing) 3002 + if (queue->card->options.performance_stats && 3003 + q_was_packing) 3002 3004 queue->card->perf_stats.bufs_sent_pack += 3003 3005 flush_cnt; 3004 - #endif 3005 3006 if (flush_cnt) 3006 3007 qeth_flush_buffers(queue, 1, index, flush_cnt); 3007 3008 atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); ··· 3030 3033 return; 3031 3034 } 3032 3035 } 3033 - #ifdef CONFIG_QETH_PERF_STATS 3034 - card->perf_stats.outbound_handler_cnt++; 3035 - card->perf_stats.outbound_handler_start_time = qeth_get_micros(); 3036 - #endif 3036 + if (card->options.performance_stats) { 3037 + card->perf_stats.outbound_handler_cnt++; 3038 + card->perf_stats.outbound_handler_start_time = 3039 + qeth_get_micros(); 3040 + } 3037 3041 for(i = first_element; i < (first_element + count); ++i){ 3038 3042 buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; 3039 3043 /*we only handle the KICK_IT error by doing a recovery */ ··· 3053 3055 qeth_check_outbound_queue(queue); 3054 3056 3055 3057 netif_wake_queue(queue->card->dev); 3056 - #ifdef CONFIG_QETH_PERF_STATS 3057 - card->perf_stats.outbound_handler_time += qeth_get_micros() - 3058 - card->perf_stats.outbound_handler_start_time; 3059 - #endif 3058 + if (card->options.performance_stats) 3059 + card->perf_stats.outbound_handler_time += qeth_get_micros() - 3060 + card->perf_stats.outbound_handler_start_time; 3060 3061 } 3061 3062 3062 3063 static void ··· 3681 3684 /* return OK; otherwise ksoftirqd goes to 100% */ 3682 3685 return NETDEV_TX_OK; 3683 3686 } 3684 - #ifdef CONFIG_QETH_PERF_STATS 3685 - card->perf_stats.outbound_cnt++; 3686 - card->perf_stats.outbound_start_time = qeth_get_micros(); 3687 - #endif 3687 + if (card->options.performance_stats) { 3688 + card->perf_stats.outbound_cnt++; 3689 + card->perf_stats.outbound_start_time = qeth_get_micros(); 3690 + } 3688 3691 netif_stop_queue(dev); 3689 3692 if ((rc = qeth_send_packet(card, skb))) { 3690 3693 if (rc == -EBUSY) { ··· 3698 3701 } 3699 3702 } 3700 3703 netif_wake_queue(dev); 3701 - #ifdef CONFIG_QETH_PERF_STATS 3702 - card->perf_stats.outbound_time += qeth_get_micros() - 3703 - card->perf_stats.outbound_start_time; 3704 - #endif 3704 + if (card->options.performance_stats) 3705 + card->perf_stats.outbound_time += qeth_get_micros() - 3706 + card->perf_stats.outbound_start_time; 3705 3707 return rc; 3706 3708 } 3707 3709 ··· 4209 4213 flush_cnt = 1; 4210 4214 } else { 4211 4215 QETH_DBF_TEXT(trace, 6, "fillbfpa"); 4212 - #ifdef CONFIG_QETH_PERF_STATS 4213 - queue->card->perf_stats.skbs_sent_pack++; 4214 - #endif 4216 + if (queue->card->options.performance_stats) 4217 + queue->card->perf_stats.skbs_sent_pack++; 4215 4218 if (buf->next_element_to_fill >= 4216 4219 QETH_MAX_BUFFER_ELEMENTS(queue->card)) { 4217 4220 /* ··· 4375 4380 qeth_flush_buffers(queue, 0, start_index, flush_count); 4376 4381 } 4377 4382 /* at this point the queue is UNLOCKED again */ 4378 - #ifdef CONFIG_QETH_PERF_STATS 4379 - if (do_pack) 4383 + if (queue->card->options.performance_stats && do_pack) 4380 4384 queue->card->perf_stats.bufs_sent_pack += flush_count; 4381 - #endif /* CONFIG_QETH_PERF_STATS */ 4382 4385 4383 4386 return rc; 4384 4387 } ··· 4413 4420 enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; 4414 4421 struct qeth_eddp_context *ctx = NULL; 4415 4422 int tx_bytes = skb->len; 4416 - #ifdef CONFIG_QETH_PERF_STATS 4417 4423 unsigned short nr_frags = skb_shinfo(skb)->nr_frags; 4418 4424 unsigned short tso_size = skb_shinfo(skb)->gso_size; 4419 - #endif 4420 4425 struct sk_buff *new_skb, *new_skb2; 4421 4426 int rc; 4422 4427 ··· 4496 4505 card->stats.tx_bytes += tx_bytes; 4497 4506 if (new_skb != skb) 4498 4507 dev_kfree_skb_any(skb); 4499 - #ifdef CONFIG_QETH_PERF_STATS 4500 - if (tso_size && 4501 - !(large_send == QETH_LARGE_SEND_NO)) { 4502 - card->perf_stats.large_send_bytes += tx_bytes; 4503 - card->perf_stats.large_send_cnt++; 4508 + if (card->options.performance_stats) { 4509 + if (tso_size && 4510 + !(large_send == QETH_LARGE_SEND_NO)) { 4511 + card->perf_stats.large_send_bytes += tx_bytes; 4512 + card->perf_stats.large_send_cnt++; 4513 + } 4514 + if (nr_frags > 0) { 4515 + card->perf_stats.sg_skbs_sent++; 4516 + /* nr_frags + skb->data */ 4517 + card->perf_stats.sg_frags_sent += 4518 + nr_frags + 1; 4519 + } 4504 4520 } 4505 - if (nr_frags > 0) { 4506 - card->perf_stats.sg_skbs_sent++; 4507 - /* nr_frags + skb->data */ 4508 - card->perf_stats.sg_frags_sent += 4509 - nr_frags + 1; 4510 - } 4511 - #endif /* CONFIG_QETH_PERF_STATS */ 4512 4521 } else { 4513 4522 card->stats.tx_dropped++; 4514 4523 __qeth_free_new_skb(skb, new_skb); ··· 7869 7878 QETH_DBF_TEXT_(setup, 2, "5err%d", rc); 7870 7879 goto out_remove; 7871 7880 } 7872 - card->state = CARD_STATE_SOFTSETUP; 7873 7881 7874 7882 if ((rc = qeth_init_qdio_queues(card))){ 7875 7883 QETH_DBF_TEXT_(setup, 2, "6err%d", rc); 7876 7884 goto out_remove; 7877 7885 } 7886 + card->state = CARD_STATE_SOFTSETUP; 7878 7887 netif_carrier_on(card->dev); 7879 7888 7880 7889 qeth_set_allowed_threads(card, 0xffffffff, 0);
+11 -12
drivers/s390/net/qeth_proc.c
··· 173 173 #define QETH_PERF_PROCFILE_NAME "qeth_perf" 174 174 static struct proc_dir_entry *qeth_perf_procfile; 175 175 176 - #ifdef CONFIG_QETH_PERF_STATS 177 176 static int 178 177 qeth_perf_procfile_seq_show(struct seq_file *s, void *it) 179 178 { ··· 191 192 CARD_DDEV_ID(card), 192 193 QETH_CARD_IFNAME(card) 193 194 ); 195 + if (!card->options.performance_stats) 196 + seq_printf(s, "Performance statistics are deactivated.\n"); 194 197 seq_printf(s, " Skb's/buffers received : %lu/%u\n" 195 198 " Skb's/buffers sent : %lu/%u\n\n", 196 - card->stats.rx_packets, card->perf_stats.bufs_rec, 197 - card->stats.tx_packets, card->perf_stats.bufs_sent 199 + card->stats.rx_packets - 200 + card->perf_stats.initial_rx_packets, 201 + card->perf_stats.bufs_rec, 202 + card->stats.tx_packets - 203 + card->perf_stats.initial_tx_packets, 204 + card->perf_stats.bufs_sent 198 205 ); 199 206 seq_printf(s, " Skb's/buffers sent without packing : %lu/%u\n" 200 207 " Skb's/buffers sent with packing : %u/%u\n\n", 201 - card->stats.tx_packets - card->perf_stats.skbs_sent_pack, 208 + card->stats.tx_packets - card->perf_stats.initial_tx_packets 209 + - card->perf_stats.skbs_sent_pack, 202 210 card->perf_stats.bufs_sent - card->perf_stats.bufs_sent_pack, 203 211 card->perf_stats.skbs_sent_pack, 204 212 card->perf_stats.bufs_sent_pack ··· 281 275 .release = seq_release, 282 276 }; 283 277 284 - #define qeth_perf_procfile_created qeth_perf_procfile 285 - #else 286 - #define qeth_perf_procfile_created 1 287 - #endif /* CONFIG_QETH_PERF_STATS */ 288 - 289 278 int __init 290 279 qeth_create_procfs_entries(void) 291 280 { ··· 289 288 if (qeth_procfile) 290 289 qeth_procfile->proc_fops = &qeth_procfile_fops; 291 290 292 - #ifdef CONFIG_QETH_PERF_STATS 293 291 qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME, 294 292 S_IFREG | 0444, NULL); 295 293 if (qeth_perf_procfile) 296 294 qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops; 297 - #endif /* CONFIG_QETH_PERF_STATS */ 298 295 299 296 if (qeth_procfile && 300 - qeth_perf_procfile_created) 297 + qeth_perf_procfile) 301 298 return 0; 302 299 else 303 300 return -ENOMEM;
+42
drivers/s390/net/qeth_sys.c
··· 743 743 qeth_dev_layer2_store); 744 744 745 745 static ssize_t 746 + qeth_dev_performance_stats_show(struct device *dev, struct device_attribute *attr, char *buf) 747 + { 748 + struct qeth_card *card = dev->driver_data; 749 + 750 + if (!card) 751 + return -EINVAL; 752 + 753 + return sprintf(buf, "%i\n", card->options.performance_stats ? 1:0); 754 + } 755 + 756 + static ssize_t 757 + qeth_dev_performance_stats_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 758 + { 759 + struct qeth_card *card = dev->driver_data; 760 + char *tmp; 761 + int i; 762 + 763 + if (!card) 764 + return -EINVAL; 765 + 766 + i = simple_strtoul(buf, &tmp, 16); 767 + if ((i == 0) || (i == 1)) { 768 + if (i == card->options.performance_stats) 769 + return count; 770 + card->options.performance_stats = i; 771 + if (i == 0) 772 + memset(&card->perf_stats, 0, 773 + sizeof(struct qeth_perf_stats)); 774 + card->perf_stats.initial_rx_packets = card->stats.rx_packets; 775 + card->perf_stats.initial_tx_packets = card->stats.tx_packets; 776 + } else { 777 + PRINT_WARN("performance_stats: write 0 or 1 to this file!\n"); 778 + return -EINVAL; 779 + } 780 + return count; 781 + } 782 + 783 + static DEVICE_ATTR(performance_stats, 0644, qeth_dev_performance_stats_show, 784 + qeth_dev_performance_stats_store); 785 + 786 + static ssize_t 746 787 qeth_dev_large_send_show(struct device *dev, struct device_attribute *attr, char *buf) 747 788 { 748 789 struct qeth_card *card = dev->driver_data; ··· 969 928 &dev_attr_canonical_macaddr, 970 929 &dev_attr_layer2, 971 930 &dev_attr_large_send, 931 + &dev_attr_performance_stats, 972 932 NULL, 973 933 }; 974 934