s390/qdio: let drivers opt-out from Output Queue scanning
If a driver wants to use the new Output Queue poll code, then the qdio layer must disable its internal Queue scanning. Let the driver select this mode by passing a special scan_threshold of 0. As the scan_threshold is the same for all Output Queues, also move it into the main qdio_irq struct. This allows for fast opt-out checking, a driver is expected to operate either _all_ or none of its Output Queues in polling mode. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Acked-by: Vasily Gorbik <gor@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
7c47f5afde
commit
313dc689b1
|
@ -359,7 +359,7 @@ struct qdio_initialize {
|
||||||
qdio_handler_t *output_handler;
|
qdio_handler_t *output_handler;
|
||||||
void (**queue_start_poll_array) (struct ccw_device *, int,
|
void (**queue_start_poll_array) (struct ccw_device *, int,
|
||||||
unsigned long);
|
unsigned long);
|
||||||
int scan_threshold;
|
unsigned int scan_threshold;
|
||||||
unsigned long int_parm;
|
unsigned long int_parm;
|
||||||
struct qdio_buffer **input_sbal_addr_array;
|
struct qdio_buffer **input_sbal_addr_array;
|
||||||
struct qdio_buffer **output_sbal_addr_array;
|
struct qdio_buffer **output_sbal_addr_array;
|
||||||
|
|
|
@ -206,8 +206,6 @@ struct qdio_output_q {
|
||||||
struct qdio_outbuf_state *sbal_state;
|
struct qdio_outbuf_state *sbal_state;
|
||||||
/* timer to check for more outbound work */
|
/* timer to check for more outbound work */
|
||||||
struct timer_list timer;
|
struct timer_list timer;
|
||||||
/* used SBALs before tasklet schedule */
|
|
||||||
int scan_threshold;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -295,6 +293,7 @@ struct qdio_irq {
|
||||||
struct qdio_ssqd_desc ssqd_desc;
|
struct qdio_ssqd_desc ssqd_desc;
|
||||||
void (*orig_handler) (struct ccw_device *, unsigned long, struct irb *);
|
void (*orig_handler) (struct ccw_device *, unsigned long, struct irb *);
|
||||||
|
|
||||||
|
unsigned int scan_threshold; /* used SBALs before tasklet schedule */
|
||||||
int perf_stat_enabled;
|
int perf_stat_enabled;
|
||||||
|
|
||||||
struct qdr *qdr;
|
struct qdr *qdr;
|
||||||
|
|
|
@ -880,7 +880,7 @@ static inline void qdio_check_outbound_pci_queues(struct qdio_irq *irq)
|
||||||
struct qdio_q *out;
|
struct qdio_q *out;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!pci_out_supported(irq))
|
if (!pci_out_supported(irq) || !irq->scan_threshold)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for_each_output_queue(irq, out, i)
|
for_each_output_queue(irq, out, i)
|
||||||
|
@ -973,7 +973,7 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pci_out_supported(irq_ptr))
|
if (!pci_out_supported(irq_ptr) || !irq_ptr->scan_threshold)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for_each_output_queue(irq_ptr, q, i) {
|
for_each_output_queue(irq_ptr, q, i) {
|
||||||
|
@ -1528,6 +1528,7 @@ set:
|
||||||
static int handle_outbound(struct qdio_q *q, unsigned int callflags,
|
static int handle_outbound(struct qdio_q *q, unsigned int callflags,
|
||||||
int bufnr, int count)
|
int bufnr, int count)
|
||||||
{
|
{
|
||||||
|
const unsigned int scan_threshold = q->irq_ptr->scan_threshold;
|
||||||
unsigned char state = 0;
|
unsigned char state = 0;
|
||||||
int used, rc = 0;
|
int used, rc = 0;
|
||||||
|
|
||||||
|
@ -1566,8 +1567,12 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
|
||||||
rc = qdio_kick_outbound_q(q, 0);
|
rc = qdio_kick_outbound_q(q, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Let drivers implement their own completion scanning: */
|
||||||
|
if (!scan_threshold)
|
||||||
|
return rc;
|
||||||
|
|
||||||
/* in case of SIGA errors we must process the error immediately */
|
/* in case of SIGA errors we must process the error immediately */
|
||||||
if (used >= q->u.out.scan_threshold || rc)
|
if (used >= scan_threshold || rc)
|
||||||
qdio_tasklet_schedule(q);
|
qdio_tasklet_schedule(q);
|
||||||
else
|
else
|
||||||
/* free the SBALs in case of no further traffic */
|
/* free the SBALs in case of no further traffic */
|
||||||
|
|
|
@ -248,7 +248,6 @@ static void setup_queues(struct qdio_irq *irq_ptr,
|
||||||
output_sbal_state_array += QDIO_MAX_BUFFERS_PER_Q;
|
output_sbal_state_array += QDIO_MAX_BUFFERS_PER_Q;
|
||||||
|
|
||||||
q->is_input_q = 0;
|
q->is_input_q = 0;
|
||||||
q->u.out.scan_threshold = qdio_init->scan_threshold;
|
|
||||||
setup_storage_lists(q, irq_ptr, output_sbal_array, i);
|
setup_storage_lists(q, irq_ptr, output_sbal_array, i);
|
||||||
output_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
|
output_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
|
||||||
|
|
||||||
|
@ -474,6 +473,7 @@ int qdio_setup_irq(struct qdio_initialize *init_data)
|
||||||
irq_ptr->nr_input_qs = init_data->no_input_qs;
|
irq_ptr->nr_input_qs = init_data->no_input_qs;
|
||||||
irq_ptr->nr_output_qs = init_data->no_output_qs;
|
irq_ptr->nr_output_qs = init_data->no_output_qs;
|
||||||
irq_ptr->cdev = init_data->cdev;
|
irq_ptr->cdev = init_data->cdev;
|
||||||
|
irq_ptr->scan_threshold = init_data->scan_threshold;
|
||||||
ccw_device_get_schid(irq_ptr->cdev, &irq_ptr->schid);
|
ccw_device_get_schid(irq_ptr->cdev, &irq_ptr->schid);
|
||||||
setup_queues(irq_ptr, init_data);
|
setup_queues(irq_ptr, init_data);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue