root/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfp_net_tlv_caps_reset
  2. nfp_net_tlv_caps_parse

   1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
   2 /* Copyright (C) 2018 Netronome Systems, Inc. */
   3 
   4 #include <linux/bitfield.h>
   5 #include <linux/device.h>
   6 #include <linux/kernel.h>
   7 #include <linux/types.h>
   8 
   9 #include "nfp_net_ctrl.h"
  10 #include "nfp_net.h"
  11 
  12 static void nfp_net_tlv_caps_reset(struct nfp_net_tlv_caps *caps)
  13 {
  14         memset(caps, 0, sizeof(*caps));
  15         caps->me_freq_mhz = 1200;
  16         caps->mbox_off = NFP_NET_CFG_MBOX_BASE;
  17         caps->mbox_len = NFP_NET_CFG_MBOX_VAL_MAX_SZ;
  18 }
  19 
  20 int nfp_net_tlv_caps_parse(struct device *dev, u8 __iomem *ctrl_mem,
  21                            struct nfp_net_tlv_caps *caps)
  22 {
  23         u8 __iomem *data = ctrl_mem + NFP_NET_CFG_TLV_BASE;
  24         u8 __iomem *end = ctrl_mem + NFP_NET_CFG_BAR_SZ;
  25         u32 hdr;
  26 
  27         nfp_net_tlv_caps_reset(caps);
  28 
  29         hdr = readl(data);
  30         if (!hdr)
  31                 return 0;
  32 
  33         while (true) {
  34                 unsigned int length, offset;
  35                 u32 hdr = readl(data);
  36 
  37                 length = FIELD_GET(NFP_NET_CFG_TLV_HEADER_LENGTH, hdr);
  38                 offset = data - ctrl_mem;
  39 
  40                 /* Advance past the header */
  41                 data += 4;
  42 
  43                 if (length % NFP_NET_CFG_TLV_LENGTH_INC) {
  44                         dev_err(dev, "TLV size not multiple of %u offset:%u len:%u\n",
  45                                 NFP_NET_CFG_TLV_LENGTH_INC, offset, length);
  46                         return -EINVAL;
  47                 }
  48                 if (data + length > end) {
  49                         dev_err(dev, "oversized TLV offset:%u len:%u\n",
  50                                 offset, length);
  51                         return -EINVAL;
  52                 }
  53 
  54                 switch (FIELD_GET(NFP_NET_CFG_TLV_HEADER_TYPE, hdr)) {
  55                 case NFP_NET_CFG_TLV_TYPE_UNKNOWN:
  56                         dev_err(dev, "NULL TLV at offset:%u\n", offset);
  57                         return -EINVAL;
  58                 case NFP_NET_CFG_TLV_TYPE_RESERVED:
  59                         break;
  60                 case NFP_NET_CFG_TLV_TYPE_END:
  61                         if (!length)
  62                                 return 0;
  63 
  64                         dev_err(dev, "END TLV should be empty, has offset:%u len:%d\n",
  65                                 offset, length);
  66                         return -EINVAL;
  67                 case NFP_NET_CFG_TLV_TYPE_ME_FREQ:
  68                         if (length != 4) {
  69                                 dev_err(dev,
  70                                         "ME FREQ TLV should be 4B, is %dB offset:%u\n",
  71                                         length, offset);
  72                                 return -EINVAL;
  73                         }
  74 
  75                         caps->me_freq_mhz = readl(data);
  76                         break;
  77                 case NFP_NET_CFG_TLV_TYPE_MBOX:
  78                         if (!length) {
  79                                 caps->mbox_off = 0;
  80                                 caps->mbox_len = 0;
  81                         } else {
  82                                 caps->mbox_off = data - ctrl_mem;
  83                                 caps->mbox_len = length;
  84                         }
  85                         break;
  86                 case NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL0:
  87                 case NFP_NET_CFG_TLV_TYPE_EXPERIMENTAL1:
  88                         dev_warn(dev,
  89                                  "experimental TLV type:%u offset:%u len:%u\n",
  90                                  FIELD_GET(NFP_NET_CFG_TLV_HEADER_TYPE, hdr),
  91                                  offset, length);
  92                         break;
  93                 case NFP_NET_CFG_TLV_TYPE_REPR_CAP:
  94                         if (length < 4) {
  95                                 dev_err(dev, "REPR CAP TLV short %dB < 4B offset:%u\n",
  96                                         length, offset);
  97                                 return -EINVAL;
  98                         }
  99 
 100                         caps->repr_cap = readl(data);
 101                         break;
 102                 case NFP_NET_CFG_TLV_TYPE_MBOX_CMSG_TYPES:
 103                         if (length >= 4)
 104                                 caps->mbox_cmsg_types = readl(data);
 105                         break;
 106                 case NFP_NET_CFG_TLV_TYPE_CRYPTO_OPS:
 107                         if (length < 32) {
 108                                 dev_err(dev,
 109                                         "CRYPTO OPS TLV should be at least 32B, is %dB offset:%u\n",
 110                                         length, offset);
 111                                 return -EINVAL;
 112                         }
 113 
 114                         caps->crypto_ops = readl(data);
 115                         caps->crypto_enable_off = data - ctrl_mem + 16;
 116                         break;
 117                 default:
 118                         if (!FIELD_GET(NFP_NET_CFG_TLV_HEADER_REQUIRED, hdr))
 119                                 break;
 120 
 121                         dev_err(dev, "unknown TLV type:%u offset:%u len:%u\n",
 122                                 FIELD_GET(NFP_NET_CFG_TLV_HEADER_TYPE, hdr),
 123                                 offset, length);
 124                         return -EINVAL;
 125                 }
 126 
 127                 data += length;
 128                 if (data + 4 > end) {
 129                         dev_err(dev, "reached end of BAR without END TLV\n");
 130                         return -EINVAL;
 131                 }
 132         }
 133 
 134         /* Not reached */
 135         return -EINVAL;
 136 }

/* [<][>][^][v][top][bottom][index][help] */