+
+ priv = container_of(file->private_data, struct intel_fcs_priv, miscdev);
+ dev = priv->client.dev;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ msg = devm_kzalloc(dev, sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ switch (cmd) {
+ case INTEL_FCS_DEV_VALIDATION_REQUEST:
+ if (copy_from_user(data, (void __user *)arg, sizeof(*data))) {
+ dev_err(dev, "failure on copy_from_user\n");
+ return -EFAULT;
+ }
+
+ /* for bitstream */
+ dev_dbg(dev, "file_name=%s, status=%d\n",
+ (char *)data->com_paras.s_request.src, data->status);
+ scnprintf(filename, FILE_NAME_SIZE, "%s",
+ (char *)data->com_paras.s_request.src);
+ ret = request_firmware(&fw, filename, priv->client.dev);
+ if (ret) {
+ dev_err(dev, "error requesting firmware %s\n",
+ (char *)data->com_paras.s_request.src);
+ return -EFAULT;
+ }
+
+ dev_dbg(dev, "FW size=%ld\n", fw->size);
+ s_buf = stratix10_svc_allocate_memory(priv->chan, fw->size);
+ if (!s_buf) {
+ dev_err(dev, "failed to allocate VAB buffer\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ memcpy(s_buf, fw->data, fw->size);
+
+ msg->payload_length = fw->size;
+ release_firmware(fw);
+
+ msg->command = COMMAND_FCS_REQUEST_SERVICE;
+ msg->payload = s_buf;
+ priv->client.receive_cb = fcs_vab_callback;
+
+ ret = fcs_request_service(priv, (void *)msg,
+ FCS_REQUEST_TIMEOUT);
+ dev_dbg(dev, "fcs_request_service ret=%d\n", ret);
+ if (!ret && !priv->status) {
+ /* to query the complete status */
+ msg->command = COMMAND_POLL_SERVICE_STATUS;
+ priv->client.receive_cb = fcs_data_callback;
+ ret = fcs_request_service(priv, (void *)msg,
+ FCS_COMPLETED_TIMEOUT);
+ dev_dbg(dev, "fcs_request_service ret=%d\n", ret);
+ if (!ret && !priv->status)
+ data->status = 0;
+ else
+ data->status = priv->status;
+ } else
+ data->status = priv->status;
+
+ if (copy_to_user((void __user *)arg, data, sizeof(*data))) {
+ dev_err(dev, "failure on copy_to_user\n");
+ fcs_close_services(priv, s_buf, NULL);
+ ret = -EFAULT;
+ }
+
+ fcs_close_services(priv, s_buf, NULL);
+ break;
+
+ case INTEL_FCS_DEV_SEND_CERTIFICATE:
+ if (copy_from_user(data, (void __user *)arg, sizeof(*data))) {
+ dev_err(dev, "failure on copy_from_user\n");
+ return -EFAULT;
+ }
+
+ dev_dbg(dev, "Test=%d, Size=%d; Address=0x%p\n",
+ data->com_paras.c_request.test.test_bit,
+ data->com_paras.c_request.size,
+ data->com_paras.c_request.addr);
+
+ /* Allocate memory for certificate + test word */
+ tsz = sizeof(struct intel_fcs_cert_test_word);
+ datasz = data->com_paras.s_request.size + tsz;
+
+ s_buf = stratix10_svc_allocate_memory(priv->chan, datasz);
+ if (!s_buf) {
+ dev_err(dev, "failed to allocate VAB buffer\n");
+ return -ENOMEM;
+ }
+
+ ps_buf = stratix10_svc_allocate_memory(priv->chan, PS_BUF_SIZE);
+ if (!ps_buf) {
+ dev_err(dev, "failed to allocate p-status buf\n");
+ stratix10_svc_free_memory(priv->chan, s_buf);
+ return -ENOMEM;
+ }
+
+ /* Copy the test word */
+ memcpy(s_buf, &data->com_paras.c_request.test, tsz);
+
+ /* Copy in the certificate data (skipping over the test word) */
+ ret = copy_from_user(s_buf + tsz,
+ data->com_paras.c_request.addr,
+ data->com_paras.s_request.size);
+ if (ret) {
+ dev_err(dev, "failed copy buf ret=%d\n", ret);
+ fcs_close_services(priv, s_buf, ps_buf);
+ return -EFAULT;
+ }
+
+ msg->payload_length = datasz;
+ msg->command = COMMAND_FCS_SEND_CERTIFICATE;
+ msg->payload = s_buf;
+ priv->client.receive_cb = fcs_vab_callback;
+
+ ret = fcs_request_service(priv, (void *)msg,
+ FCS_REQUEST_TIMEOUT);
+ dev_dbg(dev, "fcs_request_service ret=%d\n", ret);
+ if (!ret && !priv->status) {
+ /* to query the complete status */
+ msg->payload = ps_buf;
+ msg->payload_length = PS_BUF_SIZE;
+ msg->command = COMMAND_POLL_SERVICE_STATUS;
+ priv->client.receive_cb = fcs_data_callback;
+ ret = fcs_request_service(priv, (void *)msg,
+ FCS_COMPLETED_TIMEOUT);
+ dev_dbg(dev, "request service ret=%d\n", ret);
+ if (!ret && !priv->status)
+ data->status = 0;
+ else {
+ if (priv->kbuf)
+ data->com_paras.c_request.c_status =
+ (*(u32 *)priv->kbuf);
+ else
+ data->com_paras.c_request.c_status =
+ INVALID_STATUS;
+ }
+ } else
+ data->status = priv->status;
+
+ if (copy_to_user((void __user *)arg, data, sizeof(*data))) {
+ dev_err(dev, "failure on copy_to_user\n");
+ fcs_close_services(priv, s_buf, NULL);
+ ret = -EFAULT;
+ }
+
+ fcs_close_services(priv, s_buf, ps_buf);
+ break;
+
+ case INTEL_FCS_DEV_RANDOM_NUMBER_GEN:
+ if (copy_from_user(data, (void __user *)arg, sizeof(*data))) {
+ dev_err(dev, "failure on copy_from_user\n");
+ return -EFAULT;
+ }
+
+ s_buf = stratix10_svc_allocate_memory(priv->chan,
+ RANDOM_NUMBER_SIZE);
+ if (!s_buf) {
+ dev_err(dev, "failed to allocate RNG buffer\n");
+ return -ENOMEM;
+ }
+
+ msg->command = COMMAND_FCS_RANDOM_NUMBER_GEN;
+ msg->payload = s_buf;
+ msg->payload_length = RANDOM_NUMBER_SIZE;
+ priv->client.receive_cb = fcs_data_callback;
+
+ ret = fcs_request_service(priv, (void *)msg,
+ FCS_REQUEST_TIMEOUT);
+
+ if (!ret && !priv->status) {
+ if (!priv->kbuf) {
+ dev_err(dev, "failure on kbuf\n");
+ fcs_close_services(priv, s_buf, NULL);
+ return -EFAULT;
+ }
+
+ for (i = 0; i < 8; i++)
+ dev_dbg(dev, "output_data[%d]=%d\n", i,
+ *((int *)priv->kbuf + i));
+
+ for (i = 0; i < 8; i++)
+ data->com_paras.rn_gen.rndm[i] =
+ *((int *)priv->kbuf + i);
+ data->status = priv->status;
+
+ } else {
+ /* failed to get RNG */
+ data->status = priv->status;
+ }
+
+ if (copy_to_user((void __user *)arg, data, sizeof(*data))) {
+ dev_err(dev, "failure on copy_to_user\n");
+ fcs_close_services(priv, s_buf, NULL);
+ ret = -EFAULT;
+ }
+
+ fcs_close_services(priv, s_buf, NULL);
+ break;
+ case INTEL_FCS_DEV_GET_PROVISION_DATA:
+ if (copy_from_user(data, (void __user *)arg,
+ sizeof(*data))) {
+ dev_err(dev, "failure on copy_from_user\n");
+ return -EFAULT;
+ }
+
+ s_buf = stratix10_svc_allocate_memory(priv->chan,
+ data->com_paras.gp_data.size);
+ if (!s_buf) {
+ dev_err(dev, "failed allocate provision buffer\n");
+ return -ENOMEM;
+ }
+
+ msg->command = COMMAND_FCS_GET_PROVISION_DATA;
+ msg->payload = s_buf;
+ msg->payload_length = data->com_paras.gp_data.size;
+ priv->client.receive_cb = fcs_data_callback;
+
+ ret = fcs_request_service(priv, (void *)msg,
+ FCS_REQUEST_TIMEOUT);
+ if (!ret && !priv->status) {
+ if (!priv->kbuf) {
+ dev_err(dev, "failure on kbuf\n");
+ fcs_close_services(priv, s_buf, NULL);
+ return -EFAULT;
+ }
+ data->com_paras.gp_data.size = priv->size;
+ memcpy(data->com_paras.gp_data.addr, priv->kbuf,
+ priv->size);
+ data->status = 0;
+ } else {
+ data->com_paras.gp_data.addr = NULL;
+ data->com_paras.gp_data.size = 0;
+ data->status = priv->status;
+ }
+
+ if (copy_to_user((void __user *)arg, data, sizeof(*data))) {
+ dev_err(dev, "failure on copy_to_user\n");
+ fcs_close_services(priv, s_buf, NULL);
+ return -EFAULT;
+ }
+
+ fcs_close_services(priv, s_buf, NULL);
+ break;
+ case INTEL_FCS_DEV_DATA_ENCRYPTION:
+ if (copy_from_user(data, (void __user *)arg, sizeof(*data))) {
+ dev_err(dev, "failure on copy_from_user\n");
+ return -EFAULT;
+ }
+
+ if ((data->com_paras.d_encryption.src_size < MIN_SDOS_BUF_SZ) ||
+ (data->com_paras.d_encryption.src_size > MAX_SDOS_BUF_SZ)) {
+ dev_err(dev, "Invalid SDOS Buffer src size:%d\n",
+ data->com_paras.d_encryption.src_size);
+ return -EFAULT;
+ }
+
+ if ((data->com_paras.d_encryption.dst_size < MIN_SDOS_BUF_SZ) ||
+ (data->com_paras.d_encryption.dst_size > MAX_SDOS_BUF_SZ)) {
+ dev_err(dev, "Invalid SDOS Buffer dst size:%d\n",
+ data->com_paras.d_encryption.dst_size);
+ return -EFAULT;
+ }
+
+ /* allocate buffer for both source and destination */
+ s_buf = stratix10_svc_allocate_memory(priv->chan,
+ MAX_SDOS_BUF_SZ);
+ if (!s_buf) {
+ dev_err(dev, "failed allocate encrypt src buf\n");
+ return -ENOMEM;
+ }
+ d_buf = stratix10_svc_allocate_memory(priv->chan,
+ MAX_SDOS_BUF_SZ);
+ if (!d_buf) {
+ dev_err(dev, "failed allocate encrypt dst buf\n");
+ stratix10_svc_free_memory(priv->chan, s_buf);
+ return -ENOMEM;
+ }
+ ps_buf = stratix10_svc_allocate_memory(priv->chan, PS_BUF_SIZE);
+ if (!ps_buf) {
+ dev_err(dev, "failed allocate p-status buffer\n");
+ fcs_close_services(priv, s_buf, d_buf);
+ return -ENOMEM;
+ }
+ ret = copy_from_user(s_buf,
+ data->com_paras.d_encryption.src,
+ data->com_paras.d_encryption.src_size);
+ if (ret) {
+ dev_err(dev, "failure on copy_from_user\n");
+ fcs_close_services(priv, ps_buf, NULL);
+ fcs_close_services(priv, s_buf, d_buf);
+ return -ENOMEM;
+ }
+
+ msg->command = COMMAND_FCS_DATA_ENCRYPTION;
+ msg->payload = s_buf;
+ msg->payload_length =
+ data->com_paras.d_encryption.src_size;
+ msg->payload_output = d_buf;
+ msg->payload_length_output =
+ data->com_paras.d_encryption.dst_size;
+ priv->client.receive_cb = fcs_vab_callback;
+
+ ret = fcs_request_service(priv, (void *)msg,
+ FCS_REQUEST_TIMEOUT);
+ if (!ret && !priv->status) {
+ msg->payload = ps_buf;
+ msg->payload_length = PS_BUF_SIZE;
+ msg->command = COMMAND_POLL_SERVICE_STATUS;
+
+ priv->client.receive_cb = fcs_data_callback;
+ ret = fcs_request_service(priv, (void *)msg,
+ FCS_COMPLETED_TIMEOUT);
+ dev_dbg(dev, "request service ret=%d\n", ret);
+
+ if (!ret && !priv->status) {
+ if (!priv->kbuf) {
+ dev_err(dev, "failure on kbuf\n");
+ fcs_close_services(priv, ps_buf, NULL);
+ fcs_close_services(priv, s_buf, d_buf);
+ return -EFAULT;
+ }
+ buf_sz = *(unsigned int *)priv->kbuf;
+ data->com_paras.d_encryption.dst_size = buf_sz;
+ memcpy(data->com_paras.d_encryption.dst,
+ d_buf, buf_sz);
+ data->status = 0;
+ } else {
+ data->com_paras.d_encryption.dst = NULL;
+ data->com_paras.d_encryption.dst_size = 0;
+ data->status = priv->status;
+ }
+ } else {
+ data->com_paras.d_encryption.dst = NULL;
+ data->com_paras.d_encryption.dst_size = 0;
+ data->status = priv->status;
+ }
+
+ if (copy_to_user((void __user *)arg, data, sizeof(*data))) {
+ dev_err(dev, "failure on copy_to_user\n");
+ fcs_close_services(priv, ps_buf, NULL);
+ fcs_close_services(priv, s_buf, d_buf);
+ ret = -EFAULT;
+ }
+
+ fcs_close_services(priv, ps_buf, NULL);
+ fcs_close_services(priv, s_buf, d_buf);
+ break;
+ case INTEL_FCS_DEV_DATA_DECRYPTION:
+ if (copy_from_user(data, (void __user *)arg, sizeof(*data))) {
+ dev_err(dev, "failure on copy_from_user\n");
+ return -EFAULT;
+ }
+
+ if ((data->com_paras.d_encryption.src_size < MIN_SDOS_BUF_SZ) ||
+ (data->com_paras.d_encryption.src_size > MAX_SDOS_BUF_SZ)) {
+ dev_err(dev, "Invalid SDOS Buffer src size:%d\n",
+ data->com_paras.d_encryption.src_size);
+ return -EFAULT;
+ }
+
+ if ((data->com_paras.d_encryption.dst_size < MIN_SDOS_BUF_SZ) ||
+ (data->com_paras.d_encryption.dst_size > MAX_SDOS_BUF_SZ)) {
+ dev_err(dev, "Invalid SDOS Buffer dst size:%d\n",
+ data->com_paras.d_encryption.dst_size);
+ return -EFAULT;
+ }
+
+ /* allocate buffer for both source and destination */
+ s_buf = stratix10_svc_allocate_memory(priv->chan,
+ MAX_SDOS_BUF_SZ);
+ if (!s_buf) {
+ dev_err(dev, "failed allocate decrypt src buf\n");
+ return -ENOMEM;
+ }
+ d_buf = stratix10_svc_allocate_memory(priv->chan,
+ MAX_SDOS_BUF_SZ);
+ if (!d_buf) {
+ dev_err(dev, "failed allocate decrypt dst buf\n");
+ stratix10_svc_free_memory(priv->chan, s_buf);
+ return -ENOMEM;
+ }
+
+ ps_buf = stratix10_svc_allocate_memory(priv->chan,
+ PS_BUF_SIZE);
+ if (!ps_buf) {
+ dev_err(dev, "failed allocate p-status buffer\n");
+ fcs_close_services(priv, s_buf, d_buf);
+ return -ENOMEM;
+ }
+
+ ret = copy_from_user(s_buf,
+ data->com_paras.d_decryption.src,
+ data->com_paras.d_decryption.src_size);
+ if (ret) {
+ dev_err(dev, "failure on copy_from_user\n");
+ fcs_close_services(priv, ps_buf, NULL);
+ fcs_close_services(priv, s_buf, d_buf);
+ return -EFAULT;
+ }
+
+ msg->command = COMMAND_FCS_DATA_DECRYPTION;
+ msg->payload = s_buf;
+ msg->payload_length =
+ data->com_paras.d_decryption.src_size;
+ msg->payload_output = d_buf;
+ msg->payload_length_output =
+ data->com_paras.d_decryption.dst_size;
+ priv->client.receive_cb = fcs_vab_callback;
+
+ ret = fcs_request_service(priv, (void *)msg,
+ FCS_REQUEST_TIMEOUT);
+ if (!ret && !priv->status) {
+ msg->command = COMMAND_POLL_SERVICE_STATUS;
+ msg->payload = ps_buf;
+ msg->payload_length = PS_BUF_SIZE;
+ priv->client.receive_cb = fcs_data_callback;
+ ret = fcs_request_service(priv, (void *)msg,
+ FCS_COMPLETED_TIMEOUT);
+ dev_dbg(dev, "request service ret=%d\n", ret);
+ if (!ret && !priv->status) {
+ if (!priv->kbuf) {
+ dev_err(dev, "failure on kbuf\n");
+ fcs_close_services(priv, ps_buf, NULL);
+ fcs_close_services(priv, s_buf, d_buf);
+ return -EFAULT;
+ }
+ buf_sz = *((unsigned int *)priv->kbuf);
+ memcpy(data->com_paras.d_decryption.dst,
+ d_buf, buf_sz);
+ data->com_paras.d_decryption.dst_size = buf_sz;
+ data->status = 0;
+ } else {
+ data->com_paras.d_decryption.dst = NULL;
+ data->com_paras.d_decryption.dst_size = 0;
+ data->status = priv->status;
+ }
+ } else {
+ data->com_paras.d_decryption.dst = NULL;
+ data->com_paras.d_decryption.dst_size = 0;
+ data->status = priv->status;
+ }
+
+ if (copy_to_user((void __user *)arg, data, sizeof(*data))) {
+ dev_err(dev, "failure on copy_to_user\n");
+ fcs_close_services(priv, ps_buf, NULL);
+ fcs_close_services(priv, s_buf, d_buf);
+ ret = -EFAULT;
+ }
+
+ fcs_close_services(priv, ps_buf, NULL);
+ fcs_close_services(priv, s_buf, d_buf);
+ break;
+ default:
+ dev_warn(dev, "shouldn't be here [0x%x]\n", cmd);
+ break;
+ }
+
+ return ret;
+}
+
+static int fcs_open(struct inode *inode, struct file *file)
+{
+ pr_debug("%s\n", __func__);
+
+ return 0;
+}
+
+static int fcs_close(struct inode *inode, struct file *file)
+{
+
+ pr_debug("%s\n", __func__);
+
+ return 0;
+}