xref: /linux/drivers/net/ethernet/amd/pds_core/dev.c (revision e91c37f1)
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 
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 
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 
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 
87 static u8 pdsc_devcmd_status(struct pdsc *pdsc)
88 {
89 	return ioread8(&pdsc->cmd_regs->comp.status);
90 }
91 
92 static bool pdsc_devcmd_done(struct pdsc *pdsc)
93 {
94 	return ioread32(&pdsc->cmd_regs->done) & PDS_CORE_DEV_CMD_DONE;
95 }
96 
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 
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 
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 
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 ((!done || timeout) && running) {
166 		dev_err(dev, "DEVCMD %d %s timeout, done %d timeout %d max_seconds=%d\n",
167 			opcode, pdsc_devcmd_str(opcode), done, timeout,
168 			max_seconds);
169 		err = -ETIMEDOUT;
170 		pdsc_devcmd_clean(pdsc);
171 	}
172 
173 	status = pdsc_devcmd_status(pdsc);
174 	err = pdsc_err_to_errno(status);
175 	if (err && err != -EAGAIN)
176 		dev_err(dev, "DEVCMD %d %s failed, status=%d err %d %pe\n",
177 			opcode, pdsc_devcmd_str(opcode), status, err,
178 			ERR_PTR(err));
179 
180 	return err;
181 }
182 
183 int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd,
184 		       union pds_core_dev_comp *comp, int max_seconds)
185 {
186 	int err;
187 
188 	if (!pdsc->cmd_regs)
189 		return -ENXIO;
190 
191 	memcpy_toio(&pdsc->cmd_regs->cmd, cmd, sizeof(*cmd));
192 	pdsc_devcmd_dbell(pdsc);
193 	err = pdsc_devcmd_wait(pdsc, cmd->opcode, max_seconds);
194 
195 	if ((err == -ENXIO || err == -ETIMEDOUT) && pdsc->wq)
196 		queue_work(pdsc->wq, &pdsc->health_work);
197 	else
198 		memcpy_fromio(comp, &pdsc->cmd_regs->comp, sizeof(*comp));
199 
200 	return err;
201 }
202 
203 int pdsc_devcmd(struct pdsc *pdsc, union pds_core_dev_cmd *cmd,
204 		union pds_core_dev_comp *comp, int max_seconds)
205 {
206 	int err;
207 
208 	mutex_lock(&pdsc->devcmd_lock);
209 	err = pdsc_devcmd_locked(pdsc, cmd, comp, max_seconds);
210 	mutex_unlock(&pdsc->devcmd_lock);
211 
212 	return err;
213 }
214 
215 int pdsc_devcmd_init(struct pdsc *pdsc)
216 {
217 	union pds_core_dev_comp comp = {};
218 	union pds_core_dev_cmd cmd = {
219 		.opcode = PDS_CORE_CMD_INIT,
220 	};
221 
222 	return pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout);
223 }
224 
225 int pdsc_devcmd_reset(struct pdsc *pdsc)
226 {
227 	union pds_core_dev_comp comp = {};
228 	union pds_core_dev_cmd cmd = {
229 		.reset.opcode = PDS_CORE_CMD_RESET,
230 	};
231 
232 	return pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout);
233 }
234 
235 static int pdsc_devcmd_identify_locked(struct pdsc *pdsc)
236 {
237 	union pds_core_dev_comp comp = {};
238 	union pds_core_dev_cmd cmd = {
239 		.identify.opcode = PDS_CORE_CMD_IDENTIFY,
240 		.identify.ver = PDS_CORE_IDENTITY_VERSION_1,
241 	};
242 
243 	return pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout);
244 }
245 
246 static void pdsc_init_devinfo(struct pdsc *pdsc)
247 {
248 	pdsc->dev_info.asic_type = ioread8(&pdsc->info_regs->asic_type);
249 	pdsc->dev_info.asic_rev = ioread8(&pdsc->info_regs->asic_rev);
250 	pdsc->fw_generation = PDS_CORE_FW_STS_F_GENERATION &
251 			      ioread8(&pdsc->info_regs->fw_status);
252 
253 	memcpy_fromio(pdsc->dev_info.fw_version,
254 		      pdsc->info_regs->fw_version,
255 		      PDS_CORE_DEVINFO_FWVERS_BUFLEN);
256 	pdsc->dev_info.fw_version[PDS_CORE_DEVINFO_FWVERS_BUFLEN] = 0;
257 
258 	memcpy_fromio(pdsc->dev_info.serial_num,
259 		      pdsc->info_regs->serial_num,
260 		      PDS_CORE_DEVINFO_SERIAL_BUFLEN);
261 	pdsc->dev_info.serial_num[PDS_CORE_DEVINFO_SERIAL_BUFLEN] = 0;
262 
263 	dev_dbg(pdsc->dev, "fw_version %s\n", pdsc->dev_info.fw_version);
264 }
265 
266 static int pdsc_identify(struct pdsc *pdsc)
267 {
268 	struct pds_core_drv_identity drv = {};
269 	size_t sz;
270 	int err;
271 	int n;
272 
273 	drv.drv_type = cpu_to_le32(PDS_DRIVER_LINUX);
274 	/* Catching the return quiets a Wformat-truncation complaint */
275 	n = snprintf(drv.driver_ver_str, sizeof(drv.driver_ver_str),
276 		     "%s %s", PDS_CORE_DRV_NAME, utsname()->release);
277 	if (n > sizeof(drv.driver_ver_str))
278 		dev_dbg(pdsc->dev, "release name truncated, don't care\n");
279 
280 	/* Next let's get some info about the device
281 	 * We use the devcmd_lock at this level in order to
282 	 * get safe access to the cmd_regs->data before anyone
283 	 * else can mess it up
284 	 */
285 	mutex_lock(&pdsc->devcmd_lock);
286 
287 	sz = min_t(size_t, sizeof(drv), sizeof(pdsc->cmd_regs->data));
288 	memcpy_toio(&pdsc->cmd_regs->data, &drv, sz);
289 
290 	err = pdsc_devcmd_identify_locked(pdsc);
291 	if (!err) {
292 		sz = min_t(size_t, sizeof(pdsc->dev_ident),
293 			   sizeof(pdsc->cmd_regs->data));
294 		memcpy_fromio(&pdsc->dev_ident, &pdsc->cmd_regs->data, sz);
295 	}
296 	mutex_unlock(&pdsc->devcmd_lock);
297 
298 	if (err) {
299 		dev_err(pdsc->dev, "Cannot identify device: %pe\n",
300 			ERR_PTR(err));
301 		return err;
302 	}
303 
304 	if (isprint(pdsc->dev_info.fw_version[0]) &&
305 	    isascii(pdsc->dev_info.fw_version[0]))
306 		dev_info(pdsc->dev, "FW: %.*s\n",
307 			 (int)(sizeof(pdsc->dev_info.fw_version) - 1),
308 			 pdsc->dev_info.fw_version);
309 	else
310 		dev_info(pdsc->dev, "FW: (invalid string) 0x%02x 0x%02x 0x%02x 0x%02x ...\n",
311 			 (u8)pdsc->dev_info.fw_version[0],
312 			 (u8)pdsc->dev_info.fw_version[1],
313 			 (u8)pdsc->dev_info.fw_version[2],
314 			 (u8)pdsc->dev_info.fw_version[3]);
315 
316 	return 0;
317 }
318 
319 int pdsc_dev_init(struct pdsc *pdsc)
320 {
321 	unsigned int nintrs;
322 	int err;
323 
324 	/* Initial init and reset of device */
325 	pdsc_init_devinfo(pdsc);
326 	pdsc->devcmd_timeout = PDS_CORE_DEVCMD_TIMEOUT;
327 
328 	err = pdsc_devcmd_reset(pdsc);
329 	if (err)
330 		return err;
331 
332 	err = pdsc_identify(pdsc);
333 	if (err)
334 		return err;
335 
336 	pdsc_debugfs_add_ident(pdsc);
337 
338 	/* Now we can reserve interrupts */
339 	nintrs = le32_to_cpu(pdsc->dev_ident.nintrs);
340 	nintrs = min_t(unsigned int, num_online_cpus(), nintrs);
341 
342 	/* Get intr_info struct array for tracking */
343 	pdsc->intr_info = kcalloc(nintrs, sizeof(*pdsc->intr_info), GFP_KERNEL);
344 	if (!pdsc->intr_info) {
345 		err = -ENOMEM;
346 		goto err_out;
347 	}
348 
349 	err = pci_alloc_irq_vectors(pdsc->pdev, nintrs, nintrs, PCI_IRQ_MSIX);
350 	if (err != nintrs) {
351 		dev_err(pdsc->dev, "Can't get %d intrs from OS: %pe\n",
352 			nintrs, ERR_PTR(err));
353 		err = -ENOSPC;
354 		goto err_out;
355 	}
356 	pdsc->nintrs = nintrs;
357 
358 	return 0;
359 
360 err_out:
361 	kfree(pdsc->intr_info);
362 	pdsc->intr_info = NULL;
363 
364 	return err;
365 }
366