aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-01-07 17:50:50 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-07 17:50:50 -0500
commitfb5131e1880ea1ba3ba7197cd5cc66c9c288f715 (patch)
treef0d9f25f9079727b9ead5a2b4cc85a0fea9b4668 /drivers/s390/cio
parentd074b104cefcb6e8ded55a53e62fed59a246f55d (diff)
parent8e1023016cf17152972b98bce6c144834a4916d5 (diff)
Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: (65 commits) [S390] prevent unneccesary loops_per_jiffy recalculation [S390] cpuinfo: use get_online_cpus() instead of preempt_disable() [S390] smp: remove cpu hotplug messages [S390] mutex: enable spinning mutex on s390 [S390] mutex: Introduce arch_mutex_cpu_relax() [S390] cio: fix ccwgroup unregistration race condition [S390] perf: add DWARF register lookup for s390 [S390] cleanup ftrace backend functions [S390] ptrace cleanup [S390] smp/idle: call init_idle() before starting a new cpu [S390] smp: delay idle task creation [S390] dasd: Correct retry counter for terminated I/O. [S390] dasd: Add support for raw ECKD access. [S390] dasd: Prevent deadlock during suspend/resume. [S390] dasd: Improve handling of stolen DASD reservation [S390] dasd: do path verification for paths added at runtime [S390] dasd: add High Performance FICON multitrack support [S390] cio: reduce memory consumption of itcw structures [S390] nmi: enable machine checks early [S390] qeth: buffer count imbalance ...
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r--drivers/s390/cio/ccwgroup.c78
-rw-r--r--drivers/s390/cio/chsc.c19
-rw-r--r--drivers/s390/cio/chsc.h18
-rw-r--r--drivers/s390/cio/css.c8
-rw-r--r--drivers/s390/cio/device_ops.c40
-rw-r--r--drivers/s390/cio/itcw.c62
-rw-r--r--drivers/s390/cio/qdio.h31
-rw-r--r--drivers/s390/cio/qdio_debug.c1
-rw-r--r--drivers/s390/cio/qdio_main.c177
-rw-r--r--drivers/s390/cio/qdio_setup.c20
-rw-r--r--drivers/s390/cio/qdio_thinint.c56
11 files changed, 300 insertions, 210 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 97b25d68e3e7..2864581d8ecb 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -67,6 +67,27 @@ __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
67} 67}
68 68
69/* 69/*
70 * Remove references from ccw devices to ccw group device and from
71 * ccw group device to ccw devices.
72 */
73static void __ccwgroup_remove_cdev_refs(struct ccwgroup_device *gdev)
74{
75 struct ccw_device *cdev;
76 int i;
77
78 for (i = 0; i < gdev->count; i++) {
79 cdev = gdev->cdev[i];
80 if (!cdev)
81 continue;
82 spin_lock_irq(cdev->ccwlock);
83 dev_set_drvdata(&cdev->dev, NULL);
84 spin_unlock_irq(cdev->ccwlock);
85 gdev->cdev[i] = NULL;
86 put_device(&cdev->dev);
87 }
88}
89
90/*
70 * Provide an 'ungroup' attribute so the user can remove group devices no 91 * Provide an 'ungroup' attribute so the user can remove group devices no
71 * longer needed or accidentially created. Saves memory :) 92 * longer needed or accidentially created. Saves memory :)
72 */ 93 */
@@ -78,6 +99,7 @@ static void ccwgroup_ungroup_callback(struct device *dev)
78 if (device_is_registered(&gdev->dev)) { 99 if (device_is_registered(&gdev->dev)) {
79 __ccwgroup_remove_symlinks(gdev); 100 __ccwgroup_remove_symlinks(gdev);
80 device_unregister(dev); 101 device_unregister(dev);
102 __ccwgroup_remove_cdev_refs(gdev);
81 } 103 }
82 mutex_unlock(&gdev->reg_mutex); 104 mutex_unlock(&gdev->reg_mutex);
83} 105}
@@ -116,21 +138,7 @@ static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store);
116static void 138static void
117ccwgroup_release (struct device *dev) 139ccwgroup_release (struct device *dev)
118{ 140{
119 struct ccwgroup_device *gdev; 141 kfree(to_ccwgroupdev(dev));
120 int i;
121
122 gdev = to_ccwgroupdev(dev);
123
124 for (i = 0; i < gdev->count; i++) {
125 if (gdev->cdev[i]) {
126 spin_lock_irq(gdev->cdev[i]->ccwlock);
127 if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
128 dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
129 spin_unlock_irq(gdev->cdev[i]->ccwlock);
130 put_device(&gdev->cdev[i]->dev);
131 }
132 }
133 kfree(gdev);
134} 142}
135 143
136static int 144static int
@@ -639,6 +647,7 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
639 mutex_lock(&gdev->reg_mutex); 647 mutex_lock(&gdev->reg_mutex);
640 __ccwgroup_remove_symlinks(gdev); 648 __ccwgroup_remove_symlinks(gdev);
641 device_unregister(dev); 649 device_unregister(dev);
650 __ccwgroup_remove_cdev_refs(gdev);
642 mutex_unlock(&gdev->reg_mutex); 651 mutex_unlock(&gdev->reg_mutex);
643 put_device(dev); 652 put_device(dev);
644 } 653 }
@@ -660,25 +669,6 @@ int ccwgroup_probe_ccwdev(struct ccw_device *cdev)
660 return 0; 669 return 0;
661} 670}
662 671
663static struct ccwgroup_device *
664__ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
665{
666 struct ccwgroup_device *gdev;
667
668 gdev = dev_get_drvdata(&cdev->dev);
669 if (gdev) {
670 if (get_device(&gdev->dev)) {
671 mutex_lock(&gdev->reg_mutex);
672 if (device_is_registered(&gdev->dev))
673 return gdev;
674 mutex_unlock(&gdev->reg_mutex);
675 put_device(&gdev->dev);
676 }
677 return NULL;
678 }
679 return NULL;
680}
681
682/** 672/**
683 * ccwgroup_remove_ccwdev() - remove function for slave devices 673 * ccwgroup_remove_ccwdev() - remove function for slave devices
684 * @cdev: ccw device to be removed 674 * @cdev: ccw device to be removed
@@ -694,13 +684,25 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
694 /* Ignore offlining errors, device is gone anyway. */ 684 /* Ignore offlining errors, device is gone anyway. */
695 ccw_device_set_offline(cdev); 685 ccw_device_set_offline(cdev);
696 /* If one of its devices is gone, the whole group is done for. */ 686 /* If one of its devices is gone, the whole group is done for. */
697 gdev = __ccwgroup_get_gdev_by_cdev(cdev); 687 spin_lock_irq(cdev->ccwlock);
698 if (gdev) { 688 gdev = dev_get_drvdata(&cdev->dev);
689 if (!gdev) {
690 spin_unlock_irq(cdev->ccwlock);
691 return;
692 }
693 /* Get ccwgroup device reference for local processing. */
694 get_device(&gdev->dev);
695 spin_unlock_irq(cdev->ccwlock);
696 /* Unregister group device. */
697 mutex_lock(&gdev->reg_mutex);
698 if (device_is_registered(&gdev->dev)) {
699 __ccwgroup_remove_symlinks(gdev); 699 __ccwgroup_remove_symlinks(gdev);
700 device_unregister(&gdev->dev); 700 device_unregister(&gdev->dev);
701 mutex_unlock(&gdev->reg_mutex); 701 __ccwgroup_remove_cdev_refs(gdev);
702 put_device(&gdev->dev);
703 } 702 }
703 mutex_unlock(&gdev->reg_mutex);
704 /* Release ccwgroup device reference for local processing. */
705 put_device(&gdev->dev);
704} 706}
705 707
706MODULE_LICENSE("GPL"); 708MODULE_LICENSE("GPL");
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 1aaddea673e0..0689fcf23a11 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -695,6 +695,25 @@ out:
695 return ret; 695 return ret;
696} 696}
697 697
698int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid,
699 struct channel_path_desc_fmt1 *desc)
700{
701 struct chsc_response_struct *chsc_resp;
702 struct chsc_scpd *scpd_area;
703 int ret;
704
705 spin_lock_irq(&chsc_page_lock);
706 scpd_area = chsc_page;
707 ret = chsc_determine_channel_path_desc(chpid, 0, 0, 1, 0, scpd_area);
708 if (ret)
709 goto out;
710 chsc_resp = (void *)&scpd_area->response;
711 memcpy(desc, &chsc_resp->data, sizeof(*desc));
712out:
713 spin_unlock_irq(&chsc_page_lock);
714 return ret;
715}
716
698static void 717static void
699chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, 718chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
700 struct cmg_chars *chars) 719 struct cmg_chars *chars)
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 6693f5e3176f..3f15b2aaeaea 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -35,6 +35,22 @@ struct channel_path_desc {
35 u8 chpp; 35 u8 chpp;
36} __attribute__ ((packed)); 36} __attribute__ ((packed));
37 37
38struct channel_path_desc_fmt1 {
39 u8 flags;
40 u8 lsn;
41 u8 desc;
42 u8 chpid;
43 u32:24;
44 u8 chpp;
45 u32 unused[3];
46 u16 mdc;
47 u16:13;
48 u8 r:1;
49 u8 s:1;
50 u8 f:1;
51 u32 zeros[2];
52} __attribute__ ((packed));
53
38struct channel_path; 54struct channel_path;
39 55
40struct css_chsc_char { 56struct css_chsc_char {
@@ -92,6 +108,8 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
92 int c, int m, void *page); 108 int c, int m, void *page);
93int chsc_determine_base_channel_path_desc(struct chp_id chpid, 109int chsc_determine_base_channel_path_desc(struct chp_id chpid,
94 struct channel_path_desc *desc); 110 struct channel_path_desc *desc);
111int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid,
112 struct channel_path_desc_fmt1 *desc);
95void chsc_chp_online(struct chp_id chpid); 113void chsc_chp_online(struct chp_id chpid);
96void chsc_chp_offline(struct chp_id chpid); 114void chsc_chp_offline(struct chp_id chpid);
97int chsc_get_channel_measurement_chars(struct channel_path *chp); 115int chsc_get_channel_measurement_chars(struct channel_path *chp);
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 825951b6b83f..24d8e97355b9 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -618,6 +618,7 @@ EXPORT_SYMBOL_GPL(css_schedule_reprobe);
618static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow) 618static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
619{ 619{
620 struct subchannel_id mchk_schid; 620 struct subchannel_id mchk_schid;
621 struct subchannel *sch;
621 622
622 if (overflow) { 623 if (overflow) {
623 css_schedule_eval_all(); 624 css_schedule_eval_all();
@@ -637,6 +638,13 @@ static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
637 if (crw1) 638 if (crw1)
638 mchk_schid.ssid = (crw1->rsid >> 4) & 3; 639 mchk_schid.ssid = (crw1->rsid >> 4) & 3;
639 640
641 if (crw0->erc == CRW_ERC_PMOD) {
642 sch = get_subchannel_by_schid(mchk_schid);
643 if (sch) {
644 css_update_ssd_info(sch);
645 put_device(&sch->dev);
646 }
647 }
640 /* 648 /*
641 * Since we are always presented with IPI in the CRW, we have to 649 * Since we are always presented with IPI in the CRW, we have to
642 * use stsch() to find out if the subchannel in question has come 650 * use stsch() to find out if the subchannel in question has come
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 6da84543dfe9..651976b54af8 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -687,6 +687,46 @@ int ccw_device_tm_start_timeout(struct ccw_device *cdev, struct tcw *tcw,
687EXPORT_SYMBOL(ccw_device_tm_start_timeout); 687EXPORT_SYMBOL(ccw_device_tm_start_timeout);
688 688
689/** 689/**
690 * ccw_device_get_mdc - accumulate max data count
691 * @cdev: ccw device for which the max data count is accumulated
692 * @mask: mask of paths to use
693 *
694 * Return the number of 64K-bytes blocks all paths at least support
695 * for a transport command. Return values <= 0 indicate failures.
696 */
697int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask)
698{
699 struct subchannel *sch = to_subchannel(cdev->dev.parent);
700 struct channel_path_desc_fmt1 desc;
701 struct chp_id chpid;
702 int mdc = 0, ret, i;
703
704 /* Adjust requested path mask to excluded varied off paths. */
705 if (mask)
706 mask &= sch->lpm;
707 else
708 mask = sch->lpm;
709
710 chp_id_init(&chpid);
711 for (i = 0; i < 8; i++) {
712 if (!(mask & (0x80 >> i)))
713 continue;
714 chpid.id = sch->schib.pmcw.chpid[i];
715 ret = chsc_determine_fmt1_channel_path_desc(chpid, &desc);
716 if (ret)
717 return ret;
718 if (!desc.f)
719 return 0;
720 if (!desc.r)
721 mdc = 1;
722 mdc = mdc ? min(mdc, (int)desc.mdc) : desc.mdc;
723 }
724
725 return mdc;
726}
727EXPORT_SYMBOL(ccw_device_get_mdc);
728
729/**
690 * ccw_device_tm_intrg - perform interrogate function 730 * ccw_device_tm_intrg - perform interrogate function
691 * @cdev: ccw device on which to perform the interrogate function 731 * @cdev: ccw device on which to perform the interrogate function
692 * 732 *
diff --git a/drivers/s390/cio/itcw.c b/drivers/s390/cio/itcw.c
index a0ae29564774..358ee16d10a2 100644
--- a/drivers/s390/cio/itcw.c
+++ b/drivers/s390/cio/itcw.c
@@ -93,6 +93,7 @@ EXPORT_SYMBOL(itcw_get_tcw);
93size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws) 93size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws)
94{ 94{
95 size_t len; 95 size_t len;
96 int cross_count;
96 97
97 /* Main data. */ 98 /* Main data. */
98 len = sizeof(struct itcw); 99 len = sizeof(struct itcw);
@@ -105,12 +106,27 @@ size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws)
105 /* TSB */ sizeof(struct tsb) + 106 /* TSB */ sizeof(struct tsb) +
106 /* TIDAL */ intrg_max_tidaws * sizeof(struct tidaw); 107 /* TIDAL */ intrg_max_tidaws * sizeof(struct tidaw);
107 } 108 }
109
108 /* Maximum required alignment padding. */ 110 /* Maximum required alignment padding. */
109 len += /* Initial TCW */ 63 + /* Interrogate TCCB */ 7; 111 len += /* Initial TCW */ 63 + /* Interrogate TCCB */ 7;
110 /* Maximum padding for structures that may not cross 4k boundary. */ 112
111 if ((max_tidaws > 0) || (intrg_max_tidaws > 0)) 113 /* TIDAW lists may not cross a 4k boundary. To cross a
112 len += max(max_tidaws, intrg_max_tidaws) * 114 * boundary we need to add a TTIC TIDAW. We need to reserve
113 sizeof(struct tidaw) - 1; 115 * one additional TIDAW for a TTIC that we may need to add due
116 * to the placement of the data chunk in memory, and a further
117 * TIDAW for each page boundary that the TIDAW list may cross
118 * due to it's own size.
119 */
120 if (max_tidaws) {
121 cross_count = 1 + ((max_tidaws * sizeof(struct tidaw) - 1)
122 >> PAGE_SHIFT);
123 len += cross_count * sizeof(struct tidaw);
124 }
125 if (intrg_max_tidaws) {
126 cross_count = 1 + ((intrg_max_tidaws * sizeof(struct tidaw) - 1)
127 >> PAGE_SHIFT);
128 len += cross_count * sizeof(struct tidaw);
129 }
114 return len; 130 return len;
115} 131}
116EXPORT_SYMBOL(itcw_calc_size); 132EXPORT_SYMBOL(itcw_calc_size);
@@ -165,6 +181,7 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg,
165 void *chunk; 181 void *chunk;
166 addr_t start; 182 addr_t start;
167 addr_t end; 183 addr_t end;
184 int cross_count;
168 185
169 /* Check for 2G limit. */ 186 /* Check for 2G limit. */
170 start = (addr_t) buffer; 187 start = (addr_t) buffer;
@@ -177,8 +194,17 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg,
177 if (IS_ERR(chunk)) 194 if (IS_ERR(chunk))
178 return chunk; 195 return chunk;
179 itcw = chunk; 196 itcw = chunk;
180 itcw->max_tidaws = max_tidaws; 197 /* allow for TTIC tidaws that may be needed to cross a page boundary */
181 itcw->intrg_max_tidaws = intrg_max_tidaws; 198 cross_count = 0;
199 if (max_tidaws)
200 cross_count = 1 + ((max_tidaws * sizeof(struct tidaw) - 1)
201 >> PAGE_SHIFT);
202 itcw->max_tidaws = max_tidaws + cross_count;
203 cross_count = 0;
204 if (intrg_max_tidaws)
205 cross_count = 1 + ((intrg_max_tidaws * sizeof(struct tidaw) - 1)
206 >> PAGE_SHIFT);
207 itcw->intrg_max_tidaws = intrg_max_tidaws + cross_count;
182 /* Main TCW. */ 208 /* Main TCW. */
183 chunk = fit_chunk(&start, end, sizeof(struct tcw), 64, 0); 209 chunk = fit_chunk(&start, end, sizeof(struct tcw), 64, 0);
184 if (IS_ERR(chunk)) 210 if (IS_ERR(chunk))
@@ -198,7 +224,7 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg,
198 /* Data TIDAL. */ 224 /* Data TIDAL. */
199 if (max_tidaws > 0) { 225 if (max_tidaws > 0) {
200 chunk = fit_chunk(&start, end, sizeof(struct tidaw) * 226 chunk = fit_chunk(&start, end, sizeof(struct tidaw) *
201 max_tidaws, 16, 1); 227 itcw->max_tidaws, 16, 0);
202 if (IS_ERR(chunk)) 228 if (IS_ERR(chunk))
203 return chunk; 229 return chunk;
204 tcw_set_data(itcw->tcw, chunk, 1); 230 tcw_set_data(itcw->tcw, chunk, 1);
@@ -206,7 +232,7 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg,
206 /* Interrogate data TIDAL. */ 232 /* Interrogate data TIDAL. */
207 if (intrg && (intrg_max_tidaws > 0)) { 233 if (intrg && (intrg_max_tidaws > 0)) {
208 chunk = fit_chunk(&start, end, sizeof(struct tidaw) * 234 chunk = fit_chunk(&start, end, sizeof(struct tidaw) *
209 intrg_max_tidaws, 16, 1); 235 itcw->intrg_max_tidaws, 16, 0);
210 if (IS_ERR(chunk)) 236 if (IS_ERR(chunk))
211 return chunk; 237 return chunk;
212 tcw_set_data(itcw->intrg_tcw, chunk, 1); 238 tcw_set_data(itcw->intrg_tcw, chunk, 1);
@@ -283,13 +309,29 @@ EXPORT_SYMBOL(itcw_add_dcw);
283 * the new tidaw on success or -%ENOSPC if the new tidaw would exceed the 309 * the new tidaw on success or -%ENOSPC if the new tidaw would exceed the
284 * available space. 310 * available space.
285 * 311 *
286 * Note: the tidaw-list is assumed to be contiguous with no ttics. The 312 * Note: TTIC tidaws are automatically added when needed, so explicitly calling
287 * last-tidaw flag for the last tidaw in the list will be set by itcw_finalize. 313 * this interface with the TTIC flag is not supported. The last-tidaw flag
314 * for the last tidaw in the list will be set by itcw_finalize.
288 */ 315 */
289struct tidaw *itcw_add_tidaw(struct itcw *itcw, u8 flags, void *addr, u32 count) 316struct tidaw *itcw_add_tidaw(struct itcw *itcw, u8 flags, void *addr, u32 count)
290{ 317{
318 struct tidaw *following;
319
291 if (itcw->num_tidaws >= itcw->max_tidaws) 320 if (itcw->num_tidaws >= itcw->max_tidaws)
292 return ERR_PTR(-ENOSPC); 321 return ERR_PTR(-ENOSPC);
322 /*
323 * Is the tidaw, which follows the one we are about to fill, on the next
324 * page? Then we have to insert a TTIC tidaw first, that points to the
325 * tidaw on the new page.
326 */
327 following = ((struct tidaw *) tcw_get_data(itcw->tcw))
328 + itcw->num_tidaws + 1;
329 if (itcw->num_tidaws && !((unsigned long) following & ~PAGE_MASK)) {
330 tcw_add_tidaw(itcw->tcw, itcw->num_tidaws++,
331 TIDAW_FLAGS_TTIC, following, 0);
332 if (itcw->num_tidaws >= itcw->max_tidaws)
333 return ERR_PTR(-ENOSPC);
334 }
293 return tcw_add_tidaw(itcw->tcw, itcw->num_tidaws++, flags, addr, count); 335 return tcw_add_tidaw(itcw->tcw, itcw->num_tidaws++, flags, addr, count);
294} 336}
295EXPORT_SYMBOL(itcw_add_tidaw); 337EXPORT_SYMBOL(itcw_add_tidaw);
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 0f4ef8769a3d..7bc643f3f5ab 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -91,6 +91,12 @@ enum qdio_irq_states {
91#define AC1_SC_QEBSM_AVAILABLE 0x02 /* available for subchannel */ 91#define AC1_SC_QEBSM_AVAILABLE 0x02 /* available for subchannel */
92#define AC1_SC_QEBSM_ENABLED 0x01 /* enabled for subchannel */ 92#define AC1_SC_QEBSM_ENABLED 0x01 /* enabled for subchannel */
93 93
94/* SIGA flags */
95#define QDIO_SIGA_WRITE 0x00
96#define QDIO_SIGA_READ 0x01
97#define QDIO_SIGA_SYNC 0x02
98#define QDIO_SIGA_QEBSM_FLAG 0x80
99
94#ifdef CONFIG_64BIT 100#ifdef CONFIG_64BIT
95static inline int do_sqbs(u64 token, unsigned char state, int queue, 101static inline int do_sqbs(u64 token, unsigned char state, int queue,
96 int *start, int *count) 102 int *start, int *count)
@@ -142,10 +148,9 @@ struct siga_flag {
142 u8 input:1; 148 u8 input:1;
143 u8 output:1; 149 u8 output:1;
144 u8 sync:1; 150 u8 sync:1;
145 u8 no_sync_ti:1; 151 u8 sync_after_ai:1;
146 u8 no_sync_out_ti:1; 152 u8 sync_out_after_pci:1;
147 u8 no_sync_out_pci:1; 153 u8:3;
148 u8:2;
149} __attribute__ ((packed)); 154} __attribute__ ((packed));
150 155
151struct chsc_ssqd_area { 156struct chsc_ssqd_area {
@@ -202,6 +207,7 @@ struct qdio_dev_perf_stat {
202 unsigned int inbound_queue_full; 207 unsigned int inbound_queue_full;
203 unsigned int outbound_call; 208 unsigned int outbound_call;
204 unsigned int outbound_handler; 209 unsigned int outbound_handler;
210 unsigned int outbound_queue_full;
205 unsigned int fast_requeue; 211 unsigned int fast_requeue;
206 unsigned int target_full; 212 unsigned int target_full;
207 unsigned int eqbs; 213 unsigned int eqbs;
@@ -245,10 +251,10 @@ struct qdio_input_q {
245struct qdio_output_q { 251struct qdio_output_q {
246 /* PCIs are enabled for the queue */ 252 /* PCIs are enabled for the queue */
247 int pci_out_enabled; 253 int pci_out_enabled;
248 /* IQDIO: output multiple buffers (enhanced SIGA) */
249 int use_enh_siga;
250 /* timer to check for more outbound work */ 254 /* timer to check for more outbound work */
251 struct timer_list timer; 255 struct timer_list timer;
256 /* used SBALs before tasklet schedule */
257 int scan_threshold;
252}; 258};
253 259
254/* 260/*
@@ -383,12 +389,13 @@ static inline int multicast_outbound(struct qdio_q *q)
383 (q->irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) 389 (q->irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED)
384#define is_qebsm(q) (q->irq_ptr->sch_token != 0) 390#define is_qebsm(q) (q->irq_ptr->sch_token != 0)
385 391
386#define need_siga_sync_thinint(q) (!q->irq_ptr->siga_flag.no_sync_ti)
387#define need_siga_sync_out_thinint(q) (!q->irq_ptr->siga_flag.no_sync_out_ti)
388#define need_siga_in(q) (q->irq_ptr->siga_flag.input) 392#define need_siga_in(q) (q->irq_ptr->siga_flag.input)
389#define need_siga_out(q) (q->irq_ptr->siga_flag.output) 393#define need_siga_out(q) (q->irq_ptr->siga_flag.output)
390#define need_siga_sync(q) (q->irq_ptr->siga_flag.sync) 394#define need_siga_sync(q) (unlikely(q->irq_ptr->siga_flag.sync))
391#define siga_syncs_out_pci(q) (q->irq_ptr->siga_flag.no_sync_out_pci) 395#define need_siga_sync_after_ai(q) \
396 (unlikely(q->irq_ptr->siga_flag.sync_after_ai))
397#define need_siga_sync_out_after_pci(q) \
398 (unlikely(q->irq_ptr->siga_flag.sync_out_after_pci))
392 399
393#define for_each_input_queue(irq_ptr, q, i) \ 400#define for_each_input_queue(irq_ptr, q, i) \
394 for (i = 0, q = irq_ptr->input_qs[0]; \ 401 for (i = 0, q = irq_ptr->input_qs[0]; \
@@ -423,9 +430,9 @@ struct indicator_t {
423 430
424extern struct indicator_t *q_indicators; 431extern struct indicator_t *q_indicators;
425 432
426static inline int shared_ind(struct qdio_irq *irq_ptr) 433static inline int shared_ind(u32 *dsci)
427{ 434{
428 return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; 435 return dsci == &q_indicators[TIQDIO_SHARED_IND].ind;
429} 436}
430 437
431/* prototypes for thin interrupt */ 438/* prototypes for thin interrupt */
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index 28868e7471a5..f8b03a636e49 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -151,6 +151,7 @@ static char *qperf_names[] = {
151 "Inbound queue full", 151 "Inbound queue full",
152 "Outbound calls", 152 "Outbound calls",
153 "Outbound handler", 153 "Outbound handler",
154 "Outbound queue full",
154 "Outbound fast_requeue", 155 "Outbound fast_requeue",
155 "Outbound target_full", 156 "Outbound target_full",
156 "QEBSM eqbs", 157 "QEBSM eqbs",
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 5fcfa7f9e9ef..e9fff2b9bce2 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -14,6 +14,7 @@
14#include <linux/timer.h> 14#include <linux/timer.h>
15#include <linux/delay.h> 15#include <linux/delay.h>
16#include <linux/gfp.h> 16#include <linux/gfp.h>
17#include <linux/kernel_stat.h>
17#include <asm/atomic.h> 18#include <asm/atomic.h>
18#include <asm/debug.h> 19#include <asm/debug.h>
19#include <asm/qdio.h> 20#include <asm/qdio.h>
@@ -29,11 +30,12 @@ MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>,"\
29MODULE_DESCRIPTION("QDIO base support"); 30MODULE_DESCRIPTION("QDIO base support");
30MODULE_LICENSE("GPL"); 31MODULE_LICENSE("GPL");
31 32
32static inline int do_siga_sync(struct subchannel_id schid, 33static inline int do_siga_sync(unsigned long schid,
33 unsigned int out_mask, unsigned int in_mask) 34 unsigned int out_mask, unsigned int in_mask,
35 unsigned int fc)
34{ 36{
35 register unsigned long __fc asm ("0") = 2; 37 register unsigned long __fc asm ("0") = fc;
36 register struct subchannel_id __schid asm ("1") = schid; 38 register unsigned long __schid asm ("1") = schid;
37 register unsigned long out asm ("2") = out_mask; 39 register unsigned long out asm ("2") = out_mask;
38 register unsigned long in asm ("3") = in_mask; 40 register unsigned long in asm ("3") = in_mask;
39 int cc; 41 int cc;
@@ -47,10 +49,11 @@ static inline int do_siga_sync(struct subchannel_id schid,
47 return cc; 49 return cc;
48} 50}
49 51
50static inline int do_siga_input(struct subchannel_id schid, unsigned int mask) 52static inline int do_siga_input(unsigned long schid, unsigned int mask,
53 unsigned int fc)
51{ 54{
52 register unsigned long __fc asm ("0") = 1; 55 register unsigned long __fc asm ("0") = fc;
53 register struct subchannel_id __schid asm ("1") = schid; 56 register unsigned long __schid asm ("1") = schid;
54 register unsigned long __mask asm ("2") = mask; 57 register unsigned long __mask asm ("2") = mask;
55 int cc; 58 int cc;
56 59
@@ -279,16 +282,20 @@ void qdio_init_buf_states(struct qdio_irq *irq_ptr)
279static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, 282static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output,
280 unsigned int input) 283 unsigned int input)
281{ 284{
285 unsigned long schid = *((u32 *) &q->irq_ptr->schid);
286 unsigned int fc = QDIO_SIGA_SYNC;
282 int cc; 287 int cc;
283 288
284 if (!need_siga_sync(q))
285 return 0;
286
287 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr); 289 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr);
288 qperf_inc(q, siga_sync); 290 qperf_inc(q, siga_sync);
289 291
290 cc = do_siga_sync(q->irq_ptr->schid, output, input); 292 if (is_qebsm(q)) {
291 if (cc) 293 schid = q->irq_ptr->sch_token;
294 fc |= QDIO_SIGA_QEBSM_FLAG;
295 }
296
297 cc = do_siga_sync(schid, output, input, fc);
298 if (unlikely(cc))
292 DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc); 299 DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc);
293 return cc; 300 return cc;
294} 301}
@@ -301,38 +308,22 @@ static inline int qdio_siga_sync_q(struct qdio_q *q)
301 return qdio_siga_sync(q, q->mask, 0); 308 return qdio_siga_sync(q, q->mask, 0);
302} 309}
303 310
304static inline int qdio_siga_sync_out(struct qdio_q *q)
305{
306 return qdio_siga_sync(q, ~0U, 0);
307}
308
309static inline int qdio_siga_sync_all(struct qdio_q *q)
310{
311 return qdio_siga_sync(q, ~0U, ~0U);
312}
313
314static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) 311static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit)
315{ 312{
316 unsigned long schid; 313 unsigned long schid = *((u32 *) &q->irq_ptr->schid);
317 unsigned int fc = 0; 314 unsigned int fc = QDIO_SIGA_WRITE;
318 u64 start_time = 0; 315 u64 start_time = 0;
319 int cc; 316 int cc;
320 317
321 if (q->u.out.use_enh_siga)
322 fc = 3;
323
324 if (is_qebsm(q)) { 318 if (is_qebsm(q)) {
325 schid = q->irq_ptr->sch_token; 319 schid = q->irq_ptr->sch_token;
326 fc |= 0x80; 320 fc |= QDIO_SIGA_QEBSM_FLAG;
327 } 321 }
328 else
329 schid = *((u32 *)&q->irq_ptr->schid);
330
331again: 322again:
332 cc = do_siga_output(schid, q->mask, busy_bit, fc); 323 cc = do_siga_output(schid, q->mask, busy_bit, fc);
333 324
334 /* hipersocket busy condition */ 325 /* hipersocket busy condition */
335 if (*busy_bit) { 326 if (unlikely(*busy_bit)) {
336 WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2); 327 WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2);
337 328
338 if (!start_time) { 329 if (!start_time) {
@@ -347,32 +338,41 @@ again:
347 338
348static inline int qdio_siga_input(struct qdio_q *q) 339static inline int qdio_siga_input(struct qdio_q *q)
349{ 340{
341 unsigned long schid = *((u32 *) &q->irq_ptr->schid);
342 unsigned int fc = QDIO_SIGA_READ;
350 int cc; 343 int cc;
351 344
352 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-r:%1d", q->nr); 345 DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-r:%1d", q->nr);
353 qperf_inc(q, siga_read); 346 qperf_inc(q, siga_read);
354 347
355 cc = do_siga_input(q->irq_ptr->schid, q->mask); 348 if (is_qebsm(q)) {
356 if (cc) 349 schid = q->irq_ptr->sch_token;
350 fc |= QDIO_SIGA_QEBSM_FLAG;
351 }
352
353 cc = do_siga_input(schid, q->mask, fc);
354 if (unlikely(cc))
357 DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc); 355 DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc);
358 return cc; 356 return cc;
359} 357}
360 358
361static inline void qdio_sync_after_thinint(struct qdio_q *q) 359#define qdio_siga_sync_out(q) qdio_siga_sync(q, ~0U, 0)
360#define qdio_siga_sync_all(q) qdio_siga_sync(q, ~0U, ~0U)
361
362static inline void qdio_sync_queues(struct qdio_q *q)
362{ 363{
363 if (pci_out_supported(q)) { 364 /* PCI capable outbound queues will also be scanned so sync them too */
364 if (need_siga_sync_thinint(q)) 365 if (pci_out_supported(q))
365 qdio_siga_sync_all(q); 366 qdio_siga_sync_all(q);
366 else if (need_siga_sync_out_thinint(q)) 367 else
367 qdio_siga_sync_out(q);
368 } else
369 qdio_siga_sync_q(q); 368 qdio_siga_sync_q(q);
370} 369}
371 370
372int debug_get_buf_state(struct qdio_q *q, unsigned int bufnr, 371int debug_get_buf_state(struct qdio_q *q, unsigned int bufnr,
373 unsigned char *state) 372 unsigned char *state)
374{ 373{
375 qdio_siga_sync_q(q); 374 if (need_siga_sync(q))
375 qdio_siga_sync_q(q);
376 return get_buf_states(q, bufnr, state, 1, 0); 376 return get_buf_states(q, bufnr, state, 1, 0);
377} 377}
378 378
@@ -549,7 +549,8 @@ static inline int qdio_inbound_q_done(struct qdio_q *q)
549 if (!atomic_read(&q->nr_buf_used)) 549 if (!atomic_read(&q->nr_buf_used))
550 return 1; 550 return 1;
551 551
552 qdio_siga_sync_q(q); 552 if (need_siga_sync(q))
553 qdio_siga_sync_q(q);
553 get_buf_state(q, q->first_to_check, &state, 0); 554 get_buf_state(q, q->first_to_check, &state, 0);
554 555
555 if (state == SLSB_P_INPUT_PRIMED || state == SLSB_P_INPUT_ERROR) 556 if (state == SLSB_P_INPUT_PRIMED || state == SLSB_P_INPUT_ERROR)
@@ -644,9 +645,12 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
644 int count, stop; 645 int count, stop;
645 unsigned char state; 646 unsigned char state;
646 647
647 if (((queue_type(q) != QDIO_IQDIO_QFMT) && !pci_out_supported(q)) || 648 if (need_siga_sync(q))
648 (queue_type(q) == QDIO_IQDIO_QFMT && multicast_outbound(q))) 649 if (((queue_type(q) != QDIO_IQDIO_QFMT) &&
649 qdio_siga_sync_q(q); 650 !pci_out_supported(q)) ||
651 (queue_type(q) == QDIO_IQDIO_QFMT &&
652 multicast_outbound(q)))
653 qdio_siga_sync_q(q);
650 654
651 /* 655 /*
652 * Don't check 128 buffers, as otherwise qdio_inbound_q_moved 656 * Don't check 128 buffers, as otherwise qdio_inbound_q_moved
@@ -818,7 +822,8 @@ static inline void qdio_check_outbound_after_thinint(struct qdio_q *q)
818static void __tiqdio_inbound_processing(struct qdio_q *q) 822static void __tiqdio_inbound_processing(struct qdio_q *q)
819{ 823{
820 qperf_inc(q, tasklet_inbound); 824 qperf_inc(q, tasklet_inbound);
821 qdio_sync_after_thinint(q); 825 if (need_siga_sync(q) && need_siga_sync_after_ai(q))
826 qdio_sync_queues(q);
822 827
823 /* 828 /*
824 * The interrupt could be caused by a PCI request. Check the 829 * The interrupt could be caused by a PCI request. Check the
@@ -898,16 +903,14 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)
898 tasklet_schedule(&q->tasklet); 903 tasklet_schedule(&q->tasklet);
899 } 904 }
900 905
901 if (!(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED)) 906 if (!pci_out_supported(q))
902 return; 907 return;
903 908
904 for_each_output_queue(irq_ptr, q, i) { 909 for_each_output_queue(irq_ptr, q, i) {
905 if (qdio_outbound_q_done(q)) 910 if (qdio_outbound_q_done(q))
906 continue; 911 continue;
907 912 if (need_siga_sync(q) && need_siga_sync_out_after_pci(q))
908 if (!siga_syncs_out_pci(q))
909 qdio_siga_sync_q(q); 913 qdio_siga_sync_q(q);
910
911 tasklet_schedule(&q->tasklet); 914 tasklet_schedule(&q->tasklet);
912 } 915 }
913} 916}
@@ -970,6 +973,7 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm,
970 return; 973 return;
971 } 974 }
972 975
976 kstat_cpu(smp_processor_id()).irqs[IOINT_QDI]++;
973 if (irq_ptr->perf_stat_enabled) 977 if (irq_ptr->perf_stat_enabled)
974 irq_ptr->perf_stat.qdio_int++; 978 irq_ptr->perf_stat.qdio_int++;
975 979
@@ -1273,7 +1277,6 @@ int qdio_establish(struct qdio_initialize *init_data)
1273 } 1277 }
1274 1278
1275 qdio_setup_ssqd_info(irq_ptr); 1279 qdio_setup_ssqd_info(irq_ptr);
1276 DBF_EVENT("qDmmwc:%2x", irq_ptr->ssqd_desc.mmwc);
1277 DBF_EVENT("qib ac:%4x", irq_ptr->qib.ac); 1280 DBF_EVENT("qib ac:%4x", irq_ptr->qib.ac);
1278 1281
1279 /* qebsm is now setup if available, initialize buffer states */ 1282 /* qebsm is now setup if available, initialize buffer states */
@@ -1445,52 +1448,38 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags,
1445 used = atomic_add_return(count, &q->nr_buf_used); 1448 used = atomic_add_return(count, &q->nr_buf_used);
1446 BUG_ON(used > QDIO_MAX_BUFFERS_PER_Q); 1449 BUG_ON(used > QDIO_MAX_BUFFERS_PER_Q);
1447 1450
1451 if (used == QDIO_MAX_BUFFERS_PER_Q)
1452 qperf_inc(q, outbound_queue_full);
1453
1448 if (callflags & QDIO_FLAG_PCI_OUT) { 1454 if (callflags & QDIO_FLAG_PCI_OUT) {
1449 q->u.out.pci_out_enabled = 1; 1455 q->u.out.pci_out_enabled = 1;
1450 qperf_inc(q, pci_request_int); 1456 qperf_inc(q, pci_request_int);
1451 } 1457 } else
1452 else
1453 q->u.out.pci_out_enabled = 0; 1458 q->u.out.pci_out_enabled = 0;
1454 1459
1455 if (queue_type(q) == QDIO_IQDIO_QFMT) { 1460 if (queue_type(q) == QDIO_IQDIO_QFMT) {
1456 if (multicast_outbound(q)) 1461 /* One SIGA-W per buffer required for unicast HiperSockets. */
1462 WARN_ON_ONCE(count > 1 && !multicast_outbound(q));
1463
1464 rc = qdio_kick_outbound_q(q);
1465 } else if (need_siga_sync(q)) {
1466 rc = qdio_siga_sync_q(q);
1467 } else {
1468 /* try to fast requeue buffers */
1469 get_buf_state(q, prev_buf(bufnr), &state, 0);
1470 if (state != SLSB_CU_OUTPUT_PRIMED)
1457 rc = qdio_kick_outbound_q(q); 1471 rc = qdio_kick_outbound_q(q);
1458 else 1472 else
1459 if ((q->irq_ptr->ssqd_desc.mmwc > 1) && 1473 qperf_inc(q, fast_requeue);
1460 (count > 1) &&
1461 (count <= q->irq_ptr->ssqd_desc.mmwc)) {
1462 /* exploit enhanced SIGA */
1463 q->u.out.use_enh_siga = 1;
1464 rc = qdio_kick_outbound_q(q);
1465 } else {
1466 /*
1467 * One siga-w per buffer required for unicast
1468 * HiperSockets.
1469 */
1470 q->u.out.use_enh_siga = 0;
1471 while (count--) {
1472 rc = qdio_kick_outbound_q(q);
1473 if (rc)
1474 goto out;
1475 }
1476 }
1477 goto out;
1478 }
1479
1480 if (need_siga_sync(q)) {
1481 qdio_siga_sync_q(q);
1482 goto out;
1483 } 1474 }
1484 1475
1485 /* try to fast requeue buffers */ 1476 /* in case of SIGA errors we must process the error immediately */
1486 get_buf_state(q, prev_buf(bufnr), &state, 0); 1477 if (used >= q->u.out.scan_threshold || rc)
1487 if (state != SLSB_CU_OUTPUT_PRIMED) 1478 tasklet_schedule(&q->tasklet);
1488 rc = qdio_kick_outbound_q(q);
1489 else 1479 else
1490 qperf_inc(q, fast_requeue); 1480 /* free the SBALs in case of no further traffic */
1491 1481 if (!timer_pending(&q->u.out.timer))
1492out: 1482 mod_timer(&q->u.out.timer, jiffies + HZ);
1493 tasklet_schedule(&q->tasklet);
1494 return rc; 1483 return rc;
1495} 1484}
1496 1485
@@ -1550,7 +1539,7 @@ int qdio_start_irq(struct ccw_device *cdev, int nr)
1550 1539
1551 WARN_ON(queue_irqs_enabled(q)); 1540 WARN_ON(queue_irqs_enabled(q));
1552 1541
1553 if (!shared_ind(q->irq_ptr)) 1542 if (!shared_ind(q->irq_ptr->dsci))
1554 xchg(q->irq_ptr->dsci, 0); 1543 xchg(q->irq_ptr->dsci, 0);
1555 1544
1556 qdio_stop_polling(q); 1545 qdio_stop_polling(q);
@@ -1560,7 +1549,7 @@ int qdio_start_irq(struct ccw_device *cdev, int nr)
1560 * We need to check again to not lose initiative after 1549 * We need to check again to not lose initiative after
1561 * resetting the ACK state. 1550 * resetting the ACK state.
1562 */ 1551 */
1563 if (!shared_ind(q->irq_ptr) && *q->irq_ptr->dsci) 1552 if (!shared_ind(q->irq_ptr->dsci) && *q->irq_ptr->dsci)
1564 goto rescan; 1553 goto rescan;
1565 if (!qdio_inbound_q_done(q)) 1554 if (!qdio_inbound_q_done(q))
1566 goto rescan; 1555 goto rescan;
@@ -1600,12 +1589,14 @@ int qdio_get_next_buffers(struct ccw_device *cdev, int nr, int *bufnr,
1600 q = irq_ptr->input_qs[nr]; 1589 q = irq_ptr->input_qs[nr];
1601 WARN_ON(queue_irqs_enabled(q)); 1590 WARN_ON(queue_irqs_enabled(q));
1602 1591
1603 qdio_sync_after_thinint(q);
1604
1605 /* 1592 /*
1606 * The interrupt could be caused by a PCI request. Check the 1593 * Cannot rely on automatic sync after interrupt since queues may
1607 * PCI capable outbound queues. 1594 * also be examined without interrupt.
1608 */ 1595 */
1596 if (need_siga_sync(q))
1597 qdio_sync_queues(q);
1598
1599 /* check the PCI capable outbound queues. */
1609 qdio_check_outbound_after_thinint(q); 1600 qdio_check_outbound_after_thinint(q);
1610 1601
1611 if (!qdio_inbound_q_moved(q)) 1602 if (!qdio_inbound_q_moved(q))
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index a13cf7ec64b2..89107d0938c4 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -178,6 +178,7 @@ static void setup_queues(struct qdio_irq *irq_ptr,
178 setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i); 178 setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i);
179 179
180 q->is_input_q = 0; 180 q->is_input_q = 0;
181 q->u.out.scan_threshold = qdio_init->scan_threshold;
181 setup_storage_lists(q, irq_ptr, output_sbal_array, i); 182 setup_storage_lists(q, irq_ptr, output_sbal_array, i);
182 output_sbal_array += QDIO_MAX_BUFFERS_PER_Q; 183 output_sbal_array += QDIO_MAX_BUFFERS_PER_Q;
183 184
@@ -196,14 +197,10 @@ static void process_ac_flags(struct qdio_irq *irq_ptr, unsigned char qdioac)
196 irq_ptr->siga_flag.output = 1; 197 irq_ptr->siga_flag.output = 1;
197 if (qdioac & AC1_SIGA_SYNC_NEEDED) 198 if (qdioac & AC1_SIGA_SYNC_NEEDED)
198 irq_ptr->siga_flag.sync = 1; 199 irq_ptr->siga_flag.sync = 1;
199 if (qdioac & AC1_AUTOMATIC_SYNC_ON_THININT) 200 if (!(qdioac & AC1_AUTOMATIC_SYNC_ON_THININT))
200 irq_ptr->siga_flag.no_sync_ti = 1; 201 irq_ptr->siga_flag.sync_after_ai = 1;
201 if (qdioac & AC1_AUTOMATIC_SYNC_ON_OUT_PCI) 202 if (!(qdioac & AC1_AUTOMATIC_SYNC_ON_OUT_PCI))
202 irq_ptr->siga_flag.no_sync_out_pci = 1; 203 irq_ptr->siga_flag.sync_out_after_pci = 1;
203
204 if (irq_ptr->siga_flag.no_sync_out_pci &&
205 irq_ptr->siga_flag.no_sync_ti)
206 irq_ptr->siga_flag.no_sync_out_ti = 1;
207} 204}
208 205
209static void check_and_setup_qebsm(struct qdio_irq *irq_ptr, 206static void check_and_setup_qebsm(struct qdio_irq *irq_ptr,
@@ -451,7 +448,7 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr,
451 char s[80]; 448 char s[80];
452 449
453 snprintf(s, 80, "qdio: %s %s on SC %x using " 450 snprintf(s, 80, "qdio: %s %s on SC %x using "
454 "AI:%d QEBSM:%d PCI:%d TDD:%d SIGA:%s%s%s%s%s%s\n", 451 "AI:%d QEBSM:%d PCI:%d TDD:%d SIGA:%s%s%s%s%s\n",
455 dev_name(&cdev->dev), 452 dev_name(&cdev->dev),
456 (irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" : 453 (irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" :
457 ((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"), 454 ((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"),
@@ -463,9 +460,8 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr,
463 (irq_ptr->siga_flag.input) ? "R" : " ", 460 (irq_ptr->siga_flag.input) ? "R" : " ",
464 (irq_ptr->siga_flag.output) ? "W" : " ", 461 (irq_ptr->siga_flag.output) ? "W" : " ",
465 (irq_ptr->siga_flag.sync) ? "S" : " ", 462 (irq_ptr->siga_flag.sync) ? "S" : " ",
466 (!irq_ptr->siga_flag.no_sync_ti) ? "A" : " ", 463 (irq_ptr->siga_flag.sync_after_ai) ? "A" : " ",
467 (!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " ", 464 (irq_ptr->siga_flag.sync_out_after_pci) ? "P" : " ");
468 (!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " ");
469 printk(KERN_INFO "%s", s); 465 printk(KERN_INFO "%s", s);
470} 466}
471 467
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
index 5d9c66627b6e..5c4e741d8221 100644
--- a/drivers/s390/cio/qdio_thinint.c
+++ b/drivers/s390/cio/qdio_thinint.c
@@ -8,6 +8,7 @@
8 */ 8 */
9#include <linux/io.h> 9#include <linux/io.h>
10#include <linux/slab.h> 10#include <linux/slab.h>
11#include <linux/kernel_stat.h>
11#include <asm/atomic.h> 12#include <asm/atomic.h>
12#include <asm/debug.h> 13#include <asm/debug.h>
13#include <asm/qdio.h> 14#include <asm/qdio.h>
@@ -35,22 +36,8 @@ static u8 *tiqdio_alsi;
35 36
36struct indicator_t *q_indicators; 37struct indicator_t *q_indicators;
37 38
38static int css_qdio_omit_svs;
39
40static u64 last_ai_time; 39static u64 last_ai_time;
41 40
42static inline unsigned long do_clear_global_summary(void)
43{
44 register unsigned long __fn asm("1") = 3;
45 register unsigned long __tmp asm("2");
46 register unsigned long __time asm("3");
47
48 asm volatile(
49 " .insn rre,0xb2650000,2,0"
50 : "+d" (__fn), "=d" (__tmp), "=d" (__time));
51 return __time;
52}
53
54/* returns addr for the device state change indicator */ 41/* returns addr for the device state change indicator */
55static u32 *get_indicator(void) 42static u32 *get_indicator(void)
56{ 43{
@@ -83,10 +70,6 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr)
83 struct qdio_q *q; 70 struct qdio_q *q;
84 int i; 71 int i;
85 72
86 /* No TDD facility? If we must use SIGA-s we can also omit SVS. */
87 if (!css_qdio_omit_svs && irq_ptr->siga_flag.sync)
88 css_qdio_omit_svs = 1;
89
90 mutex_lock(&tiq_list_lock); 73 mutex_lock(&tiq_list_lock);
91 for_each_input_queue(irq_ptr, q, i) 74 for_each_input_queue(irq_ptr, q, i)
92 list_add_rcu(&q->entry, &tiq_list); 75 list_add_rcu(&q->entry, &tiq_list);
@@ -112,9 +95,9 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
112 } 95 }
113} 96}
114 97
115static inline int shared_ind_used(void) 98static inline u32 shared_ind_set(void)
116{ 99{
117 return atomic_read(&q_indicators[TIQDIO_SHARED_IND].count); 100 return q_indicators[TIQDIO_SHARED_IND].ind;
118} 101}
119 102
120/** 103/**
@@ -124,20 +107,11 @@ static inline int shared_ind_used(void)
124 */ 107 */
125static void tiqdio_thinint_handler(void *alsi, void *data) 108static void tiqdio_thinint_handler(void *alsi, void *data)
126{ 109{
110 u32 si_used = shared_ind_set();
127 struct qdio_q *q; 111 struct qdio_q *q;
128 112
129 last_ai_time = S390_lowcore.int_clock; 113 last_ai_time = S390_lowcore.int_clock;
130 114 kstat_cpu(smp_processor_id()).irqs[IOINT_QAI]++;
131 /*
132 * SVS only when needed: issue SVS to benefit from iqdio interrupt
133 * avoidance (SVS clears adapter interrupt suppression overwrite).
134 */
135 if (!css_qdio_omit_svs)
136 do_clear_global_summary();
137
138 /* reset local summary indicator */
139 if (shared_ind_used())
140 xchg(tiqdio_alsi, 0);
141 115
142 /* protect tiq_list entries, only changed in activate or shutdown */ 116 /* protect tiq_list entries, only changed in activate or shutdown */
143 rcu_read_lock(); 117 rcu_read_lock();
@@ -146,7 +120,10 @@ static void tiqdio_thinint_handler(void *alsi, void *data)
146 list_for_each_entry_rcu(q, &tiq_list, entry) { 120 list_for_each_entry_rcu(q, &tiq_list, entry) {
147 121
148 /* only process queues from changed sets */ 122 /* only process queues from changed sets */
149 if (!*q->irq_ptr->dsci) 123 if (unlikely(shared_ind(q->irq_ptr->dsci))) {
124 if (!si_used)
125 continue;
126 } else if (!*q->irq_ptr->dsci)
150 continue; 127 continue;
151 128
152 if (q->u.in.queue_start_poll) { 129 if (q->u.in.queue_start_poll) {
@@ -162,7 +139,7 @@ static void tiqdio_thinint_handler(void *alsi, void *data)
162 q->irq_ptr->int_parm); 139 q->irq_ptr->int_parm);
163 } else { 140 } else {
164 /* only clear it if the indicator is non-shared */ 141 /* only clear it if the indicator is non-shared */
165 if (!shared_ind(q->irq_ptr)) 142 if (!shared_ind(q->irq_ptr->dsci))
166 xchg(q->irq_ptr->dsci, 0); 143 xchg(q->irq_ptr->dsci, 0);
167 /* 144 /*
168 * Call inbound processing but not directly 145 * Call inbound processing but not directly
@@ -178,13 +155,8 @@ static void tiqdio_thinint_handler(void *alsi, void *data)
178 * If the shared indicator was used clear it now after all queues 155 * If the shared indicator was used clear it now after all queues
179 * were processed. 156 * were processed.
180 */ 157 */
181 if (shared_ind_used()) { 158 if (si_used && shared_ind_set())
182 xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0); 159 xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 0);
183
184 /* prevent racing */
185 if (*tiqdio_alsi)
186 xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1 << 7);
187 }
188} 160}
189 161
190static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) 162static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset)
@@ -269,12 +241,6 @@ int qdio_establish_thinint(struct qdio_irq *irq_ptr)
269{ 241{
270 if (!is_thinint_irq(irq_ptr)) 242 if (!is_thinint_irq(irq_ptr))
271 return 0; 243 return 0;
272
273 /* Check for aif time delay disablement. If installed,
274 * omit SVS even under LPAR
275 */
276 if (css_general_characteristics.aif_tdd)
277 css_qdio_omit_svs = 1;
278 return set_subchannel_ind(irq_ptr, 0); 244 return set_subchannel_ind(irq_ptr, 0);
279} 245}
280 246