net/bnxt: add hardware resource manager init code
[dpdk.git] / drivers / net / bnxt / bnxt_hwrm.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) Broadcom Limited.
5  *   All rights reserved.
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  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Broadcom Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <rte_byteorder.h>
35 #include <rte_common.h>
36 #include <rte_cycles.h>
37 #include <rte_malloc.h>
38 #include <rte_memzone.h>
39
40 #include "bnxt.h"
41 #include "bnxt_hwrm.h"
42 #include "hsi_struct_def_dpdk.h"
43
44 #define HWRM_CMD_TIMEOUT                2000
45
46 /*
47  * HWRM Functions (sent to HWRM)
48  * These are named bnxt_hwrm_*() and return -1 if bnxt_hwrm_send_message()
49  * fails (ie: a timeout), and a positive non-zero HWRM error code if the HWRM
50  * command was failed by the ChiMP.
51  */
52
53 static int bnxt_hwrm_send_message_locked(struct bnxt *bp, void *msg,
54                                         uint32_t msg_len)
55 {
56         unsigned int i;
57         struct input *req = msg;
58         struct output *resp = bp->hwrm_cmd_resp_addr;
59         uint32_t *data = msg;
60         uint8_t *bar;
61         uint8_t *valid;
62
63         /* Write request msg to hwrm channel */
64         for (i = 0; i < msg_len; i += 4) {
65                 bar = (uint8_t *)bp->bar0 + i;
66                 *(volatile uint32_t *)bar = *data;
67                 data++;
68         }
69
70         /* Zero the rest of the request space */
71         for (; i < bp->max_req_len; i += 4) {
72                 bar = (uint8_t *)bp->bar0 + i;
73                 *(volatile uint32_t *)bar = 0;
74         }
75
76         /* Ring channel doorbell */
77         bar = (uint8_t *)bp->bar0 + 0x100;
78         *(volatile uint32_t *)bar = 1;
79
80         /* Poll for the valid bit */
81         for (i = 0; i < HWRM_CMD_TIMEOUT; i++) {
82                 /* Sanity check on the resp->resp_len */
83                 rte_rmb();
84                 if (resp->resp_len && resp->resp_len <=
85                     bp->max_resp_len) {
86                         /* Last byte of resp contains the valid key */
87                         valid = (uint8_t *)resp + resp->resp_len - 1;
88                         if (*valid == HWRM_RESP_VALID_KEY)
89                                 break;
90                 }
91                 rte_delay_us(600);
92         }
93
94         if (i >= HWRM_CMD_TIMEOUT) {
95                 RTE_LOG(ERR, PMD, "Error sending msg %x\n",
96                         req->req_type);
97                 goto err_ret;
98         }
99         return 0;
100
101 err_ret:
102         return -1;
103 }
104
105 static int bnxt_hwrm_send_message(struct bnxt *bp, void *msg, uint32_t msg_len)
106 {
107         int rc;
108
109         rte_spinlock_lock(&bp->hwrm_lock);
110         rc = bnxt_hwrm_send_message_locked(bp, msg, msg_len);
111         rte_spinlock_unlock(&bp->hwrm_lock);
112         return rc;
113 }
114
115 #define HWRM_PREP(req, type, cr, resp) \
116         memset(bp->hwrm_cmd_resp_addr, 0, bp->max_resp_len); \
117         req.req_type = rte_cpu_to_le_16(HWRM_##type); \
118         req.cmpl_ring = rte_cpu_to_le_16(cr); \
119         req.seq_id = rte_cpu_to_le_16(bp->hwrm_cmd_seq++); \
120         req.target_id = rte_cpu_to_le_16(0xffff); \
121         req.resp_addr = rte_cpu_to_le_64(bp->hwrm_cmd_resp_dma_addr)
122
123 #define HWRM_CHECK_RESULT \
124         { \
125                 if (rc) { \
126                         RTE_LOG(ERR, PMD, "%s failed rc:%d\n", \
127                                 __func__, rc); \
128                         return rc; \
129                 } \
130                 if (resp->error_code) { \
131                         rc = rte_le_to_cpu_16(resp->error_code); \
132                         RTE_LOG(ERR, PMD, "%s error %d\n", __func__, rc); \
133                         return rc; \
134                 } \
135         }
136
137 int bnxt_hwrm_func_qcaps(struct bnxt *bp)
138 {
139         int rc = 0;
140         struct hwrm_func_qcaps_input req = {.req_type = 0 };
141         struct hwrm_func_qcaps_output *resp = bp->hwrm_cmd_resp_addr;
142
143         HWRM_PREP(req, FUNC_QCAPS, -1, resp);
144
145         req.fid = rte_cpu_to_le_16(0xffff);
146
147         rc = bnxt_hwrm_send_message(bp, &req, sizeof(req));
148
149         HWRM_CHECK_RESULT;
150
151         if (BNXT_PF(bp)) {
152                 struct bnxt_pf_info *pf = &bp->pf;
153
154                 pf->fw_fid = rte_le_to_cpu_32(resp->fid);
155                 pf->port_id = resp->port_id;
156                 memcpy(pf->mac_addr, resp->perm_mac_address, ETHER_ADDR_LEN);
157                 pf->max_rsscos_ctx = rte_le_to_cpu_16(resp->max_rsscos_ctx);
158                 pf->max_cp_rings = rte_le_to_cpu_16(resp->max_cmpl_rings);
159                 pf->max_tx_rings = rte_le_to_cpu_16(resp->max_tx_rings);
160                 pf->max_rx_rings = rte_le_to_cpu_16(resp->max_rx_rings);
161                 pf->max_l2_ctx = rte_le_to_cpu_16(resp->max_l2_ctxs);
162                 pf->max_vnics = rte_le_to_cpu_16(resp->max_vnics);
163                 pf->first_vf_id = rte_le_to_cpu_16(resp->first_vf_id);
164                 pf->max_vfs = rte_le_to_cpu_16(resp->max_vfs);
165         } else {
166                 struct bnxt_vf_info *vf = &bp->vf;
167
168                 vf->fw_fid = rte_le_to_cpu_32(resp->fid);
169                 memcpy(vf->mac_addr, &resp->perm_mac_address, ETHER_ADDR_LEN);
170                 vf->max_rsscos_ctx = rte_le_to_cpu_16(resp->max_rsscos_ctx);
171                 vf->max_cp_rings = rte_le_to_cpu_16(resp->max_cmpl_rings);
172                 vf->max_tx_rings = rte_le_to_cpu_16(resp->max_tx_rings);
173                 vf->max_rx_rings = rte_le_to_cpu_16(resp->max_rx_rings);
174                 vf->max_l2_ctx = rte_le_to_cpu_16(resp->max_l2_ctxs);
175                 vf->max_vnics = rte_le_to_cpu_16(resp->max_vnics);
176         }
177
178         return rc;
179 }
180
181 int bnxt_hwrm_ver_get(struct bnxt *bp)
182 {
183         int rc = 0;
184         struct hwrm_ver_get_input req = {.req_type = 0 };
185         struct hwrm_ver_get_output *resp = bp->hwrm_cmd_resp_addr;
186         uint32_t my_version;
187         uint32_t fw_version;
188         uint16_t max_resp_len;
189         char type[RTE_MEMZONE_NAMESIZE];
190
191         HWRM_PREP(req, VER_GET, -1, resp);
192
193         req.hwrm_intf_maj = HWRM_VERSION_MAJOR;
194         req.hwrm_intf_min = HWRM_VERSION_MINOR;
195         req.hwrm_intf_upd = HWRM_VERSION_UPDATE;
196
197         /*
198          * Hold the lock since we may be adjusting the response pointers.
199          */
200         rte_spinlock_lock(&bp->hwrm_lock);
201         rc = bnxt_hwrm_send_message_locked(bp, &req, sizeof(req));
202
203         HWRM_CHECK_RESULT;
204
205         RTE_LOG(INFO, PMD, "%d.%d.%d:%d.%d.%d\n",
206                 resp->hwrm_intf_maj, resp->hwrm_intf_min,
207                 resp->hwrm_intf_upd,
208                 resp->hwrm_fw_maj, resp->hwrm_fw_min, resp->hwrm_fw_bld);
209
210         my_version = HWRM_VERSION_MAJOR << 16;
211         my_version |= HWRM_VERSION_MINOR << 8;
212         my_version |= HWRM_VERSION_UPDATE;
213
214         fw_version = resp->hwrm_intf_maj << 16;
215         fw_version |= resp->hwrm_intf_min << 8;
216         fw_version |= resp->hwrm_intf_upd;
217
218         if (resp->hwrm_intf_maj != HWRM_VERSION_MAJOR) {
219                 RTE_LOG(ERR, PMD, "Unsupported firmware API version\n");
220                 rc = -EINVAL;
221                 goto error;
222         }
223
224         if (my_version != fw_version) {
225                 RTE_LOG(INFO, PMD, "BNXT Driver/HWRM API mismatch.\n");
226                 if (my_version < fw_version) {
227                         RTE_LOG(INFO, PMD,
228                                 "Firmware API version is newer than driver.\n");
229                         RTE_LOG(INFO, PMD,
230                                 "The driver may be missing features.\n");
231                 } else {
232                         RTE_LOG(INFO, PMD,
233                                 "Firmware API version is older than driver.\n");
234                         RTE_LOG(INFO, PMD,
235                                 "Not all driver features may be functional.\n");
236                 }
237         }
238
239         if (bp->max_req_len > resp->max_req_win_len) {
240                 RTE_LOG(ERR, PMD, "Unsupported request length\n");
241                 rc = -EINVAL;
242         }
243         bp->max_req_len = resp->max_req_win_len;
244         max_resp_len = resp->max_resp_len;
245         if (bp->max_resp_len != max_resp_len) {
246                 sprintf(type, "bnxt_hwrm_%04x:%02x:%02x:%02x",
247                         bp->pdev->addr.domain, bp->pdev->addr.bus,
248                         bp->pdev->addr.devid, bp->pdev->addr.function);
249
250                 rte_free(bp->hwrm_cmd_resp_addr);
251
252                 bp->hwrm_cmd_resp_addr = rte_malloc(type, max_resp_len, 0);
253                 if (bp->hwrm_cmd_resp_addr == NULL) {
254                         rc = -ENOMEM;
255                         goto error;
256                 }
257                 bp->hwrm_cmd_resp_dma_addr =
258                         rte_malloc_virt2phy(bp->hwrm_cmd_resp_addr);
259                 bp->max_resp_len = max_resp_len;
260         }
261
262 error:
263         rte_spinlock_unlock(&bp->hwrm_lock);
264         return rc;
265 }
266
267 int bnxt_hwrm_queue_qportcfg(struct bnxt *bp)
268 {
269         int rc = 0;
270         struct hwrm_queue_qportcfg_input req = {.req_type = 0 };
271         struct hwrm_queue_qportcfg_output *resp = bp->hwrm_cmd_resp_addr;
272
273         HWRM_PREP(req, QUEUE_QPORTCFG, -1, resp);
274
275         rc = bnxt_hwrm_send_message(bp, &req, sizeof(req));
276
277         HWRM_CHECK_RESULT;
278
279 #define GET_QUEUE_INFO(x) \
280         bp->cos_queue[x].id = resp->queue_id##x; \
281         bp->cos_queue[x].profile = resp->queue_id##x##_service_profile
282
283         GET_QUEUE_INFO(0);
284         GET_QUEUE_INFO(1);
285         GET_QUEUE_INFO(2);
286         GET_QUEUE_INFO(3);
287         GET_QUEUE_INFO(4);
288         GET_QUEUE_INFO(5);
289         GET_QUEUE_INFO(6);
290         GET_QUEUE_INFO(7);
291
292         return rc;
293 }
294
295 /*
296  * HWRM utility functions
297  */
298
299 void bnxt_free_hwrm_resources(struct bnxt *bp)
300 {
301         /* Release memzone */
302         rte_free(bp->hwrm_cmd_resp_addr);
303         bp->hwrm_cmd_resp_addr = NULL;
304         bp->hwrm_cmd_resp_dma_addr = 0;
305 }
306
307 int bnxt_alloc_hwrm_resources(struct bnxt *bp)
308 {
309         struct rte_pci_device *pdev = bp->pdev;
310         char type[RTE_MEMZONE_NAMESIZE];
311
312         sprintf(type, "bnxt_hwrm_%04x:%02x:%02x:%02x", pdev->addr.domain,
313                 pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
314         bp->max_req_len = HWRM_MAX_REQ_LEN;
315         bp->max_resp_len = HWRM_MAX_RESP_LEN;
316         bp->hwrm_cmd_resp_addr = rte_malloc(type, bp->max_resp_len, 0);
317         if (bp->hwrm_cmd_resp_addr == NULL)
318                 return -ENOMEM;
319         bp->hwrm_cmd_resp_dma_addr =
320                 rte_malloc_virt2phy(bp->hwrm_cmd_resp_addr);
321         rte_spinlock_init(&bp->hwrm_lock);
322
323         return 0;
324 }