|
@@ -25,24 +25,20 @@
|
|
*/
|
|
*/
|
|
#define TIQDIO_NR_NONSHARED_IND 63
|
|
#define TIQDIO_NR_NONSHARED_IND 63
|
|
#define TIQDIO_NR_INDICATORS (TIQDIO_NR_NONSHARED_IND + 1)
|
|
#define TIQDIO_NR_INDICATORS (TIQDIO_NR_NONSHARED_IND + 1)
|
|
-#define TIQDIO_SHARED_IND 63
|
|
|
|
|
|
|
|
/* list of thin interrupt input queues */
|
|
/* list of thin interrupt input queues */
|
|
static LIST_HEAD(tiq_list);
|
|
static LIST_HEAD(tiq_list);
|
|
DEFINE_MUTEX(tiq_list_lock);
|
|
DEFINE_MUTEX(tiq_list_lock);
|
|
|
|
|
|
/* adapter local summary indicator */
|
|
/* adapter local summary indicator */
|
|
-static unsigned char *tiqdio_alsi;
|
|
|
|
|
|
+static u8 *tiqdio_alsi;
|
|
|
|
|
|
-/* device state change indicators */
|
|
|
|
-struct indicator_t {
|
|
|
|
- u32 ind; /* u32 because of compare-and-swap performance */
|
|
|
|
- atomic_t count; /* use count, 0 or 1 for non-shared indicators */
|
|
|
|
-};
|
|
|
|
-static struct indicator_t *q_indicators;
|
|
|
|
|
|
+struct indicator_t *q_indicators;
|
|
|
|
|
|
static int css_qdio_omit_svs;
|
|
static int css_qdio_omit_svs;
|
|
|
|
|
|
|
|
+static u64 last_ai_time;
|
|
|
|
+
|
|
static inline unsigned long do_clear_global_summary(void)
|
|
static inline unsigned long do_clear_global_summary(void)
|
|
{
|
|
{
|
|
register unsigned long __fn asm("1") = 3;
|
|
register unsigned long __fn asm("1") = 3;
|
|
@@ -116,59 +112,73 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static inline int shared_ind(struct qdio_irq *irq_ptr)
|
|
|
|
|
|
+static inline int shared_ind_used(void)
|
|
{
|
|
{
|
|
- return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
|
|
|
|
|
|
+ return atomic_read(&q_indicators[TIQDIO_SHARED_IND].count);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* tiqdio_thinint_handler - thin interrupt handler for qdio
|
|
* tiqdio_thinint_handler - thin interrupt handler for qdio
|
|
- * @ind: pointer to adapter local summary indicator
|
|
|
|
- * @drv_data: NULL
|
|
|
|
|
|
+ * @alsi: pointer to adapter local summary indicator
|
|
|
|
+ * @data: NULL
|
|
*/
|
|
*/
|
|
-static void tiqdio_thinint_handler(void *ind, void *drv_data)
|
|
|
|
|
|
+static void tiqdio_thinint_handler(void *alsi, void *data)
|
|
{
|
|
{
|
|
struct qdio_q *q;
|
|
struct qdio_q *q;
|
|
|
|
|
|
|
|
+ last_ai_time = S390_lowcore.int_clock;
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* SVS only when needed: issue SVS to benefit from iqdio interrupt
|
|
* SVS only when needed: issue SVS to benefit from iqdio interrupt
|
|
- * avoidance (SVS clears adapter interrupt suppression overwrite)
|
|
|
|
|
|
+ * avoidance (SVS clears adapter interrupt suppression overwrite).
|
|
*/
|
|
*/
|
|
if (!css_qdio_omit_svs)
|
|
if (!css_qdio_omit_svs)
|
|
do_clear_global_summary();
|
|
do_clear_global_summary();
|
|
|
|
|
|
- /*
|
|
|
|
- * reset local summary indicator (tiqdio_alsi) to stop adapter
|
|
|
|
- * interrupts for now
|
|
|
|
- */
|
|
|
|
- xchg((u8 *)ind, 0);
|
|
|
|
|
|
+ /* reset local summary indicator */
|
|
|
|
+ if (shared_ind_used())
|
|
|
|
+ xchg(tiqdio_alsi, 0);
|
|
|
|
|
|
/* protect tiq_list entries, only changed in activate or shutdown */
|
|
/* protect tiq_list entries, only changed in activate or shutdown */
|
|
rcu_read_lock();
|
|
rcu_read_lock();
|
|
|
|
|
|
/* check for work on all inbound thinint queues */
|
|
/* check for work on all inbound thinint queues */
|
|
- list_for_each_entry_rcu(q, &tiq_list, entry)
|
|
|
|
|
|
+ list_for_each_entry_rcu(q, &tiq_list, entry) {
|
|
|
|
+
|
|
/* only process queues from changed sets */
|
|
/* only process queues from changed sets */
|
|
- if (*q->irq_ptr->dsci) {
|
|
|
|
- qperf_inc(q, adapter_int);
|
|
|
|
|
|
+ if (!*q->irq_ptr->dsci)
|
|
|
|
+ continue;
|
|
|
|
|
|
|
|
+ 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)) {
|
|
|
|
+ qperf_inc(q, int_discarded);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* avoid dsci clear here, done after processing */
|
|
|
|
+ q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr,
|
|
|
|
+ q->irq_ptr->int_parm);
|
|
|
|
+ } else {
|
|
/* only clear it if the indicator is non-shared */
|
|
/* only clear it if the indicator is non-shared */
|
|
if (!shared_ind(q->irq_ptr))
|
|
if (!shared_ind(q->irq_ptr))
|
|
xchg(q->irq_ptr->dsci, 0);
|
|
xchg(q->irq_ptr->dsci, 0);
|
|
/*
|
|
/*
|
|
- * don't call inbound processing directly since
|
|
|
|
- * that could starve other thinint queues
|
|
|
|
|
|
+ * Call inbound processing but not directly
|
|
|
|
+ * since that could starve other thinint queues.
|
|
*/
|
|
*/
|
|
tasklet_schedule(&q->tasklet);
|
|
tasklet_schedule(&q->tasklet);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+ qperf_inc(q, adapter_int);
|
|
|
|
+ }
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
|
|
|
|
/*
|
|
/*
|
|
- * if we used the shared indicator clear it now after all queues
|
|
|
|
- * were processed
|
|
|
|
|
|
+ * If the shared indicator was used clear it now after all queues
|
|
|
|
+ * were processed.
|
|
*/
|
|
*/
|
|
- if (atomic_read(&q_indicators[TIQDIO_SHARED_IND].count)) {
|
|
|
|
|
|
+ if (shared_ind_used()) {
|
|
xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0);
|
|
xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0);
|
|
|
|
|
|
/* prevent racing */
|
|
/* prevent racing */
|