Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 
0003 /*
0004  * Copyright 2020 IBM Corp.
0005  *
0006  * Author: Bulent Abali <abali@us.ibm.com>
0007  *
0008  */
0009 #include <stdio.h>
0010 #include <stdlib.h>
0011 #include <string.h>
0012 #include <unistd.h>
0013 #include <stdint.h>
0014 #include <sys/types.h>
0015 #include <sys/stat.h>
0016 #include <sys/time.h>
0017 #include <sys/fcntl.h>
0018 #include <sys/mman.h>
0019 #include <endian.h>
0020 #include <bits/endian.h>
0021 #include <sys/ioctl.h>
0022 #include <assert.h>
0023 #include <errno.h>
0024 #include <signal.h>
0025 #include "vas-api.h"
0026 #include "nx.h"
0027 #include "copy-paste.h"
0028 #include "nxu.h"
0029 #include "nx_dbg.h"
0030 #include <sys/platform/ppc.h>
0031 
0032 #define barrier()
0033 #define hwsync()    ({ asm volatile("sync" ::: "memory"); })
0034 
0035 #ifndef NX_NO_CPU_PRI
0036 #define cpu_pri_default()  ({ asm volatile ("or 2, 2, 2"); })
0037 #define cpu_pri_low()      ({ asm volatile ("or 31, 31, 31"); })
0038 #else
0039 #define cpu_pri_default()
0040 #define cpu_pri_low()
0041 #endif
0042 
0043 void *nx_fault_storage_address;
0044 
0045 struct nx_handle {
0046     int fd;
0047     int function;
0048     void *paste_addr;
0049 };
0050 
0051 static int open_device_nodes(char *devname, int pri, struct nx_handle *handle)
0052 {
0053     int rc, fd;
0054     void *addr;
0055     struct vas_tx_win_open_attr txattr;
0056 
0057     fd = open(devname, O_RDWR);
0058     if (fd < 0) {
0059         fprintf(stderr, " open device name %s\n", devname);
0060         return -errno;
0061     }
0062 
0063     memset(&txattr, 0, sizeof(txattr));
0064     txattr.version = 1;
0065     txattr.vas_id = pri;
0066     rc = ioctl(fd, VAS_TX_WIN_OPEN, (unsigned long)&txattr);
0067     if (rc < 0) {
0068         fprintf(stderr, "ioctl() n %d, error %d\n", rc, errno);
0069         rc = -errno;
0070         goto out;
0071     }
0072 
0073     addr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0ULL);
0074     if (addr == MAP_FAILED) {
0075         fprintf(stderr, "mmap() failed, errno %d\n", errno);
0076         rc = -errno;
0077         goto out;
0078     }
0079     handle->fd = fd;
0080     handle->paste_addr = (void *)((char *)addr + 0x400);
0081 
0082     rc = 0;
0083 out:
0084     close(fd);
0085     return rc;
0086 }
0087 
0088 void *nx_function_begin(int function, int pri)
0089 {
0090     int rc;
0091     char *devname = "/dev/crypto/nx-gzip";
0092     struct nx_handle *nxhandle;
0093 
0094     if (function != NX_FUNC_COMP_GZIP) {
0095         errno = EINVAL;
0096         fprintf(stderr, " NX_FUNC_COMP_GZIP not found\n");
0097         return NULL;
0098     }
0099 
0100 
0101     nxhandle = malloc(sizeof(*nxhandle));
0102     if (!nxhandle) {
0103         errno = ENOMEM;
0104         fprintf(stderr, " No memory\n");
0105         return NULL;
0106     }
0107 
0108     nxhandle->function = function;
0109     rc = open_device_nodes(devname, pri, nxhandle);
0110     if (rc < 0) {
0111         errno = -rc;
0112         fprintf(stderr, " open_device_nodes failed\n");
0113         return NULL;
0114     }
0115 
0116     return nxhandle;
0117 }
0118 
0119 int nx_function_end(void *handle)
0120 {
0121     int rc = 0;
0122     struct nx_handle *nxhandle = handle;
0123 
0124     rc = munmap(nxhandle->paste_addr - 0x400, 4096);
0125     if (rc < 0) {
0126         fprintf(stderr, "munmap() failed, errno %d\n", errno);
0127         return rc;
0128     }
0129     close(nxhandle->fd);
0130     free(nxhandle);
0131 
0132     return rc;
0133 }
0134 
0135 static int nx_wait_for_csb(struct nx_gzip_crb_cpb_t *cmdp)
0136 {
0137     long poll = 0;
0138     uint64_t t;
0139 
0140     /* Save power and let other threads use the h/w. top may show
0141      * 100% but only because OS doesn't know we slowed the this
0142      * h/w thread while polling. We're letting other threads have
0143      * higher throughput on the core.
0144      */
0145     cpu_pri_low();
0146 
0147 #define CSB_MAX_POLL 200000000UL
0148 #define USLEEP_TH     300000UL
0149 
0150     t = __ppc_get_timebase();
0151 
0152     while (getnn(cmdp->crb.csb, csb_v) == 0) {
0153         ++poll;
0154         hwsync();
0155 
0156         cpu_pri_low();
0157 
0158         /* usleep(0) takes around 29000 ticks ~60 us.
0159          * 300000 is spinning for about 600 us then
0160          * start sleeping.
0161          */
0162         if ((__ppc_get_timebase() - t) > USLEEP_TH) {
0163             cpu_pri_default();
0164             usleep(1);
0165         }
0166 
0167         if (poll > CSB_MAX_POLL)
0168             break;
0169 
0170         /* Fault address from signal handler */
0171         if (nx_fault_storage_address) {
0172             cpu_pri_default();
0173             return -EAGAIN;
0174         }
0175 
0176     }
0177 
0178     cpu_pri_default();
0179 
0180     /* hw has updated csb and output buffer */
0181     hwsync();
0182 
0183     /* Check CSB flags. */
0184     if (getnn(cmdp->crb.csb, csb_v) == 0) {
0185         fprintf(stderr, "CSB still not valid after %d polls.\n",
0186             (int) poll);
0187         prt_err("CSB still not valid after %d polls, giving up.\n",
0188             (int) poll);
0189         return -ETIMEDOUT;
0190     }
0191 
0192     return 0;
0193 }
0194 
0195 static int nxu_run_job(struct nx_gzip_crb_cpb_t *cmdp, void *handle)
0196 {
0197     int i, ret, retries;
0198     struct nx_handle *nxhandle = handle;
0199 
0200     assert(handle != NULL);
0201     i = 0;
0202     retries = 5000;
0203     while (i++ < retries) {
0204         hwsync();
0205         vas_copy(&cmdp->crb, 0);
0206         ret = vas_paste(nxhandle->paste_addr, 0);
0207         hwsync();
0208 
0209         NXPRT(fprintf(stderr, "Paste attempt %d/%d returns 0x%x\n",
0210                 i, retries, ret));
0211 
0212         if ((ret == 2) || (ret == 3)) {
0213 
0214             ret = nx_wait_for_csb(cmdp);
0215             if (!ret) {
0216                 goto out;
0217             } else if (ret == -EAGAIN) {
0218                 long x;
0219 
0220                 prt_err("Touching address %p, 0x%lx\n",
0221                      nx_fault_storage_address,
0222                      *(long *) nx_fault_storage_address);
0223                 x = *(long *) nx_fault_storage_address;
0224                 *(long *) nx_fault_storage_address = x;
0225                 nx_fault_storage_address = 0;
0226                 continue;
0227             } else {
0228                 prt_err("wait_for_csb() returns %d\n", ret);
0229                 break;
0230             }
0231         } else {
0232             if (i < 10) {
0233                 /* spin for few ticks */
0234 #define SPIN_TH 500UL
0235                 uint64_t fail_spin;
0236 
0237                 fail_spin = __ppc_get_timebase();
0238                 while ((__ppc_get_timebase() - fail_spin) <
0239                      SPIN_TH)
0240                     ;
0241             } else {
0242                 /* sleep */
0243                 unsigned int pr = 0;
0244 
0245                 if (pr++ % 100 == 0) {
0246                     prt_err("Paste attempt %d/", i);
0247                     prt_err("%d, failed pid= %d\n", retries,
0248                         getpid());
0249                 }
0250                 usleep(1);
0251             }
0252             continue;
0253         }
0254     }
0255 
0256 out:
0257     cpu_pri_default();
0258 
0259     return ret;
0260 }
0261 
0262 int nxu_submit_job(struct nx_gzip_crb_cpb_t *cmdp, void *handle)
0263 {
0264     int cc;
0265 
0266     cc = nxu_run_job(cmdp, handle);
0267 
0268     if (!cc)
0269         cc = getnn(cmdp->crb.csb, csb_cc);      /* CC Table 6-8 */
0270 
0271     return cc;
0272 }
0273 
0274 
0275 void nxu_sigsegv_handler(int sig, siginfo_t *info, void *ctx)
0276 {
0277     fprintf(stderr, "%d: Got signal %d si_code %d, si_addr %p\n", getpid(),
0278         sig, info->si_code, info->si_addr);
0279 
0280     nx_fault_storage_address = info->si_addr;
0281 }
0282 
0283 /*
0284  * Fault in pages prior to NX job submission.  wr=1 may be required to
0285  * touch writeable pages.  System zero pages do not fault-in the page as
0286  * intended.  Typically set wr=1 for NX target pages and set wr=0 for NX
0287  * source pages.
0288  */
0289 int nxu_touch_pages(void *buf, long buf_len, long page_len, int wr)
0290 {
0291     char *begin = buf;
0292     char *end = (char *) buf + buf_len - 1;
0293     volatile char t;
0294 
0295     assert(buf_len >= 0 && !!buf);
0296 
0297     NXPRT(fprintf(stderr, "touch %p %p len 0x%lx wr=%d\n", buf,
0298             (buf + buf_len), buf_len, wr));
0299 
0300     if (buf_len <= 0 || buf == NULL)
0301         return -1;
0302 
0303     do {
0304         t = *begin;
0305         if (wr)
0306             *begin = t;
0307         begin = begin + page_len;
0308     } while (begin < end);
0309 
0310     /* When buf_sz is small or buf tail is in another page */
0311     t = *end;
0312     if (wr)
0313         *end = t;
0314 
0315     return 0;
0316 }