// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2018 Solarflare Communications Inc. * Copyright 2019-2022 Xilinx Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, incorporated herein by reference.
*/
/* The hardware provides 'low' and 'high' (doorbell) registers * for passing the 64-bit address of an MCDI request to * firmware. However the dwords are swapped by firmware. The * least significant bits of the doorbell are then 0 for all * MCDI requests due to alignment.
*/
_efx_writed(efx, cpu_to_le32((u64)dma_addr >> 32), efx_reg(efx, ER_GZ_MC_DB_LWRD));
_efx_writed(efx, cpu_to_le32((u32)dma_addr), efx_reg(efx, ER_GZ_MC_DB_HWRD));
}
rc = ef100_get_warm_boot_count(efx); if (rc < 0) { /* The firmware is presumably in the process of * rebooting. However, we are supposed to report each * reboot just once, so we must only do that once we * can read and store the updated warm boot count.
*/ return 0;
}
net_dev->features |= tso;
net_dev->hw_features |= tso;
net_dev->hw_enc_features |= tso; /* EF100 HW can only offload outer checksums if they are UDP, * so for GRE_CSUM we have to use GSO_PARTIAL.
*/
net_dev->gso_partial_features |= NETIF_F_GSO_GRE_CSUM;
}
efx->num_mac_stats = MCDI_WORD(outbuf,
GET_CAPABILITIES_V4_OUT_MAC_STATS_NUM_STATS);
netif_dbg(efx, probe, efx->net_dev, "firmware reports num_mac_stats = %u\n",
efx->num_mac_stats); return 0;
}
/* Event handling
*/ staticint ef100_ev_probe(struct efx_channel *channel)
{ /* Allocate an extra descriptor for the QMDA status completion entry */ return efx_nic_alloc_buffer(channel->efx, &channel->eventq,
(channel->eventq_mask + 2) * sizeof(efx_qword_t),
GFP_KERNEL);
}
netif_vdbg(efx, intr, efx->net_dev, "IRQ %d on CPU %d\n", irq, raw_smp_processor_id());
if (likely(READ_ONCE(efx->irq_soft_enabled))) { /* Note test interrupts */ if (context->index == efx->irq_level)
efx->last_irq_cpu = raw_smp_processor_id();
/* Schedule processing of the channel */
efx_schedule_channel_irq(efx->channel[context->index]);
}
return IRQ_HANDLED;
}
int ef100_phy_probe(struct efx_nic *efx)
{ struct efx_mcdi_phy_data *phy_data; int rc;
/* Probe for the PHY */
efx->phy_data = kzalloc(sizeof(struct efx_mcdi_phy_data), GFP_KERNEL); if (!efx->phy_data) return -ENOMEM;
rc = efx_mcdi_get_phy_cfg(efx, efx->phy_data); if (rc) return rc;
/* Default to Autonegotiated flow control if the PHY supports it */
efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
efx->wanted_fc |= EFX_FC_AUTO;
efx_link_set_wanted_fc(efx, efx->wanted_fc);
/* Push settings to the PHY. Failure is not fatal, the user can try to * fix it using ethtool.
*/
rc = efx_mcdi_port_reconfigure(efx); if (rc && rc != -EPERM)
netif_warn(efx, drv, efx->net_dev, "could not initialise PHY settings\n");
return 0;
}
int ef100_filter_table_probe(struct efx_nic *efx)
{ return efx_mcdi_filter_table_probe(efx, true);
}
staticint ef100_filter_table_up(struct efx_nic *efx)
{ int rc;
down_write(&efx->filter_sem);
rc = efx_mcdi_filter_add_vlan(efx, EFX_FILTER_VID_UNSPEC); if (rc) goto fail_unspec;
rc = efx_mcdi_filter_add_vlan(efx, 0); if (rc) goto fail_vlan0; /* Drop the lock: we've finished altering table existence, and * filter insertion will need to take the lock for read.
*/
up_write(&efx->filter_sem); if (IS_ENABLED(CONFIG_SFC_SRIOV))
rc = efx_tc_insert_rep_filters(efx);
/* Rep filter failure is nonfatal */ if (rc)
netif_warn(efx, drv, efx->net_dev, "Failed to insert representor filters, rc %d\n",
rc); return 0;
/* MCDI_SET_QWORD is not appropriate here since EFX_POPULATE_* has * already swapped the data to little-endian order.
*/
memcpy(MCDI_PTR(inbuf, DRIVER_EVENT_IN_DATA), &event.u64[0], sizeof(efx_qword_t));
switch (offset) { case MC_CMD_GET_CAPABILITIES_V8_OUT_FLAGS1_OFST: return nic_data->datapath_caps & BIT_ULL(flag); case MC_CMD_GET_CAPABILITIES_V8_OUT_FLAGS2_OFST: return nic_data->datapath_caps2 & BIT_ULL(flag); case MC_CMD_GET_CAPABILITIES_V8_OUT_FLAGS3_OFST: return nic_data->datapath_caps3 & BIT_ULL(flag); default: return 0;
}
}
staticunsignedint efx_ef100_recycle_ring_size(conststruct efx_nic *efx)
{ /* Maximum link speed for Riverhead is 100G */ return 10 * EFX_RECYCLE_RING_SIZE_10G;
}
/* Construct mport selector for "physical network port" */
efx_mae_mport_wire(efx, &selector); /* Look up actual mport ID */
rc = efx_mae_fw_lookup_mport(efx, selector, &id); if (rc) return rc; /* The ID should always fit in 16 bits, because that's how wide the * corresponding fields in the RX prefix & TX override descriptor are
*/ if (id >> 16)
netif_warn(efx, probe, efx->net_dev, "Bad base m-port id %#x\n",
id);
nic_data->base_mport = id;
nic_data->have_mport = true;
/* Construct mport selector for "calling PF" */
efx_mae_mport_uplink(efx, &selector); /* Look up actual mport ID */
rc = efx_mae_fw_lookup_mport(efx, selector, &id); if (rc) return rc; if (id >> 16)
netif_warn(efx, probe, efx->net_dev, "Bad own m-port id %#x\n",
id);
nic_data->own_mport = id;
nic_data->have_own_mport = true;
return 0;
}
staticint compare_versions(constchar *a, constchar *b)
{ int a_major, a_minor, a_point, a_patch; int b_major, b_minor, b_point, b_patch; int a_matched, b_matched;
switch (reader->type) { case ESE_EF100_DP_GZ_PAD: /* padding, skip it */ return 0; case ESE_EF100_DP_GZ_PARTIAL_TSTAMP_SUB_NANO_BITS: /* Driver doesn't support timestamping yet, so we don't care */ return 0; case ESE_EF100_DP_GZ_EVQ_UNSOL_CREDIT_SEQ_BITS: /* Driver doesn't support unsolicited-event credits yet, so * we don't care
*/ return 0; case ESE_EF100_DP_GZ_NMMU_GROUP_SIZE: /* Driver doesn't manage the NMMU (so we don't care) */ return 0; case ESE_EF100_DP_GZ_RX_L4_CSUM_PROTOCOLS: /* Driver uses CHECKSUM_COMPLETE, so we don't care about * protocol checksum validation
*/ return 0; case ESE_EF100_DP_GZ_TSO_MAX_HDR_LEN:
nic_data->tso_max_hdr_len = min_t(u64, reader->value, 0xffff); return 0; case ESE_EF100_DP_GZ_TSO_MAX_HDR_NUM_SEGS: /* We always put HDR_NUM_SEGS=1 in our TSO descriptors */ if (!reader->value) {
pci_err(efx->pci_dev, "TSO_MAX_HDR_NUM_SEGS < 1\n"); return -EOPNOTSUPP;
} return 0; case ESE_EF100_DP_GZ_RXQ_SIZE_GRANULARITY: case ESE_EF100_DP_GZ_TXQ_SIZE_GRANULARITY: /* Our TXQ and RXQ sizes are always power-of-two and thus divisible by * EFX_MIN_DMAQ_SIZE, so we just need to check that * EFX_MIN_DMAQ_SIZE is divisible by GRANULARITY. * This is very unlikely to fail.
*/ if (!reader->value || reader->value > EFX_MIN_DMAQ_SIZE ||
EFX_MIN_DMAQ_SIZE % (u32)reader->value) {
pci_err(efx->pci_dev, "%s size granularity is %llu, can't guarantee safety\n",
reader->type == ESE_EF100_DP_GZ_RXQ_SIZE_GRANULARITY ? "RXQ" : "TXQ",
reader->value); return -EOPNOTSUPP;
} return 0; case ESE_EF100_DP_GZ_TSO_MAX_PAYLOAD_LEN:
nic_data->tso_max_payload_len = min_t(u64, reader->value,
GSO_LEGACY_MAX_SIZE); return 0; case ESE_EF100_DP_GZ_TSO_MAX_PAYLOAD_NUM_SEGS:
nic_data->tso_max_payload_num_segs = min_t(u64, reader->value, 0xffff); return 0; case ESE_EF100_DP_GZ_TSO_MAX_NUM_FRAMES:
nic_data->tso_max_frames = min_t(u64, reader->value, 0xffff); return 0; case ESE_EF100_DP_GZ_COMPAT: if (reader->value) {
pci_err(efx->pci_dev, "DP_COMPAT has unknown bits %#llx, driver not compatible with this hw\n",
reader->value); return -EOPNOTSUPP;
} return 0; case ESE_EF100_DP_GZ_MEM2MEM_MAX_LEN: /* Driver doesn't use mem2mem transfers */ return 0; case ESE_EF100_DP_GZ_EVQ_TIMER_TICK_NANOS: /* Driver doesn't currently use EVQ_TIMER */ return 0; case ESE_EF100_DP_GZ_NMMU_PAGE_SIZES: /* Driver doesn't manage the NMMU (so we don't care) */ return 0; case ESE_EF100_DP_GZ_VI_STRIDES: /* We never try to set the VI stride, and we don't rely on * being able to find VIs past VI 0 until after we've learned * the current stride from MC_CMD_GET_CAPABILITIES. * So the value of this shouldn't matter.
*/ if (reader->value != ESE_EF100_DP_GZ_VI_STRIDES_DEFAULT)
pci_dbg(efx->pci_dev, "NIC has other than default VI_STRIDES (mask " "%#llx), early probing might use wrong one\n",
reader->value); return 0; case ESE_EF100_DP_GZ_RX_MAX_RUNT: /* Driver doesn't look at L2_STATUS:LEN_ERR bit, so we don't * care whether it indicates runt or overlength for any given * packet, so we don't care about this parameter.
*/ return 0; default: /* Host interface says "Drivers should ignore design parameters * that they do not recognise."
*/
pci_dbg(efx->pci_dev, "Ignoring unrecognised design parameter %u\n",
reader->type); return 0;
}
}
efx_readd(efx, ®, ER_GZ_PARAMS_TLV_LEN);
total_len = EFX_DWORD_FIELD(reg, EFX_DWORD_0);
pci_dbg(efx->pci_dev, "%u bytes of design parameters\n", total_len); while (offset < total_len) {
efx_readd(efx, ®, ER_GZ_PARAMS_TLV + offset);
data = EFX_DWORD_FIELD(reg, EFX_DWORD_0); for (i = 0; i < sizeof(data); i++) {
rc = ef100_tlv_feed(&reader, data); /* Got a complete value? */ if (!rc && reader.state == EF100_TLV_TYPE)
rc = ef100_process_design_param(efx, &reader); if (rc) goto out;
data >>= 8;
offset++;
}
} /* Check we didn't end halfway through a TLV entry, which could either * mean that the TLV stream is truncated or just that it's corrupted * and our state machine is out of sync.
*/ if (reader.state != EF100_TLV_TYPE) { if (reader.state == EF100_TLV_TYPE_CONT)
pci_err(efx->pci_dev, "truncated design parameter (incomplete type %u)\n",
reader.type); else
pci_err(efx->pci_dev, "truncated design parameter %u\n",
reader.type);
rc = -EIO;
}
out: return rc;
}
/* NIC probe and remove
*/ staticint ef100_probe_main(struct efx_nic *efx)
{ unsignedint bar_size = resource_size(&efx->pci_dev->resource[efx->mem_bar]); struct ef100_nic_data *nic_data; char fw_version[32];
u32 priv_mask = 0; int i, rc;
/* we assume later that we can copy from this buffer in dwords */
BUILD_BUG_ON(MCDI_CTL_SDU_LEN_MAX_V2 % 4);
/* MCDI buffers must be 256 byte aligned. */
rc = efx_nic_alloc_buffer(efx, &nic_data->mcdi_buf, MCDI_BUF_LEN,
GFP_KERNEL); if (rc) goto fail;
/* Get the MC's warm boot count. In case it's rebooting right * now, be prepared to retry.
*/
i = 0; for (;;) {
rc = ef100_get_warm_boot_count(efx); if (rc >= 0) break; if (++i == 5) goto fail;
ssleep(1);
}
nic_data->warm_boot_count = rc;
/* In case we're recovering from a crash (kexec), we want to * cancel any outstanding request by the previous user of this * function. We send a special message using the least * significant bits of the 'high' (doorbell) register.
*/
_efx_writed(efx, cpu_to_le32(1), efx_reg(efx, ER_GZ_MC_DB_HWRD));
/* Post-IO section. */
rc = efx_mcdi_init(efx); if (rc) goto fail; /* Reset (most) configuration for this function */
rc = efx_mcdi_reset(efx, RESET_TYPE_ALL); if (rc) goto fail; /* Enable event logging */
rc = efx_mcdi_log_ctrl(efx, true, false, 0); if (rc) goto fail;
rc = efx_get_pf_index(efx, &nic_data->pf_index); if (rc) goto fail;
efx_mcdi_print_fwver(efx, fw_version, sizeof(fw_version));
pci_dbg(efx->pci_dev, "Firmware version %s\n", fw_version);
rc = efx_mcdi_get_privilege_mask(efx, &priv_mask); if (rc) /* non-fatal, and priv_mask will still be 0 */
pci_info(efx->pci_dev, "Failed to get privilege mask from FW, rc %d\n", rc);
nic_data->grp_mae = !!(priv_mask & MC_CMD_PRIVILEGE_MASK_IN_GRP_MAE);
if (compare_versions(fw_version, "1.1.0.1000") < 0) {
pci_info(efx->pci_dev, "Firmware uses old event descriptors\n");
rc = -EINVAL; goto fail;
}
/* MCDI commands are related to the same device issuing them. This function * allows to do an MCDI command on behalf of another device, mainly PFs setting * things for VFs.
*/ int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
{
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
size_t outlen; int rc;
int ef100_probe_netdev_pf(struct efx_nic *efx)
{ struct ef100_nic_data *nic_data = efx->nic_data; struct net_device *net_dev = efx->net_dev; int rc;
if (!IS_ENABLED(CONFIG_SFC_SRIOV) || !nic_data->grp_mae) return 0;
rc = efx_init_struct_tc(efx); if (rc) return rc;
rc = efx_ef100_get_base_mport(efx); if (rc) {
netif_warn(efx, probe, net_dev, "Failed to probe base mport rc %d; representors will not function\n",
rc);
}
rc = efx_init_mae(efx); if (rc)
netif_warn(efx, probe, net_dev, "Failed to init MAE rc %d; representors will not function\n",
rc); else
efx_ef100_init_reps(efx);
rc = efx_init_tc(efx); if (rc) { /* Either we don't have an MAE at all (i.e. legacy v-switching), * or we do but we failed to probe it. In the latter case, we * may not have set up default rules, in which case we won't be * able to pass any traffic. However, we don't fail the probe, * because the user might need to use the netdevice to apply * configuration changes to fix whatever's wrong with the MAE.
*/
netif_warn(efx, probe, net_dev, "Failed to probe MAE rc %d\n",
rc);
} else {
net_dev->features |= NETIF_F_HW_TC;
efx->fixed_features |= NETIF_F_HW_TC;
} return 0;
}
int ef100_probe_vf(struct efx_nic *efx)
{ return ef100_probe_main(efx);
}
/* Per-type bar/size configuration not used on ef100. Location of * registers is defined by extended capabilities.
*/
.mem_bar = NULL,
.mem_map_size = NULL,
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.