diff options
Diffstat (limited to 'drivers/s390/s390mach.c')
-rw-r--r-- | drivers/s390/s390mach.c | 66 |
1 files changed, 47 insertions, 19 deletions
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 4191fd9d4d11..3bf466603512 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c | |||
@@ -23,7 +23,7 @@ | |||
23 | 23 | ||
24 | static struct semaphore m_sem; | 24 | static struct semaphore m_sem; |
25 | 25 | ||
26 | extern int css_process_crw(int); | 26 | extern int css_process_crw(int, int); |
27 | extern int chsc_process_crw(void); | 27 | extern int chsc_process_crw(void); |
28 | extern int chp_process_crw(int, int); | 28 | extern int chp_process_crw(int, int); |
29 | extern void css_reiterate_subchannels(void); | 29 | extern void css_reiterate_subchannels(void); |
@@ -49,9 +49,10 @@ s390_handle_damage(char *msg) | |||
49 | static int | 49 | static int |
50 | s390_collect_crw_info(void *param) | 50 | s390_collect_crw_info(void *param) |
51 | { | 51 | { |
52 | struct crw crw; | 52 | struct crw crw[2]; |
53 | int ccode, ret, slow; | 53 | int ccode, ret, slow; |
54 | struct semaphore *sem; | 54 | struct semaphore *sem; |
55 | unsigned int chain; | ||
55 | 56 | ||
56 | sem = (struct semaphore *)param; | 57 | sem = (struct semaphore *)param; |
57 | /* Set a nice name. */ | 58 | /* Set a nice name. */ |
@@ -59,25 +60,50 @@ s390_collect_crw_info(void *param) | |||
59 | repeat: | 60 | repeat: |
60 | down_interruptible(sem); | 61 | down_interruptible(sem); |
61 | slow = 0; | 62 | slow = 0; |
63 | chain = 0; | ||
62 | while (1) { | 64 | while (1) { |
63 | ccode = stcrw(&crw); | 65 | if (unlikely(chain > 1)) { |
66 | struct crw tmp_crw; | ||
67 | |||
68 | printk(KERN_WARNING"%s: Code does not support more " | ||
69 | "than two chained crws; please report to " | ||
70 | "linux390@de.ibm.com!\n", __FUNCTION__); | ||
71 | ccode = stcrw(&tmp_crw); | ||
72 | printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, " | ||
73 | "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", | ||
74 | __FUNCTION__, tmp_crw.slct, tmp_crw.oflw, | ||
75 | tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc, | ||
76 | tmp_crw.erc, tmp_crw.rsid); | ||
77 | printk(KERN_WARNING"%s: This was crw number %x in the " | ||
78 | "chain\n", __FUNCTION__, chain); | ||
79 | if (ccode != 0) | ||
80 | break; | ||
81 | chain = tmp_crw.chn ? chain + 1 : 0; | ||
82 | continue; | ||
83 | } | ||
84 | ccode = stcrw(&crw[chain]); | ||
64 | if (ccode != 0) | 85 | if (ccode != 0) |
65 | break; | 86 | break; |
66 | DBG(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, " | 87 | DBG(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, " |
67 | "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", | 88 | "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", |
68 | crw.slct, crw.oflw, crw.chn, crw.rsc, crw.anc, | 89 | crw[chain].slct, crw[chain].oflw, crw[chain].chn, |
69 | crw.erc, crw.rsid); | 90 | crw[chain].rsc, crw[chain].anc, crw[chain].erc, |
91 | crw[chain].rsid); | ||
70 | /* Check for overflows. */ | 92 | /* Check for overflows. */ |
71 | if (crw.oflw) { | 93 | if (crw[chain].oflw) { |
72 | pr_debug("%s: crw overflow detected!\n", __FUNCTION__); | 94 | pr_debug("%s: crw overflow detected!\n", __FUNCTION__); |
73 | css_reiterate_subchannels(); | 95 | css_reiterate_subchannels(); |
96 | chain = 0; | ||
74 | slow = 1; | 97 | slow = 1; |
75 | continue; | 98 | continue; |
76 | } | 99 | } |
77 | switch (crw.rsc) { | 100 | switch (crw[chain].rsc) { |
78 | case CRW_RSC_SCH: | 101 | case CRW_RSC_SCH: |
79 | pr_debug("source is subchannel %04X\n", crw.rsid); | 102 | if (crw[0].chn && !chain) |
80 | ret = css_process_crw (crw.rsid); | 103 | break; |
104 | pr_debug("source is subchannel %04X\n", crw[0].rsid); | ||
105 | ret = css_process_crw (crw[0].rsid, | ||
106 | chain ? crw[1].rsid : 0); | ||
81 | if (ret == -EAGAIN) | 107 | if (ret == -EAGAIN) |
82 | slow = 1; | 108 | slow = 1; |
83 | break; | 109 | break; |
@@ -85,18 +111,18 @@ repeat: | |||
85 | pr_debug("source is monitoring facility\n"); | 111 | pr_debug("source is monitoring facility\n"); |
86 | break; | 112 | break; |
87 | case CRW_RSC_CPATH: | 113 | case CRW_RSC_CPATH: |
88 | pr_debug("source is channel path %02X\n", crw.rsid); | 114 | pr_debug("source is channel path %02X\n", crw[0].rsid); |
89 | switch (crw.erc) { | 115 | switch (crw[0].erc) { |
90 | case CRW_ERC_IPARM: /* Path has come. */ | 116 | case CRW_ERC_IPARM: /* Path has come. */ |
91 | ret = chp_process_crw(crw.rsid, 1); | 117 | ret = chp_process_crw(crw[0].rsid, 1); |
92 | break; | 118 | break; |
93 | case CRW_ERC_PERRI: /* Path has gone. */ | 119 | case CRW_ERC_PERRI: /* Path has gone. */ |
94 | case CRW_ERC_PERRN: | 120 | case CRW_ERC_PERRN: |
95 | ret = chp_process_crw(crw.rsid, 0); | 121 | ret = chp_process_crw(crw[0].rsid, 0); |
96 | break; | 122 | break; |
97 | default: | 123 | default: |
98 | pr_debug("Don't know how to handle erc=%x\n", | 124 | pr_debug("Don't know how to handle erc=%x\n", |
99 | crw.erc); | 125 | crw[0].erc); |
100 | ret = 0; | 126 | ret = 0; |
101 | } | 127 | } |
102 | if (ret == -EAGAIN) | 128 | if (ret == -EAGAIN) |
@@ -115,6 +141,8 @@ repeat: | |||
115 | pr_debug("unknown source\n"); | 141 | pr_debug("unknown source\n"); |
116 | break; | 142 | break; |
117 | } | 143 | } |
144 | /* chain is always 0 or 1 here. */ | ||
145 | chain = crw[chain].chn ? chain + 1 : 0; | ||
118 | } | 146 | } |
119 | if (slow) | 147 | if (slow) |
120 | queue_work(slow_path_wq, &slow_path_work); | 148 | queue_work(slow_path_wq, &slow_path_work); |
@@ -218,7 +246,7 @@ s390_revalidate_registers(struct mci *mci) | |||
218 | */ | 246 | */ |
219 | kill_task = 1; | 247 | kill_task = 1; |
220 | 248 | ||
221 | #ifndef __s390x__ | 249 | #ifndef CONFIG_64BIT |
222 | asm volatile("ld 0,0(%0)\n" | 250 | asm volatile("ld 0,0(%0)\n" |
223 | "ld 2,8(%0)\n" | 251 | "ld 2,8(%0)\n" |
224 | "ld 4,16(%0)\n" | 252 | "ld 4,16(%0)\n" |
@@ -227,7 +255,7 @@ s390_revalidate_registers(struct mci *mci) | |||
227 | #endif | 255 | #endif |
228 | 256 | ||
229 | if (MACHINE_HAS_IEEE) { | 257 | if (MACHINE_HAS_IEEE) { |
230 | #ifdef __s390x__ | 258 | #ifdef CONFIG_64BIT |
231 | fpt_save_area = &S390_lowcore.floating_pt_save_area; | 259 | fpt_save_area = &S390_lowcore.floating_pt_save_area; |
232 | fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area; | 260 | fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area; |
233 | #else | 261 | #else |
@@ -286,7 +314,7 @@ s390_revalidate_registers(struct mci *mci) | |||
286 | */ | 314 | */ |
287 | s390_handle_damage("invalid control registers."); | 315 | s390_handle_damage("invalid control registers."); |
288 | else | 316 | else |
289 | #ifdef __s390x__ | 317 | #ifdef CONFIG_64BIT |
290 | asm volatile("lctlg 0,15,0(%0)" | 318 | asm volatile("lctlg 0,15,0(%0)" |
291 | : : "a" (&S390_lowcore.cregs_save_area)); | 319 | : : "a" (&S390_lowcore.cregs_save_area)); |
292 | #else | 320 | #else |
@@ -299,7 +327,7 @@ s390_revalidate_registers(struct mci *mci) | |||
299 | * can't write something sensible into that register. | 327 | * can't write something sensible into that register. |
300 | */ | 328 | */ |
301 | 329 | ||
302 | #ifdef __s390x__ | 330 | #ifdef CONFIG_64BIT |
303 | /* | 331 | /* |
304 | * See if we can revalidate the TOD programmable register with its | 332 | * See if we can revalidate the TOD programmable register with its |
305 | * old contents (should be zero) otherwise set it to zero. | 333 | * old contents (should be zero) otherwise set it to zero. |
@@ -356,7 +384,7 @@ s390_do_machine_check(struct pt_regs *regs) | |||
356 | if (mci->b) { | 384 | if (mci->b) { |
357 | /* Processing backup -> verify if we can survive this */ | 385 | /* Processing backup -> verify if we can survive this */ |
358 | u64 z_mcic, o_mcic, t_mcic; | 386 | u64 z_mcic, o_mcic, t_mcic; |
359 | #ifdef __s390x__ | 387 | #ifdef CONFIG_64BIT |
360 | z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<29); | 388 | z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<29); |
361 | o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 | | 389 | o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 | |
362 | 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 | | 390 | 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 | |