📄 qdio.c
字号:
/* Check for aif time delay disablement fac (bit 56). If installed, * omit svs even under lpar (good point by rick again) */ omit_svs = css_general_characteristics.aif_tdd; sprintf(dbf_text,"omitsvs%1x", omit_svs); QDIO_DBF_TEXT0(0,setup,dbf_text); return 0;}static unsigned inttiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero){ unsigned long real_addr_local_summary_bit; unsigned long real_addr_dev_st_chg_ind; void *ptr; char dbf_text[15]; unsigned int resp_code; int result; struct { struct chsc_header request; u16 operation_code; u16 reserved1; u32 reserved2; u32 reserved3; u64 summary_indicator_addr; u64 subchannel_indicator_addr; u32 ks:4; u32 kc:4; u32 reserved4:21; u32 isc:3; 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; u32 reserved7; } *scssc_area; if (!irq_ptr->is_thinint_irq) return -ENODEV; if (reset_to_zero) { real_addr_local_summary_bit=0; real_addr_dev_st_chg_ind=0; } else { real_addr_local_summary_bit= virt_to_phys((volatile void *)indicators); real_addr_dev_st_chg_ind= virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind); } scssc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scssc_area) { QDIO_PRINT_WARN("No memory for setting indicators on " \ "subchannel x%x.\n", irq_ptr->irq); return -ENOMEM; } scssc_area->request = (struct chsc_header) { .length = 0x0fe0, .code = 0x0021, }; scssc_area->operation_code = 0; scssc_area->summary_indicator_addr = real_addr_local_summary_bit; scssc_area->subchannel_indicator_addr = real_addr_dev_st_chg_ind; scssc_area->ks = QDIO_STORAGE_KEY; 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) { QDIO_PRINT_WARN("could not set indicators on irq x%x, " \ "cc=%i.\n",irq_ptr->irq,result); result = -EIO; goto out; } resp_code = scssc_area->response.code; if (resp_code!=QDIO_CHSC_RESPONSE_CODE_OK) { QDIO_PRINT_WARN("response upon setting indicators " \ "is 0x%x.\n",resp_code); sprintf(dbf_text,"sidR%4x",resp_code); QDIO_DBF_TEXT1(0,trace,dbf_text); QDIO_DBF_TEXT1(0,setup,dbf_text); ptr=&scssc_area->response; QDIO_DBF_HEX2(1,setup,&ptr,QDIO_DBF_SETUP_LEN); result = -EIO; goto out; } QDIO_DBF_TEXT2(0,setup,"setscind"); QDIO_DBF_HEX2(0,setup,&real_addr_local_summary_bit, sizeof(unsigned long)); QDIO_DBF_HEX2(0,setup,&real_addr_dev_st_chg_ind,sizeof(unsigned long)); result = 0;out: free_page ((unsigned long) scssc_area); return result;}static unsigned inttiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target){ unsigned int resp_code; int result; void *ptr; char dbf_text[15]; struct { struct chsc_header request; u16 operation_code; u16 reserved1; u32 reserved2; u32 reserved3; u32 reserved4[2]; u32 delay_target; u32 reserved5[1009]; struct chsc_header response; u32 reserved6; } *scsscf_area; if (!irq_ptr->is_thinint_irq) return -ENODEV; scsscf_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scsscf_area) { QDIO_PRINT_WARN("No memory for setting delay target on " \ "subchannel x%x.\n", irq_ptr->irq); return -ENOMEM; } scsscf_area->request = (struct chsc_header) { .length = 0x0fe0, .code = 0x1027, }; scsscf_area->delay_target = delay_target<<16; result=chsc(scsscf_area); if (result) { QDIO_PRINT_WARN("could not set delay target on irq x%x, " \ "cc=%i. Continuing.\n",irq_ptr->irq,result); result = -EIO; goto out; } resp_code = scsscf_area->response.code; if (resp_code!=QDIO_CHSC_RESPONSE_CODE_OK) { QDIO_PRINT_WARN("response upon setting delay target " \ "is 0x%x. Continuing.\n",resp_code); sprintf(dbf_text,"sdtR%4x",resp_code); QDIO_DBF_TEXT1(0,trace,dbf_text); QDIO_DBF_TEXT1(0,setup,dbf_text); ptr=&scsscf_area->response; QDIO_DBF_HEX2(1,trace,&ptr,QDIO_DBF_TRACE_LEN); } QDIO_DBF_TEXT2(0,trace,"delytrgt"); QDIO_DBF_HEX2(0,trace,&delay_target,sizeof(unsigned long)); result = 0; /* not critical */out: free_page ((unsigned long) scsscf_area); return result;}intqdio_cleanup(struct ccw_device *cdev, int how){ struct qdio_irq *irq_ptr; char dbf_text[15]; int rc; irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; sprintf(dbf_text,"qcln%4x",irq_ptr->irq); QDIO_DBF_TEXT1(0,trace,dbf_text); QDIO_DBF_TEXT0(0,setup,dbf_text); rc = qdio_shutdown(cdev, how); if ((rc == 0) || (rc == -EINPROGRESS)) rc = qdio_free(cdev); return rc;}intqdio_shutdown(struct ccw_device *cdev, int how){ struct qdio_irq *irq_ptr; int i; int result = 0; int rc; unsigned long flags; int timeout; char dbf_text[15]; irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; down(&irq_ptr->setting_up_sema); sprintf(dbf_text,"qsqs%4x",irq_ptr->irq); QDIO_DBF_TEXT1(0,trace,dbf_text); QDIO_DBF_TEXT0(0,setup,dbf_text); /* mark all qs as uninteresting */ for (i=0;i<irq_ptr->no_input_qs;i++) atomic_set(&irq_ptr->input_qs[i]->is_in_shutdown,1); for (i=0;i<irq_ptr->no_output_qs;i++) atomic_set(&irq_ptr->output_qs[i]->is_in_shutdown,1); tasklet_kill(&tiqdio_tasklet); for (i=0;i<irq_ptr->no_input_qs;i++) { qdio_unmark_q(irq_ptr->input_qs[i]); tasklet_kill(&irq_ptr->input_qs[i]->tasklet); wait_event_interruptible_timeout(cdev->private->wait_q, !atomic_read(&irq_ptr-> input_qs[i]-> use_count), QDIO_NO_USE_COUNT_TIMEOUT); if (atomic_read(&irq_ptr->input_qs[i]->use_count)) result=-EINPROGRESS; } for (i=0;i<irq_ptr->no_output_qs;i++) { tasklet_kill(&irq_ptr->output_qs[i]->tasklet); wait_event_interruptible_timeout(cdev->private->wait_q, !atomic_read(&irq_ptr-> output_qs[i]-> use_count), QDIO_NO_USE_COUNT_TIMEOUT); if (atomic_read(&irq_ptr->output_qs[i]->use_count)) result=-EINPROGRESS; } /* cleanup subchannel */ spin_lock_irqsave(get_ccwdev_lock(cdev),flags); if (how&QDIO_FLAG_CLEANUP_USING_CLEAR) { rc = ccw_device_clear(cdev, QDIO_DOING_CLEANUP); timeout=QDIO_CLEANUP_CLEAR_TIMEOUT; } else if (how&QDIO_FLAG_CLEANUP_USING_HALT) { rc = ccw_device_halt(cdev, QDIO_DOING_CLEANUP); timeout=QDIO_CLEANUP_HALT_TIMEOUT; } else { /* default behaviour */ rc = ccw_device_halt(cdev, QDIO_DOING_CLEANUP); timeout=QDIO_CLEANUP_HALT_TIMEOUT; } if (rc == -ENODEV) { /* 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); spin_unlock_irqrestore(get_ccwdev_lock(cdev),flags); wait_event(cdev->private->wait_q, irq_ptr->state == QDIO_IRQ_STATE_INACTIVE || irq_ptr->state == QDIO_IRQ_STATE_ERR); } else { QDIO_PRINT_INFO("ccw_device_{halt,clear} returned %d for " "device %s\n", result, cdev->dev.bus_id); spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); result = rc; goto out; } if (irq_ptr->is_thinint_irq) { qdio_put_indicator((__u32*)irq_ptr->dev_st_chg_ind); tiqdio_set_subchannel_ind(irq_ptr,1); /* reset adapter interrupt indicators */ } /* exchange int handlers, if necessary */ if ((void*)cdev->handler == (void*)qdio_handler) cdev->handler=irq_ptr->original_int_handler; /* Ignore errors. */ qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE); ccw_device_set_timeout(cdev, 0);out: up(&irq_ptr->setting_up_sema); return result;}intqdio_free(struct ccw_device *cdev){ struct qdio_irq *irq_ptr; char dbf_text[15]; irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; down(&irq_ptr->setting_up_sema); sprintf(dbf_text,"qfqs%4x",irq_ptr->irq); QDIO_DBF_TEXT1(0,trace,dbf_text); QDIO_DBF_TEXT0(0,setup,dbf_text); cdev->private->qdio_data = 0; up(&irq_ptr->setting_up_sema); qdio_release_irq_memory(irq_ptr); module_put(THIS_MODULE); return 0;}static inline voidqdio_allocate_do_dbf(struct qdio_initialize *init_data){ char dbf_text[20]; /* if a printf printed out more than 8 chars */ sprintf(dbf_text,"qfmt:%x",init_data->q_format); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_HEX0(0,setup,init_data->adapter_name,8); sprintf(dbf_text,"qpff%4x",init_data->qib_param_field_format); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_HEX0(0,setup,&init_data->qib_param_field,sizeof(char*)); QDIO_DBF_HEX0(0,setup,&init_data->input_slib_elements,sizeof(long*)); QDIO_DBF_HEX0(0,setup,&init_data->output_slib_elements,sizeof(long*)); sprintf(dbf_text,"miit%4x",init_data->min_input_threshold); QDIO_DBF_TEXT0(0,setup,dbf_text); sprintf(dbf_text,"mait%4x",init_data->max_input_threshold); QDIO_DBF_TEXT0(0,setup,dbf_text); sprintf(dbf_text,"miot%4x",init_data->min_output_threshold); QDIO_DBF_TEXT0(0,setup,dbf_text); sprintf(dbf_text,"maot%4x",init_data->max_output_threshold); QDIO_DBF_TEXT0(0,setup,dbf_text); sprintf(dbf_text,"niq:%4x",init_data->no_input_qs); QDIO_DBF_TEXT0(0,setup,dbf_text); sprintf(dbf_text,"noq:%4x",init_data->no_output_qs); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_HEX0(0,setup,&init_data->input_handler,sizeof(void*)); QDIO_DBF_HEX0(0,setup,&init_data->output_handler,sizeof(void*)); QDIO_DBF_HEX0(0,setup,&init_data->int_parm,sizeof(long)); QDIO_DBF_HEX0(0,setup,&init_data->flags,sizeof(long)); QDIO_DBF_HEX0(0,setup,&init_data->input_sbal_addr_array,sizeof(void*)); QDIO_DBF_HEX0(0,setup,&init_data->output_sbal_addr_array,sizeof(void*));}static inline voidqdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt){ irq_ptr->input_qs[i]->is_iqdio_q = iqfmt; irq_ptr->input_qs[i]->is_thinint_q = irq_ptr->is_thinint_irq; irq_ptr->qdr->qdf0[i].sliba=(unsigned long)(irq_ptr->input_qs[i]->slib); irq_ptr->qdr->qdf0[i].sla=(unsigned long)(irq_ptr->input_qs[i]->sl); irq_ptr->qdr->qdf0[i].slsba= (unsigned long)(&irq_ptr->input_qs[i]->slsb.acc.val[0]); irq_ptr->qdr->qdf0[i].akey=QDIO_STORAGE_KEY; irq_ptr->qdr->qdf0[i].bkey=QDIO_STORAGE_KEY; irq_ptr->qdr->qdf0[i].ckey=QDIO_STORAGE_KEY; irq_ptr->qdr->qdf0[i].dkey=QDIO_STORAGE_KEY;}static inline voidqdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i, int j, int iqfmt){ irq_ptr->output_qs[i]->is_iqdio_q = iqfmt; irq_ptr->output_qs[i]->is_thinint_q = irq_ptr->is_thinint_irq; irq_ptr->qdr->qdf0[i+j].sliba=(unsigned long)(irq_ptr->output_qs[i]->slib); irq_ptr->qdr->qdf0[i+j].sla=(unsigned long)(irq_ptr->output_qs[i]->sl); irq_ptr->qdr->qdf0[i+j].slsba= (unsigned long)(&irq_ptr->output_qs[i]->slsb.acc.val[0]); irq_ptr->qdr->qdf0[i+j].akey=QDIO_STORAGE_KEY; irq_ptr->qdr->qdf0[i+j].bkey=QDIO_STORAGE_KEY; irq_ptr->qdr->qdf0[i+j].ckey=QDIO_STORAGE_KEY; irq_ptr->qdr->qdf0[i+j].dkey=QDIO_STORAGE_KEY;}static inline voidqdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr){ int i; for (i=0;i<irq_ptr->no_input_qs;i++) { irq_ptr->input_qs[i]->siga_sync= irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_NECESSARY; irq_ptr->input_qs[i]->siga_in= irq_ptr->qdioac&CHSC_FLAG_SIGA_INPUT_NECESSARY; irq_ptr->input_qs[i]->siga_out= irq_ptr->qdioac&CHSC_FLAG_SIGA_OUTPUT_NECESSARY; irq_ptr->input_qs[i]->siga_sync_done_on_thinints= irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS; irq_ptr->input_qs[i]->hydra_gives_outbound_pcis= irq_ptr->hydra_gives_outbound_pcis; irq_ptr->input_qs[i]->siga_sync_done_on_outb_tis= ((irq_ptr->qdioac& (CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS| CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS))== (CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS| CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS)); }}static inline voidqdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr){ int i; for (i=0;i<irq_ptr->no_output_qs;i++) { irq_ptr->output_qs[i]->siga_sync= irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_NECESSARY; irq_ptr->output_qs[i]->siga_in= irq_ptr->qdioac&CHSC_FLAG_SIGA_INPUT_NECESSARY; irq_ptr->output_qs[i]->siga_out= irq_ptr->qdioac&CHSC_FLAG_SIGA_OUTPUT_NECESSARY; irq_ptr->output_qs[i]->siga_sync_done_on_thinints= irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS; irq_ptr->output_qs[i]->hydra_gives_outbound_pcis= irq_ptr->hydra_gives_outbound_pcis; irq_ptr->output_qs[i]->siga_sync_done_on_outb_tis= ((irq_ptr->qdioac& (CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS| CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS))== (CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS| CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS)); }}static inline intqdio_establish_irq_check_for_errors(struct ccw_device *cdev, int cstat, int dstat){ char dbf_text[15]; struct qdio_irq *irq_ptr; irq_ptr = cdev->private->qdio_data; if (cstat || (dstat & ~(DEV_STAT_CHN_END|DEV_STAT_DEV_END))) { sprintf(dbf_text,"ick1%4x",irq_ptr->irq); QDIO_DBF_TEXT2(1,trace,dbf_text); QDIO_DBF_HEX2(0,trace,&dstat,sizeof(int)); QDIO_DBF_HEX2(0,trace,&cstat,sizeof(int)); QDIO_PRINT_ERR("received check condition on establish " \ "queues on irq 0x%x (cs=x%x, ds=x%x).\n", irq_ptr->irq,cstat,dstat); qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ERR); } if (!(dstat & DEV_STAT_DEV_END)) { QDIO_DBF_TEXT2(1,setup,"eq:no de"); QDIO_DBF_HEX2(0,setup,&dstat, sizeof(dstat)); QDIO_DBF_HEX2(0,setup,&cstat, sizeof(cstat)); QDIO_PRINT_ERR("establish queues on irq %04x: didn't get " "device end: dstat=%02x, cstat=%02x\n", irq_ptr->irq, dstat, cstat); qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); return 1; } if (dstat & ~(DEV_STAT_CHN_END|DEV_STAT_DEV_END)) { QDIO_DBF_TEXT2(1,setup,"eq:badio"); QDIO_DBF_HEX2(0,setup,&dstat, sizeof(dstat)); QDIO_DBF_HEX2(0,setup,&cstat, sizeof(cstat)); QDIO_PRINT_ERR("establish queues on irq %04x: got " "the following devstat: dstat=%02x, " "cstat=%02x\n", irq_ptr->irq, dstat, cstat); qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); return 1; } return 0;}static voidqdio_establish_handle_irq(struct ccw_device *cdev, int cstat, int dstat){ struct qdio_irq *irq_ptr; char dbf_text[15]; irq_ptr = cdev->privat
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -