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