/* SPDX-License-Identifier: GPL-2.0 */1/*2* Adjunct processor (AP) interfaces3*4* Copyright IBM Corp. 20175*6* Author(s): Tony Krowiak <[email protected]>7* Martin Schwidefsky <[email protected]>8* Harald Freudenberger <[email protected]>9*/1011#ifndef _ASM_S390_AP_H_12#define _ASM_S390_AP_H_1314#include <linux/io.h>15#include <asm/asm-extable.h>1617/**18* The ap_qid_t identifier of an ap queue.19* If the AP facilities test (APFT) facility is available,20* card and queue index are 8 bit values, otherwise21* card index is 6 bit and queue index a 4 bit value.22*/23typedef unsigned int ap_qid_t;2425#define AP_MKQID(_card, _queue) (((_card) & 0xff) << 8 | ((_queue) & 0xff))26#define AP_QID_CARD(_qid) (((_qid) >> 8) & 0xff)27#define AP_QID_QUEUE(_qid) ((_qid) & 0xff)2829/**30* struct ap_queue_status - Holds the AP queue status.31* @queue_empty: Shows if queue is empty32* @replies_waiting: Waiting replies33* @queue_full: Is 1 if the queue is full34* @irq_enabled: Shows if interrupts are enabled for the AP35* @response_code: Holds the 8 bit response code36*37* The ap queue status word is returned by all three AP functions38* (PQAP, NQAP and DQAP). There's a set of flags in the first39* byte, followed by a 1 byte response code.40*41* For convenience the 'value' field is a 32 bit access of the42* whole status and the 'status_bits' and 'rc' fields comprise43* the leftmost 8 status bits and the response_code.44*/45struct ap_queue_status {46union {47unsigned int value : 32;48struct {49unsigned int status_bits : 8;50unsigned int rc : 8;51unsigned int : 16;52};53struct {54unsigned int queue_empty : 1;55unsigned int replies_waiting : 1;56unsigned int queue_full : 1;57unsigned int : 3;58unsigned int async : 1;59unsigned int irq_enabled : 1;60unsigned int response_code : 8;61unsigned int : 16;62};63};64};6566/*67* AP queue status reg union to access the reg168* register with the lower 32 bits comprising the69* ap queue status.70*/71union ap_queue_status_reg {72unsigned long value;73struct {74u32 _pad;75struct ap_queue_status status;76};77};7879/**80* ap_intructions_available() - Test if AP instructions are available.81*82* Returns true if the AP instructions are installed, otherwise false.83*/84static inline bool ap_instructions_available(void)85{86unsigned long reg0 = AP_MKQID(0, 0);87unsigned long reg1 = 0;8889asm volatile(90" lgr 0,%[reg0]\n" /* qid into gr0 */91" lghi 1,0\n" /* 0 into gr1 */92" lghi 2,0\n" /* 0 into gr2 */93" .insn rre,0xb2af0000,0,0\n" /* PQAP(TAPQ) */94"0: la %[reg1],1\n" /* 1 into reg1 */95"1:\n"96EX_TABLE(0b, 1b)97: [reg1] "+&d" (reg1)98: [reg0] "d" (reg0)99: "cc", "0", "1", "2");100return reg1 != 0;101}102103/* TAPQ register GR2 response struct */104struct ap_tapq_hwinfo {105union {106unsigned long value;107struct {108unsigned int fac : 32; /* facility bits */109unsigned int apinfo : 32; /* ap type, ... */110};111struct {112unsigned int apsc : 1; /* APSC */113unsigned int mex4k : 1; /* AP4KM */114unsigned int crt4k : 1; /* AP4KC */115unsigned int cca : 1; /* D */116unsigned int accel : 1; /* A */117unsigned int ep11 : 1; /* X */118unsigned int apxa : 1; /* APXA */119unsigned int slcf : 1; /* Cmd filtering avail. */120unsigned int class : 8;121unsigned int bs : 2; /* SE bind/assoc */122unsigned int : 14;123unsigned int at : 8; /* ap type */124unsigned int nd : 8; /* nr of domains */125unsigned int : 4;126unsigned int ml : 4; /* apxl ml */127unsigned int : 4;128unsigned int qd : 4; /* queue depth */129};130};131};132133/*134* Convenience defines to be used with the bs field from struct ap_tapq_gr2135*/136#define AP_BS_Q_USABLE 0137#define AP_BS_Q_USABLE_NO_SECURE_KEY 1138#define AP_BS_Q_AVAIL_FOR_BINDING 2139#define AP_BS_Q_UNUSABLE 3140141/**142* ap_tapq(): Test adjunct processor queue.143* @qid: The AP queue number144* @info: Pointer to tapq hwinfo struct145*146* Returns AP queue status structure.147*/148static inline struct ap_queue_status ap_tapq(ap_qid_t qid,149struct ap_tapq_hwinfo *info)150{151union ap_queue_status_reg reg1;152unsigned long reg2;153154asm volatile(155" lgr 0,%[qid]\n" /* qid into gr0 */156" lghi 2,0\n" /* 0 into gr2 */157" .insn rre,0xb2af0000,0,0\n" /* PQAP(TAPQ) */158" lgr %[reg1],1\n" /* gr1 (status) into reg1 */159" lgr %[reg2],2" /* gr2 into reg2 */160: [reg1] "=&d" (reg1.value), [reg2] "=&d" (reg2)161: [qid] "d" (qid)162: "cc", "0", "1", "2");163if (info)164info->value = reg2;165return reg1.status;166}167168/**169* ap_test_queue(): Test adjunct processor queue.170* @qid: The AP queue number171* @tbit: Test facilities bit172* @info: Ptr to tapq gr2 struct173*174* Returns AP queue status structure.175*/176static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, int tbit,177struct ap_tapq_hwinfo *info)178{179if (tbit)180qid |= 1UL << 23; /* set T bit*/181return ap_tapq(qid, info);182}183184/**185* ap_pqap_rapq(): Reset adjunct processor queue.186* @qid: The AP queue number187* @fbit: if != 0 set F bit188*189* Returns AP queue status structure.190*/191static inline struct ap_queue_status ap_rapq(ap_qid_t qid, int fbit)192{193unsigned long reg0 = qid | (1UL << 24); /* fc 1UL is RAPQ */194union ap_queue_status_reg reg1;195196if (fbit)197reg0 |= 1UL << 22;198199asm volatile(200" lgr 0,%[reg0]\n" /* qid arg into gr0 */201" .insn rre,0xb2af0000,0,0\n" /* PQAP(RAPQ) */202" lgr %[reg1],1" /* gr1 (status) into reg1 */203: [reg1] "=&d" (reg1.value)204: [reg0] "d" (reg0)205: "cc", "0", "1");206return reg1.status;207}208209/**210* ap_pqap_zapq(): Reset and zeroize adjunct processor queue.211* @qid: The AP queue number212* @fbit: if != 0 set F bit213*214* Returns AP queue status structure.215*/216static inline struct ap_queue_status ap_zapq(ap_qid_t qid, int fbit)217{218unsigned long reg0 = qid | (2UL << 24); /* fc 2UL is ZAPQ */219union ap_queue_status_reg reg1;220221if (fbit)222reg0 |= 1UL << 22;223224asm volatile(225" lgr 0,%[reg0]\n" /* qid arg into gr0 */226" .insn rre,0xb2af0000,0,0\n" /* PQAP(ZAPQ) */227" lgr %[reg1],1" /* gr1 (status) into reg1 */228: [reg1] "=&d" (reg1.value)229: [reg0] "d" (reg0)230: "cc", "0", "1");231return reg1.status;232}233234/**235* struct ap_config_info - convenience struct for AP crypto236* config info as returned by the ap_qci() function.237*/238struct ap_config_info {239union {240unsigned int flags;241struct {242unsigned int apsc : 1; /* S bit */243unsigned int apxa : 1; /* N bit */244unsigned int qact : 1; /* C bit */245unsigned int rc8a : 1; /* R bit */246unsigned int : 4;247unsigned int apsb : 1; /* B bit */248unsigned int : 23;249};250};251unsigned char na; /* max # of APs - 1 */252unsigned char nd; /* max # of Domains - 1 */253unsigned char _reserved0[10];254unsigned int apm[8]; /* AP ID mask */255unsigned int aqm[8]; /* AP (usage) queue mask */256unsigned int adm[8]; /* AP (control) domain mask */257unsigned char _reserved1[16];258} __aligned(8);259260/**261* ap_qci(): Get AP configuration data262*263* Returns 0 on success, or -EOPNOTSUPP.264*/265static inline int ap_qci(struct ap_config_info *config)266{267unsigned long reg0 = 4UL << 24; /* fc 4UL is QCI */268unsigned long reg1 = -EOPNOTSUPP;269struct ap_config_info *reg2 = config;270271asm volatile(272" lgr 0,%[reg0]\n" /* QCI fc into gr0 */273" lgr 2,%[reg2]\n" /* ptr to config into gr2 */274" .insn rre,0xb2af0000,0,0\n" /* PQAP(QCI) */275"0: la %[reg1],0\n" /* good case, QCI fc available */276"1:\n"277EX_TABLE(0b, 1b)278: [reg1] "+&d" (reg1)279: [reg0] "d" (reg0), [reg2] "d" (reg2)280: "cc", "memory", "0", "2");281282return reg1;283}284285/*286* struct ap_qirq_ctrl - convenient struct for easy invocation287* of the ap_aqic() function. This struct is passed as GR1288* parameter to the PQAP(AQIC) instruction. For details please289* see the AR documentation.290*/291union ap_qirq_ctrl {292unsigned long value;293struct {294unsigned int : 8;295unsigned int zone : 8; /* zone info */296unsigned int ir : 1; /* ir flag: enable (1) or disable (0) irq */297unsigned int : 4;298unsigned int gisc : 3; /* guest isc field */299unsigned int : 6;300unsigned int gf : 2; /* gisa format */301unsigned int : 1;302unsigned int gisa : 27; /* gisa origin */303unsigned int : 1;304unsigned int isc : 3; /* irq sub class */305};306};307308/**309* ap_aqic(): Control interruption for a specific AP.310* @qid: The AP queue number311* @qirqctrl: struct ap_qirq_ctrl (64 bit value)312* @pa_ind: Physical address of the notification indicator byte313*314* Returns AP queue status.315*/316static inline struct ap_queue_status ap_aqic(ap_qid_t qid,317union ap_qirq_ctrl qirqctrl,318phys_addr_t pa_ind)319{320unsigned long reg0 = qid | (3UL << 24); /* fc 3UL is AQIC */321union ap_queue_status_reg reg1;322unsigned long reg2 = pa_ind;323324reg1.value = qirqctrl.value;325326asm volatile(327" lgr 0,%[reg0]\n" /* qid param into gr0 */328" lgr 1,%[reg1]\n" /* irq ctrl into gr1 */329" lgr 2,%[reg2]\n" /* ni addr into gr2 */330" .insn rre,0xb2af0000,0,0\n" /* PQAP(AQIC) */331" lgr %[reg1],1" /* gr1 (status) into reg1 */332: [reg1] "+&d" (reg1.value)333: [reg0] "d" (reg0), [reg2] "d" (reg2)334: "cc", "memory", "0", "1", "2");335336return reg1.status;337}338339/*340* union ap_qact_ap_info - used together with the341* ap_aqic() function to provide a convenient way342* to handle the ap info needed by the qact function.343*/344union ap_qact_ap_info {345unsigned long val;346struct {347unsigned int : 3;348unsigned int mode : 3;349unsigned int : 26;350unsigned int cat : 8;351unsigned int : 8;352unsigned char ver[2];353};354};355356/**357* ap_qact(): Query AP compatibility type.358* @qid: The AP queue number359* @apinfo: On input the info about the AP queue. On output the360* alternate AP queue info provided by the qact function361* in GR2 is stored in.362*363* Returns AP queue status. Check response_code field for failures.364*/365static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit,366union ap_qact_ap_info *apinfo)367{368unsigned long reg0 = qid | (5UL << 24) | ((ifbit & 0x01) << 22);369union ap_queue_status_reg reg1;370unsigned long reg2;371372reg1.value = apinfo->val;373374asm volatile(375" lgr 0,%[reg0]\n" /* qid param into gr0 */376" lgr 1,%[reg1]\n" /* qact in info into gr1 */377" .insn rre,0xb2af0000,0,0\n" /* PQAP(QACT) */378" lgr %[reg1],1\n" /* gr1 (status) into reg1 */379" lgr %[reg2],2" /* qact out info into reg2 */380: [reg1] "+&d" (reg1.value), [reg2] "=&d" (reg2)381: [reg0] "d" (reg0)382: "cc", "0", "1", "2");383apinfo->val = reg2;384return reg1.status;385}386387/*388* ap_bapq(): SE bind AP queue.389* @qid: The AP queue number390*391* Returns AP queue status structure.392*393* Invoking this function in a non-SE environment394* may case a specification exception.395*/396static inline struct ap_queue_status ap_bapq(ap_qid_t qid)397{398unsigned long reg0 = qid | (7UL << 24); /* fc 7 is BAPQ */399union ap_queue_status_reg reg1;400401asm volatile(402" lgr 0,%[reg0]\n" /* qid arg into gr0 */403" .insn rre,0xb2af0000,0,0\n" /* PQAP(BAPQ) */404" lgr %[reg1],1" /* gr1 (status) into reg1 */405: [reg1] "=&d" (reg1.value)406: [reg0] "d" (reg0)407: "cc", "0", "1");408409return reg1.status;410}411412/*413* ap_aapq(): SE associate AP queue.414* @qid: The AP queue number415* @sec_idx: The secret index416*417* Returns AP queue status structure.418*419* Invoking this function in a non-SE environment420* may case a specification exception.421*/422static inline struct ap_queue_status ap_aapq(ap_qid_t qid, unsigned int sec_idx)423{424unsigned long reg0 = qid | (8UL << 24); /* fc 8 is AAPQ */425unsigned long reg2 = sec_idx;426union ap_queue_status_reg reg1;427428asm volatile(429" lgr 0,%[reg0]\n" /* qid arg into gr0 */430" lgr 2,%[reg2]\n" /* secret index into gr2 */431" .insn rre,0xb2af0000,0,0\n" /* PQAP(AAPQ) */432" lgr %[reg1],1" /* gr1 (status) into reg1 */433: [reg1] "=&d" (reg1.value)434: [reg0] "d" (reg0), [reg2] "d" (reg2)435: "cc", "0", "1", "2");436437return reg1.status;438}439440/**441* ap_nqap(): Send message to adjunct processor queue.442* @qid: The AP queue number443* @psmid: The program supplied message identifier444* @msg: The message text445* @length: The message length446*447* Returns AP queue status structure.448* Condition code 1 on NQAP can't happen because the L bit is 1.449* Condition code 2 on NQAP also means the send is incomplete,450* because a segment boundary was reached. The NQAP is repeated.451*/452static inline struct ap_queue_status ap_nqap(ap_qid_t qid,453unsigned long long psmid,454void *msg, size_t length)455{456unsigned long reg0 = qid | 0x40000000UL; /* 0x4... is last msg part */457union register_pair nqap_r1, nqap_r2;458union ap_queue_status_reg reg1;459460nqap_r1.even = (unsigned int)(psmid >> 32);461nqap_r1.odd = psmid & 0xffffffff;462nqap_r2.even = (unsigned long)msg;463nqap_r2.odd = (unsigned long)length;464465asm volatile (466" lgr 0,%[reg0]\n" /* qid param in gr0 */467"0: .insn rre,0xb2ad0000,%[nqap_r1],%[nqap_r2]\n"468" brc 2,0b\n" /* handle partial completion */469" lgr %[reg1],1" /* gr1 (status) into reg1 */470: [reg0] "+&d" (reg0), [reg1] "=&d" (reg1.value),471[nqap_r2] "+&d" (nqap_r2.pair)472: [nqap_r1] "d" (nqap_r1.pair)473: "cc", "memory", "0", "1");474return reg1.status;475}476477/**478* ap_dqap(): Receive message from adjunct processor queue.479* @qid: The AP queue number480* @psmid: Pointer to program supplied message identifier481* @msg: Pointer to message buffer482* @msglen: Message buffer size483* @length: Pointer to length of actually written bytes484* @reslength: Residual length on return485* @resgr0: input: gr0 value (only used if != 0), output: residual gr0 content486*487* Returns AP queue status structure.488* Condition code 1 on DQAP means the receive has taken place489* but only partially. The response is incomplete, hence the490* DQAP is repeated.491* Condition code 2 on DQAP also means the receive is incomplete,492* this time because a segment boundary was reached. Again, the493* DQAP is repeated.494* Note that gpr2 is used by the DQAP instruction to keep track of495* any 'residual' length, in case the instruction gets interrupted.496* Hence it gets zeroed before the instruction.497* If the message does not fit into the buffer, this function will498* return with a truncated message and the reply in the firmware queue499* is not removed. This is indicated to the caller with an500* ap_queue_status response_code value of all bits on (0xFF) and (if501* the reslength ptr is given) the remaining length is stored in502* *reslength and (if the resgr0 ptr is given) the updated gr0 value503* for further processing of this msg entry is stored in *resgr0. The504* caller needs to detect this situation and should invoke ap_dqap505* with a valid resgr0 ptr and a value in there != 0 to indicate that506* *resgr0 is to be used instead of qid to further process this entry.507*/508static inline struct ap_queue_status ap_dqap(ap_qid_t qid,509unsigned long *psmid,510void *msg, size_t msglen,511size_t *length,512size_t *reslength,513unsigned long *resgr0)514{515unsigned long reg0 = resgr0 && *resgr0 ? *resgr0 : qid | 0x80000000UL;516union ap_queue_status_reg reg1;517unsigned long reg2;518union register_pair rp1, rp2;519520rp1.even = 0UL;521rp1.odd = 0UL;522rp2.even = (unsigned long)msg;523rp2.odd = (unsigned long)msglen;524525asm volatile(526" lgr 0,%[reg0]\n" /* qid param into gr0 */527" lghi 2,0\n" /* 0 into gr2 (res length) */528"0: ltgr %N[rp2],%N[rp2]\n" /* check buf len */529" jz 2f\n" /* go out if buf len is 0 */530"1: .insn rre,0xb2ae0000,%[rp1],%[rp2]\n"531" brc 6,0b\n" /* handle partial complete */532"2: lgr %[reg0],0\n" /* gr0 (qid + info) into reg0 */533" lgr %[reg1],1\n" /* gr1 (status) into reg1 */534" lgr %[reg2],2" /* gr2 (res length) into reg2 */535: [reg0] "+&d" (reg0), [reg1] "=&d" (reg1.value),536[reg2] "=&d" (reg2), [rp1] "+&d" (rp1.pair),537[rp2] "+&d" (rp2.pair)538:539: "cc", "memory", "0", "1", "2");540541if (reslength)542*reslength = reg2;543if (reg2 != 0 && rp2.odd == 0) {544/*545* Partially complete, status in gr1 is not set.546* Signal the caller that this dqap is only partially received547* with a special status response code 0xFF and *resgr0 updated548*/549reg1.status.response_code = 0xFF;550if (resgr0)551*resgr0 = reg0;552} else {553*psmid = (rp1.even << 32) + rp1.odd;554if (resgr0)555*resgr0 = 0;556}557558/* update *length with the nr of bytes stored into the msg buffer */559if (length)560*length = msglen - rp2.odd;561562return reg1.status;563}564565#endif /* _ASM_S390_AP_H_ */566567568