18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * FPGA Manager Driver for Intel Stratix10 SoC 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2018 Intel Corporation 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/completion.h> 88c2ecf20Sopenharmony_ci#include <linux/fpga/fpga-mgr.h> 98c2ecf20Sopenharmony_ci#include <linux/firmware/intel/stratix10-svc-client.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/of.h> 128c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * FPGA programming requires a higher level of privilege (EL3), per the SoC 168c2ecf20Sopenharmony_ci * design. 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci#define NUM_SVC_BUFS 4 198c2ecf20Sopenharmony_ci#define SVC_BUF_SIZE SZ_512K 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* Indicates buffer is in use if set */ 228c2ecf20Sopenharmony_ci#define SVC_BUF_LOCK 0 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define S10_BUFFER_TIMEOUT (msecs_to_jiffies(SVC_RECONFIG_BUFFER_TIMEOUT_MS)) 258c2ecf20Sopenharmony_ci#define S10_RECONFIG_TIMEOUT (msecs_to_jiffies(SVC_RECONFIG_REQUEST_TIMEOUT_MS)) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * struct s10_svc_buf 298c2ecf20Sopenharmony_ci * buf: virtual address of buf provided by service layer 308c2ecf20Sopenharmony_ci * lock: locked if buffer is in use 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_cistruct s10_svc_buf { 338c2ecf20Sopenharmony_ci char *buf; 348c2ecf20Sopenharmony_ci unsigned long lock; 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistruct s10_priv { 388c2ecf20Sopenharmony_ci struct stratix10_svc_chan *chan; 398c2ecf20Sopenharmony_ci struct stratix10_svc_client client; 408c2ecf20Sopenharmony_ci struct completion status_return_completion; 418c2ecf20Sopenharmony_ci struct s10_svc_buf svc_bufs[NUM_SVC_BUFS]; 428c2ecf20Sopenharmony_ci unsigned long status; 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int s10_svc_send_msg(struct s10_priv *priv, 468c2ecf20Sopenharmony_ci enum stratix10_svc_command_code command, 478c2ecf20Sopenharmony_ci void *payload, u32 payload_length) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct stratix10_svc_chan *chan = priv->chan; 508c2ecf20Sopenharmony_ci struct device *dev = priv->client.dev; 518c2ecf20Sopenharmony_ci struct stratix10_svc_client_msg msg; 528c2ecf20Sopenharmony_ci int ret; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci dev_dbg(dev, "%s cmd=%d payload=%p length=%d\n", 558c2ecf20Sopenharmony_ci __func__, command, payload, payload_length); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci msg.command = command; 588c2ecf20Sopenharmony_ci msg.payload = payload; 598c2ecf20Sopenharmony_ci msg.payload_length = payload_length; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci ret = stratix10_svc_send(chan, &msg); 628c2ecf20Sopenharmony_ci dev_dbg(dev, "stratix10_svc_send returned status %d\n", ret); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return ret; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* 688c2ecf20Sopenharmony_ci * Free buffers allocated from the service layer's pool that are not in use. 698c2ecf20Sopenharmony_ci * Return true when all buffers are freed. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_cistatic bool s10_free_buffers(struct fpga_manager *mgr) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct s10_priv *priv = mgr->priv; 748c2ecf20Sopenharmony_ci uint num_free = 0; 758c2ecf20Sopenharmony_ci uint i; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci for (i = 0; i < NUM_SVC_BUFS; i++) { 788c2ecf20Sopenharmony_ci if (!priv->svc_bufs[i].buf) { 798c2ecf20Sopenharmony_ci num_free++; 808c2ecf20Sopenharmony_ci continue; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (!test_and_set_bit_lock(SVC_BUF_LOCK, 848c2ecf20Sopenharmony_ci &priv->svc_bufs[i].lock)) { 858c2ecf20Sopenharmony_ci stratix10_svc_free_memory(priv->chan, 868c2ecf20Sopenharmony_ci priv->svc_bufs[i].buf); 878c2ecf20Sopenharmony_ci priv->svc_bufs[i].buf = NULL; 888c2ecf20Sopenharmony_ci num_free++; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci return num_free == NUM_SVC_BUFS; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* 968c2ecf20Sopenharmony_ci * Returns count of how many buffers are not in use. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_cistatic uint s10_free_buffer_count(struct fpga_manager *mgr) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct s10_priv *priv = mgr->priv; 1018c2ecf20Sopenharmony_ci uint num_free = 0; 1028c2ecf20Sopenharmony_ci uint i; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci for (i = 0; i < NUM_SVC_BUFS; i++) 1058c2ecf20Sopenharmony_ci if (!priv->svc_bufs[i].buf) 1068c2ecf20Sopenharmony_ci num_free++; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return num_free; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* 1128c2ecf20Sopenharmony_ci * s10_unlock_bufs 1138c2ecf20Sopenharmony_ci * Given the returned buffer address, match that address to our buffer struct 1148c2ecf20Sopenharmony_ci * and unlock that buffer. This marks it as available to be refilled and sent 1158c2ecf20Sopenharmony_ci * (or freed). 1168c2ecf20Sopenharmony_ci * priv: private data 1178c2ecf20Sopenharmony_ci * kaddr: kernel address of buffer that was returned from service layer 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_cistatic void s10_unlock_bufs(struct s10_priv *priv, void *kaddr) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci uint i; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (!kaddr) 1248c2ecf20Sopenharmony_ci return; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci for (i = 0; i < NUM_SVC_BUFS; i++) 1278c2ecf20Sopenharmony_ci if (priv->svc_bufs[i].buf == kaddr) { 1288c2ecf20Sopenharmony_ci clear_bit_unlock(SVC_BUF_LOCK, 1298c2ecf20Sopenharmony_ci &priv->svc_bufs[i].lock); 1308c2ecf20Sopenharmony_ci return; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci WARN(1, "Unknown buffer returned from service layer %p\n", kaddr); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* 1378c2ecf20Sopenharmony_ci * s10_receive_callback - callback for service layer to use to provide client 1388c2ecf20Sopenharmony_ci * (this driver) messages received through the mailbox. 1398c2ecf20Sopenharmony_ci * client: service layer client struct 1408c2ecf20Sopenharmony_ci * data: message from service layer 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_cistatic void s10_receive_callback(struct stratix10_svc_client *client, 1438c2ecf20Sopenharmony_ci struct stratix10_svc_cb_data *data) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct s10_priv *priv = client->priv; 1468c2ecf20Sopenharmony_ci u32 status; 1478c2ecf20Sopenharmony_ci int i; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci WARN_ONCE(!data, "%s: stratix10_svc_rc_data = NULL", __func__); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci status = data->status; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* 1548c2ecf20Sopenharmony_ci * Here we set status bits as we receive them. Elsewhere, we always use 1558c2ecf20Sopenharmony_ci * test_and_clear_bit() to check status in priv->status 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci for (i = 0; i <= SVC_STATUS_ERROR; i++) 1588c2ecf20Sopenharmony_ci if (status & (1 << i)) 1598c2ecf20Sopenharmony_ci set_bit(i, &priv->status); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (status & BIT(SVC_STATUS_BUFFER_DONE)) { 1628c2ecf20Sopenharmony_ci s10_unlock_bufs(priv, data->kaddr1); 1638c2ecf20Sopenharmony_ci s10_unlock_bufs(priv, data->kaddr2); 1648c2ecf20Sopenharmony_ci s10_unlock_bufs(priv, data->kaddr3); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci complete(&priv->status_return_completion); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/* 1718c2ecf20Sopenharmony_ci * s10_ops_write_init - prepare for FPGA reconfiguration by requesting 1728c2ecf20Sopenharmony_ci * partial reconfig and allocating buffers from the service layer. 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_cistatic int s10_ops_write_init(struct fpga_manager *mgr, 1758c2ecf20Sopenharmony_ci struct fpga_image_info *info, 1768c2ecf20Sopenharmony_ci const char *buf, size_t count) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct s10_priv *priv = mgr->priv; 1798c2ecf20Sopenharmony_ci struct device *dev = priv->client.dev; 1808c2ecf20Sopenharmony_ci struct stratix10_svc_command_config_type ctype; 1818c2ecf20Sopenharmony_ci char *kbuf; 1828c2ecf20Sopenharmony_ci uint i; 1838c2ecf20Sopenharmony_ci int ret; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci ctype.flags = 0; 1868c2ecf20Sopenharmony_ci if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) { 1878c2ecf20Sopenharmony_ci dev_dbg(dev, "Requesting partial reconfiguration.\n"); 1888c2ecf20Sopenharmony_ci ctype.flags |= BIT(COMMAND_RECONFIG_FLAG_PARTIAL); 1898c2ecf20Sopenharmony_ci } else { 1908c2ecf20Sopenharmony_ci dev_dbg(dev, "Requesting full reconfiguration.\n"); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci reinit_completion(&priv->status_return_completion); 1948c2ecf20Sopenharmony_ci ret = s10_svc_send_msg(priv, COMMAND_RECONFIG, 1958c2ecf20Sopenharmony_ci &ctype, sizeof(ctype)); 1968c2ecf20Sopenharmony_ci if (ret < 0) 1978c2ecf20Sopenharmony_ci goto init_done; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci ret = wait_for_completion_timeout( 2008c2ecf20Sopenharmony_ci &priv->status_return_completion, S10_RECONFIG_TIMEOUT); 2018c2ecf20Sopenharmony_ci if (!ret) { 2028c2ecf20Sopenharmony_ci dev_err(dev, "timeout waiting for RECONFIG_REQUEST\n"); 2038c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 2048c2ecf20Sopenharmony_ci goto init_done; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ret = 0; 2088c2ecf20Sopenharmony_ci if (!test_and_clear_bit(SVC_STATUS_OK, &priv->status)) { 2098c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 2108c2ecf20Sopenharmony_ci goto init_done; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* Allocate buffers from the service layer's pool. */ 2148c2ecf20Sopenharmony_ci for (i = 0; i < NUM_SVC_BUFS; i++) { 2158c2ecf20Sopenharmony_ci kbuf = stratix10_svc_allocate_memory(priv->chan, SVC_BUF_SIZE); 2168c2ecf20Sopenharmony_ci if (IS_ERR(kbuf)) { 2178c2ecf20Sopenharmony_ci s10_free_buffers(mgr); 2188c2ecf20Sopenharmony_ci ret = PTR_ERR(kbuf); 2198c2ecf20Sopenharmony_ci goto init_done; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci priv->svc_bufs[i].buf = kbuf; 2238c2ecf20Sopenharmony_ci priv->svc_bufs[i].lock = 0; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ciinit_done: 2278c2ecf20Sopenharmony_ci stratix10_svc_done(priv->chan); 2288c2ecf20Sopenharmony_ci return ret; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/* 2328c2ecf20Sopenharmony_ci * s10_send_buf - send a buffer to the service layer queue 2338c2ecf20Sopenharmony_ci * mgr: fpga manager struct 2348c2ecf20Sopenharmony_ci * buf: fpga image buffer 2358c2ecf20Sopenharmony_ci * count: size of buf in bytes 2368c2ecf20Sopenharmony_ci * Returns # of bytes transferred or -ENOBUFS if the all the buffers are in use 2378c2ecf20Sopenharmony_ci * or if the service queue is full. Never returns 0. 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_cistatic int s10_send_buf(struct fpga_manager *mgr, const char *buf, size_t count) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct s10_priv *priv = mgr->priv; 2428c2ecf20Sopenharmony_ci struct device *dev = priv->client.dev; 2438c2ecf20Sopenharmony_ci void *svc_buf; 2448c2ecf20Sopenharmony_ci size_t xfer_sz; 2458c2ecf20Sopenharmony_ci int ret; 2468c2ecf20Sopenharmony_ci uint i; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* get/lock a buffer that that's not being used */ 2498c2ecf20Sopenharmony_ci for (i = 0; i < NUM_SVC_BUFS; i++) 2508c2ecf20Sopenharmony_ci if (!test_and_set_bit_lock(SVC_BUF_LOCK, 2518c2ecf20Sopenharmony_ci &priv->svc_bufs[i].lock)) 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (i == NUM_SVC_BUFS) 2558c2ecf20Sopenharmony_ci return -ENOBUFS; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci xfer_sz = count < SVC_BUF_SIZE ? count : SVC_BUF_SIZE; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci svc_buf = priv->svc_bufs[i].buf; 2608c2ecf20Sopenharmony_ci memcpy(svc_buf, buf, xfer_sz); 2618c2ecf20Sopenharmony_ci ret = s10_svc_send_msg(priv, COMMAND_RECONFIG_DATA_SUBMIT, 2628c2ecf20Sopenharmony_ci svc_buf, xfer_sz); 2638c2ecf20Sopenharmony_ci if (ret < 0) { 2648c2ecf20Sopenharmony_ci dev_err(dev, 2658c2ecf20Sopenharmony_ci "Error while sending data to service layer (%d)", ret); 2668c2ecf20Sopenharmony_ci clear_bit_unlock(SVC_BUF_LOCK, &priv->svc_bufs[i].lock); 2678c2ecf20Sopenharmony_ci return ret; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return xfer_sz; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci/* 2748c2ecf20Sopenharmony_ci * Send a FPGA image to privileged layers to write to the FPGA. When done 2758c2ecf20Sopenharmony_ci * sending, free all service layer buffers we allocated in write_init. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_cistatic int s10_ops_write(struct fpga_manager *mgr, const char *buf, 2788c2ecf20Sopenharmony_ci size_t count) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct s10_priv *priv = mgr->priv; 2818c2ecf20Sopenharmony_ci struct device *dev = priv->client.dev; 2828c2ecf20Sopenharmony_ci long wait_status; 2838c2ecf20Sopenharmony_ci int sent = 0; 2848c2ecf20Sopenharmony_ci int ret = 0; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* 2878c2ecf20Sopenharmony_ci * Loop waiting for buffers to be returned. When a buffer is returned, 2888c2ecf20Sopenharmony_ci * reuse it to send more data or free if if all data has been sent. 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ci while (count > 0 || s10_free_buffer_count(mgr) != NUM_SVC_BUFS) { 2918c2ecf20Sopenharmony_ci reinit_completion(&priv->status_return_completion); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (count > 0) { 2948c2ecf20Sopenharmony_ci sent = s10_send_buf(mgr, buf, count); 2958c2ecf20Sopenharmony_ci if (sent < 0) 2968c2ecf20Sopenharmony_ci continue; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci count -= sent; 2998c2ecf20Sopenharmony_ci buf += sent; 3008c2ecf20Sopenharmony_ci } else { 3018c2ecf20Sopenharmony_ci if (s10_free_buffers(mgr)) 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci ret = s10_svc_send_msg( 3058c2ecf20Sopenharmony_ci priv, COMMAND_RECONFIG_DATA_CLAIM, 3068c2ecf20Sopenharmony_ci NULL, 0); 3078c2ecf20Sopenharmony_ci if (ret < 0) 3088c2ecf20Sopenharmony_ci break; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* 3128c2ecf20Sopenharmony_ci * If callback hasn't already happened, wait for buffers to be 3138c2ecf20Sopenharmony_ci * returned from service layer 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci wait_status = 1; /* not timed out */ 3168c2ecf20Sopenharmony_ci if (!priv->status) 3178c2ecf20Sopenharmony_ci wait_status = wait_for_completion_timeout( 3188c2ecf20Sopenharmony_ci &priv->status_return_completion, 3198c2ecf20Sopenharmony_ci S10_BUFFER_TIMEOUT); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (test_and_clear_bit(SVC_STATUS_BUFFER_DONE, &priv->status) || 3228c2ecf20Sopenharmony_ci test_and_clear_bit(SVC_STATUS_BUFFER_SUBMITTED, 3238c2ecf20Sopenharmony_ci &priv->status)) { 3248c2ecf20Sopenharmony_ci ret = 0; 3258c2ecf20Sopenharmony_ci continue; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (test_and_clear_bit(SVC_STATUS_ERROR, &priv->status)) { 3298c2ecf20Sopenharmony_ci dev_err(dev, "ERROR - giving up - SVC_STATUS_ERROR\n"); 3308c2ecf20Sopenharmony_ci ret = -EFAULT; 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (!wait_status) { 3358c2ecf20Sopenharmony_ci dev_err(dev, "timeout waiting for svc layer buffers\n"); 3368c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 3378c2ecf20Sopenharmony_ci break; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (!s10_free_buffers(mgr)) 3428c2ecf20Sopenharmony_ci dev_err(dev, "%s not all buffers were freed\n", __func__); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci return ret; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int s10_ops_write_complete(struct fpga_manager *mgr, 3488c2ecf20Sopenharmony_ci struct fpga_image_info *info) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct s10_priv *priv = mgr->priv; 3518c2ecf20Sopenharmony_ci struct device *dev = priv->client.dev; 3528c2ecf20Sopenharmony_ci unsigned long timeout; 3538c2ecf20Sopenharmony_ci int ret; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci timeout = usecs_to_jiffies(info->config_complete_timeout_us); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci do { 3588c2ecf20Sopenharmony_ci reinit_completion(&priv->status_return_completion); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci ret = s10_svc_send_msg(priv, COMMAND_RECONFIG_STATUS, NULL, 0); 3618c2ecf20Sopenharmony_ci if (ret < 0) 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci ret = wait_for_completion_timeout( 3658c2ecf20Sopenharmony_ci &priv->status_return_completion, timeout); 3668c2ecf20Sopenharmony_ci if (!ret) { 3678c2ecf20Sopenharmony_ci dev_err(dev, 3688c2ecf20Sopenharmony_ci "timeout waiting for RECONFIG_COMPLETED\n"); 3698c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 3708c2ecf20Sopenharmony_ci break; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci /* Not error or timeout, so ret is # of jiffies until timeout */ 3738c2ecf20Sopenharmony_ci timeout = ret; 3748c2ecf20Sopenharmony_ci ret = 0; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (test_and_clear_bit(SVC_STATUS_COMPLETED, &priv->status)) 3778c2ecf20Sopenharmony_ci break; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (test_and_clear_bit(SVC_STATUS_ERROR, &priv->status)) { 3808c2ecf20Sopenharmony_ci dev_err(dev, "ERROR - giving up - SVC_STATUS_ERROR\n"); 3818c2ecf20Sopenharmony_ci ret = -EFAULT; 3828c2ecf20Sopenharmony_ci break; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci } while (1); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci stratix10_svc_done(priv->chan); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci return ret; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic enum fpga_mgr_states s10_ops_state(struct fpga_manager *mgr) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci return FPGA_MGR_STATE_UNKNOWN; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic const struct fpga_manager_ops s10_ops = { 3978c2ecf20Sopenharmony_ci .state = s10_ops_state, 3988c2ecf20Sopenharmony_ci .write_init = s10_ops_write_init, 3998c2ecf20Sopenharmony_ci .write = s10_ops_write, 4008c2ecf20Sopenharmony_ci .write_complete = s10_ops_write_complete, 4018c2ecf20Sopenharmony_ci}; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic int s10_probe(struct platform_device *pdev) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 4068c2ecf20Sopenharmony_ci struct s10_priv *priv; 4078c2ecf20Sopenharmony_ci struct fpga_manager *mgr; 4088c2ecf20Sopenharmony_ci int ret; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 4118c2ecf20Sopenharmony_ci if (!priv) 4128c2ecf20Sopenharmony_ci return -ENOMEM; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci priv->client.dev = dev; 4158c2ecf20Sopenharmony_ci priv->client.receive_cb = s10_receive_callback; 4168c2ecf20Sopenharmony_ci priv->client.priv = priv; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci priv->chan = stratix10_svc_request_channel_byname(&priv->client, 4198c2ecf20Sopenharmony_ci SVC_CLIENT_FPGA); 4208c2ecf20Sopenharmony_ci if (IS_ERR(priv->chan)) { 4218c2ecf20Sopenharmony_ci dev_err(dev, "couldn't get service channel (%s)\n", 4228c2ecf20Sopenharmony_ci SVC_CLIENT_FPGA); 4238c2ecf20Sopenharmony_ci return PTR_ERR(priv->chan); 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci init_completion(&priv->status_return_completion); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci mgr = fpga_mgr_create(dev, "Stratix10 SOC FPGA Manager", 4298c2ecf20Sopenharmony_ci &s10_ops, priv); 4308c2ecf20Sopenharmony_ci if (!mgr) { 4318c2ecf20Sopenharmony_ci dev_err(dev, "unable to create FPGA manager\n"); 4328c2ecf20Sopenharmony_ci ret = -ENOMEM; 4338c2ecf20Sopenharmony_ci goto probe_err; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci ret = fpga_mgr_register(mgr); 4378c2ecf20Sopenharmony_ci if (ret) { 4388c2ecf20Sopenharmony_ci dev_err(dev, "unable to register FPGA manager\n"); 4398c2ecf20Sopenharmony_ci fpga_mgr_free(mgr); 4408c2ecf20Sopenharmony_ci goto probe_err; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, mgr); 4448c2ecf20Sopenharmony_ci return ret; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ciprobe_err: 4478c2ecf20Sopenharmony_ci stratix10_svc_free_channel(priv->chan); 4488c2ecf20Sopenharmony_ci return ret; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic int s10_remove(struct platform_device *pdev) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct fpga_manager *mgr = platform_get_drvdata(pdev); 4548c2ecf20Sopenharmony_ci struct s10_priv *priv = mgr->priv; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci fpga_mgr_unregister(mgr); 4578c2ecf20Sopenharmony_ci fpga_mgr_free(mgr); 4588c2ecf20Sopenharmony_ci stratix10_svc_free_channel(priv->chan); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return 0; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic const struct of_device_id s10_of_match[] = { 4648c2ecf20Sopenharmony_ci {.compatible = "intel,stratix10-soc-fpga-mgr"}, 4658c2ecf20Sopenharmony_ci {.compatible = "intel,agilex-soc-fpga-mgr"}, 4668c2ecf20Sopenharmony_ci {}, 4678c2ecf20Sopenharmony_ci}; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, s10_of_match); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic struct platform_driver s10_driver = { 4728c2ecf20Sopenharmony_ci .probe = s10_probe, 4738c2ecf20Sopenharmony_ci .remove = s10_remove, 4748c2ecf20Sopenharmony_ci .driver = { 4758c2ecf20Sopenharmony_ci .name = "Stratix10 SoC FPGA manager", 4768c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(s10_of_match), 4778c2ecf20Sopenharmony_ci }, 4788c2ecf20Sopenharmony_ci}; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic int __init s10_init(void) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct device_node *fw_np; 4838c2ecf20Sopenharmony_ci struct device_node *np; 4848c2ecf20Sopenharmony_ci int ret; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci fw_np = of_find_node_by_name(NULL, "svc"); 4878c2ecf20Sopenharmony_ci if (!fw_np) 4888c2ecf20Sopenharmony_ci return -ENODEV; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci of_node_get(fw_np); 4918c2ecf20Sopenharmony_ci np = of_find_matching_node(fw_np, s10_of_match); 4928c2ecf20Sopenharmony_ci if (!np) { 4938c2ecf20Sopenharmony_ci of_node_put(fw_np); 4948c2ecf20Sopenharmony_ci return -ENODEV; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci of_node_put(np); 4988c2ecf20Sopenharmony_ci ret = of_platform_populate(fw_np, s10_of_match, NULL, NULL); 4998c2ecf20Sopenharmony_ci of_node_put(fw_np); 5008c2ecf20Sopenharmony_ci if (ret) 5018c2ecf20Sopenharmony_ci return ret; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci return platform_driver_register(&s10_driver); 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic void __exit s10_exit(void) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci return platform_driver_unregister(&s10_driver); 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cimodule_init(s10_init); 5128c2ecf20Sopenharmony_cimodule_exit(s10_exit); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alan Tull <atull@kernel.org>"); 5158c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel Stratix 10 SOC FPGA Manager"); 5168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 517