#include "ioasm.h"
#include "chsc.h"
-#define VERSION_QDIO_C "$Revision: 1.80 $"
+#define VERSION_QDIO_C "$Revision: 1.98 $"
/****************** MODULE PARAMETER VARIABLES ********************/
MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
static debug_info_t *qdio_dbf_sbal;
static debug_info_t *qdio_dbf_trace;
static debug_info_t *qdio_dbf_sense;
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
static debug_info_t *qdio_dbf_slsb_out;
static debug_info_t *qdio_dbf_slsb_in;
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
/* iQDIO stuff: */
static volatile struct qdio_q *tiq_list=NULL; /* volatile as it could change
during a while loop */
-static spinlock_t ttiq_list_lock=SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ttiq_list_lock);
static int register_thinint_result;
static void tiqdio_tl(unsigned long);
static DECLARE_TASKLET(tiqdio_tasklet,tiqdio_tl,0);
SLSB_P_INPUT_NOT_INIT);
/*
* we don't issue this SYNC_MEMORY, as we trust Rick T and
- * moreover will not use the PROCESSING state, so q->polling was 0
+ * moreover will not use the PROCESSING state under VM, so
+ * q->polling was 0 anyway
*/
/*SYNC_MEMORY;*/
if (q->slsb.acc.val[gsf]!=SLSB_P_INPUT_PRIMED)
* small window we can miss between resetting it and
* checking for PRIMED state
*/
- if (q->is_iqdio_q)
+ if (q->is_thinint_q)
tiqdio_set_summary_bit((__u32*)q->dev_st_chg_ind);
return 0;
qdio_is_outbound_q_done(struct qdio_q *q)
{
int no_used;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
+#endif
no_used=atomic_read(&q->number_of_buffers_used);
+#ifdef CONFIG_QDIO_DEBUG
if (no_used) {
sprintf(dbf_text,"oqisnt%02x",no_used);
QDIO_DBF_TEXT4(0,trace,dbf_text);
QDIO_DBF_TEXT4(0,trace,"oqisdone");
}
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* CONFIG_QDIO_DEBUG */
return (no_used==0);
}
qdio_kick_outbound_q(struct qdio_q *q)
{
int result;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
QDIO_DBF_TEXT4(0,trace,"kickoutq");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* CONFIG_QDIO_DEBUG */
if (!q->siga_out)
return;
switch (result) {
case 0:
- /* went smooth this time, reset timestamp */
+ /* went smooth this time, reset timestamp */
+#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT3(0,trace,"cc2reslv");
sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no,
atomic_read(&q->busy_siga_counter));
QDIO_DBF_TEXT3(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
q->timing.busy_start=0;
break;
case (2|QDIO_SIGA_ERROR_B_BIT_SET):
/* cc=2 and busy bit: */
- atomic_inc(&q->busy_siga_counter);
+ atomic_inc(&q->busy_siga_counter);
/* if the last siga was successful, save
* timestamp here */
break;
}
QDIO_DBF_TEXT2(0,trace,"cc2REPRT");
+#ifdef CONFIG_QDIO_DEBUG
sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no,
atomic_read(&q->busy_siga_counter));
QDIO_DBF_TEXT3(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
/* else fallthrough and report error */
default:
/* for plain cc=1, 2 or 3: */
qdio_kick_outbound_handler(struct qdio_q *q)
{
int start, end, real_end, count;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
+#endif
start = q->first_element_to_kick;
/* last_move_ftc was just updated */
count = (end+QDIO_MAX_BUFFERS_PER_Q+1-start)&
(QDIO_MAX_BUFFERS_PER_Q-1);
+#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT4(0,trace,"kickouth");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
sprintf(dbf_text,"s=%2xc=%2x",start,count);
QDIO_DBF_TEXT4(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
if (q->state==QDIO_IRQ_STATE_ACTIVE)
q->handler(q->cdev,QDIO_STATUS_OUTBOUND_INT|
int f,f_mod_no;
volatile char *slsb;
int first_not_to_check;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
+#endif /* CONFIG_QDIO_DEBUG */
+#ifdef QDIO_USE_PROCESSING_STATE
+ int last_position=-1;
+#endif /* QDIO_USE_PROCESSING_STATE */
QDIO_DBF_TEXT4(0,trace,"getibfro");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
if (q->siga_sync) {
set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT);
} else {
- set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_PROCESSING);
+ /* set the previous buffer to NOT_INIT. The current
+ * buffer will be set to PROCESSING at the end of
+ * this function to avoid further interrupts. */
+ if (last_position>=0)
+ set_slsb(&slsb[last_position],
+ SLSB_P_INPUT_NOT_INIT);
atomic_set(&q->polling,1);
+ last_position=f_mod_no;
}
#else /* QDIO_USE_PROCESSING_STATE */
set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT);
#endif /* QDIO_USE_PROCESSING_STATE */
/*
* not needed, as the inbound queue will be synced on the next
- * siga-r
+ * siga-r, resp. tiqdio_is_inbound_q_done will do the siga-s
*/
/*SYNC_MEMORY;*/
f++;
/* P_ERROR means frontier is reached, break and report error */
case SLSB_P_INPUT_ERROR:
+#ifdef CONFIG_QDIO_DEBUG
sprintf(dbf_text,"inperr%2x",f_mod_no);
QDIO_DBF_TEXT3(1,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
QDIO_DBF_HEX2(1,sbal,q->sbal[f_mod_no],256);
/* kind of process the buffer */
f_mod_no=(f_mod_no+1)&(QDIO_MAX_BUFFERS_PER_Q-1);
atomic_dec(&q->number_of_buffers_used);
+#ifdef QDIO_USE_PROCESSING_STATE
+ last_position=-1;
+#endif /* QDIO_USE_PROCESSING_STATE */
+
break;
/* everything else means frontier not changed (HALTED or so) */
out:
q->first_to_check=f_mod_no;
+#ifdef QDIO_USE_PROCESSING_STATE
+ if (last_position>=0)
+ set_slsb(&slsb[last_position],SLSB_P_INPUT_PROCESSING);
+#endif /* QDIO_USE_PROCESSING_STATE */
+
QDIO_DBF_HEX4(0,trace,&q->first_to_check,sizeof(int));
return q->first_to_check;
/* means, no more buffers to be filled */
inline static int
-iqdio_is_inbound_q_done(struct qdio_q *q)
+tiqdio_is_inbound_q_done(struct qdio_q *q)
{
int no_used;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
+#endif
no_used=atomic_read(&q->number_of_buffers_used);
/* propagate the change from 82 to 80 through VM */
SYNC_MEMORY;
+#ifdef CONFIG_QDIO_DEBUG
if (no_used) {
sprintf(dbf_text,"iqisnt%02x",no_used);
QDIO_DBF_TEXT4(0,trace,dbf_text);
QDIO_DBF_TEXT4(0,trace,"iniqisdo");
}
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* CONFIG_QDIO_DEBUG */
if (!no_used)
return 1;
qdio_is_inbound_q_done(struct qdio_q *q)
{
int no_used;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
+#endif
no_used=atomic_read(&q->number_of_buffers_used);
* has (probably) not moved (see qdio_inbound_processing)
*/
if (NOW>GET_SAVED_TIMESTAMP(q)+q->timing.threshold) {
+#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT4(0,trace,"inqisdon");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
sprintf(dbf_text,"pf%02xcn%02x",q->first_to_check,no_used);
QDIO_DBF_TEXT4(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
return 1;
} else {
+#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT4(0,trace,"inqisntd");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
sprintf(dbf_text,"pf%02xcn%02x",q->first_to_check,no_used);
QDIO_DBF_TEXT4(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
return 0;
}
}
qdio_kick_inbound_handler(struct qdio_q *q)
{
int count, start, end, real_end, i;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
+#endif
QDIO_DBF_TEXT4(0,trace,"kickinh");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
i=(i+1)&(QDIO_MAX_BUFFERS_PER_Q-1);
}
+#ifdef CONFIG_QDIO_DEBUG
sprintf(dbf_text,"s=%2xc=%2x",start,count);
QDIO_DBF_TEXT4(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
if (likely(q->state==QDIO_IRQ_STATE_ACTIVE))
q->handler(q->cdev,
goto out;
qdio_kick_inbound_handler(q);
- if (iqdio_is_inbound_q_done(q))
+ if (tiqdio_is_inbound_q_done(q))
if (!qdio_stop_polling(q)) {
/*
* we set the flags to get into the stuff next time,
#ifdef QDIO_USE_PROCESSING_STATE
static inline int
-tiqdio_do_inbound_checks(struct qdio_q *q, int q_laps)
+tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
{
if (!q) {
tiqdio_sched_tl();
do {
int ret;
- ret = tiqdio_do_inbound_checks(q, q_laps);
+ ret = tiqdio_reset_processing_state(q, q_laps);
switch (ret) {
case 0:
return;
qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state)
{
int i;
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[15];
QDIO_DBF_TEXT5(0,trace,"newstate");
sprintf(dbf_text,"%4x%4x",irq_ptr->irq,state);
QDIO_DBF_TEXT5(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
irq_ptr->state=state;
for (i=0;i<irq_ptr->no_input_qs;i++)
int cstat,dstat;
char dbf_text[15];
+#ifdef CONFIG_QDIO_DEBUG
QDIO_DBF_TEXT4(0, trace, "qint");
sprintf(dbf_text, "%s", cdev->dev.bus_id);
QDIO_DBF_TEXT4(0, trace, dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
if (!intparm) {
QDIO_PRINT_ERR("got unsolicited interrupt in qdio " \
qdio_irq_check_sense(irq_ptr->irq, irb);
+#ifdef CONFIG_QDIO_DEBUG
sprintf(dbf_text, "state:%d", irq_ptr->state);
QDIO_DBF_TEXT4(0, trace, dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
cstat = irb->scsw.cstat;
dstat = irb->scsw.dstat;
int cc;
struct qdio_q *q;
struct qdio_irq *irq_ptr;
- char dbf_text[15]="SyncXXXX";
void *ptr;
+#ifdef CONFIG_QDIO_DEBUG
+ char dbf_text[15]="SyncXXXX";
+#endif
irq_ptr = cdev->private->qdio_data;
if (!irq_ptr)
return -ENODEV;
+#ifdef CONFIG_QDIO_DEBUG
*((int*)(&dbf_text[4])) = irq_ptr->irq;
QDIO_DBF_HEX4(0,trace,dbf_text,QDIO_DBF_TRACE_LEN);
*((int*)(&dbf_text[0]))=flags;
*((int*)(&dbf_text[4]))=queue_number;
QDIO_DBF_HEX4(0,trace,dbf_text,QDIO_DBF_TRACE_LEN);
+#endif /* CONFIG_QDIO_DEBUG */
if (flags&QDIO_FLAG_SYNC_INPUT) {
q=irq_ptr->input_qs[queue_number];
static unsigned int
tiqdio_check_chsc_availability(void)
{
- int result;
char dbf_text[15];
- struct {
- struct chsc_header request;
- u32 reserved1;
- u32 reserved2;
- u32 reserved3;
- struct chsc_header response;
- u32 reserved4;
- u32 general_char[510];
- u32 chsc_char[518];
- } *scsc_area;
-
- scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!scsc_area) {
- QDIO_PRINT_WARN("Was not able to determine available" \
- "CHSCs due to no memory.\n");
- return -ENOMEM;
- }
-
- scsc_area->request = (struct chsc_header) {
- .length = 0x0010,
- .code = 0x0010,
- };
-
- result=chsc(scsc_area);
- if (result) {
- QDIO_PRINT_WARN("Was not able to determine " \
- "available CHSCs, cc=%i.\n",
- result);
- result=-EIO;
- goto exit;
- }
+ if (!css_characteristics_avail)
+ return -EIO;
- if (scsc_area->response.code != 1) {
- QDIO_PRINT_WARN("Was not able to determine " \
- "available CHSCs.\n");
- result=-EIO;
- goto exit;
- }
/* Check for bit 41. */
- if ((scsc_area->general_char[1] & 0x00400000) != 0x00400000) {
+ if (!css_general_characteristics.aif) {
QDIO_PRINT_WARN("Adapter interruption facility not " \
"installed.\n");
- result=-ENOENT;
- goto exit;
+ return -ENOENT;
}
+
/* Check for bits 107 and 108. */
- if ((scsc_area->chsc_char[3] & 0x00180000) != 0x00180000) {
+ if (!css_chsc_characteristics.scssc ||
+ !css_chsc_characteristics.scsscf) {
QDIO_PRINT_WARN("Set Chan Subsys. Char. & Fast-CHSCs " \
"not available.\n");
- result=-ENOENT;
- goto exit;
+ return -ENOENT;
}
/* Check for OSA/FCP thin interrupts (bit 67). */
- hydra_thinints = ((scsc_area->general_char[2] & 0x10000000)
- == 0x10000000);
+ hydra_thinints = css_general_characteristics.aif_osa;
sprintf(dbf_text,"hydrati%1x", hydra_thinints);
QDIO_DBF_TEXT0(0,setup,dbf_text);
/* Check for aif time delay disablement fac (bit 56). If installed,
* omit svs even under lpar (good point by rick again) */
- omit_svs = ((scsc_area->general_char[1] & 0x00000080)
- == 0x00000080);
+ omit_svs = css_general_characteristics.aif_tdd;
sprintf(dbf_text,"omitsvs%1x", omit_svs);
QDIO_DBF_TEXT0(0,setup,dbf_text);
-exit:
- free_page ((unsigned long) scsc_area);
- return result;
+ return 0;
}
u32 kc:4;
u32 reserved4:21;
u32 isc:3;
- u32 reserved5[2];
+ u32 word_with_d_bit;
+ /* set to 0x10000000 to enable
+ * time delay disablement facility */
+ u32 reserved5;
u32 subsystem_id;
u32 reserved6[1004];
struct chsc_header response;
scssc_area->kc = QDIO_STORAGE_KEY;
scssc_area->isc = TIQDIO_THININT_ISC;
scssc_area->subsystem_id = (1<<16) + irq_ptr->irq;
+ /* enables the time delay disablement facility. Don't care
+ * whether it is really there (i.e. we haven't checked for
+ * it) */
+ if (css_general_characteristics.aif_tdd)
+ scssc_area->word_with_d_bit = 0x10000000;
+ else
+ QDIO_PRINT_WARN("Time delay disablement facility " \
+ "not available\n");
+
+
result = chsc(scssc_area);
if (result) {
/* No need to wait for device no longer present. */
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE);
spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+ } else if (((void *)cdev->handler != (void *)qdio_handler) && rc == 0) {
+ /*
+ * Whoever put another handler there, has to cope with the
+ * interrupt theirself. Might happen if qdio_shutdown was
+ * called on already shutdown queues, but this shouldn't have
+ * bad side effects.
+ */
+ qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE);
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
} else if (rc == 0) {
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_CLEANUP);
ccw_device_set_timeout(cdev, timeout);
init_MUTEX(&irq_ptr->setting_up_sema);
+ /* QDR must be in DMA area since CCW data address is only 32 bit */
irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA);
if (!(irq_ptr->qdr)) {
kfree(irq_ptr);
unsigned int count,struct qdio_buffer *buffers)
{
struct qdio_irq *irq_ptr;
-
+#ifdef CONFIG_QDIO_DEBUG
char dbf_text[20];
sprintf(dbf_text,"doQD%04x",cdev->private->irq);
- QDIO_DBF_TEXT3(0,trace,dbf_text);
+ QDIO_DBF_TEXT3(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
if ( (qidx>QDIO_MAX_BUFFERS_PER_Q) ||
(count>QDIO_MAX_BUFFERS_PER_Q) ||
if (!irq_ptr)
return -ENODEV;
+#ifdef CONFIG_QDIO_DEBUG
if (callflags&QDIO_FLAG_SYNC_INPUT)
QDIO_DBF_HEX3(0,trace,&irq_ptr->input_qs[queue_number],
sizeof(void*));
QDIO_DBF_TEXT3(0,trace,dbf_text);
sprintf(dbf_text,"qi%02xct%02x",qidx,count);
QDIO_DBF_TEXT3(0,trace,dbf_text);
+#endif /* CONFIG_QDIO_DEBUG */
if (irq_ptr->state!=QDIO_IRQ_STATE_ACTIVE)
return -EBUSY;
debug_unregister(qdio_dbf_sense);
if (qdio_dbf_trace)
debug_unregister(qdio_dbf_trace);
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
if (qdio_dbf_slsb_out)
debug_unregister(qdio_dbf_slsb_out);
if (qdio_dbf_slsb_in)
debug_unregister(qdio_dbf_slsb_in);
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
}
static int
debug_register_view(qdio_dbf_trace,&debug_hex_ascii_view);
debug_set_level(qdio_dbf_trace,QDIO_DBF_TRACE_LEVEL);
-#ifdef QDIO_DBF_LIKE_HELL
+#ifdef CONFIG_QDIO_DEBUG
qdio_dbf_slsb_out=debug_register(QDIO_DBF_SLSB_OUT_NAME,
QDIO_DBF_SLSB_OUT_INDEX,
QDIO_DBF_SLSB_OUT_NR_AREAS,
goto oom;
debug_register_view(qdio_dbf_slsb_in,&debug_hex_ascii_view);
debug_set_level(qdio_dbf_slsb_in,QDIO_DBF_SLSB_IN_LEVEL);
-#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* CONFIG_QDIO_DEBUG */
return 0;
oom:
QDIO_PRINT_ERR("not enough memory for dbf.\n");