diff options
Diffstat (limited to 'arch/s390/include/asm/ap.h')
-rw-r--r-- | arch/s390/include/asm/ap.h | 261 |
1 files changed, 189 insertions, 72 deletions
diff --git a/arch/s390/include/asm/ap.h b/arch/s390/include/asm/ap.h index b515cfa62bd9..43ac4a64f49b 100644 --- a/arch/s390/include/asm/ap.h +++ b/arch/s390/include/asm/ap.h @@ -43,10 +43,24 @@ struct ap_queue_status { unsigned int queue_empty : 1; unsigned int replies_waiting : 1; unsigned int queue_full : 1; - unsigned int _pad1 : 4; + unsigned int : 3; + unsigned int async : 1; unsigned int irq_enabled : 1; unsigned int response_code : 8; - unsigned int _pad2 : 16; + unsigned int : 16; +}; + +/* + * AP queue status reg union to access the reg1 + * register with the lower 32 bits comprising the + * ap queue status. + */ +union ap_queue_status_reg { + unsigned long value; + struct { + u32 _pad; + struct ap_queue_status status; + }; }; /** @@ -73,16 +87,55 @@ static inline bool ap_instructions_available(void) return reg1 != 0; } +/* TAPQ register GR2 response struct */ +struct ap_tapq_hwinfo { + union { + unsigned long value; + struct { + unsigned int fac : 32; /* facility bits */ + unsigned int apinfo : 32; /* ap type, ... */ + }; + struct { + unsigned int apsc : 1; /* APSC */ + unsigned int mex4k : 1; /* AP4KM */ + unsigned int crt4k : 1; /* AP4KC */ + unsigned int cca : 1; /* D */ + unsigned int accel : 1; /* A */ + unsigned int ep11 : 1; /* X */ + unsigned int apxa : 1; /* APXA */ + unsigned int : 1; + unsigned int class : 8; + unsigned int bs : 2; /* SE bind/assoc */ + unsigned int : 14; + unsigned int at : 8; /* ap type */ + unsigned int nd : 8; /* nr of domains */ + unsigned int : 4; + unsigned int ml : 4; /* apxl ml */ + unsigned int : 4; + unsigned int qd : 4; /* queue depth */ + }; + }; +}; + +/* + * Convenience defines to be used with the bs field from struct ap_tapq_gr2 + */ +#define AP_BS_Q_USABLE 0 +#define AP_BS_Q_USABLE_NO_SECURE_KEY 1 +#define AP_BS_Q_AVAIL_FOR_BINDING 2 +#define AP_BS_Q_UNUSABLE 3 + /** * ap_tapq(): Test adjunct processor queue. * @qid: The AP queue number - * @info: Pointer to queue descriptor + * @info: Pointer to tapq hwinfo struct * * Returns AP queue status structure. */ -static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) +static inline struct ap_queue_status ap_tapq(ap_qid_t qid, + struct ap_tapq_hwinfo *info) { - struct ap_queue_status reg1; + union ap_queue_status_reg reg1; unsigned long reg2; asm volatile( @@ -91,25 +144,24 @@ static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) " .insn rre,0xb2af0000,0,0\n" /* PQAP(TAPQ) */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ " lgr %[reg2],2\n" /* gr2 into reg2 */ - : [reg1] "=&d" (reg1), [reg2] "=&d" (reg2) + : [reg1] "=&d" (reg1.value), [reg2] "=&d" (reg2) : [qid] "d" (qid) : "cc", "0", "1", "2"); if (info) - *info = reg2; - return reg1; + info->value = reg2; + return reg1.status; } /** * ap_test_queue(): Test adjunct processor queue. * @qid: The AP queue number * @tbit: Test facilities bit - * @info: Pointer to queue descriptor + * @info: Ptr to tapq gr2 struct * * Returns AP queue status structure. */ -static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, - int tbit, - unsigned long *info) +static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, int tbit, + struct ap_tapq_hwinfo *info) { if (tbit) qid |= 1UL << 23; /* set T bit*/ @@ -119,43 +171,51 @@ static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, /** * ap_pqap_rapq(): Reset adjunct processor queue. * @qid: The AP queue number + * @fbit: if != 0 set F bit * * Returns AP queue status structure. */ -static inline struct ap_queue_status ap_rapq(ap_qid_t qid) +static inline struct ap_queue_status ap_rapq(ap_qid_t qid, int fbit) { unsigned long reg0 = qid | (1UL << 24); /* fc 1UL is RAPQ */ - struct ap_queue_status reg1; + union ap_queue_status_reg reg1; + + if (fbit) + reg0 |= 1UL << 22; asm volatile( " lgr 0,%[reg0]\n" /* qid arg into gr0 */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(RAPQ) */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ - : [reg1] "=&d" (reg1) + : [reg1] "=&d" (reg1.value) : [reg0] "d" (reg0) : "cc", "0", "1"); - return reg1; + return reg1.status; } /** * ap_pqap_zapq(): Reset and zeroize adjunct processor queue. * @qid: The AP queue number + * @fbit: if != 0 set F bit * * Returns AP queue status structure. */ -static inline struct ap_queue_status ap_zapq(ap_qid_t qid) +static inline struct ap_queue_status ap_zapq(ap_qid_t qid, int fbit) { unsigned long reg0 = qid | (2UL << 24); /* fc 2UL is ZAPQ */ - struct ap_queue_status reg1; + union ap_queue_status_reg reg1; + + if (fbit) + reg0 |= 1UL << 22; asm volatile( " lgr 0,%[reg0]\n" /* qid arg into gr0 */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(ZAPQ) */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ - : [reg1] "=&d" (reg1) + : [reg1] "=&d" (reg1.value) : [reg0] "d" (reg0) : "cc", "0", "1"); - return reg1; + return reg1.status; } /** @@ -167,15 +227,16 @@ struct ap_config_info { unsigned int apxa : 1; /* N bit */ unsigned int qact : 1; /* C bit */ unsigned int rc8a : 1; /* R bit */ - unsigned char _reserved1 : 4; - unsigned char _reserved2[3]; - unsigned char Na; /* max # of APs - 1 */ - unsigned char Nd; /* max # of Domains - 1 */ - unsigned char _reserved3[10]; + unsigned int : 4; + unsigned int apsb : 1; /* B bit */ + unsigned int : 23; + unsigned char na; /* max # of APs - 1 */ + unsigned char nd; /* max # of Domains - 1 */ + unsigned char _reserved0[10]; unsigned int apm[8]; /* AP ID mask */ unsigned int aqm[8]; /* AP (usage) queue mask */ unsigned int adm[8]; /* AP (control) domain mask */ - unsigned char _reserved4[16]; + unsigned char _reserved1[16]; } __aligned(8); /** @@ -209,41 +270,40 @@ static inline int ap_qci(struct ap_config_info *config) * parameter to the PQAP(AQIC) instruction. For details please * see the AR documentation. */ -struct ap_qirq_ctrl { - unsigned int _res1 : 8; - unsigned int zone : 8; /* zone info */ - unsigned int ir : 1; /* ir flag: enable (1) or disable (0) irq */ - unsigned int _res2 : 4; - unsigned int gisc : 3; /* guest isc field */ - unsigned int _res3 : 6; - unsigned int gf : 2; /* gisa format */ - unsigned int _res4 : 1; - unsigned int gisa : 27; /* gisa origin */ - unsigned int _res5 : 1; - unsigned int isc : 3; /* irq sub class */ +union ap_qirq_ctrl { + unsigned long value; + struct { + unsigned int : 8; + unsigned int zone : 8; /* zone info */ + unsigned int ir : 1; /* ir flag: enable (1) or disable (0) irq */ + unsigned int : 4; + unsigned int gisc : 3; /* guest isc field */ + unsigned int : 6; + unsigned int gf : 2; /* gisa format */ + unsigned int : 1; + unsigned int gisa : 27; /* gisa origin */ + unsigned int : 1; + unsigned int isc : 3; /* irq sub class */ + }; }; /** * ap_aqic(): Control interruption for a specific AP. * @qid: The AP queue number * @qirqctrl: struct ap_qirq_ctrl (64 bit value) - * @ind: The notification indicator byte + * @pa_ind: Physical address of the notification indicator byte * * Returns AP queue status. */ static inline struct ap_queue_status ap_aqic(ap_qid_t qid, - struct ap_qirq_ctrl qirqctrl, - void *ind) + union ap_qirq_ctrl qirqctrl, + phys_addr_t pa_ind) { unsigned long reg0 = qid | (3UL << 24); /* fc 3UL is AQIC */ - union { - unsigned long value; - struct ap_qirq_ctrl qirqctrl; - struct ap_queue_status status; - } reg1; - unsigned long reg2 = virt_to_phys(ind); + union ap_queue_status_reg reg1; + unsigned long reg2 = pa_ind; - reg1.qirqctrl = qirqctrl; + reg1.value = qirqctrl.value; asm volatile( " lgr 0,%[reg0]\n" /* qid param into gr0 */ @@ -251,9 +311,9 @@ static inline struct ap_queue_status ap_aqic(ap_qid_t qid, " lgr 2,%[reg2]\n" /* ni addr into gr2 */ " .insn rre,0xb2af0000,0,0\n" /* PQAP(AQIC) */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ - : [reg1] "+&d" (reg1) + : [reg1] "+&d" (reg1.value) : [reg0] "d" (reg0), [reg2] "d" (reg2) - : "cc", "0", "1", "2"); + : "cc", "memory", "0", "1", "2"); return reg1.status; } @@ -276,7 +336,7 @@ union ap_qact_ap_info { }; /** - * ap_qact(): Query AP combatibility type. + * ap_qact(): Query AP compatibility type. * @qid: The AP queue number * @apinfo: On input the info about the AP queue. On output the * alternate AP queue info provided by the qact function @@ -288,10 +348,7 @@ static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit, union ap_qact_ap_info *apinfo) { unsigned long reg0 = qid | (5UL << 24) | ((ifbit & 0x01) << 22); - union { - unsigned long value; - struct ap_queue_status status; - } reg1; + union ap_queue_status_reg reg1; unsigned long reg2; reg1.value = apinfo->val; @@ -302,13 +359,66 @@ static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit, " .insn rre,0xb2af0000,0,0\n" /* PQAP(QACT) */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ " lgr %[reg2],2\n" /* qact out info into reg2 */ - : [reg1] "+&d" (reg1), [reg2] "=&d" (reg2) + : [reg1] "+&d" (reg1.value), [reg2] "=&d" (reg2) : [reg0] "d" (reg0) : "cc", "0", "1", "2"); apinfo->val = reg2; return reg1.status; } +/* + * ap_bapq(): SE bind AP queue. + * @qid: The AP queue number + * + * Returns AP queue status structure. + * + * Invoking this function in a non-SE environment + * may case a specification exception. + */ +static inline struct ap_queue_status ap_bapq(ap_qid_t qid) +{ + unsigned long reg0 = qid | (7UL << 24); /* fc 7 is BAPQ */ + union ap_queue_status_reg reg1; + + asm volatile( + " lgr 0,%[reg0]\n" /* qid arg into gr0 */ + " .insn rre,0xb2af0000,0,0\n" /* PQAP(BAPQ) */ + " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + : [reg1] "=&d" (reg1.value) + : [reg0] "d" (reg0) + : "cc", "0", "1"); + + return reg1.status; +} + +/* + * ap_aapq(): SE associate AP queue. + * @qid: The AP queue number + * @sec_idx: The secret index + * + * Returns AP queue status structure. + * + * Invoking this function in a non-SE environment + * may case a specification exception. + */ +static inline struct ap_queue_status ap_aapq(ap_qid_t qid, unsigned int sec_idx) +{ + unsigned long reg0 = qid | (8UL << 24); /* fc 8 is AAPQ */ + unsigned long reg2 = sec_idx; + union ap_queue_status_reg reg1; + + asm volatile( + " lgr 0,%[reg0]\n" /* qid arg into gr0 */ + " lgr 2,%[reg2]\n" /* secret index into gr2 */ + " .insn rre,0xb2af0000,0,0\n" /* PQAP(AAPQ) */ + " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ + : [reg1] "=&d" (reg1.value) + : [reg0] "d" (reg0), [reg2] "d" (reg2) + : "cc", "0", "1", "2"); + + return reg1.status; +} + /** * ap_nqap(): Send message to adjunct processor queue. * @qid: The AP queue number @@ -327,7 +437,7 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, { unsigned long reg0 = qid | 0x40000000UL; /* 0x4... is last msg part */ union register_pair nqap_r1, nqap_r2; - struct ap_queue_status reg1; + union ap_queue_status_reg reg1; nqap_r1.even = (unsigned int)(psmid >> 32); nqap_r1.odd = psmid & 0xffffffff; @@ -339,21 +449,22 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, "0: .insn rre,0xb2ad0000,%[nqap_r1],%[nqap_r2]\n" " brc 2,0b\n" /* handle partial completion */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ - : [reg0] "+&d" (reg0), [reg1] "=&d" (reg1), + : [reg0] "+&d" (reg0), [reg1] "=&d" (reg1.value), [nqap_r2] "+&d" (nqap_r2.pair) : [nqap_r1] "d" (nqap_r1.pair) : "cc", "memory", "0", "1"); - return reg1; + return reg1.status; } /** * ap_dqap(): Receive message from adjunct processor queue. * @qid: The AP queue number * @psmid: Pointer to program supplied message identifier - * @msg: The message text - * @length: The message length - * @reslength: Resitual length on return - * @resgr0: input: gr0 value (only used if != 0), output: resitual gr0 content + * @msg: Pointer to message buffer + * @msglen: Message buffer size + * @length: Pointer to length of actually written bytes + * @reslength: Residual length on return + * @resgr0: input: gr0 value (only used if != 0), output: residual gr0 content * * Returns AP queue status structure. * Condition code 1 on DQAP means the receive has taken place @@ -377,20 +488,21 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, * *resgr0 is to be used instead of qid to further process this entry. */ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, - unsigned long long *psmid, - void *msg, size_t length, + unsigned long *psmid, + void *msg, size_t msglen, + size_t *length, size_t *reslength, unsigned long *resgr0) { unsigned long reg0 = resgr0 && *resgr0 ? *resgr0 : qid | 0x80000000UL; - struct ap_queue_status reg1; + union ap_queue_status_reg reg1; unsigned long reg2; union register_pair rp1, rp2; rp1.even = 0UL; rp1.odd = 0UL; rp2.even = (unsigned long)msg; - rp2.odd = (unsigned long)length; + rp2.odd = (unsigned long)msglen; asm volatile( " lgr 0,%[reg0]\n" /* qid param into gr0 */ @@ -402,8 +514,9 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, "2: lgr %[reg0],0\n" /* gr0 (qid + info) into reg0 */ " lgr %[reg1],1\n" /* gr1 (status) into reg1 */ " lgr %[reg2],2\n" /* gr2 (res length) into reg2 */ - : [reg0] "+&d" (reg0), [reg1] "=&d" (reg1), [reg2] "=&d" (reg2), - [rp1] "+&d" (rp1.pair), [rp2] "+&d" (rp2.pair) + : [reg0] "+&d" (reg0), [reg1] "=&d" (reg1.value), + [reg2] "=&d" (reg2), [rp1] "+&d" (rp1.pair), + [rp2] "+&d" (rp2.pair) : : "cc", "memory", "0", "1", "2"); @@ -415,16 +528,20 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, * Signal the caller that this dqap is only partially received * with a special status response code 0xFF and *resgr0 updated */ - reg1.response_code = 0xFF; + reg1.status.response_code = 0xFF; if (resgr0) *resgr0 = reg0; } else { - *psmid = (((unsigned long long)rp1.even) << 32) + rp1.odd; + *psmid = (rp1.even << 32) + rp1.odd; if (resgr0) *resgr0 = 0; } - return reg1; + /* update *length with the nr of bytes stored into the msg buffer */ + if (length) + *length = msglen - rp2.odd; + + return reg1.status; } /* |