+uint64_t
+sfc_tx_get_dev_offload_caps(struct sfc_adapter *sa)
+{
+ const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
+ uint64_t caps = 0;
+
+ if ((sa->dp_tx->features & SFC_DP_TX_FEAT_VLAN_INSERT) &&
+ encp->enc_hw_tx_insert_vlan_enabled)
+ caps |= DEV_TX_OFFLOAD_VLAN_INSERT;
+
+ if (sa->dp_tx->features & SFC_DP_TX_FEAT_MULTI_SEG)
+ caps |= DEV_TX_OFFLOAD_MULTI_SEGS;
+
+ if ((~sa->dp_tx->features & SFC_DP_TX_FEAT_MULTI_POOL) &&
+ (~sa->dp_tx->features & SFC_DP_TX_FEAT_REFCNT))
+ caps |= DEV_TX_OFFLOAD_MBUF_FAST_FREE;
+
+ return caps;
+}
+
+uint64_t
+sfc_tx_get_queue_offload_caps(struct sfc_adapter *sa)
+{
+ const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);
+ uint64_t caps = 0;
+
+ caps |= DEV_TX_OFFLOAD_IPV4_CKSUM;
+ caps |= DEV_TX_OFFLOAD_UDP_CKSUM;
+ caps |= DEV_TX_OFFLOAD_TCP_CKSUM;
+
+ if (encp->enc_tunnel_encapsulations_supported)
+ caps |= DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM;
+
+ if (sa->tso)
+ caps |= DEV_TX_OFFLOAD_TCP_TSO;
+
+ return caps;
+}
+
+static void
+sfc_tx_log_offloads(struct sfc_adapter *sa, const char *offload_group,
+ const char *verdict, uint64_t offloads)
+{
+ unsigned long long bit;
+
+ while ((bit = __builtin_ffsll(offloads)) != 0) {
+ uint64_t flag = (1ULL << --bit);
+
+ sfc_err(sa, "Tx %s offload %s %s", offload_group,
+ rte_eth_dev_tx_offload_name(flag), verdict);
+
+ offloads &= ~flag;
+ }
+}
+
+static int
+sfc_tx_queue_offload_mismatch(struct sfc_adapter *sa, uint64_t requested)
+{
+ uint64_t mandatory = sa->eth_dev->data->dev_conf.txmode.offloads;
+ uint64_t supported = sfc_tx_get_dev_offload_caps(sa) |
+ sfc_tx_get_queue_offload_caps(sa);
+ uint64_t rejected = requested & ~supported;
+ uint64_t missing = (requested & mandatory) ^ mandatory;
+ boolean_t mismatch = B_FALSE;
+
+ if (rejected) {
+ sfc_tx_log_offloads(sa, "queue", "is unsupported", rejected);
+ mismatch = B_TRUE;
+ }
+
+ if (missing) {
+ sfc_tx_log_offloads(sa, "queue", "must be set", missing);
+ mismatch = B_TRUE;
+ }
+
+ return mismatch;
+}
+