diff options
-rw-r--r-- | drivers/s390/cio/qdio.c | 178 | ||||
-rw-r--r-- | drivers/s390/cio/qdio.h | 28 |
2 files changed, 114 insertions, 92 deletions
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index b1d18aa471c9..c359386708e9 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c | |||
@@ -2217,9 +2217,78 @@ qdio_synchronize(struct ccw_device *cdev, unsigned int flags, | |||
2217 | return cc; | 2217 | return cc; |
2218 | } | 2218 | } |
2219 | 2219 | ||
2220 | static int | ||
2221 | qdio_get_ssqd_information(struct subchannel_id *schid, | ||
2222 | struct qdio_chsc_ssqd **ssqd_area) | ||
2223 | { | ||
2224 | int result; | ||
2225 | |||
2226 | QDIO_DBF_TEXT0(0, setup, "getssqd"); | ||
2227 | *ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); | ||
2228 | if (!ssqd_area) { | ||
2229 | QDIO_PRINT_WARN("Could not get memory for chsc on sch x%x.\n", | ||
2230 | schid->sch_no); | ||
2231 | return -ENOMEM; | ||
2232 | } | ||
2233 | |||
2234 | (*ssqd_area)->request = (struct chsc_header) { | ||
2235 | .length = 0x0010, | ||
2236 | .code = 0x0024, | ||
2237 | }; | ||
2238 | (*ssqd_area)->first_sch = schid->sch_no; | ||
2239 | (*ssqd_area)->last_sch = schid->sch_no; | ||
2240 | (*ssqd_area)->ssid = schid->ssid; | ||
2241 | result = chsc(*ssqd_area); | ||
2242 | |||
2243 | if (result) { | ||
2244 | QDIO_PRINT_WARN("CHSC returned cc %i on sch 0.%x.%x.\n", | ||
2245 | result, schid->ssid, schid->sch_no); | ||
2246 | goto out; | ||
2247 | } | ||
2248 | |||
2249 | if ((*ssqd_area)->response.code != QDIO_CHSC_RESPONSE_CODE_OK) { | ||
2250 | QDIO_PRINT_WARN("CHSC response is 0x%x on sch 0.%x.%x.\n", | ||
2251 | (*ssqd_area)->response.code, | ||
2252 | schid->ssid, schid->sch_no); | ||
2253 | goto out; | ||
2254 | } | ||
2255 | if (!((*ssqd_area)->flags & CHSC_FLAG_QDIO_CAPABILITY) || | ||
2256 | !((*ssqd_area)->flags & CHSC_FLAG_VALIDITY) || | ||
2257 | ((*ssqd_area)->sch != schid->sch_no)) { | ||
2258 | QDIO_PRINT_WARN("huh? problems checking out sch 0.%x.%x... " \ | ||
2259 | "using all SIGAs.\n", | ||
2260 | schid->ssid, schid->sch_no); | ||
2261 | goto out; | ||
2262 | } | ||
2263 | return 0; | ||
2264 | out: | ||
2265 | return -EINVAL; | ||
2266 | } | ||
2267 | |||
2268 | int | ||
2269 | qdio_get_ssqd_pct(struct ccw_device *cdev) | ||
2270 | { | ||
2271 | struct qdio_chsc_ssqd *ssqd_area; | ||
2272 | struct subchannel_id schid; | ||
2273 | char dbf_text[15]; | ||
2274 | int rc; | ||
2275 | int pct = 0; | ||
2276 | |||
2277 | QDIO_DBF_TEXT0(0, setup, "getpct"); | ||
2278 | schid = ccw_device_get_subchannel_id(cdev); | ||
2279 | rc = qdio_get_ssqd_information(&schid, &ssqd_area); | ||
2280 | if (!rc) | ||
2281 | pct = (int)ssqd_area->pct; | ||
2282 | if (rc != -ENOMEM) | ||
2283 | mempool_free(ssqd_area, qdio_mempool_scssc); | ||
2284 | sprintf(dbf_text, "pct: %d", pct); | ||
2285 | QDIO_DBF_TEXT2(0, setup, dbf_text); | ||
2286 | return pct; | ||
2287 | } | ||
2288 | EXPORT_SYMBOL(qdio_get_ssqd_pct); | ||
2289 | |||
2220 | static void | 2290 | static void |
2221 | qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, | 2291 | qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned long token) |
2222 | unsigned long token) | ||
2223 | { | 2292 | { |
2224 | struct qdio_q *q; | 2293 | struct qdio_q *q; |
2225 | int i; | 2294 | int i; |
@@ -2227,7 +2296,7 @@ qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, | |||
2227 | char dbf_text[15]; | 2296 | char dbf_text[15]; |
2228 | 2297 | ||
2229 | /*check if QEBSM is disabled */ | 2298 | /*check if QEBSM is disabled */ |
2230 | if (!(irq_ptr->is_qebsm) || !(qdioac & 0x01)) { | 2299 | if (!(irq_ptr->is_qebsm) || !(irq_ptr->qdioac & 0x01)) { |
2231 | irq_ptr->is_qebsm = 0; | 2300 | irq_ptr->is_qebsm = 0; |
2232 | irq_ptr->sch_token = 0; | 2301 | irq_ptr->sch_token = 0; |
2233 | irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM; | 2302 | irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM; |
@@ -2256,102 +2325,27 @@ qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, | |||
2256 | } | 2325 | } |
2257 | 2326 | ||
2258 | static void | 2327 | static void |
2259 | qdio_get_ssqd_information(struct qdio_irq *irq_ptr) | 2328 | qdio_get_ssqd_siga(struct qdio_irq *irq_ptr) |
2260 | { | 2329 | { |
2261 | int result; | 2330 | int rc; |
2262 | unsigned char qdioac; | 2331 | struct qdio_chsc_ssqd *ssqd_area; |
2263 | struct { | ||
2264 | struct chsc_header request; | ||
2265 | u16 reserved1:10; | ||
2266 | u16 ssid:2; | ||
2267 | u16 fmt:4; | ||
2268 | u16 first_sch; | ||
2269 | u16 reserved2; | ||
2270 | u16 last_sch; | ||
2271 | u32 reserved3; | ||
2272 | struct chsc_header response; | ||
2273 | u32 reserved4; | ||
2274 | u8 flags; | ||
2275 | u8 reserved5; | ||
2276 | u16 sch; | ||
2277 | u8 qfmt; | ||
2278 | u8 parm; | ||
2279 | u8 qdioac1; | ||
2280 | u8 sch_class; | ||
2281 | u8 reserved7; | ||
2282 | u8 icnt; | ||
2283 | u8 reserved8; | ||
2284 | u8 ocnt; | ||
2285 | u8 reserved9; | ||
2286 | u8 mbccnt; | ||
2287 | u16 qdioac2; | ||
2288 | u64 sch_token; | ||
2289 | } *ssqd_area; | ||
2290 | 2332 | ||
2291 | QDIO_DBF_TEXT0(0,setup,"getssqd"); | 2333 | QDIO_DBF_TEXT0(0,setup,"getssqd"); |
2292 | qdioac = 0; | 2334 | irq_ptr->qdioac = 0; |
2293 | ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); | 2335 | rc = qdio_get_ssqd_information(&irq_ptr->schid, &ssqd_area); |
2294 | if (!ssqd_area) { | 2336 | if (rc) { |
2295 | QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \ | 2337 | QDIO_PRINT_WARN("using all SIGAs for sch x%x.n", |
2296 | "SIGAs for sch x%x.\n", irq_ptr->schid.sch_no); | 2338 | irq_ptr->schid.sch_no); |
2297 | irq_ptr->qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | | 2339 | irq_ptr->qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | |
2298 | CHSC_FLAG_SIGA_OUTPUT_NECESSARY | | 2340 | CHSC_FLAG_SIGA_OUTPUT_NECESSARY | |
2299 | CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */ | 2341 | CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */ |
2300 | irq_ptr->is_qebsm = 0; | 2342 | irq_ptr->is_qebsm = 0; |
2301 | irq_ptr->sch_token = 0; | 2343 | } else |
2302 | irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM; | 2344 | irq_ptr->qdioac = ssqd_area->qdioac1; |
2303 | return; | ||
2304 | } | ||
2305 | |||
2306 | ssqd_area->request = (struct chsc_header) { | ||
2307 | .length = 0x0010, | ||
2308 | .code = 0x0024, | ||
2309 | }; | ||
2310 | ssqd_area->first_sch = irq_ptr->schid.sch_no; | ||
2311 | ssqd_area->last_sch = irq_ptr->schid.sch_no; | ||
2312 | ssqd_area->ssid = irq_ptr->schid.ssid; | ||
2313 | result = chsc(ssqd_area); | ||
2314 | |||
2315 | if (result) { | ||
2316 | QDIO_PRINT_WARN("CHSC returned cc %i. Using all " \ | ||
2317 | "SIGAs for sch 0.%x.%x.\n", result, | ||
2318 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no); | ||
2319 | qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | | ||
2320 | CHSC_FLAG_SIGA_OUTPUT_NECESSARY | | ||
2321 | CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */ | ||
2322 | irq_ptr->is_qebsm = 0; | ||
2323 | goto out; | ||
2324 | } | ||
2325 | 2345 | ||
2326 | if (ssqd_area->response.code != QDIO_CHSC_RESPONSE_CODE_OK) { | 2346 | qdio_check_subchannel_qebsm(irq_ptr, ssqd_area->sch_token); |
2327 | QDIO_PRINT_WARN("response upon checking SIGA needs " \ | 2347 | if (rc != -ENOMEM) |
2328 | "is 0x%x. Using all SIGAs for sch 0.%x.%x.\n", | 2348 | mempool_free(ssqd_area, qdio_mempool_scssc); |
2329 | ssqd_area->response.code, | ||
2330 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no); | ||
2331 | qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | | ||
2332 | CHSC_FLAG_SIGA_OUTPUT_NECESSARY | | ||
2333 | CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */ | ||
2334 | irq_ptr->is_qebsm = 0; | ||
2335 | goto out; | ||
2336 | } | ||
2337 | if (!(ssqd_area->flags & CHSC_FLAG_QDIO_CAPABILITY) || | ||
2338 | !(ssqd_area->flags & CHSC_FLAG_VALIDITY) || | ||
2339 | (ssqd_area->sch != irq_ptr->schid.sch_no)) { | ||
2340 | QDIO_PRINT_WARN("huh? problems checking out sch 0.%x.%x... " \ | ||
2341 | "using all SIGAs.\n", | ||
2342 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no); | ||
2343 | qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | | ||
2344 | CHSC_FLAG_SIGA_OUTPUT_NECESSARY | | ||
2345 | CHSC_FLAG_SIGA_SYNC_NECESSARY; /* worst case */ | ||
2346 | irq_ptr->is_qebsm = 0; | ||
2347 | goto out; | ||
2348 | } | ||
2349 | qdioac = ssqd_area->qdioac1; | ||
2350 | out: | ||
2351 | qdio_check_subchannel_qebsm(irq_ptr, qdioac, | ||
2352 | ssqd_area->sch_token); | ||
2353 | mempool_free(ssqd_area, qdio_mempool_scssc); | ||
2354 | irq_ptr->qdioac = qdioac; | ||
2355 | } | 2349 | } |
2356 | 2350 | ||
2357 | static unsigned int | 2351 | static unsigned int |
@@ -3227,7 +3221,7 @@ qdio_establish(struct qdio_initialize *init_data) | |||
3227 | return -EIO; | 3221 | return -EIO; |
3228 | } | 3222 | } |
3229 | 3223 | ||
3230 | qdio_get_ssqd_information(irq_ptr); | 3224 | qdio_get_ssqd_siga(irq_ptr); |
3231 | /* if this gets set once, we're running under VM and can omit SVSes */ | 3225 | /* if this gets set once, we're running under VM and can omit SVSes */ |
3232 | if (irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_NECESSARY) | 3226 | if (irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_NECESSARY) |
3233 | omit_svs=1; | 3227 | omit_svs=1; |
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index da8a272fd75b..c3df6b2c38b7 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h | |||
@@ -406,6 +406,34 @@ do_clear_global_summary(void) | |||
406 | #define CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS 0x08 | 406 | #define CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS 0x08 |
407 | #define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04 | 407 | #define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04 |
408 | 408 | ||
409 | struct qdio_chsc_ssqd { | ||
410 | struct chsc_header request; | ||
411 | u16 reserved1:10; | ||
412 | u16 ssid:2; | ||
413 | u16 fmt:4; | ||
414 | u16 first_sch; | ||
415 | u16 reserved2; | ||
416 | u16 last_sch; | ||
417 | u32 reserved3; | ||
418 | struct chsc_header response; | ||
419 | u32 reserved4; | ||
420 | u8 flags; | ||
421 | u8 reserved5; | ||
422 | u16 sch; | ||
423 | u8 qfmt; | ||
424 | u8 parm; | ||
425 | u8 qdioac1; | ||
426 | u8 sch_class; | ||
427 | u8 pct; | ||
428 | u8 icnt; | ||
429 | u8 reserved7; | ||
430 | u8 ocnt; | ||
431 | u8 reserved8; | ||
432 | u8 mbccnt; | ||
433 | u16 qdioac2; | ||
434 | u64 sch_token; | ||
435 | }; | ||
436 | |||
409 | struct qdio_perf_stats { | 437 | struct qdio_perf_stats { |
410 | #ifdef CONFIG_64BIT | 438 | #ifdef CONFIG_64BIT |
411 | atomic64_t tl_runs; | 439 | atomic64_t tl_runs; |