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