aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/s390/cio/qdio.c178
-rw-r--r--drivers/s390/cio/qdio.h28
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
2220static int
2221qdio_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;
2264out:
2265 return -EINVAL;
2266}
2267
2268int
2269qdio_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}
2288EXPORT_SYMBOL(qdio_get_ssqd_pct);
2289
2220static void 2290static void
2221qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, 2291qdio_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
2258static void 2327static void
2259qdio_get_ssqd_information(struct qdio_irq *irq_ptr) 2328qdio_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;
2350out:
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
2357static unsigned int 2351static 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
409struct 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
409struct qdio_perf_stats { 437struct qdio_perf_stats {
410#ifdef CONFIG_64BIT 438#ifdef CONFIG_64BIT
411 atomic64_t tl_runs; 439 atomic64_t tl_runs;