SBALs in PRIMED or ERROR state represent new work on the Input Queue. But while inbound_primed() does all sorts of ACK management for new PRIMED work, the same handling is currently missing for ERROR work. In particular the path for ERROR work doesn't clear up _old_ ACKs. Treat ERROR work the same as PRIMED work, but consider that the QEBSM auto-ACK feature doesn't apply here. So we need to set the ACK manually, as if it was a non-QEBSM device. Note that this doesn't aspire to actually improve performance, the main goal is to just unify the code paths and have consistent behaviour.
Unified · Split
| @@ -438,15 +438,12 @@ static void process_buffer_error(struct qdio_q *q, unsigned int start, · 437 unmodified lines | |||
| 438 | q->sbal[start]->element[15].sflags); | 438 | q->sbal[start]->element[15].sflags); |
| 439 | } | 439 | } |
| 440 | 440 | ||
| 441 | static inline void inbound_primed(struct qdio_q *q, unsigned int start, | 441 | static inline void inbound_handle_work(struct qdio_q *q, unsigned int start, |
| 442 | int count) | 442 | int count, bool auto_ack) |
| 443 | { | 443 | { |
| 444 | int new; | 444 | int new; |
| 445 | 445 | ||
| 446 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim:%1d %02x", q->nr, count); | 446 | if (auto_ack) { |
| 447 | |||
| 448 | /* for QEBSM the ACK was already set by EQBS */ | ||
| 449 | if (is_qebsm(q)) { | ||
| 450 | if (!q->u.in.ack_count) { | 447 | if (!q->u.in.ack_count) { |
| 451 | q->u.in.ack_count = count; | 448 | q->u.in.ack_count = count; |
| 452 | q->u.in.ack_start = start; | 449 | q->u.in.ack_start = start; |
| @@ -507,19 +504,21 @@ static int get_inbound_buffer_frontier(struct qdio_q *q, unsigned int start) · 54 unmodified lines | |||
| 507 | 504 | ||
| 508 | switch (state) { | 505 | switch (state) { |
| 509 | case SLSB_P_INPUT_PRIMED: | 506 | case SLSB_P_INPUT_PRIMED: |
| 510 | inbound_primed(q, start, count); | 507 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim:%1d %02x", q->nr, |
| 508 | count); | ||
| 509 | |||
| 510 | inbound_handle_work(q, start, count, is_qebsm(q)); | ||
| 511 | if (atomic_sub_return(count, &q->nr_buf_used) == 0) | 511 | if (atomic_sub_return(count, &q->nr_buf_used) == 0) |
| 512 | qperf_inc(q, inbound_queue_full); | 512 | qperf_inc(q, inbound_queue_full); |
| 513 | if (q->irq_ptr->perf_stat_enabled) | 513 | if (q->irq_ptr->perf_stat_enabled) |
| 514 | account_sbals(q, count); | 514 | account_sbals(q, count); |
| 515 | return count; | 515 | return count; |
| 516 | case SLSB_P_INPUT_ERROR: | 516 | case SLSB_P_INPUT_ERROR: |
| 517 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in err:%1d %02x", q->nr, | ||
| 518 | count); | ||
| 519 | |||
| 517 | process_buffer_error(q, start, count); | 520 | process_buffer_error(q, start, count); |
| 518 | /* | 521 | inbound_handle_work(q, start, count, false); |
| 519 | * Interrupts may be avoided as long as the error is present | ||
| 520 | * so change the buffer state immediately to avoid starvation. | ||
| 521 | */ | ||
| 522 | set_buf_states(q, start, SLSB_P_INPUT_NOT_INIT, count); | ||
| 523 | if (atomic_sub_return(count, &q->nr_buf_used) == 0) | 522 | if (atomic_sub_return(count, &q->nr_buf_used) == 0) |
| 524 | qperf_inc(q, inbound_queue_full); | 523 | qperf_inc(q, inbound_queue_full); |
| 525 | if (q->irq_ptr->perf_stat_enabled) | 524 | if (q->irq_ptr->perf_stat_enabled) |