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 struct mlx5_dump_data {
43 const struct mlx5_crspace_regmap *rege;
50 static MALLOC_DEFINE(M_MLX5_DUMP, "MLX5DUMP", "MLX5 Firmware dump");
53 mlx5_fwdump_getsize(const struct mlx5_crspace_regmap *rege)
55 const struct mlx5_crspace_regmap *r;
58 for (sz = 0, r = rege; r->cnt != 0; r++)
64 mlx5_fwdump_destroy_dd(struct mlx5_dump_data *dd)
67 mtx_destroy(&dd->dump_lock);
68 free(dd->dump, M_MLX5_DUMP);
69 free(dd, M_MLX5_DUMP);
73 mlx5_fwdump_prep(struct mlx5_core_dev *mdev)
75 struct mlx5_dump_data *dd;
78 error = mlx5_vsc_find_cap(mdev);
80 /* Inability to create a firmware dump is not fatal. */
81 device_printf((&mdev->pdev->dev)->bsddev, "WARN: "
82 "mlx5_fwdump_prep failed %d\n", error);
85 dd = malloc(sizeof(struct mlx5_dump_data), M_MLX5_DUMP, M_WAITOK);
86 switch (pci_get_device(mdev->pdev->dev.bsddev)) {
88 dd->rege = mlx5_crspace_regmap_mt4115;
91 dd->rege = mlx5_crspace_regmap_mt4117;
95 dd->rege = mlx5_crspace_regmap_connectx5;
98 free(dd, M_MLX5_DUMP);
99 return; /* silently fail, do not prevent driver attach */
101 dd->dump_size = mlx5_fwdump_getsize(dd->rege);
102 dd->dump = malloc(dd->dump_size * sizeof(uint32_t), M_MLX5_DUMP,
105 mtx_init(&dd->dump_lock, "mlx5dmp", NULL, MTX_DEF | MTX_NEW);
106 if (atomic_cmpset_rel_ptr((uintptr_t *)&mdev->dump_data, 0,
108 mlx5_fwdump_destroy_dd(dd);
112 mlx5_fwdump(struct mlx5_core_dev *mdev)
114 struct mlx5_dump_data *dd;
115 const struct mlx5_crspace_regmap *r;
119 dev_info(&mdev->pdev->dev, "Issuing FW dump\n");
120 dd = (struct mlx5_dump_data *)atomic_load_acq_ptr((uintptr_t *)
124 mtx_lock(&dd->dump_lock);
125 if (dd->dump_valid) {
127 dev_warn(&mdev->pdev->dev,
128 "Only one FW dump can be captured aborting FW dump\n");
132 /* mlx5_vsc already warns, be silent. */
133 error = mlx5_vsc_lock(mdev);
136 error = mlx5_vsc_set_space(mdev, MLX5_VSC_DOMAIN_PROTECTED_CRSPACE);
139 for (i = 0, r = dd->rege; r->cnt != 0; r++) {
140 for (ri = 0; ri < r->cnt; ri++) {
141 error = mlx5_vsc_read(mdev, r->addr + ri * 4,
148 atomic_store_rel_int(&dd->dump_valid, 1);
150 mlx5_vsc_unlock(mdev);
152 mtx_unlock(&dd->dump_lock);
156 mlx5_fwdump_clean(struct mlx5_core_dev *mdev)
158 struct mlx5_dump_data *dd;
161 dd = mdev->dump_data;
164 if (atomic_cmpset_ptr((uintptr_t *)&mdev->dump_data,
165 (uintptr_t)dd, 0) == 1) {
166 mlx5_fwdump_destroy_dd(dd);
173 mlx5_dbsf_to_core(const struct mlx5_fwdump_addr *devaddr,
174 struct mlx5_core_dev **mdev)
177 struct pci_dev *pdev;
179 dev = pci_find_dbsf(devaddr->domain, devaddr->bus, devaddr->slot,
183 if (device_get_devclass(dev) != mlx5_core_driver.bsdclass)
185 pdev = device_get_softc(dev);
186 *mdev = pci_get_drvdata(pdev);
193 mlx5_fwdump_copyout(struct mlx5_dump_data *dd, struct mlx5_fwdump_get *fwg)
195 const struct mlx5_crspace_regmap *r;
196 struct mlx5_fwdump_reg rv, *urv;
202 if (fwg->buf == NULL) {
203 fwg->reg_filled = dd->dump_size;
206 if (atomic_load_acq_int(&dd->dump_valid) == 0)
210 for (i = 0, r = dd->rege; r->cnt != 0; r++) {
211 for (ri = 0; ri < r->cnt; ri++) {
212 if (i >= fwg->reg_cnt)
214 rv.addr = r->addr + ri * 4;
215 rv.val = dd->dump[i];
216 error = copyout(&rv, urv, sizeof(rv));
229 mlx5_fwdump_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
232 struct mlx5_core_dev *mdev;
233 struct mlx5_fwdump_get *fwg;
234 struct mlx5_fwdump_addr *devaddr;
235 struct mlx5_dump_data *dd;
240 case MLX5_FWDUMP_GET:
241 if ((fflag & FREAD) == 0) {
245 fwg = (struct mlx5_fwdump_get *)data;
246 devaddr = &fwg->devaddr;
247 error = mlx5_dbsf_to_core(devaddr, &mdev);
250 error = mlx5_fwdump_copyout(mdev->dump_data, fwg);
252 case MLX5_FWDUMP_RESET:
253 if ((fflag & FWRITE) == 0) {
257 devaddr = (struct mlx5_fwdump_addr *)data;
258 error = mlx5_dbsf_to_core(devaddr, &mdev);
261 dd = mdev->dump_data;
263 atomic_store_rel_int(&dd->dump_valid, 0);
267 case MLX5_FWDUMP_FORCE:
268 if ((fflag & FWRITE) == 0) {
272 devaddr = (struct mlx5_fwdump_addr *)data;
273 error = mlx5_dbsf_to_core(devaddr, &mdev);
285 static struct cdevsw mlx5_fwdump_devsw = {
286 .d_version = D_VERSION,
287 .d_ioctl = mlx5_fwdump_ioctl,
290 static struct cdev *mlx5_fwdump_dev;
293 mlx5_fwdump_init(void)
295 struct make_dev_args mda;
298 make_dev_args_init(&mda);
299 mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME;
300 mda.mda_devsw = &mlx5_fwdump_devsw;
301 mda.mda_uid = UID_ROOT;
302 mda.mda_gid = GID_OPERATOR;
304 error = make_dev_s(&mda, &mlx5_fwdump_dev, "mlx5ctl");
309 mlx5_fwdump_fini(void)
312 if (mlx5_fwdump_dev != NULL)
313 destroy_dev(mlx5_fwdump_dev);