1 /*
2 * Broadcom NetXtreme-C/E network driver.
3 *
4 * Copyright (c) 2022 Broadcom, All Rights Reserved.
5 * The term Broadcom refers to Broadcom Limited and/or its subsidiaries
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS'
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "bnxt_mgmt.h"
30 #include "bnxt.h"
31 #include "bnxt_hwrm.h"
32 #include <dev/pci/pcireg.h>
33 #include <dev/pci/pcivar.h>
34 #include <sys/endian.h>
35 #include <sys/lock.h>
36
37 /* Function prototypes */
38 static d_open_t bnxt_mgmt_open;
39 static d_close_t bnxt_mgmt_close;
40 static d_ioctl_t bnxt_mgmt_ioctl;
41
42 /* Character device entry points */
43 static struct cdevsw bnxt_mgmt_cdevsw = {
44 .d_version = D_VERSION,
45 .d_open = bnxt_mgmt_open,
46 .d_close = bnxt_mgmt_close,
47 .d_ioctl = bnxt_mgmt_ioctl,
48 .d_name = "bnxt_mgmt",
49 };
50
51 /* Global vars */
52 static struct cdev *bnxt_mgmt_dev;
53 struct mtx mgmt_lock;
54
55 MALLOC_DEFINE(M_BNXT, "bnxt_mgmt_buffer", "buffer for bnxt_mgmt module");
56
57 /*
58 * This function is called by the kld[un]load(2) system calls to
59 * determine what actions to take when a module is loaded or unloaded.
60 */
61 static int
62 bnxt_mgmt_loader(struct module *m, int what, void *arg)
63 {
64 int error = 0;
65
66 switch (what) {
67 case MOD_LOAD:
68 error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
69 &bnxt_mgmt_dev,
70 &bnxt_mgmt_cdevsw,
71 0,
72 UID_ROOT,
73 GID_WHEEL,
74 0600,
75 "bnxt_mgmt");
76 if (error != 0) {
77 printf("%s: %s:%s:%d Failed to create the"
78 "bnxt_mgmt device node\n", DRIVER_NAME,
79 __FILE__, __FUNCTION__, __LINE__);
80 return (error);
81 }
82
83 mtx_init(&mgmt_lock, "BNXT MGMT Lock", NULL, MTX_DEF);
84
85 break;
86 case MOD_UNLOAD:
87 mtx_destroy(&mgmt_lock);
88 destroy_dev(bnxt_mgmt_dev);
89 break;
90 default:
91 error = EOPNOTSUPP;
92 break;
93 }
94
95 return (error);
96 }
97
98 static int
99 bnxt_mgmt_process_hwrm(struct cdev *dev, u_long cmd, caddr_t data,
100 int flag, struct thread *td)
101 {
102 struct bnxt_softc *softc = NULL;
103 struct bnxt_mgmt_req mgmt_req = {};
104 struct bnxt_mgmt_fw_msg msg_temp, *msg, *msg2 = NULL;
105 struct iflib_dma_info dma_data = {};
106 void *user_ptr, *req, *resp;
107 int ret = 0;
108 uint16_t num_ind = 0;
109
110 memcpy(&user_ptr, data, sizeof(user_ptr));
111 if (copyin(user_ptr, &mgmt_req, sizeof(struct bnxt_mgmt_req))) {
112 printf("%s: %s:%d Failed to copy data from user\n",
113 DRIVER_NAME, __FUNCTION__, __LINE__);
114 return -EFAULT;
115 }
116 softc = bnxt_find_dev(mgmt_req.hdr.domain, mgmt_req.hdr.bus,
117 mgmt_req.hdr.devfn, NULL);
118 if (!softc) {
119 printf("%s: %s:%d unable to find softc reference\n",
120 DRIVER_NAME, __FUNCTION__, __LINE__);
121 return -ENODEV;
122 }
123
124 if (copyin((void*)mgmt_req.req.hreq, &msg_temp, sizeof(msg_temp))) {
125 device_printf(softc->dev, "%s:%d Failed to copy data from user\n",
126 __FUNCTION__, __LINE__);
127 return -EFAULT;
128 }
129
130 if (msg_temp.len_req > BNXT_MGMT_MAX_HWRM_REQ_LENGTH ||
131 msg_temp.len_resp > BNXT_MGMT_MAX_HWRM_RESP_LENGTH) {
132 device_printf(softc->dev, "%s:%d Invalid length\n",
133 __FUNCTION__, __LINE__);
134 return -EINVAL;
135 }
136
137 if (msg_temp.num_dma_indications > 1) {
138 device_printf(softc->dev, "%s:%d Max num_dma_indications "
139 "supported is 1 \n", __FUNCTION__, __LINE__);
140 return -EINVAL;
141 }
142
143 req = malloc(msg_temp.len_req, M_BNXT, M_WAITOK | M_ZERO);
144 if(!req) {
145 device_printf(softc->dev, "%s:%d Memory allocation failed",
146 __FUNCTION__, __LINE__);
147 return -ENOMEM;
148 }
149
150 resp = malloc(msg_temp.len_resp, M_BNXT, M_WAITOK | M_ZERO);
151 if(!resp) {
152 device_printf(softc->dev, "%s:%d Memory allocation failed",
153 __FUNCTION__, __LINE__);
154 ret = -ENOMEM;
155 goto end;
156 }
157
158 if (copyin((void *)msg_temp.usr_req, req, msg_temp.len_req)) {
159 device_printf(softc->dev, "%s:%d Failed to copy data from user\n",
160 __FUNCTION__, __LINE__);
161 ret = -EFAULT;
162 goto end;
163 }
164
165 msg = &msg_temp;
166 num_ind = msg_temp.num_dma_indications;
167 if (num_ind) {
168 int size;
169 void *dma_ptr;
170 uint64_t *dmap;
171
172 size = sizeof(struct bnxt_mgmt_fw_msg) +
173 (num_ind * sizeof(struct dma_info));
174
175 msg2 = malloc(size, M_BNXT, M_WAITOK | M_ZERO);
176 if(!msg2) {
177 device_printf(softc->dev, "%s:%d Memory allocation failed",
178 __FUNCTION__, __LINE__);
179 ret = -ENOMEM;
180 goto end;
181 }
182
183 if (copyin((void *)mgmt_req.req.hreq, msg2, size)) {
184 device_printf(softc->dev, "%s:%d Failed to copy"
185 "data from user\n", __FUNCTION__, __LINE__);
186 ret = -EFAULT;
187 goto end;
188 }
189 msg = msg2;
190
191 ret = iflib_dma_alloc(softc->ctx, msg->dma[0].length, &dma_data,
192 BUS_DMA_NOWAIT);
193 if (ret) {
194 device_printf(softc->dev, "%s:%d iflib_dma_alloc"
195 "failed with ret = 0x%x\n", __FUNCTION__,
196 __LINE__, ret);
197 ret = -ENOMEM;
198 goto end;
199 }
200
201 if (!(msg->dma[0].read_or_write)) {
202 if (copyin((void *)msg->dma[0].data,
203 dma_data.idi_vaddr,
204 msg->dma[0].length)) {
205 device_printf(softc->dev, "%s:%d Failed to copy"
206 "data from user\n", __FUNCTION__,
207 __LINE__);
208 ret = -EFAULT;
209 goto end;
210 }
211 }
212 dma_ptr = (void *) ((uint64_t) req + msg->dma[0].offset);
213 dmap = dma_ptr;
214 *dmap = htole64(dma_data.idi_paddr);
215 }
216
217 ret = bnxt_hwrm_passthrough(softc, req, msg->len_req, resp, msg->len_resp, msg->timeout);
218 if(ret)
219 goto end;
220
221 if (num_ind) {
222 if ((msg->dma[0].read_or_write)) {
223 if (copyout(dma_data.idi_vaddr,
224 (void *)msg->dma[0].data,
225 msg->dma[0].length)) {
226 device_printf(softc->dev, "%s:%d Failed to copy data"
227 "to user\n", __FUNCTION__, __LINE__);
228 ret = -EFAULT;
229 goto end;
230 }
231 }
232 }
233
234 if (copyout(resp, (void *) msg->usr_resp, msg->len_resp)) {
235 device_printf(softc->dev, "%s:%d Failed to copy response to user\n",
236 __FUNCTION__, __LINE__);
237 ret = -EFAULT;
238 goto end;
239 }
240
241 end:
242 if (req)
243 free(req, M_BNXT);
244 if (resp)
245 free(resp, M_BNXT);
246 if (msg2)
247 free(msg2, M_BNXT);
248 if (dma_data.idi_paddr)
249 iflib_dma_free(&dma_data);
250 return ret;
251 }
252
253 static int
254 bnxt_mgmt_get_dev_info(struct cdev *dev, u_long cmd, caddr_t data,
255 int flag, struct thread *td)
256 {
257 struct bnxt_softc *softc = NULL;
258 struct bnxt_dev_info dev_info;
259 void *user_ptr;
260 uint32_t dev_sn_lo, dev_sn_hi;
261 int dev_sn_offset = 0;
262 char dsn[16];
263 uint16_t lnk;
264 int capreg;
265
266 memcpy(&user_ptr, data, sizeof(user_ptr));
267 if (copyin(user_ptr, &dev_info, sizeof(dev_info))) {
268 printf("%s: %s:%d Failed to copy data from user\n",
269 DRIVER_NAME, __FUNCTION__, __LINE__);
270 return -EFAULT;
271 }
272
273 softc = bnxt_find_dev(0, 0, 0, dev_info.nic_info.dev_name);
274 if (!softc) {
275 printf("%s: %s:%d unable to find softc reference\n",
276 DRIVER_NAME, __FUNCTION__, __LINE__);
277 return -ENODEV;
278 }
279
280 strncpy(dev_info.nic_info.driver_version, bnxt_driver_version, 64);
281 strncpy(dev_info.nic_info.driver_name, device_get_name(softc->dev), 64);
282 dev_info.pci_info.domain_no = softc->domain;
283 dev_info.pci_info.bus_no = softc->bus;
284 dev_info.pci_info.device_no = softc->slot;
285 dev_info.pci_info.function_no = softc->function;
286 dev_info.pci_info.vendor_id = pci_get_vendor(softc->dev);
287 dev_info.pci_info.device_id = pci_get_device(softc->dev);
288 dev_info.pci_info.sub_system_vendor_id = pci_get_subvendor(softc->dev);
289 dev_info.pci_info.sub_system_device_id = pci_get_subdevice(softc->dev);
290 dev_info.pci_info.revision = pci_read_config(softc->dev, PCIR_REVID, 1);
291 dev_info.pci_info.chip_rev_id = (dev_info.pci_info.device_id << 16);
292 dev_info.pci_info.chip_rev_id |= dev_info.pci_info.revision;
293 if (pci_find_extcap(softc->dev, PCIZ_SERNUM, &dev_sn_offset)) {
294 device_printf(softc->dev, "%s:%d device serial number is not found"
295 "or not supported\n", __FUNCTION__, __LINE__);
296 } else {
297 dev_sn_lo = pci_read_config(softc->dev, dev_sn_offset + 4, 4);
298 dev_sn_hi = pci_read_config(softc->dev, dev_sn_offset + 8, 4);
299 snprintf(dsn, sizeof(dsn), "%02x%02x%02x%02x%02x%02x%02x%02x",
300 (dev_sn_lo & 0x000000FF),
301 (dev_sn_lo >> 8) & 0x0000FF,
302 (dev_sn_lo >> 16) & 0x00FF,
303 (dev_sn_lo >> 24 ) & 0xFF,
304 (dev_sn_hi & 0x000000FF),
305 (dev_sn_hi >> 8) & 0x0000FF,
306 (dev_sn_hi >> 16) & 0x00FF,
307 (dev_sn_hi >> 24 ) & 0xFF);
308 strncpy(dev_info.nic_info.device_serial_number, dsn, sizeof(dsn));
309 }
310
311 if_t ifp = iflib_get_ifp(softc->ctx);
312 dev_info.nic_info.mtu = if_getmtu(ifp);
313 memcpy(dev_info.nic_info.mac, softc->func.mac_addr, ETHER_ADDR_LEN);
314
315 if (pci_find_cap(softc->dev, PCIY_EXPRESS, &capreg)) {
316 device_printf(softc->dev, "%s:%d pci link capability is not found"
317 "or not supported\n", __FUNCTION__, __LINE__);
318 } else {
319 lnk = pci_read_config(softc->dev, capreg + PCIER_LINK_STA, 2);
320 dev_info.nic_info.pci_link_speed = (lnk & PCIEM_LINK_STA_SPEED);
321 dev_info.nic_info.pci_link_width = (lnk & PCIEM_LINK_STA_WIDTH) >> 4;
322 }
323
324 if (copyout(&dev_info, user_ptr, sizeof(dev_info))) {
325 device_printf(softc->dev, "%s:%d Failed to copy data to user\n",
326 __FUNCTION__, __LINE__);
327 return -EFAULT;
328 }
329
330 return 0;
331 }
332
333 /*
334 * IOCTL entry point.
335 */
336 static int
337 bnxt_mgmt_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag,
338 struct thread *td)
339 {
340 int ret = 0;
341
342 switch(cmd) {
343 case BNXT_MGMT_OPCODE_GET_DEV_INFO:
344 ret = bnxt_mgmt_get_dev_info(dev, cmd, data, flag, td);
345 break;
346 case BNXT_MGMT_OPCODE_PASSTHROUGH_HWRM:
347 mtx_lock(&mgmt_lock);
348 ret = bnxt_mgmt_process_hwrm(dev, cmd, data, flag, td);
349 mtx_unlock(&mgmt_lock);
350 break;
351 default:
352 printf("%s: Unknown command 0x%lx\n", DRIVER_NAME, cmd);
353 ret = -EINVAL;
354 break;
355 }
356
357 return ret;
358 }
359
360 static int
361 bnxt_mgmt_close(struct cdev *dev, int flags, int devtype, struct thread *td)
362 {
363 return (0);
364 }
365
366 static int
367 bnxt_mgmt_open(struct cdev *dev, int flags, int devtype, struct thread *td)
368 {
369 return (0);
370 }
371
372 DEV_MODULE(bnxt_mgmt, bnxt_mgmt_loader, NULL);
373
Cache object: 7e9323e50849138cc09b6289d01618c2
|