@@ -82,6 +82,8 @@ struct pmcw {
uint32_t intparm;
#define PMCW_DNV 0x0001
#define PMCW_ENABLE 0x0080
+#define PMCW_MBUE 0x0010
+#define PMCW_DCTME 0x0008
#define PMCW_ISC_MASK 0x3800
#define PMCW_ISC_SHIFT 11
uint16_t flags;
@@ -94,6 +96,7 @@ struct pmcw {
uint8_t pom;
uint8_t pam;
uint8_t chpid[8];
+#define PMCW_MBF1 0x0004
uint32_t flags2;
};
#define PMCW_CHANNEL_TYPE(pmcw) (pmcw->flags2 >> 21)
@@ -101,7 +104,8 @@ struct pmcw {
struct schib {
struct pmcw pmcw;
struct scsw scsw;
- uint8_t md[12];
+ uint64_t mbo;
+ uint8_t md[4];
} __attribute__ ((aligned(4)));
struct irb {
@@ -355,4 +359,7 @@ bool chsc(void *p, uint16_t code, uint16_t len);
#define css_general_feature(bit) test_bit_inv(bit, chsc_scsc->general_char)
#define css_chsc_feature(bit) test_bit_inv(bit, chsc_scsc->chsc_char)
+bool css_enable_mb(int sid, uint64_t mb, uint16_t mbi, uint16_t flg, bool fmt1);
+bool css_disable_mb(int schid);
+
#endif
@@ -248,6 +248,106 @@ retry:
return -1;
}
+/*
+ * schib_update_mb: update the subchannel Measurement Block
+ * @schid: Subchannel Identifier
+ * @mb : 64bit address of the measurement block
+ * @mbi : the measurement block offset
+ * @flags : PMCW_MBUE to enable measurement block update
+ * PMCW_DCTME to enable device connect time
+ * 0 to disable measurement
+ * @format1: set if format 1 is to be used
+ */
+static bool schib_update_mb(int schid, uint64_t mb, uint16_t mbi,
+ uint16_t flags, bool format1)
+{
+ struct pmcw *pmcw = &schib.pmcw;
+ int cc;
+
+ /* Read the SCHIB for this subchannel */
+ cc = stsch(schid, &schib);
+ if (cc) {
+ report_info("stsch: sch %08x failed with cc=%d", schid, cc);
+ return false;
+ }
+
+ /* Update the SCHIB to enable the measurement block */
+ if (flags) {
+ pmcw->flags |= flags;
+
+ if (format1)
+ pmcw->flags2 |= PMCW_MBF1;
+ else
+ pmcw->flags2 &= ~PMCW_MBF1;
+
+ pmcw->mbi = mbi;
+ schib.mbo = mb & ~0x3f;
+ } else {
+ pmcw->flags &= ~(PMCW_MBUE | PMCW_DCTME);
+ }
+
+ /* Tell the CSS we want to modify the subchannel */
+ cc = msch(schid, &schib);
+ if (cc) {
+ /*
+ * If the subchannel is status pending or
+ * if a function is in progress,
+ * we consider both cases as errors.
+ */
+ report_info("msch: sch %08x failed with cc=%d", schid, cc);
+ return false;
+ }
+
+ /*
+ * Read the SCHIB again
+ */
+ cc = stsch(schid, &schib);
+ if (cc) {
+ report_info("stsch: updating sch %08x failed with cc=%d",
+ schid, cc);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * css_enable_mb: enable the subchannel Measurement Block
+ * @schid: Subchannel Identifier
+ * @mb : 64bit address of the measurement block
+ * @format1: set if format 1 is to be used
+ * @mbi : the measurement block offset
+ * @flags : PMCW_MBUE to enable measurement block update
+ * PMCW_DCTME to enable device connect time
+ */
+bool css_enable_mb(int schid, uint64_t mb, uint16_t mbi, uint16_t flags,
+ bool format1)
+{
+ int retry_count = MAX_ENABLE_RETRIES;
+ struct pmcw *pmcw = &schib.pmcw;
+
+ while (retry_count-- &&
+ !schib_update_mb(schid, mb, mbi, flags, format1))
+ mdelay(10); /* the hardware was not ready, give it some time */
+
+ return schib.mbo == mb && pmcw->mbi == mbi;
+}
+
+/*
+ * css_disable_mb: disable the subchannel Measurement Block
+ * @schid: Subchannel Identifier
+ */
+bool css_disable_mb(int schid)
+{
+ int retry_count = MAX_ENABLE_RETRIES;
+
+ while (retry_count-- &&
+ !schib_update_mb(schid, 0, 0, 0, 0))
+ mdelay(10); /* the hardware was not ready, give it some time */
+
+ return retry_count > 0;
+}
+
static struct irb irb;
void css_irq_io(void)