Message ID | 20230330114244.35559-5-frankja@linux.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | s390x: Add base AP support | expand |
On Thu, 30 Mar 2023 11:42:43 +0000 Janosch Frank <frankja@linux.ibm.com> wrote: > Let's check if we can enable/disable interrupts and if all errors are > reported if we specify bad addresses for the notification indication > byte. > > Signed-off-by: Janosch Frank <frankja@linux.ibm.com> > --- > lib/s390x/ap.c | 33 +++++++++++++++++++++++++++++ > lib/s390x/ap.h | 11 ++++++++++ > s390x/ap.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 100 insertions(+) > > diff --git a/lib/s390x/ap.c b/lib/s390x/ap.c > index 8d7f2992..aaf5b4b9 100644 > --- a/lib/s390x/ap.c > +++ b/lib/s390x/ap.c > @@ -51,6 +51,39 @@ int ap_pqap_tapq(uint8_t ap, uint8_t qn, struct ap_queue_status *apqsw, > return cc; > } > > +int ap_pqap_aqic(uint8_t ap, uint8_t qn, struct ap_queue_status *apqsw, > + struct ap_qirq_ctrl aqic, unsigned long addr) > +{ > + struct pqap_r0 r0 = {}; > + int cc; > + > + /* > + * AP-Queue Interruption Control > + * > + * Enables/disables interrupts for a APQN > + * > + * Inputs: 0,1,2 > + * Outputs: 1 (APQSW) > + * Synchronous > + */ > + r0.ap = ap; > + r0.qn = qn; > + r0.fc = PQAP_QUEUE_INT_CONTRL; > + asm volatile( > + " lgr 0,%[r0]\n" > + " lgr 1,%[aqic]\n" > + " lgr 2,%[addr]\n" > + " .insn rre,0xb2af0000,0,0\n" /* PQAP */ > + " stg 1, %[apqsw]\n" > + " ipm %[cc]\n" > + " srl %[cc],28\n" > + : [apqsw] "=T" (*apqsw), [cc] "=&d" (cc) > + : [r0] "d" (r0), [aqic] "d" (aqic), [addr] "d" (addr) > + : "cc", "memory", "0", "2"); > + > + return cc; > +} > + > int ap_pqap_qci(struct ap_config_info *info) > { > struct pqap_r0 r0 = { .fc = PQAP_QUERY_AP_CONF_INFO }; > diff --git a/lib/s390x/ap.h b/lib/s390x/ap.h > index 59595eba..3f9e2eb6 100644 > --- a/lib/s390x/ap.h > +++ b/lib/s390x/ap.h > @@ -79,6 +79,15 @@ struct pqap_r2 { > } __attribute__((packed)) __attribute__((aligned(8))); > _Static_assert(sizeof(struct pqap_r2) == sizeof(uint64_t), "pqap_r2 size"); > > +struct ap_qirq_ctrl { > + uint64_t res0 : 16; > + uint64_t ir : 1; /* ir flag: enable (1) or disable (0) irq */ > + uint64_t res1 : 44; > + uint64_t isc : 3; /* irq sub class */ > +} __attribute__((packed)) __attribute__((aligned(8))); > +_Static_assert(sizeof(struct ap_qirq_ctrl) == sizeof(uint64_t), > + "struct ap_qirq_ctrl size"); > + > #define AP_SETUP_NOINSTR -1 > #define AP_SETUP_NOAPQN 1 > > @@ -86,4 +95,6 @@ int ap_setup(uint8_t *ap, uint8_t *qn); > int ap_pqap_tapq(uint8_t ap, uint8_t qn, struct ap_queue_status *apqsw, > struct pqap_r2 *r2); > int ap_pqap_qci(struct ap_config_info *info); > +int ap_pqap_aqic(uint8_t ap, uint8_t qn, struct ap_queue_status *apqsw, > + struct ap_qirq_ctrl aqic, unsigned long addr); > #endif > diff --git a/s390x/ap.c b/s390x/ap.c > index 20b4e76e..31dcfe29 100644 > --- a/s390x/ap.c > +++ b/s390x/ap.c > @@ -292,6 +292,55 @@ static void test_priv(void) > report_prefix_pop(); > } > > +static void test_pqap_aqic(void) > +{ > + struct ap_queue_status apqsw = {}; > + static uint8_t not_ind_byte; > + struct ap_qirq_ctrl aqic = {}; > + struct pqap_r2 r2 = {}; > + > + int cc; > + > + report_prefix_push("pqap"); > + report_prefix_push("aqic"); > + > + ap_pqap_tapq(apn, qn, &apqsw, &r2); > + > + aqic.ir = 1; > + cc = ap_pqap_aqic(apn, qn, &apqsw, aqic, 0); > + report(cc == 3 && apqsw.rc == 6, "invalid addr 0"); > + > + aqic.ir = 1; > + cc = ap_pqap_aqic(apn, qn, &apqsw, aqic, -1); > + report(cc == 3 && apqsw.rc == 6, "invalid addr -1"); > + > + aqic.ir = 0; > + cc = ap_pqap_aqic(apn, qn, &apqsw, aqic, (uintptr_t)¬_ind_byte); > + report(cc == 3 && apqsw.rc == 7, "disable"); maybe call it "disable but never enabled" > + > + aqic.ir = 1; > + cc = ap_pqap_aqic(apn, qn, &apqsw, aqic, (uintptr_t)¬_ind_byte); > + report(cc == 0 && apqsw.rc == 0, "enable"); > + > + do { > + cc = ap_pqap_tapq(apn, qn, &apqsw, &r2); > + } while (cc == 0 && apqsw.irq_enabled == 0); you do this a lot, would it be worth it abstracting it? ap_pqap_wait_for_irq(..., false); (try to find a better name though) > + > + cc = ap_pqap_aqic(apn, qn, &apqsw, aqic, (uintptr_t)¬_ind_byte); > + report(cc == 3 && apqsw.rc == 7, "enable while enabled"); > + > + aqic.ir = 0; > + cc = ap_pqap_aqic(apn, qn, &apqsw, aqic, (uintptr_t)¬_ind_byte); > + assert(cc == 0 && apqsw.rc == 0); > + > + do { > + cc = ap_pqap_tapq(apn, qn, &apqsw, &r2); > + } while (cc == 0 && apqsw.irq_enabled == 1); ap_pqap_wait_for_irq(..., true); and here test disable again "disable after disable" > + > + report_prefix_pop(); > + report_prefix_pop(); > +} > + > int main(void) > { > int setup_rc = ap_setup(&apn, &qn); > @@ -307,6 +356,13 @@ int main(void) > test_pgms_nqap(); > test_pgms_dqap(); > > + /* The next tests need queues */ > + if (setup_rc == AP_SETUP_NOAPQN) { > + report_skip("No APQN available"); > + goto done; > + } > + test_pqap_aqic(); > + > done: > report_prefix_pop(); > return report_summary();
diff --git a/lib/s390x/ap.c b/lib/s390x/ap.c index 8d7f2992..aaf5b4b9 100644 --- a/lib/s390x/ap.c +++ b/lib/s390x/ap.c @@ -51,6 +51,39 @@ int ap_pqap_tapq(uint8_t ap, uint8_t qn, struct ap_queue_status *apqsw, return cc; } +int ap_pqap_aqic(uint8_t ap, uint8_t qn, struct ap_queue_status *apqsw, + struct ap_qirq_ctrl aqic, unsigned long addr) +{ + struct pqap_r0 r0 = {}; + int cc; + + /* + * AP-Queue Interruption Control + * + * Enables/disables interrupts for a APQN + * + * Inputs: 0,1,2 + * Outputs: 1 (APQSW) + * Synchronous + */ + r0.ap = ap; + r0.qn = qn; + r0.fc = PQAP_QUEUE_INT_CONTRL; + asm volatile( + " lgr 0,%[r0]\n" + " lgr 1,%[aqic]\n" + " lgr 2,%[addr]\n" + " .insn rre,0xb2af0000,0,0\n" /* PQAP */ + " stg 1, %[apqsw]\n" + " ipm %[cc]\n" + " srl %[cc],28\n" + : [apqsw] "=T" (*apqsw), [cc] "=&d" (cc) + : [r0] "d" (r0), [aqic] "d" (aqic), [addr] "d" (addr) + : "cc", "memory", "0", "2"); + + return cc; +} + int ap_pqap_qci(struct ap_config_info *info) { struct pqap_r0 r0 = { .fc = PQAP_QUERY_AP_CONF_INFO }; diff --git a/lib/s390x/ap.h b/lib/s390x/ap.h index 59595eba..3f9e2eb6 100644 --- a/lib/s390x/ap.h +++ b/lib/s390x/ap.h @@ -79,6 +79,15 @@ struct pqap_r2 { } __attribute__((packed)) __attribute__((aligned(8))); _Static_assert(sizeof(struct pqap_r2) == sizeof(uint64_t), "pqap_r2 size"); +struct ap_qirq_ctrl { + uint64_t res0 : 16; + uint64_t ir : 1; /* ir flag: enable (1) or disable (0) irq */ + uint64_t res1 : 44; + uint64_t isc : 3; /* irq sub class */ +} __attribute__((packed)) __attribute__((aligned(8))); +_Static_assert(sizeof(struct ap_qirq_ctrl) == sizeof(uint64_t), + "struct ap_qirq_ctrl size"); + #define AP_SETUP_NOINSTR -1 #define AP_SETUP_NOAPQN 1 @@ -86,4 +95,6 @@ int ap_setup(uint8_t *ap, uint8_t *qn); int ap_pqap_tapq(uint8_t ap, uint8_t qn, struct ap_queue_status *apqsw, struct pqap_r2 *r2); int ap_pqap_qci(struct ap_config_info *info); +int ap_pqap_aqic(uint8_t ap, uint8_t qn, struct ap_queue_status *apqsw, + struct ap_qirq_ctrl aqic, unsigned long addr); #endif diff --git a/s390x/ap.c b/s390x/ap.c index 20b4e76e..31dcfe29 100644 --- a/s390x/ap.c +++ b/s390x/ap.c @@ -292,6 +292,55 @@ static void test_priv(void) report_prefix_pop(); } +static void test_pqap_aqic(void) +{ + struct ap_queue_status apqsw = {}; + static uint8_t not_ind_byte; + struct ap_qirq_ctrl aqic = {}; + struct pqap_r2 r2 = {}; + + int cc; + + report_prefix_push("pqap"); + report_prefix_push("aqic"); + + ap_pqap_tapq(apn, qn, &apqsw, &r2); + + aqic.ir = 1; + cc = ap_pqap_aqic(apn, qn, &apqsw, aqic, 0); + report(cc == 3 && apqsw.rc == 6, "invalid addr 0"); + + aqic.ir = 1; + cc = ap_pqap_aqic(apn, qn, &apqsw, aqic, -1); + report(cc == 3 && apqsw.rc == 6, "invalid addr -1"); + + aqic.ir = 0; + cc = ap_pqap_aqic(apn, qn, &apqsw, aqic, (uintptr_t)¬_ind_byte); + report(cc == 3 && apqsw.rc == 7, "disable"); + + aqic.ir = 1; + cc = ap_pqap_aqic(apn, qn, &apqsw, aqic, (uintptr_t)¬_ind_byte); + report(cc == 0 && apqsw.rc == 0, "enable"); + + do { + cc = ap_pqap_tapq(apn, qn, &apqsw, &r2); + } while (cc == 0 && apqsw.irq_enabled == 0); + + cc = ap_pqap_aqic(apn, qn, &apqsw, aqic, (uintptr_t)¬_ind_byte); + report(cc == 3 && apqsw.rc == 7, "enable while enabled"); + + aqic.ir = 0; + cc = ap_pqap_aqic(apn, qn, &apqsw, aqic, (uintptr_t)¬_ind_byte); + assert(cc == 0 && apqsw.rc == 0); + + do { + cc = ap_pqap_tapq(apn, qn, &apqsw, &r2); + } while (cc == 0 && apqsw.irq_enabled == 1); + + report_prefix_pop(); + report_prefix_pop(); +} + int main(void) { int setup_rc = ap_setup(&apn, &qn); @@ -307,6 +356,13 @@ int main(void) test_pgms_nqap(); test_pgms_dqap(); + /* The next tests need queues */ + if (setup_rc == AP_SETUP_NOAPQN) { + report_skip("No APQN available"); + goto done; + } + test_pqap_aqic(); + done: report_prefix_pop(); return report_summary();
Let's check if we can enable/disable interrupts and if all errors are reported if we specify bad addresses for the notification indication byte. Signed-off-by: Janosch Frank <frankja@linux.ibm.com> --- lib/s390x/ap.c | 33 +++++++++++++++++++++++++++++ lib/s390x/ap.h | 11 ++++++++++ s390x/ap.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+)