1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2023 Advanced Micro Devices, Inc */
3
4 #include <linux/errno.h>
5 #include <linux/pci.h>
6 #include <linux/utsname.h>
7
8 #include "core.h"
9
pdsc_err_to_errno(enum pds_core_status_code code)10 int pdsc_err_to_errno(enum pds_core_status_code code)
11 {
12 switch (code) {
13 case PDS_RC_SUCCESS:
14 return 0;
15 case PDS_RC_EVERSION:
16 case PDS_RC_EQTYPE:
17 case PDS_RC_EQID:
18 case PDS_RC_EINVAL:
19 case PDS_RC_ENOSUPP:
20 return -EINVAL;
21 case PDS_RC_EPERM:
22 return -EPERM;
23 case PDS_RC_ENOENT:
24 return -ENOENT;
25 case PDS_RC_EAGAIN:
26 return -EAGAIN;
27 case PDS_RC_ENOMEM:
28 return -ENOMEM;
29 case PDS_RC_EFAULT:
30 return -EFAULT;
31 case PDS_RC_EBUSY:
32 return -EBUSY;
33 case PDS_RC_EEXIST:
34 return -EEXIST;
35 case PDS_RC_EVFID:
36 return -ENODEV;
37 case PDS_RC_ECLIENT:
38 return -ECHILD;
39 case PDS_RC_ENOSPC:
40 return -ENOSPC;
41 case PDS_RC_ERANGE:
42 return -ERANGE;
43 case PDS_RC_BAD_ADDR:
44 return -EFAULT;
45 case PDS_RC_BAD_PCI:
46 return -ENXIO;
47 case PDS_RC_EOPCODE:
48 case PDS_RC_EINTR:
49 case PDS_RC_DEV_CMD:
50 case PDS_RC_ERROR:
51 case PDS_RC_ERDMA:
52 case PDS_RC_EIO:
53 default:
54 return -EIO;
55 }
56 }
57
pdsc_is_fw_running(struct pdsc * pdsc)58 bool pdsc_is_fw_running(struct pdsc *pdsc)
59 {
60 if (!pdsc->info_regs)
61 return false;
62
63 pdsc->fw_status = ioread8(&pdsc->info_regs->fw_status);
64 pdsc->last_fw_time = jiffies;
65 pdsc->last_hb = ioread32(&pdsc->info_regs->fw_heartbeat);
66
67 /* Firmware is useful only if the running bit is set and
68 * fw_status != 0xff (bad PCI read)
69 */
70 return (pdsc->fw_status != PDS_RC_BAD_PCI) &&
71 (pdsc->fw_status & PDS_CORE_FW_STS_F_RUNNING);
72 }
73
pdsc_is_fw_good(struct pdsc * pdsc)74 bool pdsc_is_fw_good(struct pdsc *pdsc)
75 {
76 bool fw_running = pdsc_is_fw_running(pdsc);
77 u8 gen;
78
79 /* Make sure to update the cached fw_status by calling
80 * pdsc_is_fw_running() before getting the generation
81 */
82 gen = pdsc->fw_status & PDS_CORE_FW_STS_F_GENERATION;
83
84 return fw_running && gen == pdsc->fw_generation;
85 }
86
pdsc_devcmd_status(struct pdsc * pdsc)87 static u8 pdsc_devcmd_status(struct pdsc *pdsc)
88 {
89 return ioread8(&pdsc->cmd_regs->comp.status);
90 }
91
pdsc_devcmd_done(struct pdsc * pdsc)92 static bool pdsc_devcmd_done(struct pdsc *pdsc)
93 {
94 return ioread32(&pdsc->cmd_regs->done) & PDS_CORE_DEV_CMD_DONE;
95 }
96
pdsc_devcmd_dbell(struct pdsc * pdsc)97 static void pdsc_devcmd_dbell(struct pdsc *pdsc)
98 {
99 iowrite32(0, &pdsc->cmd_regs->done);
100 iowrite32(1, &pdsc->cmd_regs->doorbell);
101 }
102
pdsc_devcmd_clean(struct pdsc * pdsc)103 static void pdsc_devcmd_clean(struct pdsc *pdsc)
104 {
105 iowrite32(0, &pdsc->cmd_regs->doorbell);
106 memset_io(&pdsc->cmd_regs->cmd, 0, sizeof(pdsc->cmd_regs->cmd));
107 }
108
pdsc_devcmd_str(int opcode)109 static const char *pdsc_devcmd_str(int opcode)
110 {
111 switch (opcode) {
112 case PDS_CORE_CMD_NOP:
113 return "PDS_CORE_CMD_NOP";
114 case PDS_CORE_CMD_IDENTIFY:
115 return "PDS_CORE_CMD_IDENTIFY";
116 case PDS_CORE_CMD_RESET:
117 return "PDS_CORE_CMD_RESET";
118 case PDS_CORE_CMD_INIT:
119 return "PDS_CORE_CMD_INIT";
120 case PDS_CORE_CMD_FW_DOWNLOAD:
121 return "PDS_CORE_CMD_FW_DOWNLOAD";
122 case PDS_CORE_CMD_FW_CONTROL:
123 return "PDS_CORE_CMD_FW_CONTROL";
124 default:
125 return "PDS_CORE_CMD_UNKNOWN";
126 }
127 }
128
pdsc_devcmd_wait(struct pdsc * pdsc,u8 opcode,int max_seconds)129 static int pdsc_devcmd_wait(struct pdsc *pdsc, u8 opcode, int max_seconds)
130 {
131 struct device *dev = pdsc->dev;
132 unsigned long start_time;
133 unsigned long max_wait;
134 unsigned long duration;
135 int timeout = 0;
136 bool running;
137 int done = 0;
138 int err = 0;
139 int status;
140
141 start_time = jiffies;
142 max_wait = start_time + (max_seconds * HZ);
143
144 while (!done && !timeout) {
145 running = pdsc_is_fw_running(pdsc);
146 if (!running)
147 break;
148
149 done = pdsc_devcmd_done(pdsc);
150 if (done)
151 break;
152
153 timeout = time_after(jiffies, max_wait);
154 if (timeout)
155 break;
156
157 usleep_range(100, 200);
158 }
159 duration = jiffies - start_time;
160
161 if (done && duration > HZ)
162 dev_dbg(dev, "DEVCMD %d %s after %ld secs\n",
163 opcode, pdsc_devcmd_str(opcode), duration / HZ);
164
165 if (!running) {
166 dev_err(dev, "DEVCMD %d %s fw not running\n",
167 opcode, pdsc_devcmd_str(opcode));
168 pdsc_devcmd_clean(pdsc);
169 return -ENXIO;
170 }
171
172 if (!done || timeout) {
173 dev_err(dev, "DEVCMD %d %s timeout, done %d timeout %d max_seconds=%d\n",
174 opcode, pdsc_devcmd_str(opcode), done, timeout,
175 max_seconds);
176 pdsc_devcmd_clean(pdsc);
177 return -ETIMEDOUT;
178 }
179
180 status = pdsc_devcmd_status(pdsc);
181 err = pdsc_err_to_errno(status);
182 if (err && err != -EAGAIN)
183 dev_err(dev, "DEVCMD %d %s failed, status=%d err %d %pe\n",
184 opcode, pdsc_devcmd_str(opcode), status, err,
185 ERR_PTR(err));
186
187 return err;
188 }
189
pdsc_devcmd_locked(struct pdsc * pdsc,union pds_core_dev_cmd * cmd,union pds_core_dev_comp * comp,int max_seconds)190 int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd,
191 union pds_core_dev_comp *comp, int max_seconds)
192 {
193 int err;
194
195 if (!pdsc->cmd_regs)
196 return -ENXIO;
197
198 memcpy_toio(&pdsc->cmd_regs->cmd, cmd, sizeof(*cmd));
199 pdsc_devcmd_dbell(pdsc);
200 err = pdsc_devcmd_wait(pdsc, cmd->opcode, max_seconds);
201
202 if ((err == -ENXIO || err == -ETIMEDOUT) && pdsc->wq)
203 queue_work(pdsc->wq, &pdsc->health_work);
204 else
205 memcpy_fromio(comp, &pdsc->cmd_regs->comp, sizeof(*comp));
206
207 return err;
208 }
209
pdsc_devcmd(struct pdsc * pdsc,union pds_core_dev_cmd * cmd,union pds_core_dev_comp * comp,int max_seconds)210 int pdsc_devcmd(struct pdsc *pdsc, union pds_core_dev_cmd *cmd,
211 union pds_core_dev_comp *comp, int max_seconds)
212 {
213 int err;
214
215 mutex_lock(&pdsc->devcmd_lock);
216 err = pdsc_devcmd_locked(pdsc, cmd, comp, max_seconds);
217 mutex_unlock(&pdsc->devcmd_lock);
218
219 return err;
220 }
221
pdsc_devcmd_init(struct pdsc * pdsc)222 int pdsc_devcmd_init(struct pdsc *pdsc)
223 {
224 union pds_core_dev_comp comp = {};
225 union pds_core_dev_cmd cmd = {
226 .opcode = PDS_CORE_CMD_INIT,
227 };
228
229 return pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout);
230 }
231
pdsc_devcmd_reset(struct pdsc * pdsc)232 int pdsc_devcmd_reset(struct pdsc *pdsc)
233 {
234 union pds_core_dev_comp comp = {};
235 union pds_core_dev_cmd cmd = {
236 .reset.opcode = PDS_CORE_CMD_RESET,
237 };
238
239 if (!pdsc_is_fw_running(pdsc))
240 return 0;
241
242 return pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout);
243 }
244
pdsc_devcmd_identify_locked(struct pdsc * pdsc)245 static int pdsc_devcmd_identify_locked(struct pdsc *pdsc)
246 {
247 union pds_core_dev_comp comp = {};
248 union pds_core_dev_cmd cmd = {
249 .identify.opcode = PDS_CORE_CMD_IDENTIFY,
250 .identify.ver = PDS_CORE_IDENTITY_VERSION_1,
251 };
252
253 return pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout);
254 }
255
pdsc_init_devinfo(struct pdsc * pdsc)256 static void pdsc_init_devinfo(struct pdsc *pdsc)
257 {
258 pdsc->dev_info.asic_type = ioread8(&pdsc->info_regs->asic_type);
259 pdsc->dev_info.asic_rev = ioread8(&pdsc->info_regs->asic_rev);
260 pdsc->fw_generation = PDS_CORE_FW_STS_F_GENERATION &
261 ioread8(&pdsc->info_regs->fw_status);
262
263 memcpy_fromio(pdsc->dev_info.fw_version,
264 pdsc->info_regs->fw_version,
265 PDS_CORE_DEVINFO_FWVERS_BUFLEN);
266 pdsc->dev_info.fw_version[PDS_CORE_DEVINFO_FWVERS_BUFLEN] = 0;
267
268 memcpy_fromio(pdsc->dev_info.serial_num,
269 pdsc->info_regs->serial_num,
270 PDS_CORE_DEVINFO_SERIAL_BUFLEN);
271 pdsc->dev_info.serial_num[PDS_CORE_DEVINFO_SERIAL_BUFLEN] = 0;
272
273 dev_dbg(pdsc->dev, "fw_version %s\n", pdsc->dev_info.fw_version);
274 }
275
pdsc_identify(struct pdsc * pdsc)276 static int pdsc_identify(struct pdsc *pdsc)
277 {
278 struct pds_core_drv_identity drv = {};
279 size_t sz;
280 int err;
281 int n;
282
283 drv.drv_type = cpu_to_le32(PDS_DRIVER_LINUX);
284 /* Catching the return quiets a Wformat-truncation complaint */
285 n = snprintf(drv.driver_ver_str, sizeof(drv.driver_ver_str),
286 "%s %s", PDS_CORE_DRV_NAME, utsname()->release);
287 if (n > sizeof(drv.driver_ver_str))
288 dev_dbg(pdsc->dev, "release name truncated, don't care\n");
289
290 /* Next let's get some info about the device
291 * We use the devcmd_lock at this level in order to
292 * get safe access to the cmd_regs->data before anyone
293 * else can mess it up
294 */
295 mutex_lock(&pdsc->devcmd_lock);
296
297 sz = min_t(size_t, sizeof(drv), sizeof(pdsc->cmd_regs->data));
298 memcpy_toio(&pdsc->cmd_regs->data, &drv, sz);
299
300 err = pdsc_devcmd_identify_locked(pdsc);
301 if (!err) {
302 sz = min_t(size_t, sizeof(pdsc->dev_ident),
303 sizeof(pdsc->cmd_regs->data));
304 memcpy_fromio(&pdsc->dev_ident, &pdsc->cmd_regs->data, sz);
305 }
306 mutex_unlock(&pdsc->devcmd_lock);
307
308 if (err) {
309 dev_err(pdsc->dev, "Cannot identify device: %pe\n",
310 ERR_PTR(err));
311 return err;
312 }
313
314 if (isprint(pdsc->dev_info.fw_version[0]) &&
315 isascii(pdsc->dev_info.fw_version[0]))
316 dev_info(pdsc->dev, "FW: %.*s\n",
317 (int)(sizeof(pdsc->dev_info.fw_version) - 1),
318 pdsc->dev_info.fw_version);
319 else
320 dev_info(pdsc->dev, "FW: (invalid string) 0x%02x 0x%02x 0x%02x 0x%02x ...\n",
321 (u8)pdsc->dev_info.fw_version[0],
322 (u8)pdsc->dev_info.fw_version[1],
323 (u8)pdsc->dev_info.fw_version[2],
324 (u8)pdsc->dev_info.fw_version[3]);
325
326 return 0;
327 }
328
pdsc_dev_uninit(struct pdsc * pdsc)329 void pdsc_dev_uninit(struct pdsc *pdsc)
330 {
331 if (pdsc->intr_info) {
332 int i;
333
334 for (i = 0; i < pdsc->nintrs; i++)
335 pdsc_intr_free(pdsc, i);
336
337 kfree(pdsc->intr_info);
338 pdsc->intr_info = NULL;
339 pdsc->nintrs = 0;
340 }
341
342 pci_free_irq_vectors(pdsc->pdev);
343 }
344
pdsc_dev_init(struct pdsc * pdsc)345 int pdsc_dev_init(struct pdsc *pdsc)
346 {
347 unsigned int nintrs;
348 int err;
349
350 /* Initial init and reset of device */
351 pdsc_init_devinfo(pdsc);
352 pdsc->devcmd_timeout = PDS_CORE_DEVCMD_TIMEOUT;
353
354 err = pdsc_devcmd_reset(pdsc);
355 if (err)
356 return err;
357
358 err = pdsc_identify(pdsc);
359 if (err)
360 return err;
361
362 pdsc_debugfs_add_ident(pdsc);
363
364 /* Now we can reserve interrupts */
365 nintrs = le32_to_cpu(pdsc->dev_ident.nintrs);
366 nintrs = min_t(unsigned int, num_online_cpus(), nintrs);
367
368 /* Get intr_info struct array for tracking */
369 pdsc->intr_info = kzalloc_objs(*pdsc->intr_info, nintrs);
370 if (!pdsc->intr_info)
371 return -ENOMEM;
372
373 err = pci_alloc_irq_vectors(pdsc->pdev, nintrs, nintrs, PCI_IRQ_MSIX);
374 if (err != nintrs) {
375 dev_err(pdsc->dev, "Can't get %d intrs from OS: %pe\n",
376 nintrs, ERR_PTR(err));
377 err = -ENOSPC;
378 goto err_out;
379 }
380 pdsc->nintrs = nintrs;
381
382 return 0;
383
384 err_out:
385 kfree(pdsc->intr_info);
386 pdsc->intr_info = NULL;
387
388 return err;
389 }
390