diff options
author | David Woodhouse <dwmw2@infradead.org> | 2008-04-22 12:34:25 +0100 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2008-04-22 12:34:25 +0100 |
commit | f838bad1b3be8ca0c785ee0e0c570dfda74cf377 (patch) | |
tree | 5a842a8056a708cfad55a20fa8ab733dd94b0903 /drivers/s390/cio/qdio.c | |
parent | dd919660aacdf4adfcd279556aa03e595f7f0fc2 (diff) | |
parent | 807501475fce0ebe68baedf87f202c3e4ee0d12c (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/s390/cio/qdio.c')
-rw-r--r-- | drivers/s390/cio/qdio.c | 195 |
1 files changed, 90 insertions, 105 deletions
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 097fc0967e9..10aa1e78080 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -32,17 +32,17 @@ #include <linux/module.h> #include <linux/init.h> - +#include <linux/delay.h> #include <linux/slab.h> #include <linux/kernel.h> #include <linux/proc_fs.h> #include <linux/timer.h> #include <linux/mempool.h> +#include <linux/semaphore.h> #include <asm/ccwdev.h> #include <asm/io.h> #include <asm/atomic.h> -#include <asm/semaphore.h> #include <asm/timex.h> #include <asm/debug.h> @@ -1215,9 +1215,6 @@ tiqdio_is_inbound_q_done(struct qdio_q *q) if (!no_used) return 1; - if (!q->siga_sync && !irq->is_qebsm) - /* we'll check for more primed buffers in qeth_stop_polling */ - return 0; if (irq->is_qebsm) { count = 1; start_buf = q->first_to_check; @@ -1402,7 +1399,7 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set) * q->dev_st_chg_ind is the indicator, be it shared or not. * only clear it, if indicator is non-shared */ - if (!spare_ind_was_set) + if (q->dev_st_chg_ind != &spare_indicator) tiqdio_clear_summary_bit((__u32*)q->dev_st_chg_ind); if (q->hydra_gives_outbound_pcis) { @@ -2220,9 +2217,78 @@ qdio_synchronize(struct ccw_device *cdev, unsigned int flags, return cc; } +static int +qdio_get_ssqd_information(struct subchannel_id *schid, + struct qdio_chsc_ssqd **ssqd_area) +{ + int result; + + QDIO_DBF_TEXT0(0, setup, "getssqd"); + *ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); + if (!ssqd_area) { + QDIO_PRINT_WARN("Could not get memory for chsc on sch x%x.\n", + schid->sch_no); + return -ENOMEM; + } + + (*ssqd_area)->request = (struct chsc_header) { + .length = 0x0010, + .code = 0x0024, + }; + (*ssqd_area)->first_sch = schid->sch_no; + (*ssqd_area)->last_sch = schid->sch_no; + (*ssqd_area)->ssid = schid->ssid; + result = chsc(*ssqd_area); + + if (result) { + QDIO_PRINT_WARN("CHSC returned cc %i on sch 0.%x.%x.\n", + result, schid->ssid, schid->sch_no); + goto out; + } + + if ((*ssqd_area)->response.code != QDIO_CHSC_RESPONSE_CODE_OK) { + QDIO_PRINT_WARN("CHSC response is 0x%x on sch 0.%x.%x.\n", + (*ssqd_area)->response.code, + schid->ssid, schid->sch_no); + goto out; + } + if (!((*ssqd_area)->flags & CHSC_FLAG_QDIO_CAPABILITY) || + !((*ssqd_area)->flags & CHSC_FLAG_VALIDITY) || + ((*ssqd_area)->sch != schid->sch_no)) { + QDIO_PRINT_WARN("huh? problems checking out sch 0.%x.%x... " \ + "using all SIGAs.\n", + schid->ssid, schid->sch_no); + goto out; + } + return 0; +out: + return -EINVAL; +} + +int +qdio_get_ssqd_pct(struct ccw_device *cdev) +{ + struct qdio_chsc_ssqd *ssqd_area; + struct subchannel_id schid; + char dbf_text[15]; + int rc; + int pct = 0; + + QDIO_DBF_TEXT0(0, setup, "getpct"); + schid = ccw_device_get_subchannel_id(cdev); + rc = qdio_get_ssqd_information(&schid, &ssqd_area); + if (!rc) + pct = (int)ssqd_area->pct; + if (rc != -ENOMEM) + mempool_free(ssqd_area, qdio_mempool_scssc); + sprintf(dbf_text, "pct: %d", pct); + QDIO_DBF_TEXT2(0, setup, dbf_text); + return pct; +} +EXPORT_SYMBOL(qdio_get_ssqd_pct); + static void -qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, - unsigned long token) +qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned long token) { struct qdio_q *q; int i; @@ -2230,7 +2296,7 @@ qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, char dbf_text[15]; /*check if QEBSM is disabled */ - if (!(irq_ptr->is_qebsm) || !(qdioac & 0x01)) { + if (!(irq_ptr->is_qebsm) || !(irq_ptr->qdioac & 0x01)) { irq_ptr->is_qebsm = 0; irq_ptr->sch_token = 0; irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM; @@ -2259,102 +2325,27 @@ qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, } static void -qdio_get_ssqd_information(struct qdio_irq *irq_ptr) +qdio_get_ssqd_siga(struct qdio_irq *irq_ptr) { - int result; - unsigned char qdioac; - struct { - struct chsc_header request; - u16 reserved1:10; - u16 ssid:2; - u16 fmt:4; - u16 first_sch; - u16 reserved2; - u16 last_sch; - u32 reserved3; - struct chsc_header response; - u32 reserved4; - u8 flags; - u8 reserved5; - u16 sch; - u8 qfmt; - u8 parm; - u8 qdioac1; - u8 sch_class; - u8 reserved7; - u8 icnt; - u8 reserved8; - u8 ocnt; - u8 reserved9; - u8 mbccnt; - u16 qdioac2; - u64 sch_token; - } *ssqd_area; + int rc; + struct qdio_chsc_ssqd *ssqd_area; QDIO_DBF_TEXT0(0,setup,"getssqd"); - qdioac = 0; - ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); - if (!ssqd_area) { - QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \ - "SIGAs for sch x%x.\n", irq_ptr->schid.sch_no); + irq_ptr->qdioac = 0; + rc = qdio_get_ssqd_information(&irq_ptr->schid, &ssqd_area); + if (rc) { + QDIO_PRINT_WARN("using all SIGAs for sch x%x.n", + irq_ptr->schid.sch_no); irq_ptr->qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | CHSC_FLAG_SIGA_OUTPUT_NECESSARY | CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */ irq_ptr->is_qebsm = 0; - irq_ptr->sch_token = 0; - irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM; - return; - } - - ssqd_area->request = (struct chsc_header) { - .length = 0x0010, - .code = 0x0024, - }; - ssqd_area->first_sch = irq_ptr->schid.sch_no; - ssqd_area->last_sch = irq_ptr->schid.sch_no; - ssqd_area->ssid = irq_ptr->schid.ssid; - result = chsc(ssqd_area); - - if (result) { - QDIO_PRINT_WARN("CHSC returned cc %i. Using all " \ - "SIGAs for sch 0.%x.%x.\n", result, - irq_ptr->schid.ssid, irq_ptr->schid.sch_no); - qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | - CHSC_FLAG_SIGA_OUTPUT_NECESSARY | - CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */ - irq_ptr->is_qebsm = 0; - goto out; - } + } else + irq_ptr->qdioac = ssqd_area->qdioac1; - if (ssqd_area->response.code != QDIO_CHSC_RESPONSE_CODE_OK) { - QDIO_PRINT_WARN("response upon checking SIGA needs " \ - "is 0x%x. Using all SIGAs for sch 0.%x.%x.\n", - ssqd_area->response.code, - irq_ptr->schid.ssid, irq_ptr->schid.sch_no); - qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | - CHSC_FLAG_SIGA_OUTPUT_NECESSARY | - CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */ - irq_ptr->is_qebsm = 0; - goto out; - } - if (!(ssqd_area->flags & CHSC_FLAG_QDIO_CAPABILITY) || - !(ssqd_area->flags & CHSC_FLAG_VALIDITY) || - (ssqd_area->sch != irq_ptr->schid.sch_no)) { - QDIO_PRINT_WARN("huh? problems checking out sch 0.%x.%x... " \ - "using all SIGAs.\n", - irq_ptr->schid.ssid, irq_ptr->schid.sch_no); - qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | - CHSC_FLAG_SIGA_OUTPUT_NECESSARY | - CHSC_FLAG_SIGA_SYNC_NECESSARY; /* worst case */ - irq_ptr->is_qebsm = 0; - goto out; - } - qdioac = ssqd_area->qdioac1; -out: - qdio_check_subchannel_qebsm(irq_ptr, qdioac, - ssqd_area->sch_token); - mempool_free(ssqd_area, qdio_mempool_scssc); - irq_ptr->qdioac = qdioac; + qdio_check_subchannel_qebsm(irq_ptr, ssqd_area->sch_token); + if (rc != -ENOMEM) + mempool_free(ssqd_area, qdio_mempool_scssc); } static unsigned int @@ -3230,7 +3221,7 @@ qdio_establish(struct qdio_initialize *init_data) return -EIO; } - qdio_get_ssqd_information(irq_ptr); + qdio_get_ssqd_siga(irq_ptr); /* if this gets set once, we're running under VM and can omit SVSes */ if (irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_NECESSARY) omit_svs=1; @@ -3332,13 +3323,7 @@ qdio_activate(struct ccw_device *cdev, int flags) } } - wait_event_interruptible_timeout(cdev->private->wait_q, - ((irq_ptr->state == - QDIO_IRQ_STATE_STOPPED) || - (irq_ptr->state == - QDIO_IRQ_STATE_ERR)), - QDIO_ACTIVATE_TIMEOUT); - + msleep(QDIO_ACTIVATE_TIMEOUT); switch (irq_ptr->state) { case QDIO_IRQ_STATE_STOPPED: case QDIO_IRQ_STATE_ERR: |