xref: /dpdk/drivers/net/nfp/nfp_net_ctrl.c (revision b6de43530dfa30cbf6b70857e3835099701063d4)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2023 Corigine Systems, Inc.
3  * All rights reserved.
4  */
5 
6 #include "nfp_net_ctrl.h"
7 
8 #include <ethdev_pci.h>
9 #include <nfp_platform.h>
10 
11 #include "nfp_logs.h"
12 #include "nfp_net_common.h"
13 
14 static void
15 nfp_net_tlv_caps_reset(struct nfp_net_tlv_caps *caps)
16 {
17 	memset(caps, 0, sizeof(*caps));
18 	caps->mbox_off = NFP_NET_CFG_MBOX_BASE;
19 	caps->mbox_len = NFP_NET_CFG_MBOX_VAL_MAX_SZ;
20 }
21 
22 int
23 nfp_net_tlv_caps_parse(struct rte_eth_dev *dev)
24 {
25 	uint32_t hdr;
26 	uint8_t *end;
27 	uint8_t *data;
28 	uint32_t length;
29 	uint32_t offset;
30 	uint32_t tlv_type;
31 	struct nfp_net_hw *net_hw;
32 	struct nfp_net_tlv_caps *caps;
33 	struct nfp_net_hw_priv *hw_priv;
34 
35 	net_hw = dev->data->dev_private;
36 	hw_priv = dev->process_private;
37 	caps = &net_hw->tlv_caps;
38 	nfp_net_tlv_caps_reset(caps);
39 
40 	data = net_hw->super.ctrl_bar + NFP_NET_CFG_TLV_BASE;
41 	end = net_hw->super.ctrl_bar + hw_priv->pf_dev->ctrl_bar_size;
42 
43 	hdr = rte_read32(data);
44 	if (hdr == 0) {
45 		PMD_DRV_LOG(INFO, "TLV is empty!");
46 		return 0;
47 	}
48 
49 	for (; ; data += length) {
50 		offset = data - net_hw->super.ctrl_bar;
51 
52 		if (data + NFP_NET_CFG_TLV_VALUE > end) {
53 			PMD_DRV_LOG(ERR, "Reached end of BAR without END TLV.");
54 			return -EINVAL;
55 		}
56 
57 		hdr = rte_read32(data);
58 
59 		length = FIELD_GET(NFP_NET_CFG_TLV_HEADER_LENGTH, hdr);
60 		if ((length & (NFP_NET_CFG_TLV_LENGTH_INC - 1)) != 0) {
61 			PMD_DRV_LOG(ERR, "TLV size not multiple of 4B len: %u.", length);
62 			return -EINVAL;
63 		}
64 
65 		/* Advance past the header */
66 		data += NFP_NET_CFG_TLV_VALUE;
67 		if (data + length > end) {
68 			PMD_DRV_LOG(ERR, "Oversized TLV offset: %u len: %u.",
69 					offset, length);
70 			return -EINVAL;
71 		}
72 
73 		tlv_type = FIELD_GET(NFP_NET_CFG_TLV_HEADER_TYPE, hdr);
74 
75 		switch (tlv_type) {
76 		case NFP_NET_CFG_TLV_TYPE_UNKNOWN:
77 			PMD_DRV_LOG(ERR, "Unknown TLV at offset: %u.", offset);
78 			return -EINVAL;
79 		case NFP_NET_CFG_TLV_TYPE_RESERVED:
80 			break;
81 		case NFP_NET_CFG_TLV_TYPE_END:
82 			if (length == 0)
83 				return 0;
84 
85 			PMD_DRV_LOG(ERR, "END TLV should be empty, has len: %u.", length);
86 			return -EINVAL;
87 		case NFP_NET_CFG_TLV_TYPE_MBOX:
88 			caps->mbox_len = length;
89 
90 			if (length != 0)
91 				caps->mbox_off = data - net_hw->super.ctrl_bar;
92 			else
93 				caps->mbox_off = 0;
94 			break;
95 		case NFP_NET_CFG_TLV_TYPE_MBOX_CMSG_TYPES:
96 			if (length != 0)
97 				caps->mbox_cmsg_types = rte_read32(data);
98 			break;
99 		default:
100 			if (FIELD_GET(NFP_NET_CFG_TLV_HEADER_REQUIRED, hdr) == 0)
101 				break;
102 
103 			PMD_DRV_LOG(ERR, "Unknown TLV type: %u offset: %u len: %u.",
104 					tlv_type, offset, length);
105 			return -EINVAL;
106 		}
107 	}
108 
109 	PMD_DRV_LOG(ERR, "Reached end of BAR without END TLV.");
110 	return -EINVAL;
111 }
112