diff options
Diffstat (limited to 'drivers/s390')
| -rw-r--r-- | drivers/s390/cio/qdio.h | 11 | ||||
| -rw-r--r-- | drivers/s390/cio/qdio_debug.c | 4 | ||||
| -rw-r--r-- | drivers/s390/cio/qdio_main.c | 50 | ||||
| -rw-r--r-- | drivers/s390/cio/qdio_setup.c | 16 | ||||
| -rw-r--r-- | drivers/s390/cio/qdio_thinint.c | 38 | ||||
| -rw-r--r-- | drivers/s390/net/qeth_core_main.c | 68 | 
6 files changed, 83 insertions, 104 deletions
| diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index ff74eb5fce50..f72f961cc78f 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -177,8 +177,8 @@ struct qdio_queue_perf_stat {  	unsigned int nr_sbal_total;  }; -enum qdio_queue_irq_states { -	QDIO_QUEUE_IRQS_DISABLED, +enum qdio_irq_poll_states { +	QDIO_IRQ_DISABLED,  };  struct qdio_input_q { @@ -188,10 +188,6 @@ struct qdio_input_q {  	int ack_count;  	/* last time of noticing incoming data */  	u64 timestamp; -	/* upper-layer polling flag */ -	unsigned long queue_irq_state; -	/* callback to start upper-layer polling */ -	void (*queue_start_poll) (struct ccw_device *, int, unsigned long);  };  struct qdio_output_q { @@ -299,6 +295,9 @@ struct qdio_irq {  	struct qdio_q *input_qs[QDIO_MAX_QUEUES_PER_IRQ];  	struct qdio_q *output_qs[QDIO_MAX_QUEUES_PER_IRQ]; +	void (*irq_poll)(struct ccw_device *cdev, unsigned long data); +	unsigned long poll_state; +  	debug_info_t *debug_area;  	struct mutex setup_mutex;  	struct qdio_dev_perf_stat perf_stat; diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index 9c0370b27426..00244607c8c0 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -128,8 +128,8 @@ static int qstat_show(struct seq_file *m, void *v)  			   q->u.in.ack_start, q->u.in.ack_count);  		seq_printf(m, "DSCI: %x   IRQs disabled: %u\n",  			   *(u8 *)q->irq_ptr->dsci, -			   test_bit(QDIO_QUEUE_IRQS_DISABLED, -			   &q->u.in.queue_irq_state)); +			   test_bit(QDIO_IRQ_DISABLED, +				    &q->irq_ptr->poll_state));  	}  	seq_printf(m, "SBAL states:\n");  	seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n"); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 3475317c42e5..02ced5949287 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -950,19 +950,14 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)  	if (unlikely(irq_ptr->state != QDIO_IRQ_STATE_ACTIVE))  		return; -	for_each_input_queue(irq_ptr, q, i) { -		if (q->u.in.queue_start_poll) { -			/* skip if polling is enabled or already in work */ -			if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, -				     &q->u.in.queue_irq_state)) { -				QDIO_PERF_STAT_INC(irq_ptr, int_discarded); -				continue; -			} -			q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr, -						 q->irq_ptr->int_parm); -		} else { +	if (irq_ptr->irq_poll) { +		if (!test_and_set_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state)) +			irq_ptr->irq_poll(irq_ptr->cdev, irq_ptr->int_parm); +		else +			QDIO_PERF_STAT_INC(irq_ptr, int_discarded); +	} else { +		for_each_input_queue(irq_ptr, q, i)  			tasklet_schedule(&q->tasklet); -		}  	}  	if (!pci_out_supported(irq_ptr) || !irq_ptr->scan_threshold) @@ -1610,24 +1605,26 @@ EXPORT_SYMBOL_GPL(do_QDIO);  /**   * qdio_start_irq - process input buffers   * @cdev: associated ccw_device for the qdio subchannel - * @nr: input queue number   *   * Return codes   *   0 - success   *   1 - irqs not started since new data is available   */ -int qdio_start_irq(struct ccw_device *cdev, int nr) +int qdio_start_irq(struct ccw_device *cdev)  {  	struct qdio_q *q;  	struct qdio_irq *irq_ptr = cdev->private->qdio_data; +	unsigned int i;  	if (!irq_ptr)  		return -ENODEV; -	q = irq_ptr->input_qs[nr];  	clear_nonshared_ind(irq_ptr); -	qdio_stop_polling(q); -	clear_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state); + +	for_each_input_queue(irq_ptr, q, i) +		qdio_stop_polling(q); + +	clear_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state);  	/*  	 * We need to check again to not lose initiative after @@ -1635,13 +1632,16 @@ int qdio_start_irq(struct ccw_device *cdev, int nr)  	 */  	if (test_nonshared_ind(irq_ptr))  		goto rescan; -	if (!qdio_inbound_q_done(q, q->first_to_check)) -		goto rescan; + +	for_each_input_queue(irq_ptr, q, i) { +		if (!qdio_inbound_q_done(q, q->first_to_check)) +			goto rescan; +	} +  	return 0;  rescan: -	if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, -			     &q->u.in.queue_irq_state)) +	if (test_and_set_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state))  		return 0;  	else  		return 1; @@ -1729,23 +1729,19 @@ EXPORT_SYMBOL(qdio_get_next_buffers);  /**   * qdio_stop_irq - disable interrupt processing for the device   * @cdev: associated ccw_device for the qdio subchannel - * @nr: input queue number   *   * Return codes   *   0 - interrupts were already disabled   *   1 - interrupts successfully disabled   */ -int qdio_stop_irq(struct ccw_device *cdev, int nr) +int qdio_stop_irq(struct ccw_device *cdev)  { -	struct qdio_q *q;  	struct qdio_irq *irq_ptr = cdev->private->qdio_data;  	if (!irq_ptr)  		return -ENODEV; -	q = irq_ptr->input_qs[nr]; -	if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, -			     &q->u.in.queue_irq_state)) +	if (test_and_set_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state))  		return 0;  	else  		return 1; diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 66e4bdca9d89..7b831bb4e229 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -224,15 +224,6 @@ static void setup_queues(struct qdio_irq *irq_ptr,  		setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i);  		q->is_input_q = 1; -		if (qdio_init->queue_start_poll_array && -		    qdio_init->queue_start_poll_array[i]) { -			q->u.in.queue_start_poll = -				qdio_init->queue_start_poll_array[i]; -			set_bit(QDIO_QUEUE_IRQS_DISABLED, -				&q->u.in.queue_irq_state); -		} else { -			q->u.in.queue_start_poll = NULL; -		}  		setup_storage_lists(q, irq_ptr, input_sbal_array, i);  		input_sbal_array += QDIO_MAX_BUFFERS_PER_Q; @@ -483,6 +474,13 @@ int qdio_setup_irq(struct qdio_initialize *init_data)  	ccw_device_get_schid(irq_ptr->cdev, &irq_ptr->schid);  	setup_queues(irq_ptr, init_data); +	if (init_data->irq_poll) { +		irq_ptr->irq_poll = init_data->irq_poll; +		set_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state); +	} else { +		irq_ptr->irq_poll = NULL; +	} +  	setup_qib(irq_ptr, init_data);  	qdio_setup_thinint(irq_ptr);  	set_impl_params(irq_ptr, init_data->qib_param_field_format, diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 7c4e4ec08a12..8f315c53de23 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -135,28 +135,24 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)  	    has_multiple_inq_on_dsci(irq))  		xchg(irq->dsci, 0); +	if (irq->irq_poll) { +		if (!test_and_set_bit(QDIO_IRQ_DISABLED, &irq->poll_state)) +			irq->irq_poll(irq->cdev, irq->int_parm); +		else +			QDIO_PERF_STAT_INC(irq, int_discarded); + +		return; +	} +  	for_each_input_queue(irq, q, i) { -		if (q->u.in.queue_start_poll) { -			/* skip if polling is enabled or already in work */ -			if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, -					     &q->u.in.queue_irq_state)) { -				QDIO_PERF_STAT_INC(irq, int_discarded); -				continue; -			} - -			/* avoid dsci clear here, done after processing */ -			q->u.in.queue_start_poll(irq->cdev, q->nr, -						 irq->int_parm); -		} else { -			if (!shared_ind(irq)) -				xchg(irq->dsci, 0); - -			/* -			 * Call inbound processing but not directly -			 * since that could starve other thinint queues. -			 */ -			tasklet_schedule(&q->tasklet); -		} +		if (!shared_ind(irq)) +			xchg(irq->dsci, 0); + +		/* +		 * Call inbound processing but not directly +		 * since that could starve other thinint queues. +		 */ +		tasklet_schedule(&q->tasklet);  	}  } diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 13facf2d602b..68bba8d057d1 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -548,14 +548,6 @@ static void qeth_qdio_handle_aob(struct qeth_card *card,  	qdio_release_aob(aob);  } -static inline int qeth_is_cq(struct qeth_card *card, unsigned int queue) -{ -	return card->options.cq == QETH_CQ_ENABLED && -	    card->qdio.c_q != NULL && -	    queue != 0 && -	    queue == card->qdio.no_in_queues - 1; -} -  static void qeth_setup_ccw(struct ccw1 *ccw, u8 cmd_code, u8 flags, u32 len,  			   void *data)  { @@ -3469,8 +3461,7 @@ static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)  	}  } -static void qeth_qdio_start_poll(struct ccw_device *ccwdev, int queue, -				 unsigned long card_ptr) +static void qeth_qdio_poll(struct ccw_device *cdev, unsigned long card_ptr)  {  	struct qeth_card *card = (struct qeth_card *)card_ptr; @@ -3508,9 +3499,6 @@ static void qeth_qdio_cq_handler(struct qeth_card *card, unsigned int qdio_err,  	int i;  	int rc; -	if (!qeth_is_cq(card, queue)) -		return; -  	QETH_CARD_TEXT_(card, 5, "qcqhe%d", first_element);  	QETH_CARD_TEXT_(card, 5, "qcqhc%d", count);  	QETH_CARD_TEXT_(card, 5, "qcqherr%d", qdio_err); @@ -3556,9 +3544,7 @@ static void qeth_qdio_input_handler(struct ccw_device *ccwdev,  	QETH_CARD_TEXT_(card, 2, "qihq%d", queue);  	QETH_CARD_TEXT_(card, 2, "qiec%d", qdio_err); -	if (qeth_is_cq(card, queue)) -		qeth_qdio_cq_handler(card, qdio_err, queue, first_elem, count); -	else if (qdio_err) +	if (qdio_err)  		qeth_schedule_recovery(card);  } @@ -4805,10 +4791,7 @@ out:  }  static void qeth_qdio_establish_cq(struct qeth_card *card, -				   struct qdio_buffer **in_sbal_ptrs, -				   void (**queue_start_poll) -					(struct ccw_device *, int, -					 unsigned long)) +				   struct qdio_buffer **in_sbal_ptrs)  {  	int i; @@ -4819,8 +4802,6 @@ static void qeth_qdio_establish_cq(struct qeth_card *card,  		for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++)  			in_sbal_ptrs[offset + i] =  				card->qdio.c_q->bufs[i].buffer; - -		queue_start_poll[card->qdio.no_in_queues - 1] = NULL;  	}  } @@ -4829,7 +4810,6 @@ static int qeth_qdio_establish(struct qeth_card *card)  	struct qdio_initialize init_data;  	char *qib_param_field;  	struct qdio_buffer **in_sbal_ptrs; -	void (**queue_start_poll) (struct ccw_device *, int, unsigned long);  	struct qdio_buffer **out_sbal_ptrs;  	int i, j, k;  	int rc = 0; @@ -4856,16 +4836,7 @@ static int qeth_qdio_establish(struct qeth_card *card)  	for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++)  		in_sbal_ptrs[i] = card->qdio.in_q->bufs[i].buffer; -	queue_start_poll = kcalloc(card->qdio.no_in_queues, sizeof(void *), -				   GFP_KERNEL); -	if (!queue_start_poll) { -		rc = -ENOMEM; -		goto out_free_in_sbals; -	} -	for (i = 0; i < card->qdio.no_in_queues; ++i) -		queue_start_poll[i] = qeth_qdio_start_poll; - -	qeth_qdio_establish_cq(card, in_sbal_ptrs, queue_start_poll); +	qeth_qdio_establish_cq(card, in_sbal_ptrs);  	out_sbal_ptrs =  		kcalloc(card->qdio.no_out_queues * QDIO_MAX_BUFFERS_PER_Q, @@ -4873,7 +4844,7 @@ static int qeth_qdio_establish(struct qeth_card *card)  			GFP_KERNEL);  	if (!out_sbal_ptrs) {  		rc = -ENOMEM; -		goto out_free_queue_start_poll; +		goto out_free_in_sbals;  	}  	for (i = 0, k = 0; i < card->qdio.no_out_queues; ++i) @@ -4891,7 +4862,7 @@ static int qeth_qdio_establish(struct qeth_card *card)  	init_data.no_output_qs           = card->qdio.no_out_queues;  	init_data.input_handler		 = qeth_qdio_input_handler;  	init_data.output_handler	 = qeth_qdio_output_handler; -	init_data.queue_start_poll_array = queue_start_poll; +	init_data.irq_poll		 = qeth_qdio_poll;  	init_data.int_parm               = (unsigned long) card;  	init_data.input_sbal_addr_array  = in_sbal_ptrs;  	init_data.output_sbal_addr_array = out_sbal_ptrs; @@ -4924,8 +4895,6 @@ static int qeth_qdio_establish(struct qeth_card *card)  	}  out:  	kfree(out_sbal_ptrs); -out_free_queue_start_poll: -	kfree(queue_start_poll);  out_free_in_sbals:  	kfree(in_sbal_ptrs);  out_free_qib_param: @@ -5581,6 +5550,24 @@ static unsigned int qeth_rx_poll(struct qeth_card *card, int budget)  	return work_done;  } +static void qeth_cq_poll(struct qeth_card *card) +{ +	unsigned int work_done = 0; + +	while (work_done < QDIO_MAX_BUFFERS_PER_Q) { +		unsigned int start, error; +		int completed; + +		completed = qdio_inspect_queue(CARD_DDEV(card), 1, true, &start, +					       &error); +		if (completed <= 0) +			return; + +		qeth_qdio_cq_handler(card, error, 1, start, completed); +		work_done += completed; +	} +} +  int qeth_poll(struct napi_struct *napi, int budget)  {  	struct qeth_card *card = container_of(napi, struct qeth_card, napi); @@ -5588,12 +5575,15 @@ int qeth_poll(struct napi_struct *napi, int budget)  	work_done = qeth_rx_poll(card, budget); +	if (card->options.cq == QETH_CQ_ENABLED) +		qeth_cq_poll(card); +  	/* Exhausted the RX budget. Keep IRQ disabled, we get called again. */  	if (budget && work_done >= budget)  		return work_done;  	if (napi_complete_done(napi, work_done) && -	    qdio_start_irq(CARD_DDEV(card), 0)) +	    qdio_start_irq(CARD_DDEV(card)))  		napi_schedule(napi);  	return work_done; @@ -6756,7 +6746,7 @@ int qeth_stop(struct net_device *dev)  	}  	napi_disable(&card->napi); -	qdio_stop_irq(CARD_DDEV(card), 0); +	qdio_stop_irq(CARD_DDEV(card));  	return 0;  } |