aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Glauber <jang@linux.vnet.ibm.com>2012-11-29 08:34:48 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-11-30 11:47:24 -0500
commitcbc0dd1f856b52b59c2c73a477b6cb210c8c66ad (patch)
tree064ceb4d1b2acb8716867b2a3fb65ae05bef1a31
parent828b35f60eb0148f994bb13e328df94578b07142 (diff)
s390/pci: CHSC PCI support for error and availability events
Add CHSC store-event-information support for PCI (notfication type 2) and report error and availability events to the PCI architecture layer. Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/pci.h4
-rw-r--r--arch/s390/pci/Makefile3
-rw-r--r--arch/s390/pci/pci_event.c93
-rw-r--r--drivers/s390/cio/chsc.c156
4 files changed, 211 insertions, 45 deletions
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index e9dc0090ac43..d3597dcfec33 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -127,6 +127,10 @@ void zpci_teardown_msi_irq(struct zpci_dev *, struct msi_desc *);
127int zpci_msihash_init(void); 127int zpci_msihash_init(void);
128void zpci_msihash_exit(void); 128void zpci_msihash_exit(void);
129 129
130/* Error handling and recovery */
131void zpci_event_error(void *);
132void zpci_event_availability(void *);
133
130/* Helpers */ 134/* Helpers */
131struct zpci_dev *get_zdev(struct pci_dev *); 135struct zpci_dev *get_zdev(struct pci_dev *);
132struct zpci_dev *get_zdev_by_fid(u32); 136struct zpci_dev *get_zdev_by_fid(u32);
diff --git a/arch/s390/pci/Makefile b/arch/s390/pci/Makefile
index 4590596d8b25..7e36f42ba086 100644
--- a/arch/s390/pci/Makefile
+++ b/arch/s390/pci/Makefile
@@ -2,4 +2,5 @@
2# Makefile for the s390 PCI subsystem. 2# Makefile for the s390 PCI subsystem.
3# 3#
4 4
5obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_msi.o 5obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_msi.o \
6 pci_event.o
diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c
new file mode 100644
index 000000000000..dbed8cd3370c
--- /dev/null
+++ b/arch/s390/pci/pci_event.c
@@ -0,0 +1,93 @@
1/*
2 * Copyright IBM Corp. 2012
3 *
4 * Author(s):
5 * Jan Glauber <jang@linux.vnet.ibm.com>
6 */
7
8#define COMPONENT "zPCI"
9#define pr_fmt(fmt) COMPONENT ": " fmt
10
11#include <linux/kernel.h>
12#include <linux/pci.h>
13
14/* Content Code Description for PCI Function Error */
15struct zpci_ccdf_err {
16 u32 reserved1;
17 u32 fh; /* function handle */
18 u32 fid; /* function id */
19 u32 ett : 4; /* expected table type */
20 u32 mvn : 12; /* MSI vector number */
21 u32 dmaas : 8; /* DMA address space */
22 u32 : 6;
23 u32 q : 1; /* event qualifier */
24 u32 rw : 1; /* read/write */
25 u64 faddr; /* failing address */
26 u32 reserved3;
27 u16 reserved4;
28 u16 pec; /* PCI event code */
29} __packed;
30
31/* Content Code Description for PCI Function Availability */
32struct zpci_ccdf_avail {
33 u32 reserved1;
34 u32 fh; /* function handle */
35 u32 fid; /* function id */
36 u32 reserved2;
37 u32 reserved3;
38 u32 reserved4;
39 u32 reserved5;
40 u16 reserved6;
41 u16 pec; /* PCI event code */
42} __packed;
43
44static void zpci_event_log_err(struct zpci_ccdf_err *ccdf)
45{
46 struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
47
48 dev_err(&zdev->pdev->dev, "event code: 0x%x\n", ccdf->pec);
49}
50
51static void zpci_event_log_avail(struct zpci_ccdf_avail *ccdf)
52{
53 struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
54
55 pr_err("%s%s: availability event: fh: 0x%x fid: 0x%x event code: 0x%x reason:",
56 (zdev) ? dev_driver_string(&zdev->pdev->dev) : "?",
57 (zdev) ? dev_name(&zdev->pdev->dev) : "?",
58 ccdf->fh, ccdf->fid, ccdf->pec);
59 print_hex_dump(KERN_CONT, "ccdf", DUMP_PREFIX_OFFSET,
60 16, 1, ccdf, sizeof(*ccdf), false);
61
62 switch (ccdf->pec) {
63 case 0x0301:
64 zpci_enable_device(zdev);
65 break;
66 case 0x0302:
67 clp_add_pci_device(ccdf->fid, ccdf->fh, 0);
68 break;
69 case 0x0306:
70 clp_find_pci_devices();
71 break;
72 default:
73 break;
74 }
75}
76
77void zpci_event_error(void *data)
78{
79 struct zpci_ccdf_err *ccdf = data;
80 struct zpci_dev *zdev;
81
82 zpci_event_log_err(ccdf);
83 zdev = get_zdev_by_fid(ccdf->fid);
84 if (!zdev) {
85 pr_err("Error event for unknown fid: %x", ccdf->fid);
86 return;
87 }
88}
89
90void zpci_event_availability(void *data)
91{
92 zpci_event_log_avail(data);
93}
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 4d51a7c4eb8b..68e80e2734a4 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * S/390 common I/O routines -- channel subsystem call 2 * S/390 common I/O routines -- channel subsystem call
3 * 3 *
4 * Copyright IBM Corp. 1999, 2010 4 * Copyright IBM Corp. 1999,2012
5 * Author(s): Ingo Adlung (adlung@de.ibm.com) 5 * Author(s): Ingo Adlung (adlung@de.ibm.com)
6 * Cornelia Huck (cornelia.huck@de.ibm.com) 6 * Cornelia Huck (cornelia.huck@de.ibm.com)
7 * Arnd Bergmann (arndb@de.ibm.com) 7 * Arnd Bergmann (arndb@de.ibm.com)
@@ -14,6 +14,7 @@
14#include <linux/slab.h> 14#include <linux/slab.h>
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/device.h> 16#include <linux/device.h>
17#include <linux/pci.h>
17 18
18#include <asm/cio.h> 19#include <asm/cio.h>
19#include <asm/chpid.h> 20#include <asm/chpid.h>
@@ -260,26 +261,45 @@ __get_chpid_from_lir(void *data)
260 return (u16) (lir->indesc[0]&0x000000ff); 261 return (u16) (lir->indesc[0]&0x000000ff);
261} 262}
262 263
263struct chsc_sei_area { 264struct chsc_sei_nt0_area {
264 struct chsc_header request; 265 u8 flags;
266 u8 vf; /* validity flags */
267 u8 rs; /* reporting source */
268 u8 cc; /* content code */
269 u16 fla; /* full link address */
270 u16 rsid; /* reporting source id */
265 u32 reserved1; 271 u32 reserved1;
266 u32 reserved2; 272 u32 reserved2;
267 u32 reserved3;
268 struct chsc_header response;
269 u32 reserved4;
270 u8 flags;
271 u8 vf; /* validity flags */
272 u8 rs; /* reporting source */
273 u8 cc; /* content code */
274 u16 fla; /* full link address */
275 u16 rsid; /* reporting source id */
276 u32 reserved5;
277 u32 reserved6;
278 u8 ccdf[4096 - 16 - 24]; /* content-code dependent field */
279 /* ccdf has to be big enough for a link-incident record */ 273 /* ccdf has to be big enough for a link-incident record */
280} __attribute__ ((packed)); 274 u8 ccdf[PAGE_SIZE - 24 - 16]; /* content-code dependent field */
281 275} __packed;
282static void chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) 276
277struct chsc_sei_nt2_area {
278 u8 flags; /* p and v bit */
279 u8 reserved1;
280 u8 reserved2;
281 u8 cc; /* content code */
282 u32 reserved3[13];
283 u8 ccdf[PAGE_SIZE - 24 - 56]; /* content-code dependent field */
284} __packed;
285
286#define CHSC_SEI_NT0 0ULL
287#define CHSC_SEI_NT2 (1ULL << 61)
288
289struct chsc_sei {
290 struct chsc_header request;
291 u32 reserved1;
292 u64 ntsm; /* notification type mask */
293 struct chsc_header response;
294 u32 reserved2;
295 union {
296 struct chsc_sei_nt0_area nt0_area;
297 struct chsc_sei_nt2_area nt2_area;
298 u8 nt_area[PAGE_SIZE - 24];
299 } u;
300} __packed;
301
302static void chsc_process_sei_link_incident(struct chsc_sei_nt0_area *sei_area)
283{ 303{
284 struct chp_id chpid; 304 struct chp_id chpid;
285 int id; 305 int id;
@@ -298,7 +318,7 @@ static void chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
298 } 318 }
299} 319}
300 320
301static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) 321static void chsc_process_sei_res_acc(struct chsc_sei_nt0_area *sei_area)
302{ 322{
303 struct chp_link link; 323 struct chp_link link;
304 struct chp_id chpid; 324 struct chp_id chpid;
@@ -330,7 +350,7 @@ static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
330 s390_process_res_acc(&link); 350 s390_process_res_acc(&link);
331} 351}
332 352
333static void chsc_process_sei_chp_avail(struct chsc_sei_area *sei_area) 353static void chsc_process_sei_chp_avail(struct chsc_sei_nt0_area *sei_area)
334{ 354{
335 struct channel_path *chp; 355 struct channel_path *chp;
336 struct chp_id chpid; 356 struct chp_id chpid;
@@ -366,7 +386,7 @@ struct chp_config_data {
366 u8 pc; 386 u8 pc;
367}; 387};
368 388
369static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) 389static void chsc_process_sei_chp_config(struct chsc_sei_nt0_area *sei_area)
370{ 390{
371 struct chp_config_data *data; 391 struct chp_config_data *data;
372 struct chp_id chpid; 392 struct chp_id chpid;
@@ -398,7 +418,7 @@ static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area)
398 } 418 }
399} 419}
400 420
401static void chsc_process_sei_scm_change(struct chsc_sei_area *sei_area) 421static void chsc_process_sei_scm_change(struct chsc_sei_nt0_area *sei_area)
402{ 422{
403 int ret; 423 int ret;
404 424
@@ -412,13 +432,26 @@ static void chsc_process_sei_scm_change(struct chsc_sei_area *sei_area)
412 " failed (rc=%d).\n", ret); 432 " failed (rc=%d).\n", ret);
413} 433}
414 434
415static void chsc_process_sei(struct chsc_sei_area *sei_area) 435static void chsc_process_sei_nt2(struct chsc_sei_nt2_area *sei_area)
416{ 436{
417 /* Check if we might have lost some information. */ 437#ifdef CONFIG_PCI
418 if (sei_area->flags & 0x40) { 438 switch (sei_area->cc) {
419 CIO_CRW_EVENT(2, "chsc: event overflow\n"); 439 case 1:
420 css_schedule_eval_all(); 440 zpci_event_error(sei_area->ccdf);
441 break;
442 case 2:
443 zpci_event_availability(sei_area->ccdf);
444 break;
445 default:
446 CIO_CRW_EVENT(2, "chsc: unhandled sei content code %d\n",
447 sei_area->cc);
448 break;
421 } 449 }
450#endif
451}
452
453static void chsc_process_sei_nt0(struct chsc_sei_nt0_area *sei_area)
454{
422 /* which kind of information was stored? */ 455 /* which kind of information was stored? */
423 switch (sei_area->cc) { 456 switch (sei_area->cc) {
424 case 1: /* link incident*/ 457 case 1: /* link incident*/
@@ -443,9 +476,51 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area)
443 } 476 }
444} 477}
445 478
479static int __chsc_process_crw(struct chsc_sei *sei, u64 ntsm)
480{
481 do {
482 memset(sei, 0, sizeof(*sei));
483 sei->request.length = 0x0010;
484 sei->request.code = 0x000e;
485 sei->ntsm = ntsm;
486
487 if (chsc(sei))
488 break;
489
490 if (sei->response.code == 0x0001) {
491 CIO_CRW_EVENT(2, "chsc: sei successful\n");
492
493 /* Check if we might have lost some information. */
494 if (sei->u.nt0_area.flags & 0x40) {
495 CIO_CRW_EVENT(2, "chsc: event overflow\n");
496 css_schedule_eval_all();
497 }
498
499 switch (sei->ntsm) {
500 case CHSC_SEI_NT0:
501 chsc_process_sei_nt0(&sei->u.nt0_area);
502 return 1;
503 case CHSC_SEI_NT2:
504 chsc_process_sei_nt2(&sei->u.nt2_area);
505 return 1;
506 default:
507 CIO_CRW_EVENT(2, "chsc: unhandled nt (nt=%08Lx)\n",
508 sei->ntsm);
509 return 0;
510 }
511 } else {
512 CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n",
513 sei->response.code);
514 break;
515 }
516 } while (sei->u.nt0_area.flags & 0x80);
517
518 return 0;
519}
520
446static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow) 521static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
447{ 522{
448 struct chsc_sei_area *sei_area; 523 struct chsc_sei *sei;
449 524
450 if (overflow) { 525 if (overflow) {
451 css_schedule_eval_all(); 526 css_schedule_eval_all();
@@ -459,25 +534,18 @@ static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
459 return; 534 return;
460 /* Access to sei_page is serialized through machine check handler 535 /* Access to sei_page is serialized through machine check handler
461 * thread, so no need for locking. */ 536 * thread, so no need for locking. */
462 sei_area = sei_page; 537 sei = sei_page;
463 538
464 CIO_TRACE_EVENT(2, "prcss"); 539 CIO_TRACE_EVENT(2, "prcss");
465 do {
466 memset(sei_area, 0, sizeof(*sei_area));
467 sei_area->request.length = 0x0010;
468 sei_area->request.code = 0x000e;
469 if (chsc(sei_area))
470 break;
471 540
472 if (sei_area->response.code == 0x0001) { 541 /*
473 CIO_CRW_EVENT(4, "chsc: sei successful\n"); 542 * The ntsm does not allow to select NT0 and NT2 together. We need to
474 chsc_process_sei(sei_area); 543 * first check for NT2, than additionally for NT0...
475 } else { 544 */
476 CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n", 545#ifdef CONFIG_PCI
477 sei_area->response.code); 546 if (!__chsc_process_crw(sei, CHSC_SEI_NT2))
478 break; 547#endif
479 } 548 __chsc_process_crw(sei, CHSC_SEI_NT0);
480 } while (sei_area->flags & 0x80);
481} 549}
482 550
483void chsc_chp_online(struct chp_id chpid) 551void chsc_chp_online(struct chp_id chpid)