Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.10 191 lines 5.6 kB view raw
1/* 2 * Copyright IBM Corp. 2016 3 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> 4 * 5 * Adjunct processor bus inline assemblies. 6 */ 7 8#ifndef _AP_ASM_H_ 9#define _AP_ASM_H_ 10 11#include <asm/isc.h> 12 13/** 14 * ap_intructions_available() - Test if AP instructions are available. 15 * 16 * Returns 0 if the AP instructions are installed. 17 */ 18static inline int ap_instructions_available(void) 19{ 20 register unsigned long reg0 asm ("0") = AP_MKQID(0, 0); 21 register unsigned long reg1 asm ("1") = -ENODEV; 22 register unsigned long reg2 asm ("2") = 0UL; 23 24 asm volatile( 25 " .long 0xb2af0000\n" /* PQAP(TAPQ) */ 26 "0: la %1,0\n" 27 "1:\n" 28 EX_TABLE(0b, 1b) 29 : "+d" (reg0), "+d" (reg1), "+d" (reg2) : : "cc"); 30 return reg1; 31} 32 33/** 34 * ap_tapq(): Test adjunct processor queue. 35 * @qid: The AP queue number 36 * @info: Pointer to queue descriptor 37 * 38 * Returns AP queue status structure. 39 */ 40static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) 41{ 42 register unsigned long reg0 asm ("0") = qid; 43 register struct ap_queue_status reg1 asm ("1"); 44 register unsigned long reg2 asm ("2") = 0UL; 45 46 asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */ 47 : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); 48 if (info) 49 *info = reg2; 50 return reg1; 51} 52 53/** 54 * ap_pqap_rapq(): Reset adjunct processor queue. 55 * @qid: The AP queue number 56 * 57 * Returns AP queue status structure. 58 */ 59static inline struct ap_queue_status ap_rapq(ap_qid_t qid) 60{ 61 register unsigned long reg0 asm ("0") = qid | 0x01000000UL; 62 register struct ap_queue_status reg1 asm ("1"); 63 register unsigned long reg2 asm ("2") = 0UL; 64 65 asm volatile( 66 ".long 0xb2af0000" /* PQAP(RAPQ) */ 67 : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); 68 return reg1; 69} 70 71/** 72 * ap_aqic(): Enable interruption for a specific AP. 73 * @qid: The AP queue number 74 * @ind: The notification indicator byte 75 * 76 * Returns AP queue status. 77 */ 78static inline struct ap_queue_status ap_aqic(ap_qid_t qid, void *ind) 79{ 80 register unsigned long reg0 asm ("0") = qid | (3UL << 24); 81 register unsigned long reg1_in asm ("1") = (8UL << 44) | AP_ISC; 82 register struct ap_queue_status reg1_out asm ("1"); 83 register void *reg2 asm ("2") = ind; 84 85 asm volatile( 86 ".long 0xb2af0000" /* PQAP(AQIC) */ 87 : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2) 88 : 89 : "cc"); 90 return reg1_out; 91} 92 93/** 94 * ap_qci(): Get AP configuration data 95 * 96 * Returns 0 on success, or -EOPNOTSUPP. 97 */ 98static inline int ap_qci(void *config) 99{ 100 register unsigned long reg0 asm ("0") = 0x04000000UL; 101 register unsigned long reg1 asm ("1") = -EINVAL; 102 register void *reg2 asm ("2") = (void *) config; 103 104 asm volatile( 105 ".long 0xb2af0000\n" /* PQAP(QCI) */ 106 "0: la %1,0\n" 107 "1:\n" 108 EX_TABLE(0b, 1b) 109 : "+d" (reg0), "+d" (reg1), "+d" (reg2) 110 : 111 : "cc", "memory"); 112 113 return reg1; 114} 115 116/** 117 * ap_nqap(): Send message to adjunct processor queue. 118 * @qid: The AP queue number 119 * @psmid: The program supplied message identifier 120 * @msg: The message text 121 * @length: The message length 122 * 123 * Returns AP queue status structure. 124 * Condition code 1 on NQAP can't happen because the L bit is 1. 125 * Condition code 2 on NQAP also means the send is incomplete, 126 * because a segment boundary was reached. The NQAP is repeated. 127 */ 128static inline struct ap_queue_status ap_nqap(ap_qid_t qid, 129 unsigned long long psmid, 130 void *msg, size_t length) 131{ 132 struct msgblock { char _[length]; }; 133 register unsigned long reg0 asm ("0") = qid | 0x40000000UL; 134 register struct ap_queue_status reg1 asm ("1"); 135 register unsigned long reg2 asm ("2") = (unsigned long) msg; 136 register unsigned long reg3 asm ("3") = (unsigned long) length; 137 register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32); 138 register unsigned long reg5 asm ("5") = psmid & 0xffffffff; 139 140 asm volatile ( 141 "0: .long 0xb2ad0042\n" /* NQAP */ 142 " brc 2,0b" 143 : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3) 144 : "d" (reg4), "d" (reg5), "m" (*(struct msgblock *) msg) 145 : "cc"); 146 return reg1; 147} 148 149/** 150 * ap_dqap(): Receive message from adjunct processor queue. 151 * @qid: The AP queue number 152 * @psmid: Pointer to program supplied message identifier 153 * @msg: The message text 154 * @length: The message length 155 * 156 * Returns AP queue status structure. 157 * Condition code 1 on DQAP means the receive has taken place 158 * but only partially. The response is incomplete, hence the 159 * DQAP is repeated. 160 * Condition code 2 on DQAP also means the receive is incomplete, 161 * this time because a segment boundary was reached. Again, the 162 * DQAP is repeated. 163 * Note that gpr2 is used by the DQAP instruction to keep track of 164 * any 'residual' length, in case the instruction gets interrupted. 165 * Hence it gets zeroed before the instruction. 166 */ 167static inline struct ap_queue_status ap_dqap(ap_qid_t qid, 168 unsigned long long *psmid, 169 void *msg, size_t length) 170{ 171 struct msgblock { char _[length]; }; 172 register unsigned long reg0 asm("0") = qid | 0x80000000UL; 173 register struct ap_queue_status reg1 asm ("1"); 174 register unsigned long reg2 asm("2") = 0UL; 175 register unsigned long reg4 asm("4") = (unsigned long) msg; 176 register unsigned long reg5 asm("5") = (unsigned long) length; 177 register unsigned long reg6 asm("6") = 0UL; 178 register unsigned long reg7 asm("7") = 0UL; 179 180 181 asm volatile( 182 "0: .long 0xb2ae0064\n" /* DQAP */ 183 " brc 6,0b\n" 184 : "+d" (reg0), "=d" (reg1), "+d" (reg2), 185 "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7), 186 "=m" (*(struct msgblock *) msg) : : "cc"); 187 *psmid = (((unsigned long long) reg6) << 32) + reg7; 188 return reg1; 189} 190 191#endif /* _AP_ASM_H_ */