linux/drivers/s390/crypto/ap_asm.h
<<
>>
Prefs
   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        register unsigned long reg0 asm ("0") = qid | 0x40000000UL;
 133        register struct ap_queue_status reg1 asm ("1");
 134        register unsigned long reg2 asm ("2") = (unsigned long) msg;
 135        register unsigned long reg3 asm ("3") = (unsigned long) length;
 136        register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32);
 137        register unsigned long reg5 asm ("5") = psmid & 0xffffffff;
 138
 139        asm volatile (
 140                "0: .long 0xb2ad0042\n"         /* NQAP */
 141                "   brc   2,0b"
 142                : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3)
 143                : "d" (reg4), "d" (reg5)
 144                : "cc", "memory");
 145        return reg1;
 146}
 147
 148/**
 149 * ap_dqap(): Receive message from adjunct processor queue.
 150 * @qid: The AP queue number
 151 * @psmid: Pointer to program supplied message identifier
 152 * @msg: The message text
 153 * @length: The message length
 154 *
 155 * Returns AP queue status structure.
 156 * Condition code 1 on DQAP means the receive has taken place
 157 * but only partially.  The response is incomplete, hence the
 158 * DQAP is repeated.
 159 * Condition code 2 on DQAP also means the receive is incomplete,
 160 * this time because a segment boundary was reached. Again, the
 161 * DQAP is repeated.
 162 * Note that gpr2 is used by the DQAP instruction to keep track of
 163 * any 'residual' length, in case the instruction gets interrupted.
 164 * Hence it gets zeroed before the instruction.
 165 */
 166static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
 167                                             unsigned long long *psmid,
 168                                             void *msg, size_t length)
 169{
 170        register unsigned long reg0 asm("0") = qid | 0x80000000UL;
 171        register struct ap_queue_status reg1 asm ("1");
 172        register unsigned long reg2 asm("2") = 0UL;
 173        register unsigned long reg4 asm("4") = (unsigned long) msg;
 174        register unsigned long reg5 asm("5") = (unsigned long) length;
 175        register unsigned long reg6 asm("6") = 0UL;
 176        register unsigned long reg7 asm("7") = 0UL;
 177
 178
 179        asm volatile(
 180                "0: .long 0xb2ae0064\n"         /* DQAP */
 181                "   brc   6,0b\n"
 182                : "+d" (reg0), "=d" (reg1), "+d" (reg2),
 183                  "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7)
 184                : : "cc", "memory");
 185        *psmid = (((unsigned long long) reg6) << 32) + reg7;
 186        return reg1;
 187}
 188
 189#endif /* _AP_ASM_H_ */
 190