sfc: Add support for SFC9000 family (2)
This integrates support for the SFC9000 family of 10G Ethernet controllers and LAN-on-motherboard chips, starting with the SFL9021 'Siena' and SFC9020 'Bethpage'. Credit for this code is largely due to my colleagues at Solarflare: Guido Barzini Steve Hodgson Kieran Mansley Matthew Slattery Neil Turton Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
afd4aea03f
commit
8880f4ec21
@@ -1,5 +1,5 @@
|
|||||||
config SFC
|
config SFC
|
||||||
tristate "Solarflare Solarstorm SFC4000 support"
|
tristate "Solarflare Solarstorm SFC4000/SFC9000-family support"
|
||||||
depends on PCI && INET
|
depends on PCI && INET
|
||||||
select MDIO
|
select MDIO
|
||||||
select CRC32
|
select CRC32
|
||||||
@@ -7,15 +7,16 @@ config SFC
|
|||||||
select I2C_ALGOBIT
|
select I2C_ALGOBIT
|
||||||
help
|
help
|
||||||
This driver supports 10-gigabit Ethernet cards based on
|
This driver supports 10-gigabit Ethernet cards based on
|
||||||
the Solarflare Communications Solarstorm SFC4000 controller.
|
the Solarflare Communications Solarstorm SFC4000 and
|
||||||
|
SFC9000-family controllers.
|
||||||
|
|
||||||
To compile this driver as a module, choose M here. The module
|
To compile this driver as a module, choose M here. The module
|
||||||
will be called sfc.
|
will be called sfc.
|
||||||
config SFC_MTD
|
config SFC_MTD
|
||||||
bool "Solarflare Solarstorm SFC4000 flash MTD support"
|
bool "Solarflare Solarstorm SFC4000/SFC9000-family MTD support"
|
||||||
depends on SFC && MTD && !(SFC=y && MTD=m)
|
depends on SFC && MTD && !(SFC=y && MTD=m)
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
This exposes the on-board flash memory as an MTD device (e.g.
|
This exposes the on-board flash memory as MTD devices (e.g.
|
||||||
/dev/mtd1). This makes it possible to upload new boot code
|
/dev/mtd1). This makes it possible to upload new firmware
|
||||||
to the NIC.
|
to the NIC.
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
sfc-y += efx.o nic.o falcon.o tx.o rx.o falcon_gmac.o \
|
sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o \
|
||||||
falcon_xmac.o selftest.o ethtool.o qt202x_phy.o \
|
falcon_gmac.o falcon_xmac.o mcdi_mac.o \
|
||||||
mdio_10g.o tenxpress.o falcon_boards.o
|
selftest.o ethtool.o qt202x_phy.o mdio_10g.o \
|
||||||
|
tenxpress.o falcon_boards.o mcdi.o mcdi_phy.o
|
||||||
sfc-$(CONFIG_SFC_MTD) += mtd.o
|
sfc-$(CONFIG_SFC_MTD) += mtd.o
|
||||||
|
|
||||||
obj-$(CONFIG_SFC) += sfc.o
|
obj-$(CONFIG_SFC) += sfc.o
|
||||||
|
@@ -37,6 +37,8 @@
|
|||||||
#define EFX_DWORD_2_WIDTH 32
|
#define EFX_DWORD_2_WIDTH 32
|
||||||
#define EFX_DWORD_3_LBN 96
|
#define EFX_DWORD_3_LBN 96
|
||||||
#define EFX_DWORD_3_WIDTH 32
|
#define EFX_DWORD_3_WIDTH 32
|
||||||
|
#define EFX_QWORD_0_LBN 0
|
||||||
|
#define EFX_QWORD_0_WIDTH 64
|
||||||
|
|
||||||
/* Specified attribute (e.g. LBN) of the specified field */
|
/* Specified attribute (e.g. LBN) of the specified field */
|
||||||
#define EFX_VAL(field, attribute) field ## _ ## attribute
|
#define EFX_VAL(field, attribute) field ## _ ## attribute
|
||||||
|
@@ -25,6 +25,8 @@
|
|||||||
#include "mdio_10g.h"
|
#include "mdio_10g.h"
|
||||||
#include "nic.h"
|
#include "nic.h"
|
||||||
|
|
||||||
|
#include "mcdi.h"
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
*
|
*
|
||||||
* Type name strings
|
* Type name strings
|
||||||
@@ -84,6 +86,7 @@ const char *efx_reset_type_names[] = {
|
|||||||
[RESET_TYPE_RX_DESC_FETCH] = "RX_DESC_FETCH",
|
[RESET_TYPE_RX_DESC_FETCH] = "RX_DESC_FETCH",
|
||||||
[RESET_TYPE_TX_DESC_FETCH] = "TX_DESC_FETCH",
|
[RESET_TYPE_TX_DESC_FETCH] = "TX_DESC_FETCH",
|
||||||
[RESET_TYPE_TX_SKIP] = "TX_SKIP",
|
[RESET_TYPE_TX_SKIP] = "TX_SKIP",
|
||||||
|
[RESET_TYPE_MC_FAILURE] = "MC_FAILURE",
|
||||||
};
|
};
|
||||||
|
|
||||||
#define EFX_MAX_MTU (9 * 1024)
|
#define EFX_MAX_MTU (9 * 1024)
|
||||||
@@ -1191,6 +1194,15 @@ static void efx_start_all(struct efx_nic *efx)
|
|||||||
|
|
||||||
efx_nic_enable_interrupts(efx);
|
efx_nic_enable_interrupts(efx);
|
||||||
|
|
||||||
|
/* Switch to event based MCDI completions after enabling interrupts.
|
||||||
|
* If a reset has been scheduled, then we need to stay in polled mode.
|
||||||
|
* Rather than serialising efx_mcdi_mode_event() [which sleeps] and
|
||||||
|
* reset_pending [modified from an atomic context], we instead guarantee
|
||||||
|
* that efx_mcdi_mode_poll() isn't reverted erroneously */
|
||||||
|
efx_mcdi_mode_event(efx);
|
||||||
|
if (efx->reset_pending != RESET_TYPE_NONE)
|
||||||
|
efx_mcdi_mode_poll(efx);
|
||||||
|
|
||||||
/* Start the hardware monitor if there is one. Otherwise (we're link
|
/* Start the hardware monitor if there is one. Otherwise (we're link
|
||||||
* event driven), we have to poll the PHY because after an event queue
|
* event driven), we have to poll the PHY because after an event queue
|
||||||
* flush, we could have a missed a link state change */
|
* flush, we could have a missed a link state change */
|
||||||
@@ -1242,6 +1254,9 @@ static void efx_stop_all(struct efx_nic *efx)
|
|||||||
|
|
||||||
efx->type->stop_stats(efx);
|
efx->type->stop_stats(efx);
|
||||||
|
|
||||||
|
/* Switch to MCDI polling on Siena before disabling interrupts */
|
||||||
|
efx_mcdi_mode_poll(efx);
|
||||||
|
|
||||||
/* Disable interrupts and wait for ISR to complete */
|
/* Disable interrupts and wait for ISR to complete */
|
||||||
efx_nic_disable_interrupts(efx);
|
efx_nic_disable_interrupts(efx);
|
||||||
if (efx->legacy_irq)
|
if (efx->legacy_irq)
|
||||||
@@ -1445,6 +1460,8 @@ static int efx_net_open(struct net_device *net_dev)
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
if (efx->phy_mode & PHY_MODE_SPECIAL)
|
if (efx->phy_mode & PHY_MODE_SPECIAL)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
if (efx_mcdi_poll_reboot(efx) && efx_reset(efx, RESET_TYPE_ALL))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
/* Notify the kernel of the link state polled during driver load,
|
/* Notify the kernel of the link state polled during driver load,
|
||||||
* before the monitor starts running */
|
* before the monitor starts running */
|
||||||
@@ -1895,6 +1912,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
|
|||||||
case RESET_TYPE_TX_SKIP:
|
case RESET_TYPE_TX_SKIP:
|
||||||
method = RESET_TYPE_INVISIBLE;
|
method = RESET_TYPE_INVISIBLE;
|
||||||
break;
|
break;
|
||||||
|
case RESET_TYPE_MC_FAILURE:
|
||||||
default:
|
default:
|
||||||
method = RESET_TYPE_ALL;
|
method = RESET_TYPE_ALL;
|
||||||
break;
|
break;
|
||||||
@@ -1908,6 +1926,10 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
|
|||||||
|
|
||||||
efx->reset_pending = method;
|
efx->reset_pending = method;
|
||||||
|
|
||||||
|
/* efx_process_channel() will no longer read events once a
|
||||||
|
* reset is scheduled. So switch back to poll'd MCDI completions. */
|
||||||
|
efx_mcdi_mode_poll(efx);
|
||||||
|
|
||||||
queue_work(reset_workqueue, &efx->reset_work);
|
queue_work(reset_workqueue, &efx->reset_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1923,6 +1945,10 @@ static struct pci_device_id efx_pci_table[] __devinitdata = {
|
|||||||
.driver_data = (unsigned long) &falcon_a1_nic_type},
|
.driver_data = (unsigned long) &falcon_a1_nic_type},
|
||||||
{PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID),
|
{PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID),
|
||||||
.driver_data = (unsigned long) &falcon_b0_nic_type},
|
.driver_data = (unsigned long) &falcon_b0_nic_type},
|
||||||
|
{PCI_DEVICE(EFX_VENDID_SFC, BETHPAGE_A_P_DEVID),
|
||||||
|
.driver_data = (unsigned long) &siena_a0_nic_type},
|
||||||
|
{PCI_DEVICE(EFX_VENDID_SFC, SIENA_A_P_DEVID),
|
||||||
|
.driver_data = (unsigned long) &siena_a0_nic_type},
|
||||||
{0} /* end of list */
|
{0} /* end of list */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -18,6 +18,8 @@
|
|||||||
#define FALCON_A_P_DEVID 0x0703
|
#define FALCON_A_P_DEVID 0x0703
|
||||||
#define FALCON_A_S_DEVID 0x6703
|
#define FALCON_A_S_DEVID 0x6703
|
||||||
#define FALCON_B_P_DEVID 0x0710
|
#define FALCON_B_P_DEVID 0x0710
|
||||||
|
#define BETHPAGE_A_P_DEVID 0x0803
|
||||||
|
#define SIENA_A_P_DEVID 0x0813
|
||||||
|
|
||||||
/* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */
|
/* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */
|
||||||
#define EFX_MEM_BAR 2
|
#define EFX_MEM_BAR 2
|
||||||
|
@@ -144,6 +144,7 @@ enum efx_loopback_mode {
|
|||||||
* @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch
|
* @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch
|
||||||
* @RESET_TYPE_TX_DESC_FETCH: pcie error during tx descriptor fetch
|
* @RESET_TYPE_TX_DESC_FETCH: pcie error during tx descriptor fetch
|
||||||
* @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors
|
* @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors
|
||||||
|
* @RESET_TYPE_MC_FAILURE: MC reboot/assertion
|
||||||
*/
|
*/
|
||||||
enum reset_type {
|
enum reset_type {
|
||||||
RESET_TYPE_NONE = -1,
|
RESET_TYPE_NONE = -1,
|
||||||
@@ -158,6 +159,7 @@ enum reset_type {
|
|||||||
RESET_TYPE_RX_DESC_FETCH,
|
RESET_TYPE_RX_DESC_FETCH,
|
||||||
RESET_TYPE_TX_DESC_FETCH,
|
RESET_TYPE_TX_DESC_FETCH,
|
||||||
RESET_TYPE_TX_SKIP,
|
RESET_TYPE_TX_SKIP,
|
||||||
|
RESET_TYPE_MC_FAILURE,
|
||||||
RESET_TYPE_MAX,
|
RESET_TYPE_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -236,6 +236,9 @@ static void efx_ethtool_get_drvinfo(struct net_device *net_dev,
|
|||||||
|
|
||||||
strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver));
|
strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver));
|
||||||
strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
|
strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
|
||||||
|
if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0)
|
||||||
|
siena_print_fwver(efx, info->fw_version,
|
||||||
|
sizeof(info->fw_version));
|
||||||
strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info));
|
strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
|
|
||||||
extern struct efx_mac_operations falcon_gmac_operations;
|
extern struct efx_mac_operations falcon_gmac_operations;
|
||||||
extern struct efx_mac_operations falcon_xmac_operations;
|
extern struct efx_mac_operations falcon_xmac_operations;
|
||||||
|
extern struct efx_mac_operations efx_mcdi_mac_operations;
|
||||||
extern void falcon_reconfigure_xmac_core(struct efx_nic *efx);
|
extern void falcon_reconfigure_xmac_core(struct efx_nic *efx);
|
||||||
|
extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
|
||||||
|
u32 dma_len, int enable, int clear);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
* by the Free Software Foundation, incorporated herein by reference.
|
* by the Free Software Foundation, incorporated herein by reference.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitops.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/mtd/mtd.h>
|
#include <linux/mtd/mtd.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
@@ -18,12 +19,22 @@
|
|||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
#include "efx.h"
|
#include "efx.h"
|
||||||
#include "nic.h"
|
#include "nic.h"
|
||||||
|
#include "mcdi.h"
|
||||||
|
#include "mcdi_pcol.h"
|
||||||
|
|
||||||
#define EFX_SPI_VERIFY_BUF_LEN 16
|
#define EFX_SPI_VERIFY_BUF_LEN 16
|
||||||
|
#define EFX_MCDI_CHUNK_LEN 128
|
||||||
|
|
||||||
struct efx_mtd_partition {
|
struct efx_mtd_partition {
|
||||||
struct mtd_info mtd;
|
struct mtd_info mtd;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
bool updating;
|
||||||
|
u8 nvram_type;
|
||||||
|
u16 fw_subtype;
|
||||||
|
} mcdi;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
|
};
|
||||||
const char *type_name;
|
const char *type_name;
|
||||||
char name[IFNAMSIZ + 20];
|
char name[IFNAMSIZ + 20];
|
||||||
};
|
};
|
||||||
@@ -56,6 +67,7 @@ struct efx_mtd {
|
|||||||
container_of(mtd, struct efx_mtd_partition, mtd)
|
container_of(mtd, struct efx_mtd_partition, mtd)
|
||||||
|
|
||||||
static int falcon_mtd_probe(struct efx_nic *efx);
|
static int falcon_mtd_probe(struct efx_nic *efx);
|
||||||
|
static int siena_mtd_probe(struct efx_nic *efx);
|
||||||
|
|
||||||
/* SPI utilities */
|
/* SPI utilities */
|
||||||
|
|
||||||
@@ -223,6 +235,11 @@ static void efx_mtd_rename_device(struct efx_mtd *efx_mtd)
|
|||||||
struct efx_mtd_partition *part;
|
struct efx_mtd_partition *part;
|
||||||
|
|
||||||
efx_for_each_partition(part, efx_mtd)
|
efx_for_each_partition(part, efx_mtd)
|
||||||
|
if (efx_nic_rev(efx_mtd->efx) >= EFX_REV_SIENA_A0)
|
||||||
|
snprintf(part->name, sizeof(part->name),
|
||||||
|
"%s %s:%02x", efx_mtd->efx->name,
|
||||||
|
part->type_name, part->mcdi.fw_subtype);
|
||||||
|
else
|
||||||
snprintf(part->name, sizeof(part->name),
|
snprintf(part->name, sizeof(part->name),
|
||||||
"%s %s", efx_mtd->efx->name,
|
"%s %s", efx_mtd->efx->name,
|
||||||
part->type_name);
|
part->type_name);
|
||||||
@@ -285,6 +302,9 @@ void efx_mtd_rename(struct efx_nic *efx)
|
|||||||
|
|
||||||
int efx_mtd_probe(struct efx_nic *efx)
|
int efx_mtd_probe(struct efx_nic *efx)
|
||||||
{
|
{
|
||||||
|
if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0)
|
||||||
|
return siena_mtd_probe(efx);
|
||||||
|
else
|
||||||
return falcon_mtd_probe(efx);
|
return falcon_mtd_probe(efx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,3 +413,240 @@ static int falcon_mtd_probe(struct efx_nic *efx)
|
|||||||
kfree(efx_mtd);
|
kfree(efx_mtd);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Implementation of MTD operations for Siena */
|
||||||
|
|
||||||
|
static int siena_mtd_read(struct mtd_info *mtd, loff_t start,
|
||||||
|
size_t len, size_t *retlen, u8 *buffer)
|
||||||
|
{
|
||||||
|
struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
|
||||||
|
struct efx_mtd *efx_mtd = mtd->priv;
|
||||||
|
struct efx_nic *efx = efx_mtd->efx;
|
||||||
|
loff_t offset = start;
|
||||||
|
loff_t end = min_t(loff_t, start + len, mtd->size);
|
||||||
|
size_t chunk;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
while (offset < end) {
|
||||||
|
chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN);
|
||||||
|
rc = efx_mcdi_nvram_read(efx, part->mcdi.nvram_type, offset,
|
||||||
|
buffer, chunk);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
offset += chunk;
|
||||||
|
buffer += chunk;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
*retlen = offset - start;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int siena_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len)
|
||||||
|
{
|
||||||
|
struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
|
||||||
|
struct efx_mtd *efx_mtd = mtd->priv;
|
||||||
|
struct efx_nic *efx = efx_mtd->efx;
|
||||||
|
loff_t offset = start & ~((loff_t)(mtd->erasesize - 1));
|
||||||
|
loff_t end = min_t(loff_t, start + len, mtd->size);
|
||||||
|
size_t chunk = part->mtd.erasesize;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!part->mcdi.updating) {
|
||||||
|
rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
part->mcdi.updating = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The MCDI interface can in fact do multiple erase blocks at once;
|
||||||
|
* but erasing may be slow, so we make multiple calls here to avoid
|
||||||
|
* tripping the MCDI RPC timeout. */
|
||||||
|
while (offset < end) {
|
||||||
|
rc = efx_mcdi_nvram_erase(efx, part->mcdi.nvram_type, offset,
|
||||||
|
chunk);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
offset += chunk;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int siena_mtd_write(struct mtd_info *mtd, loff_t start,
|
||||||
|
size_t len, size_t *retlen, const u8 *buffer)
|
||||||
|
{
|
||||||
|
struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
|
||||||
|
struct efx_mtd *efx_mtd = mtd->priv;
|
||||||
|
struct efx_nic *efx = efx_mtd->efx;
|
||||||
|
loff_t offset = start;
|
||||||
|
loff_t end = min_t(loff_t, start + len, mtd->size);
|
||||||
|
size_t chunk;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!part->mcdi.updating) {
|
||||||
|
rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
part->mcdi.updating = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (offset < end) {
|
||||||
|
chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN);
|
||||||
|
rc = efx_mcdi_nvram_write(efx, part->mcdi.nvram_type, offset,
|
||||||
|
buffer, chunk);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
offset += chunk;
|
||||||
|
buffer += chunk;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
*retlen = offset - start;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int siena_mtd_sync(struct mtd_info *mtd)
|
||||||
|
{
|
||||||
|
struct efx_mtd_partition *part = to_efx_mtd_partition(mtd);
|
||||||
|
struct efx_mtd *efx_mtd = mtd->priv;
|
||||||
|
struct efx_nic *efx = efx_mtd->efx;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (part->mcdi.updating) {
|
||||||
|
part->mcdi.updating = 0;
|
||||||
|
rc = efx_mcdi_nvram_update_finish(efx, part->mcdi.nvram_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct efx_mtd_ops siena_mtd_ops = {
|
||||||
|
.read = siena_mtd_read,
|
||||||
|
.erase = siena_mtd_erase,
|
||||||
|
.write = siena_mtd_write,
|
||||||
|
.sync = siena_mtd_sync,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct siena_nvram_type_info {
|
||||||
|
int port;
|
||||||
|
const char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct siena_nvram_type_info siena_nvram_types[] = {
|
||||||
|
[MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO] = { 0, "sfc_dummy_phy" },
|
||||||
|
[MC_CMD_NVRAM_TYPE_MC_FW] = { 0, "sfc_mcfw" },
|
||||||
|
[MC_CMD_NVRAM_TYPE_MC_FW_BACKUP] = { 0, "sfc_mcfw_backup" },
|
||||||
|
[MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0] = { 0, "sfc_static_cfg" },
|
||||||
|
[MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1] = { 1, "sfc_static_cfg" },
|
||||||
|
[MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0] = { 0, "sfc_dynamic_cfg" },
|
||||||
|
[MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1] = { 1, "sfc_dynamic_cfg" },
|
||||||
|
[MC_CMD_NVRAM_TYPE_EXP_ROM] = { 0, "sfc_exp_rom" },
|
||||||
|
[MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0] = { 0, "sfc_exp_rom_cfg" },
|
||||||
|
[MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1] = { 1, "sfc_exp_rom_cfg" },
|
||||||
|
[MC_CMD_NVRAM_TYPE_PHY_PORT0] = { 0, "sfc_phy_fw" },
|
||||||
|
[MC_CMD_NVRAM_TYPE_PHY_PORT1] = { 1, "sfc_phy_fw" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int siena_mtd_probe_partition(struct efx_nic *efx,
|
||||||
|
struct efx_mtd *efx_mtd,
|
||||||
|
unsigned int part_id,
|
||||||
|
unsigned int type)
|
||||||
|
{
|
||||||
|
struct efx_mtd_partition *part = &efx_mtd->part[part_id];
|
||||||
|
struct siena_nvram_type_info *info;
|
||||||
|
size_t size, erase_size;
|
||||||
|
bool protected;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (type >= ARRAY_SIZE(siena_nvram_types))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
info = &siena_nvram_types[type];
|
||||||
|
|
||||||
|
if (info->port != efx_port_num(efx))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
if (protected)
|
||||||
|
return -ENODEV; /* hide it */
|
||||||
|
|
||||||
|
part->mcdi.nvram_type = type;
|
||||||
|
part->type_name = info->name;
|
||||||
|
|
||||||
|
part->mtd.type = MTD_NORFLASH;
|
||||||
|
part->mtd.flags = MTD_CAP_NORFLASH;
|
||||||
|
part->mtd.size = size;
|
||||||
|
part->mtd.erasesize = erase_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int siena_mtd_get_fw_subtypes(struct efx_nic *efx,
|
||||||
|
struct efx_mtd *efx_mtd)
|
||||||
|
{
|
||||||
|
struct efx_mtd_partition *part;
|
||||||
|
uint16_t fw_subtype_list[MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN /
|
||||||
|
sizeof(uint16_t)];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = efx_mcdi_get_board_cfg(efx, NULL, fw_subtype_list);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
efx_for_each_partition(part, efx_mtd)
|
||||||
|
part->mcdi.fw_subtype = fw_subtype_list[part->mcdi.nvram_type];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int siena_mtd_probe(struct efx_nic *efx)
|
||||||
|
{
|
||||||
|
struct efx_mtd *efx_mtd;
|
||||||
|
int rc = -ENODEV;
|
||||||
|
u32 nvram_types;
|
||||||
|
unsigned int type;
|
||||||
|
|
||||||
|
ASSERT_RTNL();
|
||||||
|
|
||||||
|
rc = efx_mcdi_nvram_types(efx, &nvram_types);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
efx_mtd = kzalloc(sizeof(*efx_mtd) +
|
||||||
|
hweight32(nvram_types) * sizeof(efx_mtd->part[0]),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!efx_mtd)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
efx_mtd->name = "Siena NVRAM manager";
|
||||||
|
|
||||||
|
efx_mtd->ops = &siena_mtd_ops;
|
||||||
|
|
||||||
|
type = 0;
|
||||||
|
efx_mtd->n_parts = 0;
|
||||||
|
|
||||||
|
while (nvram_types != 0) {
|
||||||
|
if (nvram_types & 1) {
|
||||||
|
rc = siena_mtd_probe_partition(efx, efx_mtd,
|
||||||
|
efx_mtd->n_parts, type);
|
||||||
|
if (rc == 0)
|
||||||
|
efx_mtd->n_parts++;
|
||||||
|
else if (rc != -ENODEV)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
type++;
|
||||||
|
nvram_types >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = siena_mtd_get_fw_subtypes(efx, efx_mtd);
|
||||||
|
if (rc)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
rc = efx_mtd_probe_device(efx, efx_mtd);
|
||||||
|
fail:
|
||||||
|
if (rc)
|
||||||
|
kfree(efx_mtd);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -706,6 +706,7 @@ union efx_multicast_hash {
|
|||||||
* @phy_op: PHY interface
|
* @phy_op: PHY interface
|
||||||
* @phy_data: PHY private data (including PHY-specific stats)
|
* @phy_data: PHY private data (including PHY-specific stats)
|
||||||
* @mdio: PHY MDIO interface
|
* @mdio: PHY MDIO interface
|
||||||
|
* @mdio_bus: PHY MDIO bus ID (only used by Siena)
|
||||||
* @phy_mode: PHY operating mode. Serialised by @mac_lock.
|
* @phy_mode: PHY operating mode. Serialised by @mac_lock.
|
||||||
* @xmac_poll_required: XMAC link state needs polling
|
* @xmac_poll_required: XMAC link state needs polling
|
||||||
* @link_advertising: Autonegotiation advertising flags
|
* @link_advertising: Autonegotiation advertising flags
|
||||||
@@ -756,6 +757,7 @@ struct efx_nic {
|
|||||||
|
|
||||||
struct efx_buffer irq_status;
|
struct efx_buffer irq_status;
|
||||||
volatile signed int last_irq_cpu;
|
volatile signed int last_irq_cpu;
|
||||||
|
unsigned long irq_zero_count;
|
||||||
|
|
||||||
struct efx_spi_device *spi_flash;
|
struct efx_spi_device *spi_flash;
|
||||||
struct efx_spi_device *spi_eeprom;
|
struct efx_spi_device *spi_eeprom;
|
||||||
@@ -766,7 +768,7 @@ struct efx_nic {
|
|||||||
|
|
||||||
unsigned n_rx_nodesc_drop_cnt;
|
unsigned n_rx_nodesc_drop_cnt;
|
||||||
|
|
||||||
struct falcon_nic_data *nic_data;
|
void *nic_data;
|
||||||
|
|
||||||
struct mutex mac_lock;
|
struct mutex mac_lock;
|
||||||
struct work_struct mac_work;
|
struct work_struct mac_work;
|
||||||
@@ -792,6 +794,7 @@ struct efx_nic {
|
|||||||
struct efx_phy_operations *phy_op;
|
struct efx_phy_operations *phy_op;
|
||||||
void *phy_data;
|
void *phy_data;
|
||||||
struct mdio_if_info mdio;
|
struct mdio_if_info mdio;
|
||||||
|
unsigned int mdio_bus;
|
||||||
enum efx_phy_mode phy_mode;
|
enum efx_phy_mode phy_mode;
|
||||||
|
|
||||||
bool xmac_poll_required;
|
bool xmac_poll_required;
|
||||||
@@ -824,6 +827,11 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
|
|||||||
return efx_dev_registered(efx) ? efx->name : "";
|
return efx_dev_registered(efx) ? efx->name : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline unsigned int efx_port_num(struct efx_nic *efx)
|
||||||
|
{
|
||||||
|
return PCI_FUNC(efx->pci_dev->devfn);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct efx_nic_type - Efx device type definition
|
* struct efx_nic_type - Efx device type definition
|
||||||
* @probe: Probe the controller
|
* @probe: Probe the controller
|
||||||
|
@@ -997,6 +997,9 @@ int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota)
|
|||||||
case FSE_AZ_EV_CODE_DRIVER_EV:
|
case FSE_AZ_EV_CODE_DRIVER_EV:
|
||||||
efx_handle_driver_event(channel, &event);
|
efx_handle_driver_event(channel, &event);
|
||||||
break;
|
break;
|
||||||
|
case FSE_CZ_EV_CODE_MCDI_EV:
|
||||||
|
efx_mcdi_process_event(channel, &event);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
EFX_ERR(channel->efx, "channel %d unknown event type %d"
|
EFX_ERR(channel->efx, "channel %d unknown event type %d"
|
||||||
" (data " EFX_QWORD_FMT ")\n", channel->channel,
|
" (data " EFX_QWORD_FMT ")\n", channel->channel,
|
||||||
@@ -1025,13 +1028,21 @@ int efx_nic_probe_eventq(struct efx_channel *channel)
|
|||||||
|
|
||||||
void efx_nic_init_eventq(struct efx_channel *channel)
|
void efx_nic_init_eventq(struct efx_channel *channel)
|
||||||
{
|
{
|
||||||
efx_oword_t evq_ptr;
|
efx_oword_t reg;
|
||||||
struct efx_nic *efx = channel->efx;
|
struct efx_nic *efx = channel->efx;
|
||||||
|
|
||||||
EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n",
|
EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n",
|
||||||
channel->channel, channel->eventq.index,
|
channel->channel, channel->eventq.index,
|
||||||
channel->eventq.index + channel->eventq.entries - 1);
|
channel->eventq.index + channel->eventq.entries - 1);
|
||||||
|
|
||||||
|
if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) {
|
||||||
|
EFX_POPULATE_OWORD_3(reg,
|
||||||
|
FRF_CZ_TIMER_Q_EN, 1,
|
||||||
|
FRF_CZ_HOST_NOTIFY_MODE, 0,
|
||||||
|
FRF_CZ_TIMER_MODE, FFE_CZ_TIMER_MODE_DIS);
|
||||||
|
efx_writeo_table(efx, ®, FR_BZ_TIMER_TBL, channel->channel);
|
||||||
|
}
|
||||||
|
|
||||||
/* Pin event queue buffer */
|
/* Pin event queue buffer */
|
||||||
efx_init_special_buffer(efx, &channel->eventq);
|
efx_init_special_buffer(efx, &channel->eventq);
|
||||||
|
|
||||||
@@ -1039,11 +1050,11 @@ void efx_nic_init_eventq(struct efx_channel *channel)
|
|||||||
memset(channel->eventq.addr, 0xff, channel->eventq.len);
|
memset(channel->eventq.addr, 0xff, channel->eventq.len);
|
||||||
|
|
||||||
/* Push event queue to card */
|
/* Push event queue to card */
|
||||||
EFX_POPULATE_OWORD_3(evq_ptr,
|
EFX_POPULATE_OWORD_3(reg,
|
||||||
FRF_AZ_EVQ_EN, 1,
|
FRF_AZ_EVQ_EN, 1,
|
||||||
FRF_AZ_EVQ_SIZE, __ffs(channel->eventq.entries),
|
FRF_AZ_EVQ_SIZE, __ffs(channel->eventq.entries),
|
||||||
FRF_AZ_EVQ_BUF_BASE_ID, channel->eventq.index);
|
FRF_AZ_EVQ_BUF_BASE_ID, channel->eventq.index);
|
||||||
efx_writeo_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base,
|
efx_writeo_table(efx, ®, efx->type->evq_ptr_tbl_base,
|
||||||
channel->channel);
|
channel->channel);
|
||||||
|
|
||||||
efx->type->push_irq_moderation(channel);
|
efx->type->push_irq_moderation(channel);
|
||||||
@@ -1051,13 +1062,15 @@ void efx_nic_init_eventq(struct efx_channel *channel)
|
|||||||
|
|
||||||
void efx_nic_fini_eventq(struct efx_channel *channel)
|
void efx_nic_fini_eventq(struct efx_channel *channel)
|
||||||
{
|
{
|
||||||
efx_oword_t eventq_ptr;
|
efx_oword_t reg;
|
||||||
struct efx_nic *efx = channel->efx;
|
struct efx_nic *efx = channel->efx;
|
||||||
|
|
||||||
/* Remove event queue from card */
|
/* Remove event queue from card */
|
||||||
EFX_ZERO_OWORD(eventq_ptr);
|
EFX_ZERO_OWORD(reg);
|
||||||
efx_writeo_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base,
|
efx_writeo_table(efx, ®, efx->type->evq_ptr_tbl_base,
|
||||||
channel->channel);
|
channel->channel);
|
||||||
|
if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0)
|
||||||
|
efx_writeo_table(efx, ®, FR_BZ_TIMER_TBL, channel->channel);
|
||||||
|
|
||||||
/* Unpin event queue */
|
/* Unpin event queue */
|
||||||
efx_fini_special_buffer(efx, &channel->eventq);
|
efx_fini_special_buffer(efx, &channel->eventq);
|
||||||
@@ -1220,8 +1233,15 @@ static inline void efx_nic_interrupts(struct efx_nic *efx,
|
|||||||
bool enabled, bool force)
|
bool enabled, bool force)
|
||||||
{
|
{
|
||||||
efx_oword_t int_en_reg_ker;
|
efx_oword_t int_en_reg_ker;
|
||||||
|
unsigned int level = 0;
|
||||||
|
|
||||||
EFX_POPULATE_OWORD_2(int_en_reg_ker,
|
if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx))
|
||||||
|
/* Set the level always even if we're generating a test
|
||||||
|
* interrupt, because our legacy interrupt handler is safe */
|
||||||
|
level = 0x1f;
|
||||||
|
|
||||||
|
EFX_POPULATE_OWORD_3(int_en_reg_ker,
|
||||||
|
FRF_AZ_KER_INT_LEVE_SEL, level,
|
||||||
FRF_AZ_KER_INT_KER, force,
|
FRF_AZ_KER_INT_KER, force,
|
||||||
FRF_AZ_DRV_INT_EN_KER, enabled);
|
FRF_AZ_DRV_INT_EN_KER, enabled);
|
||||||
efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER);
|
efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER);
|
||||||
@@ -1334,16 +1354,31 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
|
|||||||
if (unlikely(syserr))
|
if (unlikely(syserr))
|
||||||
return efx_nic_fatal_interrupt(efx);
|
return efx_nic_fatal_interrupt(efx);
|
||||||
|
|
||||||
|
if (queues != 0) {
|
||||||
|
if (EFX_WORKAROUND_15783(efx))
|
||||||
|
efx->irq_zero_count = 0;
|
||||||
|
|
||||||
/* Schedule processing of any interrupting queues */
|
/* Schedule processing of any interrupting queues */
|
||||||
efx_for_each_channel(channel, efx) {
|
efx_for_each_channel(channel, efx) {
|
||||||
if ((queues & 1) ||
|
if (queues & 1)
|
||||||
efx_event_present(
|
|
||||||
efx_event(channel, channel->eventq_read_ptr))) {
|
|
||||||
efx_schedule_channel(channel);
|
efx_schedule_channel(channel);
|
||||||
result = IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
queues >>= 1;
|
queues >>= 1;
|
||||||
}
|
}
|
||||||
|
result = IRQ_HANDLED;
|
||||||
|
|
||||||
|
} else if (EFX_WORKAROUND_15783(efx) &&
|
||||||
|
efx->irq_zero_count++ == 0) {
|
||||||
|
efx_qword_t *event;
|
||||||
|
|
||||||
|
/* Ensure we rearm all event queues */
|
||||||
|
efx_for_each_channel(channel, efx) {
|
||||||
|
event = efx_event(channel, channel->eventq_read_ptr);
|
||||||
|
if (efx_event_present(event))
|
||||||
|
efx_schedule_channel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
if (result == IRQ_HANDLED) {
|
if (result == IRQ_HANDLED) {
|
||||||
efx->last_irq_cpu = raw_smp_processor_id();
|
efx->last_irq_cpu = raw_smp_processor_id();
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
#include <linux/i2c-algo-bit.h>
|
#include <linux/i2c-algo-bit.h>
|
||||||
#include "net_driver.h"
|
#include "net_driver.h"
|
||||||
#include "efx.h"
|
#include "efx.h"
|
||||||
|
#include "mcdi.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Falcon hardware control
|
* Falcon hardware control
|
||||||
@@ -23,6 +24,7 @@ enum {
|
|||||||
EFX_REV_FALCON_A0 = 0,
|
EFX_REV_FALCON_A0 = 0,
|
||||||
EFX_REV_FALCON_A1 = 1,
|
EFX_REV_FALCON_A1 = 1,
|
||||||
EFX_REV_FALCON_B0 = 2,
|
EFX_REV_FALCON_B0 = 2,
|
||||||
|
EFX_REV_SIENA_A0 = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int efx_nic_rev(struct efx_nic *efx)
|
static inline int efx_nic_rev(struct efx_nic *efx)
|
||||||
@@ -32,6 +34,10 @@ static inline int efx_nic_rev(struct efx_nic *efx)
|
|||||||
|
|
||||||
extern u32 efx_nic_fpga_ver(struct efx_nic *efx);
|
extern u32 efx_nic_fpga_ver(struct efx_nic *efx);
|
||||||
|
|
||||||
|
static inline bool efx_nic_has_mc(struct efx_nic *efx)
|
||||||
|
{
|
||||||
|
return efx_nic_rev(efx) >= EFX_REV_SIENA_A0;
|
||||||
|
}
|
||||||
/* NIC has two interlinked PCI functions for the same port. */
|
/* NIC has two interlinked PCI functions for the same port. */
|
||||||
static inline bool efx_nic_is_dual_func(struct efx_nic *efx)
|
static inline bool efx_nic_is_dual_func(struct efx_nic *efx)
|
||||||
{
|
{
|
||||||
@@ -123,8 +129,25 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx)
|
|||||||
return &data->board;
|
return &data->board;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct siena_nic_data - Siena NIC state
|
||||||
|
* @fw_version: Management controller firmware version
|
||||||
|
* @fw_build: Firmware build number
|
||||||
|
* @mcdi: Management-Controller-to-Driver Interface
|
||||||
|
* @wol_filter_id: Wake-on-LAN packet filter id
|
||||||
|
*/
|
||||||
|
struct siena_nic_data {
|
||||||
|
u64 fw_version;
|
||||||
|
u32 fw_build;
|
||||||
|
struct efx_mcdi_iface mcdi;
|
||||||
|
int wol_filter_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len);
|
||||||
|
|
||||||
extern struct efx_nic_type falcon_a1_nic_type;
|
extern struct efx_nic_type falcon_a1_nic_type;
|
||||||
extern struct efx_nic_type falcon_b0_nic_type;
|
extern struct efx_nic_type falcon_b0_nic_type;
|
||||||
|
extern struct efx_nic_type siena_a0_nic_type;
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
*
|
*
|
||||||
|
@@ -41,4 +41,21 @@ extern struct efx_phy_operations falcon_qt202x_phy_ops;
|
|||||||
|
|
||||||
extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state);
|
extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Siena managed PHYs
|
||||||
|
*/
|
||||||
|
extern struct efx_phy_operations efx_mcdi_phy_ops;
|
||||||
|
|
||||||
|
extern int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus,
|
||||||
|
unsigned int prtad, unsigned int devad,
|
||||||
|
u16 addr, u16 *value_out, u32 *status_out);
|
||||||
|
extern int efx_mcdi_mdio_write(struct efx_nic *efx, unsigned int bus,
|
||||||
|
unsigned int prtad, unsigned int devad,
|
||||||
|
u16 addr, u16 value, u32 *status_out);
|
||||||
|
extern void efx_mcdi_phy_decode_link(struct efx_nic *efx,
|
||||||
|
struct efx_link_state *link_state,
|
||||||
|
u32 speed, u32 flags, u32 fcntl);
|
||||||
|
extern int efx_mcdi_phy_reconfigure(struct efx_nic *efx);
|
||||||
|
extern void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#define EFX_WORKAROUND_ALWAYS(efx) 1
|
#define EFX_WORKAROUND_ALWAYS(efx) 1
|
||||||
#define EFX_WORKAROUND_FALCON_A(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_A1)
|
#define EFX_WORKAROUND_FALCON_A(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_A1)
|
||||||
#define EFX_WORKAROUND_FALCON_AB(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_B0)
|
#define EFX_WORKAROUND_FALCON_AB(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_B0)
|
||||||
|
#define EFX_WORKAROUND_SIENA(efx) (efx_nic_rev(efx) == EFX_REV_SIENA_A0)
|
||||||
#define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx)
|
#define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx)
|
||||||
#define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \
|
#define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \
|
||||||
(efx)->phy_type == PHY_TYPE_SFT9001B)
|
(efx)->phy_type == PHY_TYPE_SFT9001B)
|
||||||
@@ -35,6 +36,10 @@
|
|||||||
#define EFX_WORKAROUND_11482 EFX_WORKAROUND_FALCON_AB
|
#define EFX_WORKAROUND_11482 EFX_WORKAROUND_FALCON_AB
|
||||||
/* Truncated IPv4 packets can confuse the TX packet parser */
|
/* Truncated IPv4 packets can confuse the TX packet parser */
|
||||||
#define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB
|
#define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB
|
||||||
|
/* Legacy ISR read can return zero once */
|
||||||
|
#define EFX_WORKAROUND_15783 EFX_WORKAROUND_SIENA
|
||||||
|
/* Legacy interrupt storm when interrupt fifo fills */
|
||||||
|
#define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA
|
||||||
|
|
||||||
/* Spurious parity errors in TSORT buffers */
|
/* Spurious parity errors in TSORT buffers */
|
||||||
#define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A
|
#define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A
|
||||||
|
Reference in New Issue
Block a user