2 * Copyright (c) 2018, Mellanox Technologies, Ltd. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
29 #include <sys/param.h>
30 #include <sys/systm.h>
32 #include <sys/fcntl.h>
33 #include <dev/mlx5/driver.h>
34 #include <dev/mlx5/device.h>
35 #include <dev/mlx5/mlx5_core/mlx5_core.h>
36 #include <dev/mlx5/mlx5io.h>
38 extern const struct mlx5_crspace_regmap mlx5_crspace_regmap_mt4117[];
39 extern const struct mlx5_crspace_regmap mlx5_crspace_regmap_mt4115[];
40 extern const struct mlx5_crspace_regmap mlx5_crspace_regmap_connectx5[];
42 static MALLOC_DEFINE(M_MLX5_DUMP, "MLX5DUMP", "MLX5 Firmware dump");
45 mlx5_fwdump_getsize(const struct mlx5_crspace_regmap *rege)
47 const struct mlx5_crspace_regmap *r;
50 for (sz = 0, r = rege; r->cnt != 0; r++)
56 mlx5_fwdump_destroy_dd(struct mlx5_core_dev *mdev)
59 mtx_assert(&mdev->dump_lock, MA_OWNED);
60 free(mdev->dump_data, M_MLX5_DUMP);
61 mdev->dump_data = NULL;
65 mlx5_fwdump_prep(struct mlx5_core_dev *mdev)
69 mdev->dump_data = NULL;
70 error = mlx5_vsc_find_cap(mdev);
72 /* Inability to create a firmware dump is not fatal. */
73 device_printf((&mdev->pdev->dev)->bsddev, "WARN: "
74 "mlx5_fwdump_prep failed %d\n", error);
77 switch (pci_get_device(mdev->pdev->dev.bsddev)) {
79 mdev->dump_rege = mlx5_crspace_regmap_mt4115;
82 mdev->dump_rege = mlx5_crspace_regmap_mt4117;
86 mdev->dump_rege = mlx5_crspace_regmap_connectx5;
89 return; /* silently fail, do not prevent driver attach */
91 mdev->dump_size = mlx5_fwdump_getsize(mdev->dump_rege);
92 mdev->dump_data = malloc(mdev->dump_size * sizeof(uint32_t),
93 M_MLX5_DUMP, M_WAITOK | M_ZERO);
94 mdev->dump_valid = false;
95 mdev->dump_copyout = false;
99 mlx5_fwdump(struct mlx5_core_dev *mdev)
101 const struct mlx5_crspace_regmap *r;
105 dev_info(&mdev->pdev->dev, "Issuing FW dump\n");
106 mtx_lock(&mdev->dump_lock);
107 if (mdev->dump_data == NULL)
109 if (mdev->dump_valid) {
111 dev_warn(&mdev->pdev->dev,
112 "Only one FW dump can be captured aborting FW dump\n");
116 /* mlx5_vsc already warns, be silent. */
117 error = mlx5_vsc_lock(mdev);
120 error = mlx5_vsc_set_space(mdev, MLX5_VSC_DOMAIN_PROTECTED_CRSPACE);
123 for (i = 0, r = mdev->dump_rege; r->cnt != 0; r++) {
124 for (ri = 0; ri < r->cnt; ri++) {
125 error = mlx5_vsc_read(mdev, r->addr + ri * 4,
126 &mdev->dump_data[i]);
132 mdev->dump_valid = true;
134 mlx5_vsc_unlock(mdev);
136 mtx_unlock(&mdev->dump_lock);
140 mlx5_fwdump_clean(struct mlx5_core_dev *mdev)
143 mtx_lock(&mdev->dump_lock);
144 while (mdev->dump_copyout)
145 msleep(&mdev->dump_copyout, &mdev->dump_lock, 0, "mlx5fwc", 0);
146 mlx5_fwdump_destroy_dd(mdev);
147 mtx_unlock(&mdev->dump_lock);
151 mlx5_fwdump_reset(struct mlx5_core_dev *mdev)
156 mtx_lock(&mdev->dump_lock);
157 if (mdev->dump_data != NULL) {
158 while (mdev->dump_copyout) {
159 msleep(&mdev->dump_copyout, &mdev->dump_lock,
162 mdev->dump_valid = false;
166 mtx_unlock(&mdev->dump_lock);
171 mlx5_dbsf_to_core(const struct mlx5_tool_addr *devaddr,
172 struct mlx5_core_dev **mdev)
175 struct pci_dev *pdev;
177 dev = pci_find_dbsf(devaddr->domain, devaddr->bus, devaddr->slot,
181 if (device_get_devclass(dev) != mlx5_core_driver.bsdclass)
183 pdev = device_get_softc(dev);
184 *mdev = pci_get_drvdata(pdev);
191 mlx5_fwdump_copyout(struct mlx5_core_dev *mdev, struct mlx5_fwdump_get *fwg)
193 const struct mlx5_crspace_regmap *r;
194 struct mlx5_fwdump_reg rv, *urv;
198 mtx_lock(&mdev->dump_lock);
199 if (mdev->dump_data == NULL) {
200 mtx_unlock(&mdev->dump_lock);
203 if (fwg->buf == NULL) {
204 fwg->reg_filled = mdev->dump_size;
205 mtx_unlock(&mdev->dump_lock);
208 if (!mdev->dump_valid) {
209 mtx_unlock(&mdev->dump_lock);
212 mdev->dump_copyout = true;
213 mtx_unlock(&mdev->dump_lock);
216 for (i = 0, r = mdev->dump_rege; r->cnt != 0; r++) {
217 for (ri = 0; ri < r->cnt; ri++) {
218 if (i >= fwg->reg_cnt)
220 rv.addr = r->addr + ri * 4;
221 rv.val = mdev->dump_data[i];
222 error = copyout(&rv, urv, sizeof(rv));
231 mtx_lock(&mdev->dump_lock);
232 mdev->dump_copyout = false;
233 wakeup(&mdev->dump_copyout);
234 mtx_unlock(&mdev->dump_lock);
239 mlx5_fw_reset(struct mlx5_core_dev *mdev)
244 error = -mlx5_set_mfrl_reg(mdev, MLX5_FRL_LEVEL3);
246 dev = mdev->pdev->dev.bsddev;
248 bus = device_get_parent(dev);
249 error = BUS_RESET_CHILD(device_get_parent(bus), bus,
257 mlx5_ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
260 struct mlx5_core_dev *mdev;
261 struct mlx5_fwdump_get *fwg;
262 struct mlx5_tool_addr *devaddr;
263 struct mlx5_fw_update *fu;
264 struct firmware fake_fw;
269 case MLX5_FWDUMP_GET:
270 if ((fflag & FREAD) == 0) {
274 fwg = (struct mlx5_fwdump_get *)data;
275 devaddr = &fwg->devaddr;
276 error = mlx5_dbsf_to_core(devaddr, &mdev);
279 error = mlx5_fwdump_copyout(mdev, fwg);
281 case MLX5_FWDUMP_RESET:
282 if ((fflag & FWRITE) == 0) {
286 devaddr = (struct mlx5_tool_addr *)data;
287 error = mlx5_dbsf_to_core(devaddr, &mdev);
289 error = mlx5_fwdump_reset(mdev);
291 case MLX5_FWDUMP_FORCE:
292 if ((fflag & FWRITE) == 0) {
296 devaddr = (struct mlx5_tool_addr *)data;
297 error = mlx5_dbsf_to_core(devaddr, &mdev);
303 if ((fflag & FWRITE) == 0) {
307 fu = (struct mlx5_fw_update *)data;
308 if (fu->img_fw_data_len > 10 * 1024 * 1024) {
312 devaddr = &fu->devaddr;
313 error = mlx5_dbsf_to_core(devaddr, &mdev);
316 bzero(&fake_fw, sizeof(fake_fw));
317 fake_fw.name = "umlx_fw_up";
318 fake_fw.datasize = fu->img_fw_data_len;
320 fake_fw.data = (void *)kmem_malloc(fu->img_fw_data_len,
322 if (fake_fw.data == NULL) {
326 error = copyin(fu->img_fw_data, __DECONST(void *, fake_fw.data),
327 fu->img_fw_data_len);
329 error = -mlx5_firmware_flash(mdev, &fake_fw);
330 kmem_free((vm_offset_t)fake_fw.data, fu->img_fw_data_len);
333 if ((fflag & FWRITE) == 0) {
337 devaddr = (struct mlx5_tool_addr *)data;
338 error = mlx5_dbsf_to_core(devaddr, &mdev);
341 error = mlx5_fw_reset(mdev);
350 static struct cdevsw mlx5_ctl_devsw = {
351 .d_version = D_VERSION,
352 .d_ioctl = mlx5_ctl_ioctl,
355 static struct cdev *mlx5_ctl_dev;
360 struct make_dev_args mda;
363 make_dev_args_init(&mda);
364 mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME;
365 mda.mda_devsw = &mlx5_ctl_devsw;
366 mda.mda_uid = UID_ROOT;
367 mda.mda_gid = GID_OPERATOR;
369 error = make_dev_s(&mda, &mlx5_ctl_dev, "mlx5ctl");
377 if (mlx5_ctl_dev != NULL)
378 destroy_dev(mlx5_ctl_dev);