0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef _ASM_S390_AP_H_
0013 #define _ASM_S390_AP_H_
0014
0015 #include <linux/io.h>
0016 #include <asm/asm-extable.h>
0017
0018
0019
0020
0021
0022
0023
0024 typedef unsigned int ap_qid_t;
0025
0026 #define AP_MKQID(_card, _queue) (((_card) & 0xff) << 8 | ((_queue) & 0xff))
0027 #define AP_QID_CARD(_qid) (((_qid) >> 8) & 0xff)
0028 #define AP_QID_QUEUE(_qid) ((_qid) & 0xff)
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 struct ap_queue_status {
0043 unsigned int queue_empty : 1;
0044 unsigned int replies_waiting : 1;
0045 unsigned int queue_full : 1;
0046 unsigned int _pad1 : 4;
0047 unsigned int irq_enabled : 1;
0048 unsigned int response_code : 8;
0049 unsigned int _pad2 : 16;
0050 };
0051
0052
0053
0054
0055
0056
0057 static inline bool ap_instructions_available(void)
0058 {
0059 unsigned long reg0 = AP_MKQID(0, 0);
0060 unsigned long reg1 = 0;
0061
0062 asm volatile(
0063 " lgr 0,%[reg0]\n"
0064 " lghi 1,0\n"
0065 " lghi 2,0\n"
0066 " .insn rre,0xb2af0000,0,0\n"
0067 "0: la %[reg1],1\n"
0068 "1:\n"
0069 EX_TABLE(0b, 1b)
0070 : [reg1] "+&d" (reg1)
0071 : [reg0] "d" (reg0)
0072 : "cc", "0", "1", "2");
0073 return reg1 != 0;
0074 }
0075
0076
0077
0078
0079
0080
0081
0082
0083 static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info)
0084 {
0085 struct ap_queue_status reg1;
0086 unsigned long reg2;
0087
0088 asm volatile(
0089 " lgr 0,%[qid]\n"
0090 " lghi 2,0\n"
0091 " .insn rre,0xb2af0000,0,0\n"
0092 " lgr %[reg1],1\n"
0093 " lgr %[reg2],2\n"
0094 : [reg1] "=&d" (reg1), [reg2] "=&d" (reg2)
0095 : [qid] "d" (qid)
0096 : "cc", "0", "1", "2");
0097 if (info)
0098 *info = reg2;
0099 return reg1;
0100 }
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110 static inline struct ap_queue_status ap_test_queue(ap_qid_t qid,
0111 int tbit,
0112 unsigned long *info)
0113 {
0114 if (tbit)
0115 qid |= 1UL << 23;
0116 return ap_tapq(qid, info);
0117 }
0118
0119
0120
0121
0122
0123
0124
0125 static inline struct ap_queue_status ap_rapq(ap_qid_t qid)
0126 {
0127 unsigned long reg0 = qid | (1UL << 24);
0128 struct ap_queue_status reg1;
0129
0130 asm volatile(
0131 " lgr 0,%[reg0]\n"
0132 " .insn rre,0xb2af0000,0,0\n"
0133 " lgr %[reg1],1\n"
0134 : [reg1] "=&d" (reg1)
0135 : [reg0] "d" (reg0)
0136 : "cc", "0", "1");
0137 return reg1;
0138 }
0139
0140
0141
0142
0143
0144
0145
0146 static inline struct ap_queue_status ap_zapq(ap_qid_t qid)
0147 {
0148 unsigned long reg0 = qid | (2UL << 24);
0149 struct ap_queue_status reg1;
0150
0151 asm volatile(
0152 " lgr 0,%[reg0]\n"
0153 " .insn rre,0xb2af0000,0,0\n"
0154 " lgr %[reg1],1\n"
0155 : [reg1] "=&d" (reg1)
0156 : [reg0] "d" (reg0)
0157 : "cc", "0", "1");
0158 return reg1;
0159 }
0160
0161
0162
0163
0164
0165 struct ap_config_info {
0166 unsigned int apsc : 1;
0167 unsigned int apxa : 1;
0168 unsigned int qact : 1;
0169 unsigned int rc8a : 1;
0170 unsigned char _reserved1 : 4;
0171 unsigned char _reserved2[3];
0172 unsigned char Na;
0173 unsigned char Nd;
0174 unsigned char _reserved3[10];
0175 unsigned int apm[8];
0176 unsigned int aqm[8];
0177 unsigned int adm[8];
0178 unsigned char _reserved4[16];
0179 } __aligned(8);
0180
0181
0182
0183
0184
0185
0186 static inline int ap_qci(struct ap_config_info *config)
0187 {
0188 unsigned long reg0 = 4UL << 24;
0189 unsigned long reg1 = -EOPNOTSUPP;
0190 struct ap_config_info *reg2 = config;
0191
0192 asm volatile(
0193 " lgr 0,%[reg0]\n"
0194 " lgr 2,%[reg2]\n"
0195 " .insn rre,0xb2af0000,0,0\n"
0196 "0: la %[reg1],0\n"
0197 "1:\n"
0198 EX_TABLE(0b, 1b)
0199 : [reg1] "+&d" (reg1)
0200 : [reg0] "d" (reg0), [reg2] "d" (reg2)
0201 : "cc", "memory", "0", "2");
0202
0203 return reg1;
0204 }
0205
0206
0207
0208
0209
0210
0211
0212 struct ap_qirq_ctrl {
0213 unsigned int _res1 : 8;
0214 unsigned int zone : 8;
0215 unsigned int ir : 1;
0216 unsigned int _res2 : 4;
0217 unsigned int gisc : 3;
0218 unsigned int _res3 : 6;
0219 unsigned int gf : 2;
0220 unsigned int _res4 : 1;
0221 unsigned int gisa : 27;
0222 unsigned int _res5 : 1;
0223 unsigned int isc : 3;
0224 };
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234 static inline struct ap_queue_status ap_aqic(ap_qid_t qid,
0235 struct ap_qirq_ctrl qirqctrl,
0236 phys_addr_t pa_ind)
0237 {
0238 unsigned long reg0 = qid | (3UL << 24);
0239 union {
0240 unsigned long value;
0241 struct ap_qirq_ctrl qirqctrl;
0242 struct ap_queue_status status;
0243 } reg1;
0244 unsigned long reg2 = pa_ind;
0245
0246 reg1.qirqctrl = qirqctrl;
0247
0248 asm volatile(
0249 " lgr 0,%[reg0]\n"
0250 " lgr 1,%[reg1]\n"
0251 " lgr 2,%[reg2]\n"
0252 " .insn rre,0xb2af0000,0,0\n"
0253 " lgr %[reg1],1\n"
0254 : [reg1] "+&d" (reg1)
0255 : [reg0] "d" (reg0), [reg2] "d" (reg2)
0256 : "cc", "0", "1", "2");
0257
0258 return reg1.status;
0259 }
0260
0261
0262
0263
0264
0265
0266 union ap_qact_ap_info {
0267 unsigned long val;
0268 struct {
0269 unsigned int : 3;
0270 unsigned int mode : 3;
0271 unsigned int : 26;
0272 unsigned int cat : 8;
0273 unsigned int : 8;
0274 unsigned char ver[2];
0275 };
0276 };
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287 static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit,
0288 union ap_qact_ap_info *apinfo)
0289 {
0290 unsigned long reg0 = qid | (5UL << 24) | ((ifbit & 0x01) << 22);
0291 union {
0292 unsigned long value;
0293 struct ap_queue_status status;
0294 } reg1;
0295 unsigned long reg2;
0296
0297 reg1.value = apinfo->val;
0298
0299 asm volatile(
0300 " lgr 0,%[reg0]\n"
0301 " lgr 1,%[reg1]\n"
0302 " .insn rre,0xb2af0000,0,0\n"
0303 " lgr %[reg1],1\n"
0304 " lgr %[reg2],2\n"
0305 : [reg1] "+&d" (reg1), [reg2] "=&d" (reg2)
0306 : [reg0] "d" (reg0)
0307 : "cc", "0", "1", "2");
0308 apinfo->val = reg2;
0309 return reg1.status;
0310 }
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324 static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
0325 unsigned long long psmid,
0326 void *msg, size_t length)
0327 {
0328 unsigned long reg0 = qid | 0x40000000UL;
0329 union register_pair nqap_r1, nqap_r2;
0330 struct ap_queue_status reg1;
0331
0332 nqap_r1.even = (unsigned int)(psmid >> 32);
0333 nqap_r1.odd = psmid & 0xffffffff;
0334 nqap_r2.even = (unsigned long)msg;
0335 nqap_r2.odd = (unsigned long)length;
0336
0337 asm volatile (
0338 " lgr 0,%[reg0]\n"
0339 "0: .insn rre,0xb2ad0000,%[nqap_r1],%[nqap_r2]\n"
0340 " brc 2,0b\n"
0341 " lgr %[reg1],1\n"
0342 : [reg0] "+&d" (reg0), [reg1] "=&d" (reg1),
0343 [nqap_r2] "+&d" (nqap_r2.pair)
0344 : [nqap_r1] "d" (nqap_r1.pair)
0345 : "cc", "memory", "0", "1");
0346 return reg1;
0347 }
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379 static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
0380 unsigned long long *psmid,
0381 void *msg, size_t length,
0382 size_t *reslength,
0383 unsigned long *resgr0)
0384 {
0385 unsigned long reg0 = resgr0 && *resgr0 ? *resgr0 : qid | 0x80000000UL;
0386 struct ap_queue_status reg1;
0387 unsigned long reg2;
0388 union register_pair rp1, rp2;
0389
0390 rp1.even = 0UL;
0391 rp1.odd = 0UL;
0392 rp2.even = (unsigned long)msg;
0393 rp2.odd = (unsigned long)length;
0394
0395 asm volatile(
0396 " lgr 0,%[reg0]\n"
0397 " lghi 2,0\n"
0398 "0: ltgr %N[rp2],%N[rp2]\n"
0399 " jz 2f\n"
0400 "1: .insn rre,0xb2ae0000,%[rp1],%[rp2]\n"
0401 " brc 6,0b\n"
0402 "2: lgr %[reg0],0\n"
0403 " lgr %[reg1],1\n"
0404 " lgr %[reg2],2\n"
0405 : [reg0] "+&d" (reg0), [reg1] "=&d" (reg1), [reg2] "=&d" (reg2),
0406 [rp1] "+&d" (rp1.pair), [rp2] "+&d" (rp2.pair)
0407 :
0408 : "cc", "memory", "0", "1", "2");
0409
0410 if (reslength)
0411 *reslength = reg2;
0412 if (reg2 != 0 && rp2.odd == 0) {
0413
0414
0415
0416
0417
0418 reg1.response_code = 0xFF;
0419 if (resgr0)
0420 *resgr0 = reg0;
0421 } else {
0422 *psmid = (((unsigned long long)rp1.even) << 32) + rp1.odd;
0423 if (resgr0)
0424 *resgr0 = 0;
0425 }
0426
0427 return reg1;
0428 }
0429
0430
0431
0432
0433
0434
0435 #if IS_ENABLED(CONFIG_ZCRYPT)
0436 void ap_bus_cfg_chg(void);
0437 #else
0438 static inline void ap_bus_cfg_chg(void){}
0439 #endif
0440
0441 #endif