From cbc0dd1f856b52b59c2c73a477b6cb210c8c66ad Mon Sep 17 00:00:00 2001
From: Jan Glauber <jang@linux.vnet.ibm.com>
Date: Thu, 29 Nov 2012 14:34:48 +0100
Subject: 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>
---
 arch/s390/include/asm/pci.h |  4 ++
 arch/s390/pci/Makefile      |  3 +-
 arch/s390/pci/pci_event.c   | 93 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 99 insertions(+), 1 deletion(-)
 create mode 100644 arch/s390/pci/pci_event.c

(limited to 'arch/s390')

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 *);
 int zpci_msihash_init(void);
 void zpci_msihash_exit(void);
 
+/* Error handling and recovery */
+void zpci_event_error(void *);
+void zpci_event_availability(void *);
+
 /* Helpers */
 struct zpci_dev *get_zdev(struct pci_dev *);
 struct 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 @@
 # Makefile for the s390 PCI subsystem.
 #
 
-obj-$(CONFIG_PCI)	+= pci.o pci_dma.o pci_clp.o pci_msi.o
+obj-$(CONFIG_PCI)	+= pci.o pci_dma.o pci_clp.o pci_msi.o \
+			   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 @@
+/*
+ *  Copyright IBM Corp. 2012
+ *
+ *  Author(s):
+ *    Jan Glauber <jang@linux.vnet.ibm.com>
+ */
+
+#define COMPONENT "zPCI"
+#define pr_fmt(fmt) COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+/* Content Code Description for PCI Function Error */
+struct zpci_ccdf_err {
+	u32 reserved1;
+	u32 fh;				/* function handle */
+	u32 fid;			/* function id */
+	u32 ett		:  4;		/* expected table type */
+	u32 mvn		: 12;		/* MSI vector number */
+	u32 dmaas	:  8;		/* DMA address space */
+	u32		:  6;
+	u32 q		:  1;		/* event qualifier */
+	u32 rw		:  1;		/* read/write */
+	u64 faddr;			/* failing address */
+	u32 reserved3;
+	u16 reserved4;
+	u16 pec;			/* PCI event code */
+} __packed;
+
+/* Content Code Description for PCI Function Availability */
+struct zpci_ccdf_avail {
+	u32 reserved1;
+	u32 fh;				/* function handle */
+	u32 fid;			/* function id */
+	u32 reserved2;
+	u32 reserved3;
+	u32 reserved4;
+	u32 reserved5;
+	u16 reserved6;
+	u16 pec;			/* PCI event code */
+} __packed;
+
+static void zpci_event_log_err(struct zpci_ccdf_err *ccdf)
+{
+	struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
+
+	dev_err(&zdev->pdev->dev, "event code: 0x%x\n", ccdf->pec);
+}
+
+static void zpci_event_log_avail(struct zpci_ccdf_avail *ccdf)
+{
+	struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
+
+	pr_err("%s%s: availability event: fh: 0x%x  fid: 0x%x  event code: 0x%x  reason:",
+		(zdev) ? dev_driver_string(&zdev->pdev->dev) : "?",
+		(zdev) ? dev_name(&zdev->pdev->dev) : "?",
+		ccdf->fh, ccdf->fid, ccdf->pec);
+	print_hex_dump(KERN_CONT, "ccdf", DUMP_PREFIX_OFFSET,
+		       16, 1, ccdf, sizeof(*ccdf), false);
+
+	switch (ccdf->pec) {
+	case 0x0301:
+		zpci_enable_device(zdev);
+		break;
+	case 0x0302:
+		clp_add_pci_device(ccdf->fid, ccdf->fh, 0);
+		break;
+	case 0x0306:
+		clp_find_pci_devices();
+		break;
+	default:
+		break;
+	}
+}
+
+void zpci_event_error(void *data)
+{
+	struct zpci_ccdf_err *ccdf = data;
+	struct zpci_dev *zdev;
+
+	zpci_event_log_err(ccdf);
+	zdev = get_zdev_by_fid(ccdf->fid);
+	if (!zdev) {
+		pr_err("Error event for unknown fid: %x", ccdf->fid);
+		return;
+	}
+}
+
+void zpci_event_availability(void *data)
+{
+	zpci_event_log_avail(data);
+}
-- 
cgit v1.2.3