// SPDX-License-Identifier: GPL-2.0-only /**************************************************************************** * Driver for Solarflare network controllers and boards * Copyright 2005-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.
*/
/* Number of bytes at start of vendor specified extended capability that indicate * that the capability is vendor specified. i.e. offset from value returned by * pci_find_next_ext_capability() to beginning of vendor specified capability * header.
*/ #define PCI_EXT_CAP_HDR_LENGTH 4
/* Expected size of a Xilinx continuation address table entry. */ #define ESE_GZ_CFGBAR_CONT_CAP_MIN_LENGTH 16
if (bar == ESE_GZ_CFGBAR_EF100_BAR_NUM_EXPANSION_ROM ||
bar == ESE_GZ_CFGBAR_EF100_BAR_NUM_INVALID) {
netif_err(efx, probe, efx->net_dev, "Bad BAR value of %d in Xilinx capabilities EF100 entry.\n",
bar); return -EINVAL;
}
if (bar == ESE_GZ_VSEC_BAR_NUM_EXPANSION_ROM ||
bar == ESE_GZ_VSEC_BAR_NUM_INVALID) {
netif_err(efx, probe, efx->net_dev, "Bad BAR value of %d in Xilinx capabilities sub-table.\n",
bar); return -EINVAL;
}
if (bar != previous_bar) {
efx_fini_io(efx);
if (ef100_pci_does_bar_overflow(efx, bar, offset)) {
netif_err(efx, probe, efx->net_dev, "Xilinx table will overrun BAR[%d] offset=0x%llx\n",
bar, offset); return -EINVAL;
}
/* Temporarily map new BAR. */
rc = efx_init_io(efx, bar,
(dma_addr_t)DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
pci_resource_len(efx->pci_dev, bar)); if (rc) {
netif_err(efx, probe, efx->net_dev, "Mapping new BAR for Xilinx table failed, rc=%d\n", rc); return rc;
}
}
rc = ef100_pci_walk_xilinx_table(efx, offset, result); if (rc) return rc;
if (bar != previous_bar) {
efx_fini_io(efx);
/* Put old BAR back. */
rc = efx_init_io(efx, previous_bar,
(dma_addr_t)DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
pci_resource_len(efx->pci_dev, previous_bar)); if (rc) {
netif_err(efx, probe, efx->net_dev, "Putting old BAR back failed, rc=%d\n", rc); return rc;
}
}
return 0;
}
/* Iterate over the Xilinx capabilities table in the currently mapped BAR and * call ef100_pci_parse_ef100_entry() on any EF100 entries and * ef100_pci_parse_continue_entry() on any table continuations.
*/ staticint ef100_pci_walk_xilinx_table(struct efx_nic *efx, u64 offset, struct ef100_func_ctl_window *result)
{
u64 current_entry = offset; int rc = 0;
while (true) {
u32 id = ef100_pci_get_bar_bits(efx, current_entry, ENTRY_FORMAT);
u32 last = ef100_pci_get_bar_bits(efx, current_entry, ENTRY_LAST);
u32 rev = ef100_pci_get_bar_bits(efx, current_entry, ENTRY_REV);
u32 entry_size;
if (bar == ESE_GZ_CFGBAR_CONT_CAP_BAR_NUM_EXPANSION_ROM ||
bar == ESE_GZ_CFGBAR_CONT_CAP_BAR_NUM_INVALID) {
netif_err(efx, probe, efx->net_dev, "Bad BAR value of %d in Xilinx capabilities sub-table.\n",
bar); return -EINVAL;
}
/* Get length of whole capability - i.e. starting at cap */
rc = ef100_pci_get_config_bits(efx, vndr_cap, LEN, &vsec_len); if (rc) {
netif_err(efx, probe, efx->net_dev, "Failed to read ESF_GZ_VSEC_LEN, rc=%d\n",
rc); return rc;
}
if (num_xilinx_caps && !result->valid) {
netif_err(efx, probe, efx->net_dev, "Seen %d Xilinx tables, but no EF100 entry.\n",
num_xilinx_caps); return -EINVAL;
}
return 0;
}
/* Final NIC shutdown * This is called only at module unload (or hotplug removal). A PF can call * this on its VFs to ensure they are unbound first.
*/ staticvoid ef100_pci_remove(struct pci_dev *pci_dev)
{ struct efx_nic *efx = pci_get_drvdata(pci_dev); struct efx_probe_data *probe_data;
efx->vi_stride = EF100_DEFAULT_VI_STRIDE;
pci_info(pci_dev, "Solarflare EF100 NIC detected\n");
rc = ef100_pci_find_func_ctrl_window(efx, &fcw); if (rc) {
pci_err(pci_dev, "Error looking for ef100 function control window, rc=%d\n",
rc); goto fail;
}
if (!fcw.valid) { /* Extended capability not found - use defaults. */
fcw.bar = EFX_EF100_PCI_DEFAULT_BAR;
fcw.offset = 0;
fcw.valid = true;
}
if (fcw.offset > pci_resource_len(efx->pci_dev, fcw.bar) - ESE_GZ_FCW_LEN) {
pci_err(pci_dev, "Func control window overruns BAR\n");
rc = -EIO; goto fail;
}
/* Set up basic I/O (BAR mappings etc) */
rc = efx_init_io(efx, fcw.bar,
(dma_addr_t)DMA_BIT_MASK(ESF_GZ_TX_SEND_ADDR_WIDTH),
pci_resource_len(efx->pci_dev, fcw.bar)); if (rc) goto fail;
efx->reg_base = fcw.offset;
rc = efx->type->probe(efx); if (rc) goto fail;
efx->state = STATE_PROBED;
rc = ef100_probe_netdev(probe_data); if (rc) goto fail;
pci_dbg(pci_dev, "initialisation successful\n");
return 0;
fail:
ef100_pci_remove(pci_dev); return rc;
}
#ifdef CONFIG_SFC_SRIOV staticint ef100_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
{ struct efx_nic *efx = pci_get_drvdata(dev); int rc;
if (efx->type->sriov_configure) {
rc = efx->type->sriov_configure(efx, num_vfs); if (rc) return rc; else return num_vfs;
} return -ENOENT;
} #endif
/* PCI device ID table */ staticconststruct pci_device_id ef100_pci_table[] = {
{PCI_DEVICE(PCI_VENDOR_ID_XILINX, 0x0100), /* Riverhead PF */
.driver_data = (unsignedlong) &ef100_pf_nic_type },
{PCI_DEVICE(PCI_VENDOR_ID_XILINX, 0x1100), /* Riverhead VF */
.driver_data = (unsignedlong) &ef100_vf_nic_type },
{0} /* end of list */
};
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.