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