* [PATCH 02/16] sfc: Treat all MAC registers as 128-bit
From: Ben Hutchings @ 2009-11-26 2:08 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
Although all the defined fields in these registers are within 32 bits,
they are architecturally defined as 128-bit like most other Falcon
registers. In particular, we must use efx_reado() to ensure proper
locking when reading MD_STAT_REG.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/falcon.c | 14 +++++++-------
drivers/net/sfc/falcon_xmac.c | 14 +++++++-------
2 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 7b19686..f97ef3e 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -2042,18 +2042,18 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
/* Wait for GMII access to complete */
static int falcon_gmii_wait(struct efx_nic *efx)
{
- efx_dword_t md_stat;
+ efx_oword_t md_stat;
int count;
/* wait upto 50ms - taken max from datasheet */
for (count = 0; count < 5000; count++) {
- efx_readd(efx, &md_stat, FR_AB_MD_STAT);
- if (EFX_DWORD_FIELD(md_stat, FRF_AB_MD_BSY) == 0) {
- if (EFX_DWORD_FIELD(md_stat, FRF_AB_MD_LNFL) != 0 ||
- EFX_DWORD_FIELD(md_stat, FRF_AB_MD_BSERR) != 0) {
+ efx_reado(efx, &md_stat, FR_AB_MD_STAT);
+ if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSY) == 0) {
+ if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_LNFL) != 0 ||
+ EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSERR) != 0) {
EFX_ERR(efx, "error from GMII access "
- EFX_DWORD_FMT"\n",
- EFX_DWORD_VAL(md_stat));
+ EFX_OWORD_FMT"\n",
+ EFX_OWORD_VAL(md_stat));
return -EIO;
}
return 0;
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index 69cb55f..cf24513 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -64,7 +64,7 @@ int falcon_reset_xaui(struct efx_nic *efx)
int count;
/* Start reset sequence */
- EFX_POPULATE_DWORD_1(reg, FRF_AB_XX_RST_XX_EN, 1);
+ EFX_POPULATE_OWORD_1(reg, FRF_AB_XX_RST_XX_EN, 1);
efx_writeo(efx, ®, FR_AB_XX_PWR_RST);
/* Wait up to 10 ms for completion, then reinitialise */
@@ -146,14 +146,14 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
bool rx_fc = !!(efx->link_state.fc & EFX_FC_RX);
/* Configure MAC - cut-thru mode is hard wired on */
- EFX_POPULATE_DWORD_3(reg,
+ EFX_POPULATE_OWORD_3(reg,
FRF_AB_XM_RX_JUMBO_MODE, 1,
FRF_AB_XM_TX_STAT_EN, 1,
FRF_AB_XM_RX_STAT_EN, 1);
efx_writeo(efx, ®, FR_AB_XM_GLB_CFG);
/* Configure TX */
- EFX_POPULATE_DWORD_6(reg,
+ EFX_POPULATE_OWORD_6(reg,
FRF_AB_XM_TXEN, 1,
FRF_AB_XM_TX_PRMBL, 1,
FRF_AB_XM_AUTO_PAD, 1,
@@ -163,7 +163,7 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
efx_writeo(efx, ®, FR_AB_XM_TX_CFG);
/* Configure RX */
- EFX_POPULATE_DWORD_5(reg,
+ EFX_POPULATE_OWORD_5(reg,
FRF_AB_XM_RXEN, 1,
FRF_AB_XM_AUTO_DEPAD, 0,
FRF_AB_XM_ACPT_ALL_MCAST, 1,
@@ -173,14 +173,14 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
/* Set frame length */
max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
- EFX_POPULATE_DWORD_1(reg, FRF_AB_XM_MAX_RX_FRM_SIZE, max_frame_len);
+ EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_MAX_RX_FRM_SIZE, max_frame_len);
efx_writeo(efx, ®, FR_AB_XM_RX_PARAM);
- EFX_POPULATE_DWORD_2(reg,
+ EFX_POPULATE_OWORD_2(reg,
FRF_AB_XM_MAX_TX_FRM_SIZE, max_frame_len,
FRF_AB_XM_TX_JUMBO_MODE, 1);
efx_writeo(efx, ®, FR_AB_XM_TX_PARAM);
- EFX_POPULATE_DWORD_2(reg,
+ EFX_POPULATE_OWORD_2(reg,
FRF_AB_XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
FRF_AB_XM_DIS_FCNTL, !rx_fc);
efx_writeo(efx, ®, FR_AB_XM_FC);
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH 03/16] sfc: Strengthen EFX_ASSERT_RESET_SERIALISED
From: Ben Hutchings @ 2009-11-26 2:08 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/efx.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 4787faa..9f3ef38 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -186,7 +186,8 @@ static void efx_fini_channels(struct efx_nic *efx);
#define EFX_ASSERT_RESET_SERIALISED(efx) \
do { \
- if (efx->state == STATE_RUNNING) \
+ if ((efx->state == STATE_RUNNING) || \
+ (efx->state == STATE_DISABLED)) \
ASSERT_RTNL(); \
} while (0)
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH 04/16] sfc: Comment corrections
From: Ben Hutchings @ 2009-11-26 2:09 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/falcon.c | 5 +----
drivers/net/sfc/falcon.h | 2 +-
drivers/net/sfc/falcon_boards.c | 2 +-
3 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index f97ef3e..140087f 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -27,10 +27,7 @@
#include "phy.h"
#include "workarounds.h"
-/* Falcon hardware control.
- * Falcon is the internal codename for the SFC4000 controller that is
- * present in SFE400X evaluation boards
- */
+/* Hardware control for SFC4000 (aka Falcon). */
/**************************************************************************
*
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index 0da5ea7..ea6ac06 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -61,7 +61,7 @@ struct falcon_board {
/**
* struct falcon_nic_data - Falcon NIC state
- * @pci_dev2: The secondary PCI device if present
+ * @pci_dev2: Secondary function of Falcon A
* @board: Board state and functions
*/
struct falcon_nic_data {
diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c
index 333ccc1..f05c9d3 100644
--- a/drivers/net/sfc/falcon_boards.c
+++ b/drivers/net/sfc/falcon_boards.c
@@ -144,7 +144,7 @@ static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask)
*/
/**************************************************************************
- * Support for I2C IO Expander device on SFE40001
+ * Support for I2C IO Expander device on SFE4001
*/
#define PCA9539 0x74
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH 05/16] sfc: Remove unused constant
From: Ben Hutchings @ 2009-11-26 2:09 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/falcon.c | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 140087f..2c0be6c 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -109,9 +109,6 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
/* Size and alignment of special buffers (4KB) */
#define FALCON_BUF_SIZE 4096
-/* Dummy SRAM size code */
-#define SRM_NB_BSZ_ONCHIP_ONLY (-1)
-
#define FALCON_IS_DUAL_FUNC(efx) \
(falcon_rev(efx) < FALCON_REV_B0)
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH 06/16] sfc: Clean up struct falcon_board and struct falcon_board_data
From: Ben Hutchings @ 2009-11-26 2:09 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
Put all static information in struct falcon_board_type and replace it
with a pointer in struct falcon_board. Simplify probing aocordingly.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/efx.c | 2 +-
drivers/net/sfc/ethtool.c | 6 +-
drivers/net/sfc/falcon.c | 4 +-
drivers/net/sfc/falcon.h | 34 ++++++++----
drivers/net/sfc/falcon_boards.c | 115 ++++++++++++++++++---------------------
drivers/net/sfc/qt202x_phy.c | 2 +-
drivers/net/sfc/tenxpress.c | 2 +-
7 files changed, 85 insertions(+), 80 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 9f3ef38..dc85efa 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1309,7 +1309,7 @@ static void efx_monitor(struct work_struct *data)
goto out_requeue;
if (!efx->port_enabled)
goto out_unlock;
- rc = falcon_board(efx)->monitor(efx);
+ rc = falcon_board(efx)->type->monitor(efx);
if (rc) {
EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
(rc == -ERANGE) ? "reported fault" : "failed");
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index d8915b9..bb9abf2 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -174,14 +174,14 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count)
struct efx_nic *efx = netdev_priv(net_dev);
do {
- falcon_board(efx)->set_id_led(efx, EFX_LED_ON);
+ falcon_board(efx)->type->set_id_led(efx, EFX_LED_ON);
schedule_timeout_interruptible(HZ / 2);
- falcon_board(efx)->set_id_led(efx, EFX_LED_OFF);
+ falcon_board(efx)->type->set_id_led(efx, EFX_LED_OFF);
schedule_timeout_interruptible(HZ / 2);
} while (!signal_pending(current) && --count != 0);
- falcon_board(efx)->set_id_led(efx, EFX_LED_DEFAULT);
+ falcon_board(efx)->type->set_id_led(efx, EFX_LED_DEFAULT);
return 0;
}
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 2c0be6c..2f1f1fc 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -2864,7 +2864,7 @@ int falcon_probe_nic(struct efx_nic *efx)
if (rc)
goto fail5;
- rc = falcon_board(efx)->init(efx);
+ rc = falcon_board(efx)->type->init(efx);
if (rc) {
EFX_ERR(efx, "failed to initialise board\n");
goto fail6;
@@ -3067,7 +3067,7 @@ void falcon_remove_nic(struct efx_nic *efx)
struct falcon_board *board = falcon_board(efx);
int rc;
- falcon_board(efx)->fini(efx);
+ board->type->fini(efx);
/* Remove I2C adapter and clear it in preparation for a retry */
rc = i2c_del_adapter(&board->i2c_adap);
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index ea6ac06..b331889 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -31,29 +31,41 @@ static inline int falcon_rev(struct efx_nic *efx)
}
/**
- * struct falcon_board - board information
- * @type: Board model type
- * @major: Major rev. ('A', 'B' ...)
- * @minor: Minor rev. (0, 1, ...)
+ * struct falcon_board_type - board operations and type information
+ * @id: Board type id, as found in NVRAM
+ * @ref_model: Model number of Solarflare reference design
+ * @gen_type: Generic board type description
* @init: Allocate resources and initialise peripheral hardware
* @init_phy: Do board-specific PHY initialisation
+ * @fini: Shut down hardware and free resources
* @set_id_led: Set state of identifying LED or revert to automatic function
* @monitor: Board-specific health check function
- * @fini: Shut down hardware and free resources
+ */
+struct falcon_board_type {
+ u8 id;
+ const char *ref_model;
+ const char *gen_type;
+ int (*init) (struct efx_nic *nic);
+ void (*init_phy) (struct efx_nic *efx);
+ void (*fini) (struct efx_nic *nic);
+ void (*set_id_led) (struct efx_nic *efx, enum efx_led_mode mode);
+ int (*monitor) (struct efx_nic *nic);
+};
+
+/**
+ * struct falcon_board - board information
+ * @type: Type of board
+ * @major: Major rev. ('A', 'B' ...)
+ * @minor: Minor rev. (0, 1, ...)
* @i2c_adap: I2C adapter for on-board peripherals
* @i2c_data: Data for bit-banging algorithm
* @hwmon_client: I2C client for hardware monitor
* @ioexp_client: I2C client for power/port control
*/
struct falcon_board {
- int type;
+ const struct falcon_board_type *type;
int major;
int minor;
- int (*init) (struct efx_nic *nic);
- void (*init_phy) (struct efx_nic *efx);
- void (*set_id_led) (struct efx_nic *efx, enum efx_led_mode mode);
- int (*monitor) (struct efx_nic *nic);
- void (*fini) (struct efx_nic *nic);
struct i2c_adapter i2c_adap;
struct i2c_algo_bit_data i2c_data;
struct i2c_client *hwmon_client, *ioexp_client;
diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c
index f05c9d3..ac1258e 100644
--- a/drivers/net/sfc/falcon_boards.c
+++ b/drivers/net/sfc/falcon_boards.c
@@ -348,7 +348,7 @@ static ssize_t set_phy_flash_cfg(struct device *dev,
efx->phy_mode = new_mode;
if (new_mode & PHY_MODE_SPECIAL)
efx_stats_disable(efx);
- if (falcon_board(efx)->type == FALCON_BOARD_SFE4001)
+ if (falcon_board(efx)->type->id == FALCON_BOARD_SFE4001)
err = sfe4001_poweron(efx);
else
err = sfn4111t_reset(efx);
@@ -438,13 +438,6 @@ static int sfe4001_init(struct efx_nic *efx)
goto fail_hwmon;
}
- /* 10Xpress has fixed-function LED pins, so there is no board-specific
- * blink code. */
- board->set_id_led = tenxpress_set_id_led;
-
- board->monitor = sfe4001_check_hw;
- board->fini = sfe4001_fini;
-
if (efx->phy_mode & PHY_MODE_SPECIAL) {
/* PHY won't generate a 156.25 MHz clock and MAC stats fetch
* will fail. */
@@ -531,11 +524,6 @@ static int sfn4111t_init(struct efx_nic *efx)
if (!board->hwmon_client)
return -EIO;
- board->init_phy = sfn4111t_init_phy;
- board->set_id_led = tenxpress_set_id_led;
- board->monitor = sfn4111t_check_hw;
- board->fini = sfn4111t_fini;
-
rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
if (rc)
goto fail_hwmon;
@@ -620,15 +608,7 @@ static int sfe4002_check_hw(struct efx_nic *efx)
static int sfe4002_init(struct efx_nic *efx)
{
- struct falcon_board *board = falcon_board(efx);
- int rc = efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs);
- if (rc)
- return rc;
- board->monitor = sfe4002_check_hw;
- board->init_phy = sfe4002_init_phy;
- board->set_id_led = sfe4002_set_id_led;
- board->fini = efx_fini_lm87;
- return 0;
+ return efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs);
}
/*****************************************************************************
@@ -692,67 +672,80 @@ static int sfn4112f_check_hw(struct efx_nic *efx)
static int sfn4112f_init(struct efx_nic *efx)
{
- struct falcon_board *board = falcon_board(efx);
-
- int rc = efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs);
- if (rc)
- return rc;
- board->monitor = sfn4112f_check_hw;
- board->init_phy = sfn4112f_init_phy;
- board->set_id_led = sfn4112f_set_id_led;
- board->fini = efx_fini_lm87;
- return 0;
+ return efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs);
}
-/* This will get expanded as board-specific details get moved out of the
- * PHY drivers. */
-struct falcon_board_data {
- u8 type;
- const char *ref_model;
- const char *gen_type;
- int (*init) (struct efx_nic *nic);
-};
-
-
-static struct falcon_board_data board_data[] = {
- { FALCON_BOARD_SFE4001, "SFE4001", "10GBASE-T adapter", sfe4001_init },
- { FALCON_BOARD_SFE4002, "SFE4002", "XFP adapter", sfe4002_init },
- { FALCON_BOARD_SFN4111T, "SFN4111T", "100/1000/10GBASE-T adapter",
- sfn4111t_init },
- { FALCON_BOARD_SFN4112F, "SFN4112F", "SFP+ adapter",
- sfn4112f_init },
+static const struct falcon_board_type board_types[] = {
+ {
+ .id = FALCON_BOARD_SFE4001,
+ .ref_model = "SFE4001",
+ .gen_type = "10GBASE-T adapter",
+ .init = sfe4001_init,
+ .init_phy = efx_port_dummy_op_void,
+ .fini = sfe4001_fini,
+ .set_id_led = tenxpress_set_id_led,
+ .monitor = sfe4001_check_hw,
+ },
+ {
+ .id = FALCON_BOARD_SFE4002,
+ .ref_model = "SFE4002",
+ .gen_type = "XFP adapter",
+ .init = sfe4002_init,
+ .init_phy = sfe4002_init_phy,
+ .fini = efx_fini_lm87,
+ .set_id_led = sfe4002_set_id_led,
+ .monitor = sfe4002_check_hw,
+ },
+ {
+ .id = FALCON_BOARD_SFN4111T,
+ .ref_model = "SFN4111T",
+ .gen_type = "100/1000/10GBASE-T adapter",
+ .init = sfn4111t_init,
+ .init_phy = sfn4111t_init_phy,
+ .fini = sfn4111t_fini,
+ .set_id_led = tenxpress_set_id_led,
+ .monitor = sfn4111t_check_hw,
+ },
+ {
+ .id = FALCON_BOARD_SFN4112F,
+ .ref_model = "SFN4112F",
+ .gen_type = "SFP+ adapter",
+ .init = sfn4112f_init,
+ .init_phy = sfn4112f_init_phy,
+ .fini = efx_fini_lm87,
+ .set_id_led = sfn4112f_set_id_led,
+ .monitor = sfn4112f_check_hw,
+ },
};
-static struct falcon_board falcon_dummy_board = {
+static const struct falcon_board_type falcon_dummy_board = {
.init = efx_port_dummy_op_int,
.init_phy = efx_port_dummy_op_void,
+ .fini = efx_port_dummy_op_void,
.set_id_led = efx_port_dummy_op_set_id_led,
.monitor = efx_port_dummy_op_int,
- .fini = efx_port_dummy_op_void,
};
void falcon_probe_board(struct efx_nic *efx, u16 revision_info)
{
struct falcon_board *board = falcon_board(efx);
- struct falcon_board_data *data = NULL;
+ u8 type_id = FALCON_BOARD_TYPE(revision_info);
int i;
- *board = falcon_dummy_board;
- board->type = FALCON_BOARD_TYPE(revision_info);
board->major = FALCON_BOARD_MAJOR(revision_info);
board->minor = FALCON_BOARD_MINOR(revision_info);
- for (i = 0; i < ARRAY_SIZE(board_data); i++)
- if (board_data[i].type == board->type)
- data = &board_data[i];
+ for (i = 0; i < ARRAY_SIZE(board_types); i++)
+ if (board_types[i].id == type_id)
+ board->type = &board_types[i];
- if (data) {
+ if (board->type) {
EFX_INFO(efx, "board is %s rev %c%d\n",
(efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
- ? data->ref_model : data->gen_type,
+ ? board->type->ref_model : board->type->gen_type,
'A' + board->major, board->minor);
- board->init = data->init;
} else {
- EFX_ERR(efx, "unknown board type %d\n", board->type);
+ EFX_ERR(efx, "unknown board type %d\n", type_id);
+ board->type = &falcon_dummy_board;
}
}
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
index 8208ac0..f9c354e 100644
--- a/drivers/net/sfc/qt202x_phy.c
+++ b/drivers/net/sfc/qt202x_phy.c
@@ -126,7 +126,7 @@ static int qt202x_reset_phy(struct efx_nic *efx)
if (rc < 0)
goto fail;
- falcon_board(efx)->init_phy(efx);
+ falcon_board(efx)->type->init_phy(efx);
return rc;
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index b001f38..a95402d 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -303,7 +303,7 @@ static int tenxpress_phy_init(struct efx_nic *efx)
u16 old_adv, adv;
int rc = 0;
- falcon_board(efx)->init_phy(efx);
+ falcon_board(efx)->type->init_phy(efx);
phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
if (!phy_data)
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH 07/16] sfc: Fix bugs in RX queue flushing
From: Ben Hutchings @ 2009-11-26 2:09 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
Avoid overrunning the hardware limit of 4 concurrent RX queue flushes.
Expand the queue flush state to support this. Make similar changes to
TX flushing to keep the code symmetric.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/falcon.c | 103 ++++++++++++++++++++++++++----------------
drivers/net/sfc/net_driver.h | 11 ++++-
2 files changed, 73 insertions(+), 41 deletions(-)
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 2f1f1fc..e1b9ce3 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -109,6 +109,9 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
/* Size and alignment of special buffers (4KB) */
#define FALCON_BUF_SIZE 4096
+/* Depth of RX flush request fifo */
+#define FALCON_RX_FLUSH_COUNT 4
+
#define FALCON_IS_DUAL_FUNC(efx) \
(falcon_rev(efx) < FALCON_REV_B0)
@@ -426,7 +429,7 @@ void falcon_init_tx(struct efx_tx_queue *tx_queue)
efx_oword_t tx_desc_ptr;
struct efx_nic *efx = tx_queue->efx;
- tx_queue->flushed = false;
+ tx_queue->flushed = FLUSH_NONE;
/* Pin TX descriptor ring */
falcon_init_special_buffer(efx, &tx_queue->txd);
@@ -476,6 +479,8 @@ static void falcon_flush_tx_queue(struct efx_tx_queue *tx_queue)
struct efx_nic *efx = tx_queue->efx;
efx_oword_t tx_flush_descq;
+ tx_queue->flushed = FLUSH_PENDING;
+
/* Post a flush command */
EFX_POPULATE_OWORD_2(tx_flush_descq,
FRF_AZ_TX_FLUSH_DESCQ_CMD, 1,
@@ -489,7 +494,7 @@ void falcon_fini_tx(struct efx_tx_queue *tx_queue)
efx_oword_t tx_desc_ptr;
/* The queue should have been flushed */
- WARN_ON(!tx_queue->flushed);
+ WARN_ON(tx_queue->flushed != FLUSH_DONE);
/* Remove TX descriptor ring from card */
EFX_ZERO_OWORD(tx_desc_ptr);
@@ -578,7 +583,7 @@ void falcon_init_rx(struct efx_rx_queue *rx_queue)
rx_queue->queue, rx_queue->rxd.index,
rx_queue->rxd.index + rx_queue->rxd.entries - 1);
- rx_queue->flushed = false;
+ rx_queue->flushed = FLUSH_NONE;
/* Pin RX descriptor ring */
falcon_init_special_buffer(efx, &rx_queue->rxd);
@@ -607,6 +612,8 @@ static void falcon_flush_rx_queue(struct efx_rx_queue *rx_queue)
struct efx_nic *efx = rx_queue->efx;
efx_oword_t rx_flush_descq;
+ rx_queue->flushed = FLUSH_PENDING;
+
/* Post a flush command */
EFX_POPULATE_OWORD_2(rx_flush_descq,
FRF_AZ_RX_FLUSH_DESCQ_CMD, 1,
@@ -620,7 +627,7 @@ void falcon_fini_rx(struct efx_rx_queue *rx_queue)
struct efx_nic *efx = rx_queue->efx;
/* The queue should already have been flushed */
- WARN_ON(!rx_queue->flushed);
+ WARN_ON(rx_queue->flushed != FLUSH_DONE);
/* Remove RX descriptor ring from card */
EFX_ZERO_OWORD(rx_desc_ptr);
@@ -1181,7 +1188,7 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
FSF_AZ_DRIVER_EV_SUBDATA);
if (ev_queue < EFX_TX_QUEUE_COUNT) {
tx_queue = efx->tx_queue + ev_queue;
- tx_queue->flushed = true;
+ tx_queue->flushed = FLUSH_DONE;
}
} else if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV &&
ev_sub_code == FSE_AZ_RX_DESCQ_FLS_DONE_EV) {
@@ -1191,17 +1198,29 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
*event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL);
if (ev_queue < efx->n_rx_queues) {
rx_queue = efx->rx_queue + ev_queue;
-
- /* retry the rx flush */
- if (ev_failed)
- falcon_flush_rx_queue(rx_queue);
- else
- rx_queue->flushed = true;
+ rx_queue->flushed =
+ ev_failed ? FLUSH_FAILED : FLUSH_DONE;
}
}
+ /* We're about to destroy the queue anyway, so
+ * it's ok to throw away every non-flush event */
+ EFX_SET_QWORD(*event);
+
read_ptr = (read_ptr + 1) & EFX_EVQ_MASK;
} while (read_ptr != end_ptr);
+
+ channel->eventq_read_ptr = read_ptr;
+}
+
+static void falcon_prepare_flush(struct efx_nic *efx)
+{
+ falcon_deconfigure_mac_wrapper(efx);
+
+ /* Wait for the tx and rx fifo's to get to the next packet boundary
+ * (~1ms without back-pressure), then to drain the remainder of the
+ * fifo's at data path speeds (negligible), with a healthy margin. */
+ msleep(10);
}
/* Handle tx and rx flushes at the same time, since they run in
@@ -1211,50 +1230,56 @@ int falcon_flush_queues(struct efx_nic *efx)
{
struct efx_rx_queue *rx_queue;
struct efx_tx_queue *tx_queue;
- int i;
- bool outstanding;
+ int i, tx_pending, rx_pending;
- /* Issue flush requests */
- efx_for_each_tx_queue(tx_queue, efx) {
- tx_queue->flushed = false;
+ falcon_prepare_flush(efx);
+
+ /* Flush all tx queues in parallel */
+ efx_for_each_tx_queue(tx_queue, efx)
falcon_flush_tx_queue(tx_queue);
- }
- efx_for_each_rx_queue(rx_queue, efx) {
- rx_queue->flushed = false;
- falcon_flush_rx_queue(rx_queue);
- }
- /* Poll the evq looking for flush completions. Since we're not pushing
- * any more rx or tx descriptors at this point, we're in no danger of
- * overflowing the evq whilst we wait */
+ /* The hardware supports four concurrent rx flushes, each of which may
+ * need to be retried if there is an outstanding descriptor fetch */
for (i = 0; i < FALCON_FLUSH_POLL_COUNT; ++i) {
- msleep(FALCON_FLUSH_INTERVAL);
- falcon_poll_flush_events(efx);
+ rx_pending = tx_pending = 0;
+ efx_for_each_rx_queue(rx_queue, efx) {
+ if (rx_queue->flushed == FLUSH_PENDING)
+ ++rx_pending;
+ }
+ efx_for_each_rx_queue(rx_queue, efx) {
+ if (rx_pending == FALCON_RX_FLUSH_COUNT)
+ break;
+ if (rx_queue->flushed == FLUSH_FAILED ||
+ rx_queue->flushed == FLUSH_NONE) {
+ falcon_flush_rx_queue(rx_queue);
+ ++rx_pending;
+ }
+ }
+ efx_for_each_tx_queue(tx_queue, efx) {
+ if (tx_queue->flushed != FLUSH_DONE)
+ ++tx_pending;
+ }
- /* Check if every queue has been succesfully flushed */
- outstanding = false;
- efx_for_each_tx_queue(tx_queue, efx)
- outstanding |= !tx_queue->flushed;
- efx_for_each_rx_queue(rx_queue, efx)
- outstanding |= !rx_queue->flushed;
- if (!outstanding)
+ if (rx_pending == 0 && tx_pending == 0)
return 0;
+
+ msleep(FALCON_FLUSH_INTERVAL);
+ falcon_poll_flush_events(efx);
}
/* Mark the queues as all flushed. We're going to return failure
- * leading to a reset, or fake up success anyway. "flushed" now
- * indicates that we tried to flush. */
+ * leading to a reset, or fake up success anyway */
efx_for_each_tx_queue(tx_queue, efx) {
- if (!tx_queue->flushed)
+ if (tx_queue->flushed != FLUSH_DONE)
EFX_ERR(efx, "tx queue %d flush command timed out\n",
tx_queue->queue);
- tx_queue->flushed = true;
+ tx_queue->flushed = FLUSH_DONE;
}
efx_for_each_rx_queue(rx_queue, efx) {
- if (!rx_queue->flushed)
+ if (rx_queue->flushed != FLUSH_DONE)
EFX_ERR(efx, "rx queue %d flush command timed out\n",
rx_queue->queue);
- rx_queue->flushed = true;
+ rx_queue->flushed = FLUSH_DONE;
}
if (EFX_WORKAROUND_7803(efx))
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index ac808d5..d0755ab 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -113,6 +113,13 @@ struct efx_special_buffer {
int entries;
};
+enum efx_flush_state {
+ FLUSH_NONE,
+ FLUSH_PENDING,
+ FLUSH_FAILED,
+ FLUSH_DONE,
+};
+
/**
* struct efx_tx_buffer - An Efx TX buffer
* @skb: The associated socket buffer.
@@ -189,7 +196,7 @@ struct efx_tx_queue {
struct efx_nic *nic;
struct efx_tx_buffer *buffer;
struct efx_special_buffer txd;
- bool flushed;
+ enum efx_flush_state flushed;
/* Members used mainly on the completion path */
unsigned int read_count ____cacheline_aligned_in_smp;
@@ -284,7 +291,7 @@ struct efx_rx_queue {
struct page *buf_page;
dma_addr_t buf_dma_addr;
char *buf_data;
- bool flushed;
+ enum efx_flush_state flushed;
};
/**
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH 08/16] sfc: Remove unused function efx_flush_queues()
From: Ben Hutchings @ 2009-11-26 2:10 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/efx.c | 13 -------------
drivers/net/sfc/efx.h | 1 -
2 files changed, 0 insertions(+), 14 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index dc85efa..4ebad61 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1237,19 +1237,6 @@ static void efx_remove_all(struct efx_nic *efx)
efx_remove_nic(efx);
}
-/* A convinience function to safely flush all the queues */
-void efx_flush_queues(struct efx_nic *efx)
-{
- EFX_ASSERT_RESET_SERIALISED(efx);
-
- efx_stop_all(efx);
-
- efx_fini_channels(efx);
- efx_init_channels(efx);
-
- efx_start_all(efx);
-}
-
/**************************************************************************
*
* Interrupt moderation
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index 3497b03..7acf821 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -56,7 +56,6 @@ extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay);
/* Channels */
extern void efx_process_channel_now(struct efx_channel *channel);
-extern void efx_flush_queues(struct efx_nic *efx);
#define EFX_EVQ_SIZE 4096
#define EFX_EVQ_MASK (EFX_EVQ_SIZE - 1)
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH 09/16] sfc: Only switch Falcon MAC clocks as necessary
From: Ben Hutchings @ 2009-11-26 2:11 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
From: Steve Hodgson <shodgson@solarflare.com>
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/falcon.c | 42 +++++++++++++++++++++++++-----------------
1 files changed, 25 insertions(+), 17 deletions(-)
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index e1b9ce3..9eec885 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -2183,11 +2183,29 @@ static int falcon_mdio_read(struct net_device *net_dev,
return rc;
}
+static void falcon_clock_mac(struct efx_nic *efx)
+{
+ unsigned strap_val;
+ efx_oword_t nic_stat;
+
+ /* Configure the NIC generated MAC clock correctly */
+ efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
+ strap_val = EFX_IS10G(efx) ? 5 : 3;
+ if (falcon_rev(efx) >= FALCON_REV_B0) {
+ EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP_EN, 1);
+ EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP, strap_val);
+ efx_writeo(efx, &nic_stat, FR_AB_NIC_STAT);
+ } else {
+ /* Falcon A1 does not support 1G/10G speed switching
+ * and must not be used with a PHY that does. */
+ BUG_ON(EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_PINS) !=
+ strap_val);
+ }
+}
+
int falcon_switch_mac(struct efx_nic *efx)
{
struct efx_mac_operations *old_mac_op = efx->mac_op;
- efx_oword_t nic_stat;
- unsigned strap_val;
int rc = 0;
/* Don't try to fetch MAC stats while we're switching MACs */
@@ -2206,24 +2224,11 @@ int falcon_switch_mac(struct efx_nic *efx)
efx->mac_op = (EFX_IS10G(efx) ?
&falcon_xmac_operations : &falcon_gmac_operations);
- /* Always push the NIC_STAT_REG setting even if the mac hasn't
- * changed, because this function is run post online reset */
- efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
- strap_val = EFX_IS10G(efx) ? 5 : 3;
- if (falcon_rev(efx) >= FALCON_REV_B0) {
- EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP_EN, 1);
- EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP, strap_val);
- efx_writeo(efx, &nic_stat, FR_AB_NIC_STAT);
- } else {
- /* Falcon A1 does not support 1G/10G speed switching
- * and must not be used with a PHY that does. */
- BUG_ON(EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_PINS) !=
- strap_val);
- }
-
if (old_mac_op == efx->mac_op)
goto out;
+ falcon_clock_mac(efx);
+
EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G');
/* Not all macs support a mac-level link state */
efx->mac_up = true;
@@ -2982,6 +2987,9 @@ int falcon_init_nic(struct efx_nic *efx)
efx_writeo(efx, &temp, FR_AB_GPIO_CTL);
}
+ /* Select the correct MAC */
+ falcon_clock_mac(efx);
+
rc = falcon_reset_sram(efx);
if (rc)
return rc;
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH 10/16] sfc: Hold MAC lock for longer in efx_init_port()
From: Ben Hutchings @ 2009-11-26 2:11 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
Although efx_init_port() is only called at probe time and so cannot
race with port reconfiguration, most of the functions it calls can
expect to be called with the MAC lock held.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/efx.c | 14 +++++++++-----
1 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 4ebad61..155aa1c 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -737,23 +737,27 @@ static int efx_init_port(struct efx_nic *efx)
EFX_LOG(efx, "init port\n");
+ mutex_lock(&efx->mac_lock);
+
rc = efx->phy_op->init(efx);
if (rc)
- return rc;
- mutex_lock(&efx->mac_lock);
+ goto fail1;
efx->phy_op->reconfigure(efx);
rc = falcon_switch_mac(efx);
- mutex_unlock(&efx->mac_lock);
if (rc)
- goto fail;
+ goto fail2;
efx->mac_op->reconfigure(efx);
efx->port_initialized = true;
efx_stats_enable(efx);
+
+ mutex_unlock(&efx->mac_lock);
return 0;
-fail:
+fail2:
efx->phy_op->fini(efx);
+fail1:
+ mutex_unlock(&efx->mac_lock);
return rc;
}
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH 11/16] sfc: Split MAC stats DMA initiation and completion
From: Ben Hutchings @ 2009-11-26 2:11 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
From: Steve Hodgson <shodgson@solarflare.com>
Currently we initiate MAC stats DMA and busy-wait for completion when
stats are requested. We can improve on this with a periodic timer to
initiate and poll for stats, and opportunistically poll when stats are
requested.
Since efx_nic::stats_disable_count and efx_stats_{disable,enable}()
are Falcon-specific, rename them and move them accordingly.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/efx.c | 48 ++++----------
drivers/net/sfc/efx.h | 2 -
drivers/net/sfc/falcon.c | 131 ++++++++++++++++++++++++++++++---------
drivers/net/sfc/falcon.h | 12 +++-
drivers/net/sfc/falcon_boards.c | 10 ++--
drivers/net/sfc/falcon_gmac.c | 5 --
drivers/net/sfc/falcon_xmac.c | 13 +++--
drivers/net/sfc/net_driver.h | 2 -
drivers/net/sfc/tenxpress.c | 4 +-
9 files changed, 139 insertions(+), 88 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 155aa1c..41ca5db 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -637,6 +637,7 @@ void __efx_reconfigure_port(struct efx_nic *efx)
netif_addr_unlock_bh(efx->net_dev);
}
+ falcon_stop_nic_stats(efx);
falcon_deconfigure_mac_wrapper(efx);
/* Reconfigure the PHY, disabling transmit in mac level loopback. */
@@ -651,6 +652,8 @@ void __efx_reconfigure_port(struct efx_nic *efx)
efx->mac_op->reconfigure(efx);
+ falcon_start_nic_stats(efx);
+
/* Inform kernel of loss/gain of carrier */
efx_link_status_changed(efx);
return;
@@ -749,7 +752,6 @@ static int efx_init_port(struct efx_nic *efx)
efx->mac_op->reconfigure(efx);
efx->port_initialized = true;
- efx_stats_enable(efx);
mutex_unlock(&efx->mac_lock);
return 0;
@@ -802,7 +804,6 @@ static void efx_fini_port(struct efx_nic *efx)
if (!efx->port_initialized)
return;
- efx_stats_disable(efx);
efx->phy_op->fini(efx);
efx->port_initialized = false;
@@ -1158,6 +1159,8 @@ static void efx_start_all(struct efx_nic *efx)
if (efx->state == STATE_RUNNING)
queue_delayed_work(efx->workqueue, &efx->monitor_work,
efx_monitor_interval);
+
+ falcon_start_nic_stats(efx);
}
/* Flush all delayed work. Should only be called when no more delayed work
@@ -1195,6 +1198,8 @@ static void efx_stop_all(struct efx_nic *efx)
if (!efx->port_enabled)
return;
+ falcon_stop_nic_stats(efx);
+
/* Disable interrupts and wait for ISR to complete */
falcon_disable_interrupts(efx);
if (efx->legacy_irq)
@@ -1438,20 +1443,6 @@ static int efx_net_stop(struct net_device *net_dev)
return 0;
}
-void efx_stats_disable(struct efx_nic *efx)
-{
- spin_lock(&efx->stats_lock);
- ++efx->stats_disable_count;
- spin_unlock(&efx->stats_lock);
-}
-
-void efx_stats_enable(struct efx_nic *efx)
-{
- spin_lock(&efx->stats_lock);
- --efx->stats_disable_count;
- spin_unlock(&efx->stats_lock);
-}
-
/* Context: process, dev_base_lock or RTNL held, non-blocking. */
static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
{
@@ -1459,17 +1450,9 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
struct efx_mac_stats *mac_stats = &efx->mac_stats;
struct net_device_stats *stats = &net_dev->stats;
- /* Update stats if possible, but do not wait if another thread
- * is updating them or if MAC stats fetches are temporarily
- * disabled; slightly stale stats are acceptable.
- */
- if (!spin_trylock(&efx->stats_lock))
- return stats;
- if (!efx->stats_disable_count) {
- efx->mac_op->update_stats(efx);
- falcon_update_nic_stats(efx);
- }
- spin_unlock(&efx->stats_lock);
+ spin_lock_bh(&efx->stats_lock);
+ falcon_update_nic_stats(efx);
+ spin_unlock_bh(&efx->stats_lock);
stats->rx_packets = mac_stats->rx_packets;
stats->tx_packets = mac_stats->tx_packets;
@@ -1726,7 +1709,6 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method,
{
EFX_ASSERT_RESET_SERIALISED(efx);
- efx_stats_disable(efx);
efx_stop_all(efx);
mutex_lock(&efx->mac_lock);
mutex_lock(&efx->spi_lock);
@@ -1776,10 +1758,8 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method,
mutex_unlock(&efx->spi_lock);
mutex_unlock(&efx->mac_lock);
- if (ok) {
+ if (ok)
efx_start_all(efx);
- efx_stats_enable(efx);
- }
return rc;
}
@@ -1977,7 +1957,6 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
efx->rx_checksum_enabled = true;
spin_lock_init(&efx->netif_stop_lock);
spin_lock_init(&efx->stats_lock);
- efx->stats_disable_count = 1;
mutex_init(&efx->mac_lock);
efx->mac_op = &efx_dummy_mac_operations;
efx->phy_op = &efx_dummy_phy_operations;
@@ -2219,9 +2198,8 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
goto fail4;
}
- /* Switch to the running state before we expose the device to
- * the OS. This is to ensure that the initial gathering of
- * MAC stats succeeds. */
+ /* Switch to the running state before we expose the device to the OS,
+ * so that dev_open()|efx_start_all() will actually start the device */
efx->state = STATE_RUNNING;
rc = efx_register_netdev(efx);
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index 7acf821..01b93f9 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -60,8 +60,6 @@ extern void efx_process_channel_now(struct efx_channel *channel);
#define EFX_EVQ_MASK (EFX_EVQ_SIZE - 1)
/* Ports */
-extern void efx_stats_disable(struct efx_nic *efx);
-extern void efx_stats_enable(struct efx_nic *efx);
extern void efx_reconfigure_port(struct efx_nic *efx);
extern void __efx_reconfigure_port(struct efx_nic *efx);
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 9eec885..3ab2daf 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -36,8 +36,6 @@
**************************************************************************
*/
-static int disable_dma_stats;
-
/* This is set to 16 for a good reason. In summary, if larger than
* 16, the descriptor cache holds more than a default socket
* buffer's worth of packets (for UDP we can only have at most one
@@ -1890,7 +1888,7 @@ static int falcon_reset_macs(struct efx_nic *efx)
/* MAC stats will fail whilst the TX fifo is draining. Serialise
* the drain sequence with the statistics fetch */
- efx_stats_disable(efx);
+ falcon_stop_nic_stats(efx);
efx_reado(efx, ®, FR_AB_MAC_CTRL);
EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, 1);
@@ -1920,13 +1918,13 @@ static int falcon_reset_macs(struct efx_nic *efx)
udelay(10);
}
- efx_stats_enable(efx);
-
/* If we've reset the EM block and the link is up, then
* we'll have to kick the XAUI link so the PHY can recover */
if (efx->link_state.up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx))
falcon_reset_xaui(efx);
+ falcon_start_nic_stats(efx);
+
return 0;
}
@@ -2010,25 +2008,19 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
efx_writeo(efx, ®, FR_AZ_RX_CFG);
}
-int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
+static void falcon_stats_request(struct efx_nic *efx)
{
+ struct falcon_nic_data *nic_data = efx->nic_data;
efx_oword_t reg;
- u32 *dma_done;
- int i;
- if (disable_dma_stats)
- return 0;
+ WARN_ON(nic_data->stats_pending);
+ WARN_ON(nic_data->stats_disable_count);
- /* Statistics fetch will fail if the MAC is in TX drain */
- if (falcon_rev(efx) >= FALCON_REV_B0) {
- efx_oword_t temp;
- efx_reado(efx, &temp, FR_AB_MAC_CTRL);
- if (EFX_OWORD_FIELD(temp, FRF_BB_TXFIFO_DRAIN_EN))
- return 0;
- }
+ if (nic_data->stats_dma_done == NULL)
+ return; /* no mac selected */
- dma_done = (efx->stats_buffer.addr + done_offset);
- *dma_done = FALCON_STATS_NOT_DONE;
+ *nic_data->stats_dma_done = FALCON_STATS_NOT_DONE;
+ nic_data->stats_pending = true;
wmb(); /* ensure done flag is clear */
/* Initiate DMA transfer of stats */
@@ -2038,17 +2030,37 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
efx->stats_buffer.dma_addr);
efx_writeo(efx, ®, FR_AB_MAC_STAT_DMA);
- /* Wait for transfer to complete */
- for (i = 0; i < 400; i++) {
- if (*(volatile u32 *)dma_done == FALCON_STATS_DONE) {
- rmb(); /* Ensure the stats are valid. */
- return 0;
- }
- udelay(10);
+ mod_timer(&nic_data->stats_timer, round_jiffies_up(jiffies + HZ / 2));
+}
+
+static void falcon_stats_complete(struct efx_nic *efx)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+
+ if (!nic_data->stats_pending)
+ return;
+
+ nic_data->stats_pending = 0;
+ if (*nic_data->stats_dma_done == FALCON_STATS_DONE) {
+ rmb(); /* read the done flag before the stats */
+ efx->mac_op->update_stats(efx);
+ } else {
+ EFX_ERR(efx, "timed out waiting for statistics\n");
}
+}
- EFX_ERR(efx, "timed out waiting for statistics\n");
- return -ETIMEDOUT;
+static void falcon_stats_timer_func(unsigned long context)
+{
+ struct efx_nic *efx = (struct efx_nic *)context;
+ struct falcon_nic_data *nic_data = efx->nic_data;
+
+ spin_lock(&efx->stats_lock);
+
+ falcon_stats_complete(efx);
+ if (nic_data->stats_disable_count == 0)
+ falcon_stats_request(efx);
+
+ spin_unlock(&efx->stats_lock);
}
/**************************************************************************
@@ -2206,10 +2218,12 @@ static void falcon_clock_mac(struct efx_nic *efx)
int falcon_switch_mac(struct efx_nic *efx)
{
struct efx_mac_operations *old_mac_op = efx->mac_op;
+ struct falcon_nic_data *nic_data = efx->nic_data;
+ unsigned int stats_done_offset;
int rc = 0;
/* Don't try to fetch MAC stats while we're switching MACs */
- efx_stats_disable(efx);
+ falcon_stop_nic_stats(efx);
/* Internal loopbacks override the phy speed setting */
if (efx->loopback_mode == LOOPBACK_GMAC) {
@@ -2224,6 +2238,12 @@ int falcon_switch_mac(struct efx_nic *efx)
efx->mac_op = (EFX_IS10G(efx) ?
&falcon_xmac_operations : &falcon_gmac_operations);
+ if (EFX_IS10G(efx))
+ stats_done_offset = XgDmaDone_offset;
+ else
+ stats_done_offset = GDmaDone_offset;
+ nic_data->stats_dma_done = efx->stats_buffer.addr + stats_done_offset;
+
if (old_mac_op == efx->mac_op)
goto out;
@@ -2235,7 +2255,7 @@ int falcon_switch_mac(struct efx_nic *efx)
rc = falcon_reset_macs(efx);
out:
- efx_stats_enable(efx);
+ falcon_start_nic_stats(efx);
return rc;
}
@@ -2900,6 +2920,10 @@ int falcon_probe_nic(struct efx_nic *efx)
goto fail6;
}
+ nic_data->stats_disable_count = 1;
+ setup_timer(&nic_data->stats_timer, &falcon_stats_timer_func,
+ (unsigned long)efx);
+
return 0;
fail6:
@@ -3125,11 +3149,58 @@ void falcon_remove_nic(struct efx_nic *efx)
void falcon_update_nic_stats(struct efx_nic *efx)
{
+ struct falcon_nic_data *nic_data = efx->nic_data;
efx_oword_t cnt;
+ if (nic_data->stats_disable_count)
+ return;
+
efx_reado(efx, &cnt, FR_AZ_RX_NODESC_DROP);
efx->n_rx_nodesc_drop_cnt +=
EFX_OWORD_FIELD(cnt, FRF_AB_RX_NODESC_DROP_CNT);
+
+ if (nic_data->stats_pending &&
+ *nic_data->stats_dma_done == FALCON_STATS_DONE) {
+ nic_data->stats_pending = false;
+ rmb(); /* read the done flag before the stats */
+ efx->mac_op->update_stats(efx);
+ }
+}
+
+void falcon_start_nic_stats(struct efx_nic *efx)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+
+ spin_lock_bh(&efx->stats_lock);
+ if (--nic_data->stats_disable_count == 0)
+ falcon_stats_request(efx);
+ spin_unlock_bh(&efx->stats_lock);
+}
+
+void falcon_stop_nic_stats(struct efx_nic *efx)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+ int i;
+
+ might_sleep();
+
+ spin_lock_bh(&efx->stats_lock);
+ ++nic_data->stats_disable_count;
+ spin_unlock_bh(&efx->stats_lock);
+
+ del_timer_sync(&nic_data->stats_timer);
+
+ /* Wait enough time for the most recent transfer to
+ * complete. */
+ for (i = 0; i < 4 && nic_data->stats_pending; i++) {
+ if (*nic_data->stats_dma_done == FALCON_STATS_DONE)
+ break;
+ msleep(1);
+ }
+
+ spin_lock_bh(&efx->stats_lock);
+ falcon_stats_complete(efx);
+ spin_unlock_bh(&efx->stats_lock);
}
/**************************************************************************
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index b331889..61fab0a 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -75,10 +75,18 @@ struct falcon_board {
* struct falcon_nic_data - Falcon NIC state
* @pci_dev2: Secondary function of Falcon A
* @board: Board state and functions
+ * @stats_disable_count: Nest count for disabling statistics fetches
+ * @stats_pending: Is there a pending DMA of MAC statistics.
+ * @stats_timer: A timer for regularly fetching MAC statistics.
+ * @stats_dma_done: Pointer to the flag which indicates DMA completion.
*/
struct falcon_nic_data {
struct pci_dev *pci_dev2;
struct falcon_board board;
+ unsigned int stats_disable_count;
+ bool stats_pending;
+ struct timer_list stats_timer;
+ u32 *stats_dma_done;
};
static inline struct falcon_board *falcon_board(struct efx_nic *efx)
@@ -128,8 +136,6 @@ extern void falcon_remove_port(struct efx_nic *efx);
/* MAC/PHY */
extern int falcon_switch_mac(struct efx_nic *efx);
extern bool falcon_xaui_link_ok(struct efx_nic *efx);
-extern int falcon_dma_stats(struct efx_nic *efx,
- unsigned int done_offset);
extern void falcon_drain_tx_fifo(struct efx_nic *efx);
extern void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx);
@@ -154,6 +160,8 @@ extern int falcon_flush_queues(struct efx_nic *efx);
extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method);
extern void falcon_remove_nic(struct efx_nic *efx);
extern void falcon_update_nic_stats(struct efx_nic *efx);
+extern void falcon_start_nic_stats(struct efx_nic *efx);
+extern void falcon_stop_nic_stats(struct efx_nic *efx);
extern void falcon_set_multicast_hash(struct efx_nic *efx);
extern int falcon_reset_xaui(struct efx_nic *efx);
diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c
index ac1258e..72d1c78 100644
--- a/drivers/net/sfc/falcon_boards.c
+++ b/drivers/net/sfc/falcon_boards.c
@@ -347,14 +347,14 @@ static ssize_t set_phy_flash_cfg(struct device *dev,
* MAC stats accordingly. */
efx->phy_mode = new_mode;
if (new_mode & PHY_MODE_SPECIAL)
- efx_stats_disable(efx);
+ falcon_stop_nic_stats(efx);
if (falcon_board(efx)->type->id == FALCON_BOARD_SFE4001)
err = sfe4001_poweron(efx);
else
err = sfn4111t_reset(efx);
efx_reconfigure_port(efx);
if (!(new_mode & PHY_MODE_SPECIAL))
- efx_stats_enable(efx);
+ falcon_start_nic_stats(efx);
}
rtnl_unlock();
@@ -441,7 +441,7 @@ static int sfe4001_init(struct efx_nic *efx)
if (efx->phy_mode & PHY_MODE_SPECIAL) {
/* PHY won't generate a 156.25 MHz clock and MAC stats fetch
* will fail. */
- efx_stats_disable(efx);
+ falcon_stop_nic_stats(efx);
}
rc = sfe4001_poweron(efx);
if (rc)
@@ -504,7 +504,7 @@ static void sfn4111t_init_phy(struct efx_nic *efx)
return;
efx->phy_mode = PHY_MODE_SPECIAL;
- efx_stats_disable(efx);
+ falcon_stop_nic_stats(efx);
}
sfn4111t_reset(efx);
@@ -531,7 +531,7 @@ static int sfn4111t_init(struct efx_nic *efx)
if (efx->phy_mode & PHY_MODE_SPECIAL)
/* PHY may not generate a 156.25 MHz clock and MAC
* stats fetch will fail. */
- efx_stats_disable(efx);
+ falcon_stop_nic_stats(efx);
return 0;
diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c
index 967f3fb..2aeb3fc 100644
--- a/drivers/net/sfc/falcon_gmac.c
+++ b/drivers/net/sfc/falcon_gmac.c
@@ -130,11 +130,6 @@ static void falcon_update_stats_gmac(struct efx_nic *efx)
struct efx_mac_stats *mac_stats = &efx->mac_stats;
unsigned long old_rx_pause, old_tx_pause;
unsigned long new_rx_pause, new_tx_pause;
- int rc;
-
- rc = falcon_dma_stats(efx, GDmaDone_offset);
- if (rc)
- return;
/* Pause frames are erroneously counted as errors (SFC bug 3269) */
old_rx_pause = mac_stats->rx_pause;
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index cf24513..e57545d 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -60,9 +60,13 @@ static void falcon_setup_xaui(struct efx_nic *efx)
int falcon_reset_xaui(struct efx_nic *efx)
{
+ struct falcon_nic_data *nic_data = efx->nic_data;
efx_oword_t reg;
int count;
+ /* Don't fetch MAC statistics over an XMAC reset */
+ WARN_ON(nic_data->stats_disable_count == 0);
+
/* Start reset sequence */
EFX_POPULATE_OWORD_1(reg, FRF_AB_XX_RST_XX_EN, 1);
efx_writeo(efx, ®, FR_AB_XX_PWR_RST);
@@ -250,6 +254,8 @@ static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries)
/* XAUI link is expected to be down */
return;
+ falcon_stop_nic_stats(efx);
+
while (!efx->mac_up && tries) {
EFX_LOG(efx, "bashing xaui\n");
falcon_reset_xaui(efx);
@@ -258,6 +264,8 @@ static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries)
efx->mac_up = falcon_xaui_link_ok(efx);
--tries;
}
+
+ falcon_start_nic_stats(efx);
}
static void falcon_reconfigure_xmac(struct efx_nic *efx)
@@ -276,11 +284,6 @@ static void falcon_reconfigure_xmac(struct efx_nic *efx)
static void falcon_update_stats_xmac(struct efx_nic *efx)
{
struct efx_mac_stats *mac_stats = &efx->mac_stats;
- int rc;
-
- rc = falcon_dma_stats(efx, XgDmaDone_offset);
- if (rc)
- return;
/* Update MAC stats from DMAed values */
FALCON_STAT(efx, XgRxOctets, rx_bytes);
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index d0755ab..262aeab 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -717,7 +717,6 @@ union efx_multicast_hash {
* &struct net_device_stats.
* @stats_buffer: DMA buffer for statistics
* @stats_lock: Statistics update lock. Serialises statistics fetches
- * @stats_disable_count: Nest count for disabling statistics fetches
* @mac_op: MAC interface
* @mac_address: Permanent MAC address
* @phy_type: PHY type
@@ -799,7 +798,6 @@ struct efx_nic {
struct efx_mac_stats mac_stats;
struct efx_buffer stats_buffer;
spinlock_t stats_lock;
- unsigned int stats_disable_count;
struct efx_mac_operations *mac_op;
unsigned char mac_address[ETH_ALEN];
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index a95402d..e6232fe 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -374,7 +374,7 @@ static int tenxpress_special_reset(struct efx_nic *efx)
/* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so
* a special software reset can glitch the XGMAC sufficiently for stats
* requests to fail. */
- efx_stats_disable(efx);
+ falcon_stop_nic_stats(efx);
/* Initiate reset */
reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG);
@@ -396,7 +396,7 @@ static int tenxpress_special_reset(struct efx_nic *efx)
/* Wait for the XGXS state machine to churn */
mdelay(10);
out:
- efx_stats_enable(efx);
+ falcon_start_nic_stats(efx);
return rc;
}
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH 12/16] sfc: Move Falcon board/PHY/MAC monitoring code to falcon.c
From: Ben Hutchings @ 2009-11-26 2:11 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/efx.c | 11 +----------
drivers/net/sfc/falcon.c | 15 +++++++++++++++
drivers/net/sfc/falcon.h | 1 +
3 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 41ca5db..d17cea9 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1293,7 +1293,6 @@ static void efx_monitor(struct work_struct *data)
{
struct efx_nic *efx = container_of(data, struct efx_nic,
monitor_work.work);
- int rc;
EFX_TRACE(efx, "hardware monitor executing on CPU %d\n",
raw_smp_processor_id());
@@ -1305,15 +1304,7 @@ static void efx_monitor(struct work_struct *data)
goto out_requeue;
if (!efx->port_enabled)
goto out_unlock;
- rc = falcon_board(efx)->type->monitor(efx);
- if (rc) {
- EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
- (rc == -ERANGE) ? "reported fault" : "failed");
- efx->phy_mode |= PHY_MODE_LOW_POWER;
- falcon_sim_phy_event(efx);
- }
- efx->phy_op->poll(efx);
- efx->mac_op->poll(efx);
+ falcon_monitor(efx);
out_unlock:
mutex_unlock(&efx->mac_lock);
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 3ab2daf..c43c5e6 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -2612,6 +2612,21 @@ fail5:
return rc;
}
+void falcon_monitor(struct efx_nic *efx)
+{
+ int rc;
+
+ rc = falcon_board(efx)->type->monitor(efx);
+ if (rc) {
+ EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
+ (rc == -ERANGE) ? "reported fault" : "failed");
+ efx->phy_mode |= PHY_MODE_LOW_POWER;
+ falcon_sim_phy_event(efx);
+ }
+ efx->phy_op->poll(efx);
+ efx->mac_op->poll(efx);
+}
+
/* Zeroes out the SRAM contents. This routine must be called in
* process context and is allowed to sleep.
*/
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index 61fab0a..05e51c2 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -158,6 +158,7 @@ extern int falcon_probe_nic(struct efx_nic *efx);
extern int falcon_init_nic(struct efx_nic *efx);
extern int falcon_flush_queues(struct efx_nic *efx);
extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method);
+extern void falcon_monitor(struct efx_nic *efx);
extern void falcon_remove_nic(struct efx_nic *efx);
extern void falcon_update_nic_stats(struct efx_nic *efx);
extern void falcon_start_nic_stats(struct efx_nic *efx);
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH 13/16] sfc: Simplify XMAC link polling
From: Ben Hutchings @ 2009-11-26 2:12 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
From: Steve Hodgson <shodgson@solarflare.com>
Only the XMAC on Falcon needs help from the driver to poll and reset
the MAC-PHY link (XAUI); GMII is a simple parallel bus and on later
NICs firmware takes care of the XAUI link. Also, an XMAC interrupt
currently schedules a work item which simply clears a flag
(efx_nic::mac_up) to be checked by the regular monitor (or the next
link reconfiguration, if that is sooner).
Rename the flag to xmac_poll_required, changing its sense. Remove the
needless indirection and just set the flag immediately. Call
falcon_xmac_poll() directly where required.
Add a new generic operation mac_op::check_fault to check the link
outside of regular monitoring, as required during self-tests.
(Note that this leaves us with an unused work item, but we will
immediately have another use for it.)
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/efx.c | 5 ----
drivers/net/sfc/falcon.c | 7 +++--
drivers/net/sfc/falcon.h | 2 +
drivers/net/sfc/falcon_boards.c | 4 +-
drivers/net/sfc/falcon_gmac.c | 8 ++++-
drivers/net/sfc/falcon_xmac.c | 50 +++++++++++++++-----------------------
drivers/net/sfc/net_driver.h | 10 +++----
drivers/net/sfc/selftest.c | 9 ++----
8 files changed, 41 insertions(+), 54 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index d17cea9..15616dd 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -693,8 +693,6 @@ static void efx_mac_work(struct work_struct *data)
struct efx_nic *efx = container_of(data, struct efx_nic, mac_work);
mutex_lock(&efx->mac_lock);
- if (efx->port_enabled)
- efx->mac_op->irq(efx);
mutex_unlock(&efx->mac_lock);
}
@@ -774,7 +772,6 @@ static void efx_start_port(struct efx_nic *efx)
mutex_lock(&efx->mac_lock);
efx->port_enabled = true;
__efx_reconfigure_port(efx);
- efx->mac_op->irq(efx);
mutex_unlock(&efx->mac_lock);
}
@@ -1903,8 +1900,6 @@ void efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
static struct efx_mac_operations efx_dummy_mac_operations = {
.reconfigure = efx_port_dummy_op_void,
- .poll = efx_port_dummy_op_void,
- .irq = efx_port_dummy_op_void,
};
static struct efx_phy_operations efx_dummy_phy_operations = {
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index c43c5e6..fac534a 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -900,7 +900,7 @@ static void falcon_handle_global_event(struct efx_channel *channel,
if ((falcon_rev(efx) >= FALCON_REV_B0) &&
EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) {
- queue_work(efx->workqueue, &efx->mac_work);
+ efx->xmac_poll_required = true;
handled = true;
}
@@ -2251,7 +2251,7 @@ int falcon_switch_mac(struct efx_nic *efx)
EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G');
/* Not all macs support a mac-level link state */
- efx->mac_up = true;
+ efx->xmac_poll_required = false;
rc = falcon_reset_macs(efx);
out:
@@ -2624,7 +2624,8 @@ void falcon_monitor(struct efx_nic *efx)
falcon_sim_phy_event(efx);
}
efx->phy_op->poll(efx);
- efx->mac_op->poll(efx);
+ if (EFX_IS10G(efx))
+ falcon_poll_xmac(efx);
}
/* Zeroes out the SRAM contents. This routine must be called in
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index 05e51c2..9ae1b6c 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -209,4 +209,6 @@ extern int falcon_test_registers(struct efx_nic *efx);
extern void falcon_generate_event(struct efx_channel *channel,
efx_qword_t *event);
+extern void falcon_poll_xmac(struct efx_nic *efx);
+
#endif /* EFX_FALCON_H */
diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c
index 72d1c78..da75095 100644
--- a/drivers/net/sfc/falcon_boards.c
+++ b/drivers/net/sfc/falcon_boards.c
@@ -380,7 +380,7 @@ static int sfe4001_check_hw(struct efx_nic *efx)
s32 status;
/* If XAUI link is up then do not monitor */
- if (EFX_WORKAROUND_7884(efx) && efx->mac_up)
+ if (EFX_WORKAROUND_7884(efx) && !efx->xmac_poll_required)
return 0;
/* Check the powered status of the PHY. Lack of power implies that
@@ -468,7 +468,7 @@ static int sfn4111t_check_hw(struct efx_nic *efx)
s32 status;
/* If XAUI link is up then do not monitor */
- if (EFX_WORKAROUND_7884(efx) && efx->mac_up)
+ if (EFX_WORKAROUND_7884(efx) && !efx->xmac_poll_required)
return 0;
/* Test LHIGH, RHIGH, FAULT, EOT and IOT alarms */
diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c
index 2aeb3fc..66d499c 100644
--- a/drivers/net/sfc/falcon_gmac.c
+++ b/drivers/net/sfc/falcon_gmac.c
@@ -216,9 +216,13 @@ static void falcon_update_stats_gmac(struct efx_nic *efx)
mac_stats->rx_lt64 = mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64;
}
+static bool falcon_gmac_check_fault(struct efx_nic *efx)
+{
+ return false;
+}
+
struct efx_mac_operations falcon_gmac_operations = {
.reconfigure = falcon_reconfigure_gmac,
.update_stats = falcon_update_stats_gmac,
- .irq = efx_port_dummy_op_void,
- .poll = efx_port_dummy_op_void,
+ .check_fault = falcon_gmac_check_fault,
};
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index e57545d..784260f 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -98,7 +98,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
/* We can only use this interrupt to signal the negative edge of
* xaui_align [we have to poll the positive edge]. */
- if (!efx->mac_up)
+ if (efx->xmac_poll_required)
return;
/* Flush the ISR */
@@ -243,29 +243,35 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx)
}
-/* Try and bring the Falcon side of the Falcon-Phy XAUI link fails
- * to come back up. Bash it until it comes back up */
-static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries)
+/* Try to bring up the Falcon side of the Falcon-Phy XAUI link */
+static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries)
{
- efx->mac_up = falcon_xaui_link_ok(efx);
+ bool mac_up = falcon_xaui_link_ok(efx);
if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
efx_phy_mode_disabled(efx->phy_mode))
/* XAUI link is expected to be down */
- return;
+ return mac_up;
falcon_stop_nic_stats(efx);
- while (!efx->mac_up && tries) {
+ while (!mac_up && tries) {
EFX_LOG(efx, "bashing xaui\n");
falcon_reset_xaui(efx);
udelay(200);
- efx->mac_up = falcon_xaui_link_ok(efx);
+ mac_up = falcon_xaui_link_ok(efx);
--tries;
}
falcon_start_nic_stats(efx);
+
+ return mac_up;
+}
+
+static bool falcon_xmac_check_fault(struct efx_nic *efx)
+{
+ return !falcon_check_xaui_link_up(efx, 5);
}
static void falcon_reconfigure_xmac(struct efx_nic *efx)
@@ -277,7 +283,7 @@ static void falcon_reconfigure_xmac(struct efx_nic *efx)
falcon_reconfigure_mac_wrapper(efx);
- falcon_check_xaui_link_up(efx, 5);
+ efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 5);
falcon_mask_status_intr(efx, true);
}
@@ -341,35 +347,19 @@ static void falcon_update_stats_xmac(struct efx_nic *efx)
mac_stats->rx_control * 64);
}
-static void falcon_xmac_irq(struct efx_nic *efx)
-{
- /* The XGMII link has a transient fault, which indicates either:
- * - there's a transient xgmii fault
- * - falcon's end of the xaui link may need a kick
- * - the wire-side link may have gone down, but the lasi/poll()
- * hasn't noticed yet.
- *
- * We only want to even bother polling XAUI if we're confident it's
- * not (1) or (3). In both cases, the only reliable way to spot this
- * is to wait a bit. We do this here by forcing the mac link state
- * to down, and waiting for the mac poll to come round and check
- */
- efx->mac_up = false;
-}
-
-static void falcon_poll_xmac(struct efx_nic *efx)
+void falcon_poll_xmac(struct efx_nic *efx)
{
- if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up || efx->mac_up)
+ if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up ||
+ !efx->xmac_poll_required)
return;
falcon_mask_status_intr(efx, false);
- falcon_check_xaui_link_up(efx, 1);
+ efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 1);
falcon_mask_status_intr(efx, true);
}
struct efx_mac_operations falcon_xmac_operations = {
.reconfigure = falcon_reconfigure_xmac,
.update_stats = falcon_update_stats_xmac,
- .irq = falcon_xmac_irq,
- .poll = falcon_poll_xmac,
+ .check_fault = falcon_xmac_check_fault,
};
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 262aeab..cc1a97b 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -507,14 +507,12 @@ struct efx_link_state {
* struct efx_mac_operations - Efx MAC operations table
* @reconfigure: Reconfigure MAC. Serialised by the mac_lock
* @update_stats: Update statistics
- * @irq: Hardware MAC event callback. Serialised by the mac_lock
- * @poll: Poll for hardware state. Serialised by the mac_lock
+ * @check_fault: Check fault state. True if fault present.
*/
struct efx_mac_operations {
void (*reconfigure) (struct efx_nic *efx);
void (*update_stats) (struct efx_nic *efx);
- void (*irq) (struct efx_nic *efx);
- void (*poll) (struct efx_nic *efx);
+ bool (*check_fault)(struct efx_nic *efx);
};
/**
@@ -725,7 +723,7 @@ union efx_multicast_hash {
* @phy_data: PHY private data (including PHY-specific stats)
* @mdio: PHY MDIO interface
* @phy_mode: PHY operating mode. Serialised by @mac_lock.
- * @mac_up: MAC link state
+ * @xmac_poll_required: XMAC link state needs polling
* @link_state: Current state of the link
* @n_link_state_changes: Number of times the link has changed state
* @promiscuous: Promiscuous flag. Protected by netif_tx_lock.
@@ -810,7 +808,7 @@ struct efx_nic {
struct mdio_if_info mdio;
enum efx_phy_mode phy_mode;
- bool mac_up;
+ bool xmac_poll_required;
struct efx_link_state link_state;
unsigned int n_link_state_changes;
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 63ff295..23e646a 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -610,13 +610,10 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
flush_workqueue(efx->workqueue);
rmb();
- /* We need both the phy and xaui links to be ok.
- * rather than relying on the falcon_xmac irq/poll
- * regime, just poll xaui directly */
+ /* We need both the PHY and MAC-PHY links to be OK */
link_up = efx->link_state.up;
- if (link_up && EFX_IS10G(efx) &&
- !falcon_xaui_link_ok(efx))
- link_up = false;
+ if (link_up)
+ link_up = !efx->mac_op->check_fault(efx);
} while ((++count < 20) && !link_up);
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH 14/16] sfc: Change MAC promiscuity and multicast hash at the same time
From: Ben Hutchings @ 2009-11-26 2:12 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
From: Steve Hodgson <shodgson@solarflare.com>
Currently we can set multicast hash immediately (in atomic context)
but must delay setting MAC promiscuity. There is not that much
point in deferring one but not the other, and setting the multicast
hash on Siena will involve a firmware request. So process them
both in efx_mac_work().
Also, set the broadcast bit in the multicast hash in
efx_set_multicast_list(), since this is required for both Falcon and
Siena.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/efx.c | 38 ++++++++++++++++++++++++--------------
drivers/net/sfc/falcon.c | 10 +++-------
drivers/net/sfc/falcon.h | 2 +-
drivers/net/sfc/net_driver.h | 2 +-
4 files changed, 29 insertions(+), 23 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 15616dd..1009d1e 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -688,11 +688,18 @@ static void efx_phy_work(struct work_struct *data)
mutex_unlock(&efx->mac_lock);
}
+/* Asynchronous work item for changing MAC promiscuity and multicast
+ * hash. Avoid a drain/rx_ingress enable by reconfiguring the current
+ * MAC directly. */
static void efx_mac_work(struct work_struct *data)
{
struct efx_nic *efx = container_of(data, struct efx_nic, mac_work);
mutex_lock(&efx->mac_lock);
+ if (efx->port_enabled) {
+ falcon_push_multicast_hash(efx);
+ efx->mac_op->reconfigure(efx);
+ }
mutex_unlock(&efx->mac_lock);
}
@@ -771,7 +778,12 @@ static void efx_start_port(struct efx_nic *efx)
mutex_lock(&efx->mac_lock);
efx->port_enabled = true;
- __efx_reconfigure_port(efx);
+
+ /* efx_mac_work() might have been scheduled after efx_stop_port(),
+ * and then cancelled by efx_flush_all() */
+ falcon_push_multicast_hash(efx);
+ efx->mac_op->reconfigure(efx);
+
mutex_unlock(&efx->mac_lock);
}
@@ -1534,16 +1546,14 @@ static void efx_set_multicast_list(struct net_device *net_dev)
struct efx_nic *efx = netdev_priv(net_dev);
struct dev_mc_list *mc_list = net_dev->mc_list;
union efx_multicast_hash *mc_hash = &efx->multicast_hash;
- bool promiscuous = !!(net_dev->flags & IFF_PROMISC);
- bool changed = (efx->promiscuous != promiscuous);
u32 crc;
int bit;
int i;
- efx->promiscuous = promiscuous;
+ efx->promiscuous = !!(net_dev->flags & IFF_PROMISC);
/* Build multicast hash table */
- if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) {
+ if (efx->promiscuous || (net_dev->flags & IFF_ALLMULTI)) {
memset(mc_hash, 0xff, sizeof(*mc_hash));
} else {
memset(mc_hash, 0x00, sizeof(*mc_hash));
@@ -1553,17 +1563,17 @@ static void efx_set_multicast_list(struct net_device *net_dev)
set_bit_le(bit, mc_hash->byte);
mc_list = mc_list->next;
}
- }
- if (!efx->port_enabled)
- /* Delay pushing settings until efx_start_port() */
- return;
-
- if (changed)
- queue_work(efx->workqueue, &efx->phy_work);
+ /* Broadcast packets go through the multicast hash filter.
+ * ether_crc_le() of the broadcast address is 0xbe2612ff
+ * so we always add bit 0xff to the mask.
+ */
+ set_bit_le(0xff, mc_hash->byte);
+ }
- /* Create and activate new global multicast hash table */
- falcon_set_multicast_hash(efx);
+ if (efx->port_enabled)
+ queue_work(efx->workqueue, &efx->mac_work);
+ /* Otherwise efx_start_port() will do this */
}
static const struct net_device_ops efx_netdev_ops = {
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index fac534a..e26043e 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1993,7 +1993,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
efx_writeo(efx, ®, FR_AB_MAC_CTRL);
/* Restore the multicast hash registers. */
- falcon_set_multicast_hash(efx);
+ falcon_push_multicast_hash(efx);
/* Transmission of pause frames when RX crosses the threshold is
* covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL.
@@ -2327,15 +2327,11 @@ void falcon_remove_port(struct efx_nic *efx)
**************************************************************************
*/
-void falcon_set_multicast_hash(struct efx_nic *efx)
+void falcon_push_multicast_hash(struct efx_nic *efx)
{
union efx_multicast_hash *mc_hash = &efx->multicast_hash;
- /* Broadcast packets go through the multicast hash filter.
- * ether_crc_le() of the broadcast address is 0xbe2612ff
- * so we always add bit 0xff to the mask.
- */
- set_bit_le(0xff, mc_hash->byte);
+ WARN_ON(!mutex_is_locked(&efx->mac_lock));
efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0);
efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1);
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index 9ae1b6c..c70bb08 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -163,7 +163,7 @@ extern void falcon_remove_nic(struct efx_nic *efx);
extern void falcon_update_nic_stats(struct efx_nic *efx);
extern void falcon_start_nic_stats(struct efx_nic *efx);
extern void falcon_stop_nic_stats(struct efx_nic *efx);
-extern void falcon_set_multicast_hash(struct efx_nic *efx);
+extern void falcon_push_multicast_hash(struct efx_nic *efx);
extern int falcon_reset_xaui(struct efx_nic *efx);
/* Tests */
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index cc1a97b..ead1c98 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -730,7 +730,7 @@ union efx_multicast_hash {
* @multicast_hash: Multicast hash table
* @wanted_fc: Wanted flow control flags
* @phy_work: work item for dealing with PHY events
- * @mac_work: work item for dealing with MAC events
+ * @mac_work: Work item for changing MAC promiscuity and multicast hash
* @loopback_mode: Loopback status
* @loopback_modes: Supported loopback mode bitmask
* @loopback_selftest: Offline self-test private state
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH 15/16] sfc: Move inline comment into kernel-doc
From: Ben Hutchings @ 2009-11-26 2:12 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/selftest.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 23e646a..4f4f287 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -55,6 +55,7 @@ static const char *payload_msg =
* @flush: Drop all packets in efx_loopback_rx_packet
* @packet_count: Number of packets being used in this test
* @skbs: An array of skbs transmitted
+ * @offload_csum: Checksums are being offloaded
* @rx_good: RX good packet count
* @rx_bad: RX bad packet count
* @payload: Payload used in tests
@@ -63,10 +64,7 @@ struct efx_loopback_state {
bool flush;
int packet_count;
struct sk_buff **skbs;
-
- /* Checksums are being offloaded */
bool offload_csum;
-
atomic_t rx_good;
atomic_t rx_bad;
struct efx_loopback_payload payload;
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH 16/16] sfc: Do not set net_device::trans_start in self-test
From: Ben Hutchings @ 2009-11-26 2:12 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/selftest.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 4f4f287..1580607 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -435,7 +435,6 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue)
kfree_skb(skb);
return -EPIPE;
}
- efx->net_dev->trans_start = jiffies;
}
return 0;
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* linux-next: manual merge of the net tree with the wireless-current tree
From: Stephen Rothwell @ 2009-11-26 3:10 UTC (permalink / raw)
To: David Miller, netdev
Cc: linux-next, linux-kernel, Jean Tourrilhes, John W. Linville,
Johannes Berg
[-- Attachment #1: Type: text/plain, Size: 587 bytes --]
Hi all,
Today's linux-next merge of the net tree got a conflict in
net/wireless/wext.c between commit
9fed059667d35fca9288460106e92dbb8ba35ea1 ("WE: Fix set events not
propagated") from the tree and commit
3d23e349d807177eaf519d444677cee86b1a04cf ("wext: refactor") from the net
tree.
The latter deleted the file that the former modified. I just ignored the
wireless-current change and removed the file (which seems to have been
done in the latter change anyway).
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: [PATCH v3 5/7] via-velocity: Re-enable transmit scatter-gather support
From: Simon Kagstrom @ 2009-11-26 7:36 UTC (permalink / raw)
To: David Miller; +Cc: netdev, davej, shemminger, romieu
In-Reply-To: <20091125.153735.28806618.davem@davemloft.net>
On Wed, 25 Nov 2009 15:37:35 -0800 (PST)
David Miller <davem@davemloft.net> wrote:
> The case where you aren't getting this right:
>
> + /* If it's still above 6 we can't do anything */
> + if (skb_shinfo(skb)->nr_frags > 6) {
> + dev_err(&vptr->pdev->dev,
> + "via-velocity: more than 6 frags, can't send.\n");
> + return NETDEV_TX_OK;
> + }
>
> is bogus because you just did __skb_linearize() and it returned zero, therefore
> it would be illegal to see ->nr_frags with a > 6 value here.
Thanks for the explanation, I'll submit an updated patch. I put the
check there because I was a bit unsure about what __skb_linearize()
could do to the number of fragments. In particular, __pskb_pull_tail()
ends with
pull_pages:
eat = delta;
k = 0;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
if (skb_shinfo(skb)->frags[i].size <= eat) {
put_page(skb_shinfo(skb)->frags[i].page);
eat -= skb_shinfo(skb)->frags[i].size;
} else {
skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i];
if (eat) {
skb_shinfo(skb)->frags[k].page_offset += eat;
skb_shinfo(skb)->frags[k].size -= eat;
eat = 0;
}
k++;
}
}
skb_shinfo(skb)->nr_frags = k;
skb->tail += delta;
skb->data_len -= delta;
return skb_tail_pointer(skb);
}
and after having crunched this in my head for a while, I couldn't
convince myself that nr_frags would always come out as less than 7 from
here. I don't claim to have done a thorough examination though.
Anyway, patch coming up.
// Simon
^ permalink raw reply
* [PATCH v4 0/7] via-velocity performance fixes
From: Simon Kagstrom @ 2009-11-26 8:04 UTC (permalink / raw)
To: netdev; +Cc: davem, davej, shemminger, romieu
In-Reply-To: <20091123152724.2871cf4d@marrow.netinsight.se>
Hi again!
This is version four of the series posted here:
http://marc.info/?l=linux-netdev&m=125873023117769&w=2
The new version integrates Davids comments. There are 7 patches:
1. See to it that data is 64-byte aligned (same as before)
2. Add ethtool interrupt coalescing support. (same as before)
3. NAPI support for via-velocity (same as before)
4. Change DMA length default (same as before)
5. Re-enable scatter-gather support. (removed the double-check of
nr_frags according to Davids comment)
6. Set tx checksum from ethtool instead of a module parameter (rebased)
7. Bump the version.
To get the same performance results (or better!) as with the VIA
driver, you now need to setup interrupt supression with
ethtool -C ethX rx-usecs 20 tx-usecs 100 tx-frames 31 rx-frames 31
(which are the defaults from the VIA driver). Scatter-gather support is
enabled with
ethtool -K ethX sg on
// Simon
^ permalink raw reply
* [PATCH v4 1/7] via-velocity: Correct 64-byte alignment for rx buffers
From: Simon Kagstrom @ 2009-11-26 8:09 UTC (permalink / raw)
To: netdev; +Cc: davem, davej, shemminger, romieu
In-Reply-To: <20091126090429.39cb37ac@marrow.netinsight.se>
(From the VIA driver). The current code does not guarantee 64-byte
alignment since it simply does
int add = skb->data & 63;
skb->data += add;
(via skb_reserve). So for example, if the skb->data address would be
0x10, this would result in 32-byte alignment (0x10 + 0x10).
Correct by adding
64 - (skb->data & 63)
instead.
Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
---
drivers/net/via-velocity.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index e04e5be..b6cf3b5 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -1483,7 +1483,8 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
* Do the gymnastics to get the buffer head for data at
* 64byte alignment.
*/
- skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63);
+ skb_reserve(rd_info->skb,
+ 64 - ((unsigned long) rd_info->skb->data & 63));
rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data,
vptr->rx.buf_sz, PCI_DMA_FROMDEVICE);
--
1.6.0.4
^ permalink raw reply related
* [PATCH v4 2/7] via-velocity: Add ethtool interrupt coalescing support
From: Simon Kagstrom @ 2009-11-26 8:10 UTC (permalink / raw)
To: netdev; +Cc: davem, davej, shemminger, romieu
In-Reply-To: <20091126090429.39cb37ac@marrow.netinsight.se>
(Partially from the upstream VIA driver). Tweaking the number of
frames-per-interrupt and timer-until-interrupt can reduce the amount of
CPU work quite a lot.
Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
---
drivers/net/via-velocity.c | 160 +++++++++++++++++++++++++++++++++++++++++++-
drivers/net/via-velocity.h | 7 ++-
2 files changed, 165 insertions(+), 2 deletions(-)
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index b6cf3b5..85ee898 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -1259,6 +1259,66 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status)
}
}
+/**
+ * setup_queue_timers - Setup interrupt timers
+ *
+ * Setup interrupt frequency during suppression (timeout if the frame
+ * count isn't filled).
+ */
+static void setup_queue_timers(struct velocity_info *vptr)
+{
+ /* Only for newer revisions */
+ if (vptr->rev_id >= REV_ID_VT3216_A0) {
+ u8 txqueue_timer = 0;
+ u8 rxqueue_timer = 0;
+
+ if (vptr->mii_status & (VELOCITY_SPEED_1000 |
+ VELOCITY_SPEED_100)) {
+ txqueue_timer = vptr->options.txqueue_timer;
+ rxqueue_timer = vptr->options.rxqueue_timer;
+ }
+
+ writeb(txqueue_timer, &vptr->mac_regs->TQETMR);
+ writeb(rxqueue_timer, &vptr->mac_regs->RQETMR);
+ }
+}
+/**
+ * setup_adaptive_interrupts - Setup interrupt suppression
+ *
+ * @vptr velocity adapter
+ *
+ * The velocity is able to suppress interrupt during high interrupt load.
+ * This function turns on that feature.
+ */
+static void setup_adaptive_interrupts(struct velocity_info *vptr)
+{
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ u16 tx_intsup = vptr->options.tx_intsup;
+ u16 rx_intsup = vptr->options.rx_intsup;
+
+ /* Setup default interrupt mask (will be changed below) */
+ vptr->int_mask = INT_MASK_DEF;
+
+ /* Set Tx Interrupt Suppression Threshold */
+ writeb(CAMCR_PS0, ®s->CAMCR);
+ if (tx_intsup != 0) {
+ vptr->int_mask &= ~(ISR_PTXI | ISR_PTX0I | ISR_PTX1I |
+ ISR_PTX2I | ISR_PTX3I);
+ writew(tx_intsup, ®s->ISRCTL);
+ } else
+ writew(ISRCTL_TSUPDIS, ®s->ISRCTL);
+
+ /* Set Rx Interrupt Suppression Threshold */
+ writeb(CAMCR_PS1, ®s->CAMCR);
+ if (rx_intsup != 0) {
+ vptr->int_mask &= ~ISR_PRXI;
+ writew(rx_intsup, ®s->ISRCTL);
+ } else
+ writew(ISRCTL_RSUPDIS, ®s->ISRCTL);
+
+ /* Select page to interrupt hold timer */
+ writeb(0, ®s->CAMCR);
+}
/**
* velocity_init_registers - initialise MAC registers
@@ -1345,7 +1405,7 @@ static void velocity_init_registers(struct velocity_info *vptr,
*/
enable_mii_autopoll(regs);
- vptr->int_mask = INT_MASK_DEF;
+ setup_adaptive_interrupts(vptr);
writel(vptr->rx.pool_dma, ®s->RDBaseLo);
writew(vptr->options.numrx - 1, ®s->RDCSize);
@@ -1802,6 +1862,8 @@ static void velocity_error(struct velocity_info *vptr, int status)
BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG);
else
BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG);
+
+ setup_queue_timers(vptr);
}
/*
* Get link status from PHYSR0
@@ -3223,6 +3285,100 @@ static void velocity_set_msglevel(struct net_device *dev, u32 value)
msglevel = value;
}
+static int get_pending_timer_val(int val)
+{
+ int mult_bits = val >> 6;
+ int mult = 1;
+
+ switch (mult_bits)
+ {
+ case 1:
+ mult = 4; break;
+ case 2:
+ mult = 16; break;
+ case 3:
+ mult = 64; break;
+ case 0:
+ default:
+ break;
+ }
+
+ return (val & 0x3f) * mult;
+}
+
+static void set_pending_timer_val(int *val, u32 us)
+{
+ u8 mult = 0;
+ u8 shift = 0;
+
+ if (us >= 0x3f) {
+ mult = 1; /* mult with 4 */
+ shift = 2;
+ }
+ if (us >= 0x3f * 4) {
+ mult = 2; /* mult with 16 */
+ shift = 4;
+ }
+ if (us >= 0x3f * 16) {
+ mult = 3; /* mult with 64 */
+ shift = 6;
+ }
+
+ *val = (mult << 6) | ((us >> shift) & 0x3f);
+}
+
+
+static int velocity_get_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *ecmd)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+
+ ecmd->tx_max_coalesced_frames = vptr->options.tx_intsup;
+ ecmd->rx_max_coalesced_frames = vptr->options.rx_intsup;
+
+ ecmd->rx_coalesce_usecs = get_pending_timer_val(vptr->options.rxqueue_timer);
+ ecmd->tx_coalesce_usecs = get_pending_timer_val(vptr->options.txqueue_timer);
+
+ return 0;
+}
+
+static int velocity_set_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *ecmd)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+ int max_us = 0x3f * 64;
+
+ /* 6 bits of */
+ if (ecmd->tx_coalesce_usecs > max_us)
+ return -EINVAL;
+ if (ecmd->rx_coalesce_usecs > max_us)
+ return -EINVAL;
+
+ if (ecmd->tx_max_coalesced_frames > 0xff)
+ return -EINVAL;
+ if (ecmd->rx_max_coalesced_frames > 0xff)
+ return -EINVAL;
+
+ vptr->options.rx_intsup = ecmd->rx_max_coalesced_frames;
+ vptr->options.tx_intsup = ecmd->tx_max_coalesced_frames;
+
+ set_pending_timer_val(&vptr->options.rxqueue_timer,
+ ecmd->rx_coalesce_usecs);
+ set_pending_timer_val(&vptr->options.txqueue_timer,
+ ecmd->tx_coalesce_usecs);
+
+ /* Setup the interrupt suppression and queue timers */
+ mac_disable_int(vptr->mac_regs);
+ setup_adaptive_interrupts(vptr);
+ setup_queue_timers(vptr);
+
+ mac_write_int_mask(vptr->int_mask, vptr->mac_regs);
+ mac_clear_isr(vptr->mac_regs);
+ mac_enable_int(vptr->mac_regs);
+
+ return 0;
+}
+
static const struct ethtool_ops velocity_ethtool_ops = {
.get_settings = velocity_get_settings,
.set_settings = velocity_set_settings,
@@ -3232,6 +3388,8 @@ static const struct ethtool_ops velocity_ethtool_ops = {
.get_msglevel = velocity_get_msglevel,
.set_msglevel = velocity_set_msglevel,
.get_link = velocity_get_link,
+ .get_coalesce = velocity_get_coalesce,
+ .set_coalesce = velocity_set_coalesce,
.begin = velocity_ethtool_up,
.complete = velocity_ethtool_down
};
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index 2f00c13..6091946 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -1005,7 +1005,8 @@ struct mac_regs {
volatile __le32 RDBaseLo; /* 0x38 */
volatile __le16 RDIdx; /* 0x3C */
- volatile __le16 reserved_3E;
+ volatile u8 TQETMR; /* 0x3E, VT3216 and above only */
+ volatile u8 RQETMR; /* 0x3F, VT3216 and above only */
volatile __le32 TDBaseLo[4]; /* 0x40 */
@@ -1491,6 +1492,10 @@ struct velocity_opt {
int rx_bandwidth_hi;
int rx_bandwidth_lo;
int rx_bandwidth_en;
+ int rxqueue_timer;
+ int txqueue_timer;
+ int tx_intsup;
+ int rx_intsup;
u32 flags;
};
--
1.6.0.4
^ permalink raw reply related
* [PATCH v4 3/7] via-velocity: Implement NAPI support
From: Simon Kagstrom @ 2009-11-26 8:10 UTC (permalink / raw)
To: netdev; +Cc: davem, davej, shemminger, romieu
In-Reply-To: <20091126090429.39cb37ac@marrow.netinsight.se>
This patch adds NAPI support for VIA velocity. The new velocity_poll
function also pairs tx/rx handling twice which improves perforamance on
some workloads (e.g., netperf UDP_STREAM) significantly (that part is
from the VIA driver).
Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
---
drivers/net/via-velocity.c | 81 +++++++++++++++++++++++++-------------------
drivers/net/via-velocity.h | 3 ++
2 files changed, 49 insertions(+), 35 deletions(-)
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 85ee898..668cdf6 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -354,12 +354,6 @@ VELOCITY_PARAM(ValPktLen, "Receiving or Drop invalid 802.3 frame");
*/
VELOCITY_PARAM(wol_opts, "Wake On Lan options");
-#define INT_WORKS_DEF 20
-#define INT_WORKS_MIN 10
-#define INT_WORKS_MAX 64
-
-VELOCITY_PARAM(int_works, "Number of packets per interrupt services");
-
static int rx_copybreak = 200;
module_param(rx_copybreak, int, 0644);
MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
@@ -516,7 +510,6 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
velocity_set_bool_opt(&opts->flags, ValPktLen[index], VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN, "ValPktLen", devname);
velocity_set_int_opt((int *) &opts->spd_dpx, speed_duplex[index], MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF, "Media link mode", devname);
velocity_set_int_opt((int *) &opts->wol_opts, wol_opts[index], WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF, "Wake On Lan options", devname);
- velocity_set_int_opt((int *) &opts->int_works, int_works[index], INT_WORKS_MIN, INT_WORKS_MAX, INT_WORKS_DEF, "Interrupt service works", devname);
opts->numrx = (opts->numrx & ~3);
}
@@ -2123,13 +2116,14 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
* any received packets from the receive queue. Hand the ring
* slots back to the adapter for reuse.
*/
-static int velocity_rx_srv(struct velocity_info *vptr, int status)
+static int velocity_rx_srv(struct velocity_info *vptr, int status,
+ int budget_left)
{
struct net_device_stats *stats = &vptr->dev->stats;
int rd_curr = vptr->rx.curr;
int works = 0;
- do {
+ while (works < budget_left) {
struct rx_desc *rd = vptr->rx.ring + rd_curr;
if (!vptr->rx.info[rd_curr].skb)
@@ -2160,7 +2154,8 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status)
rd_curr++;
if (rd_curr >= vptr->options.numrx)
rd_curr = 0;
- } while (++works <= 15);
+ works++;
+ }
vptr->rx.curr = rd_curr;
@@ -2171,6 +2166,40 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status)
return works;
}
+static int velocity_poll(struct napi_struct *napi, int budget)
+{
+ struct velocity_info *vptr = container_of(napi,
+ struct velocity_info, napi);
+ unsigned int rx_done;
+ u32 isr_status;
+
+ spin_lock(&vptr->lock);
+ isr_status = mac_read_isr(vptr->mac_regs);
+
+ /* Ack the interrupt */
+ mac_write_isr(vptr->mac_regs, isr_status);
+ if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
+ velocity_error(vptr, isr_status);
+
+ /*
+ * Do rx and tx twice for performance (taken from the VIA
+ * out-of-tree driver).
+ */
+ rx_done = velocity_rx_srv(vptr, isr_status, budget / 2);
+ velocity_tx_srv(vptr, isr_status);
+ rx_done += velocity_rx_srv(vptr, isr_status, budget - rx_done);
+ velocity_tx_srv(vptr, isr_status);
+
+ spin_unlock(&vptr->lock);
+
+ /* If budget not fully consumed, exit the polling mode */
+ if (rx_done < budget) {
+ napi_complete(napi);
+ mac_enable_int(vptr->mac_regs);
+ }
+
+ return rx_done;
+}
/**
* velocity_intr - interrupt callback
@@ -2187,8 +2216,6 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance)
struct net_device *dev = dev_instance;
struct velocity_info *vptr = netdev_priv(dev);
u32 isr_status;
- int max_count = 0;
-
spin_lock(&vptr->lock);
isr_status = mac_read_isr(vptr->mac_regs);
@@ -2199,32 +2226,13 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance)
return IRQ_NONE;
}
- mac_disable_int(vptr->mac_regs);
-
- /*
- * Keep processing the ISR until we have completed
- * processing and the isr_status becomes zero
- */
-
- while (isr_status != 0) {
- mac_write_isr(vptr->mac_regs, isr_status);
- if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
- velocity_error(vptr, isr_status);
- if (isr_status & (ISR_PRXI | ISR_PPRXI))
- max_count += velocity_rx_srv(vptr, isr_status);
- if (isr_status & (ISR_PTXI | ISR_PPTXI))
- max_count += velocity_tx_srv(vptr, isr_status);
- isr_status = mac_read_isr(vptr->mac_regs);
- if (max_count > vptr->options.int_works) {
- printk(KERN_WARNING "%s: excessive work at interrupt.\n",
- dev->name);
- max_count = 0;
- }
+ if (likely(napi_schedule_prep(&vptr->napi))) {
+ mac_disable_int(vptr->mac_regs);
+ __napi_schedule(&vptr->napi);
}
spin_unlock(&vptr->lock);
- mac_enable_int(vptr->mac_regs);
- return IRQ_HANDLED;
+ return IRQ_HANDLED;
}
/**
@@ -2264,6 +2272,7 @@ static int velocity_open(struct net_device *dev)
mac_enable_int(vptr->mac_regs);
netif_start_queue(dev);
+ napi_enable(&vptr->napi);
vptr->flags |= VELOCITY_FLAGS_OPENED;
out:
return ret;
@@ -2499,6 +2508,7 @@ static int velocity_close(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
+ napi_disable(&vptr->napi);
netif_stop_queue(dev);
velocity_shutdown(vptr);
@@ -2818,6 +2828,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
dev->irq = pdev->irq;
dev->netdev_ops = &velocity_netdev_ops;
dev->ethtool_ops = &velocity_ethtool_ops;
+ netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT);
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
NETIF_F_HW_VLAN_RX;
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index 6091946..22bfea4 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -32,6 +32,7 @@
#define VELOCITY_VERSION "1.14"
#define VELOCITY_IO_SIZE 256
+#define VELOCITY_NAPI_WEIGHT 64
#define PKT_BUF_SZ 1540
@@ -1564,6 +1565,8 @@ struct velocity_info {
u32 ticks;
u8 rev_id;
+
+ struct napi_struct napi;
};
/**
--
1.6.0.4
^ permalink raw reply related
* [PATCH v4 4/7] via-velocity: Change DMA_LENGTH_DEF (from the VIA driver)
From: Simon Kagstrom @ 2009-11-26 8:10 UTC (permalink / raw)
Cc: netdev, davem, davej, shemminger, romieu
In-Reply-To: <20091126090429.39cb37ac@marrow.netinsight.se>
The VIA driver has changed the default for the DMA_LENGTH_DEF parameter.
Together with adaptive interrupt supression and NAPI support, this
improves performance quite a bit
Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
---
drivers/net/via-velocity.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 668cdf6..06a6d80 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -275,7 +275,7 @@ VELOCITY_PARAM(rx_thresh, "Receive fifo threshold");
#define DMA_LENGTH_MIN 0
#define DMA_LENGTH_MAX 7
-#define DMA_LENGTH_DEF 0
+#define DMA_LENGTH_DEF 6
/* DMA_length[] is used for controlling the DMA length
0: 8 DWORDs
--
1.6.0.4
^ permalink raw reply related
* [PATCH v4 5/7] via-velocity: Re-enable transmit scatter-gather support
From: Simon Kagstrom @ 2009-11-26 8:10 UTC (permalink / raw)
To: netdev, davem; +Cc: davej, shemminger, romieu
In-Reply-To: <20091126090429.39cb37ac@marrow.netinsight.se>
The velocity hardware can handle up to 7 memory segments. This can be
turned on and off via ethtool. The support was removed in commit
83c98a8cd04dd0f848574370594886ba3bf56750
but is re-enabled and cleaned up here. It's off by default.
Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
---
ChangeLog:
* (David Miller): Remove the second check for too-many-fragments
drivers/net/via-velocity.c | 83 ++++++++++++++++++++++++++++----------------
1 files changed, 53 insertions(+), 30 deletions(-)
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 06a6d80..b7f676b 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -9,7 +9,6 @@
*
* TODO
* rx_copybreak/alignment
- * Scatter gather
* More testing
*
* The changes are (c) Copyright 2004, Red Hat Inc. <alan@lxorguk.ukuu.org.uk>
@@ -1656,12 +1655,10 @@ out:
*/
static int velocity_init_td_ring(struct velocity_info *vptr)
{
- dma_addr_t curr;
int j;
/* Init the TD ring entries */
for (j = 0; j < vptr->tx.numq; j++) {
- curr = vptr->tx.pool_dma[j];
vptr->tx.infos[j] = kcalloc(vptr->options.numtx,
sizeof(struct velocity_td_info),
@@ -1727,21 +1724,27 @@ err_free_dma_rings_0:
* Release an transmit buffer. If the buffer was preallocated then
* recycle it, if not then unmap the buffer.
*/
-static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
+static void velocity_free_tx_buf(struct velocity_info *vptr,
+ struct velocity_td_info *tdinfo, struct tx_desc *td)
{
struct sk_buff *skb = tdinfo->skb;
- int i;
- int pktlen;
/*
* Don't unmap the pre-allocated tx_bufs
*/
if (tdinfo->skb_dma) {
+ int i;
- pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
for (i = 0; i < tdinfo->nskb_dma; i++) {
- pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE);
- tdinfo->skb_dma[i] = 0;
+ size_t pktlen = max_t(size_t, skb->len, ETH_ZLEN);
+
+ /* For scatter-gather */
+ if (skb_shinfo(skb)->nr_frags > 0)
+ pktlen = max_t(size_t, pktlen,
+ td->td_buf[i].size & ~TD_QUEUE);
+
+ pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i],
+ le16_to_cpu(pktlen), PCI_DMA_TODEVICE);
}
}
dev_kfree_skb_irq(skb);
@@ -1943,7 +1946,7 @@ static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
stats->tx_packets++;
stats->tx_bytes += tdinfo->skb->len;
}
- velocity_free_tx_buf(vptr, tdinfo);
+ velocity_free_tx_buf(vptr, tdinfo, td);
vptr->tx.used[qnum]--;
}
vptr->tx.tail[qnum] = idx;
@@ -2543,14 +2546,22 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
struct velocity_td_info *tdinfo;
unsigned long flags;
int pktlen;
- __le16 len;
- int index;
+ int index, prev;
+ int i = 0;
if (skb_padto(skb, ETH_ZLEN))
goto out;
- pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
- len = cpu_to_le16(pktlen);
+ /* The hardware can handle at most 7 memory segments, so merge
+ * the skb if there are more */
+ if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
+ kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ pktlen = skb_shinfo(skb)->nr_frags == 0 ?
+ max_t(unsigned int, skb->len, ETH_ZLEN) :
+ skb_headlen(skb);
spin_lock_irqsave(&vptr->lock, flags);
@@ -2567,11 +2578,24 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
*/
tdinfo->skb = skb;
tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
- td_ptr->tdesc0.len = len;
+ td_ptr->tdesc0.len = cpu_to_le16(pktlen);
td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
td_ptr->td_buf[0].pa_high = 0;
- td_ptr->td_buf[0].size = len;
- tdinfo->nskb_dma = 1;
+ td_ptr->td_buf[0].size = cpu_to_le16(pktlen);
+
+ /* Handle fragments */
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ tdinfo->skb_dma[i + 1] = pci_map_page(vptr->pdev, frag->page,
+ frag->page_offset, frag->size,
+ PCI_DMA_TODEVICE);
+
+ td_ptr->td_buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]);
+ td_ptr->td_buf[i + 1].pa_high = 0;
+ td_ptr->td_buf[i + 1].size = cpu_to_le16(frag->size);
+ }
+ tdinfo->nskb_dma = i + 1;
td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16;
@@ -2592,23 +2616,21 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
td_ptr->tdesc1.TCR |= (TCR0_UDPCK);
td_ptr->tdesc1.TCR |= TCR0_IPCK;
}
- {
- int prev = index - 1;
+ prev = index - 1;
+ if (prev < 0)
+ prev = vptr->options.numtx - 1;
+ td_ptr->tdesc0.len |= OWNED_BY_NIC;
+ vptr->tx.used[qnum]++;
+ vptr->tx.curr[qnum] = (index + 1) % vptr->options.numtx;
- if (prev < 0)
- prev = vptr->options.numtx - 1;
- td_ptr->tdesc0.len |= OWNED_BY_NIC;
- vptr->tx.used[qnum]++;
- vptr->tx.curr[qnum] = (index + 1) % vptr->options.numtx;
+ if (AVAIL_TD(vptr, qnum) < 1)
+ netif_stop_queue(dev);
- if (AVAIL_TD(vptr, qnum) < 1)
- netif_stop_queue(dev);
+ td_ptr = &(vptr->tx.rings[qnum][prev]);
+ td_ptr->td_buf[0].size |= TD_QUEUE;
+ mac_tx_queue_wake(vptr->mac_regs, qnum);
- td_ptr = &(vptr->tx.rings[qnum][prev]);
- td_ptr->td_buf[0].size |= TD_QUEUE;
- mac_tx_queue_wake(vptr->mac_regs, qnum);
- }
dev->trans_start = jiffies;
spin_unlock_irqrestore(&vptr->lock, flags);
out:
@@ -3398,6 +3420,7 @@ static const struct ethtool_ops velocity_ethtool_ops = {
.set_wol = velocity_ethtool_set_wol,
.get_msglevel = velocity_get_msglevel,
.set_msglevel = velocity_set_msglevel,
+ .set_sg = ethtool_op_set_sg,
.get_link = velocity_get_link,
.get_coalesce = velocity_get_coalesce,
.set_coalesce = velocity_set_coalesce,
--
1.6.0.4
^ permalink raw reply related
* [PATCH v4 6/7] via-velocity: Set tx checksum from ethtool instead of module parameter
From: Simon Kagstrom @ 2009-11-26 8:10 UTC (permalink / raw)
To: netdev; +Cc: davem, davej, shemminger, romieu
In-Reply-To: <20091126090429.39cb37ac@marrow.netinsight.se>
Defaults to on (as before).
Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
---
drivers/net/via-velocity.c | 18 ++++--------------
drivers/net/via-velocity.h | 1 -
2 files changed, 4 insertions(+), 15 deletions(-)
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index b7f676b..9572890 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -297,14 +297,6 @@ VELOCITY_PARAM(DMA_length, "DMA length");
*/
VELOCITY_PARAM(IP_byte_align, "Enable IP header dword aligned");
-#define TX_CSUM_DEF 1
-/* txcsum_offload[] is used for setting the checksum offload ability of NIC.
- (We only support RX checksum offload now)
- 0: disable csum_offload[checksum offload
- 1: enable checksum offload. (Default)
-*/
-VELOCITY_PARAM(txcsum_offload, "Enable transmit packet checksum offload");
-
#define FLOW_CNTL_DEF 1
#define FLOW_CNTL_MIN 1
#define FLOW_CNTL_MAX 5
@@ -503,7 +495,6 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
velocity_set_int_opt(&opts->numrx, RxDescriptors[index], RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF, "RxDescriptors", devname);
velocity_set_int_opt(&opts->numtx, TxDescriptors[index], TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF, "TxDescriptors", devname);
- velocity_set_bool_opt(&opts->flags, txcsum_offload[index], TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM, "txcsum_offload", devname);
velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname);
velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname);
velocity_set_bool_opt(&opts->flags, ValPktLen[index], VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN, "ValPktLen", devname);
@@ -2607,7 +2598,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
/*
* Handle hardware checksum
*/
- if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM)
+ if ( (dev->features & NETIF_F_IP_CSUM)
&& (skb->ip_summed == CHECKSUM_PARTIAL)) {
const struct iphdr *ip = ip_hdr(skb);
if (ip->protocol == IPPROTO_TCP)
@@ -2853,10 +2844,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT);
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
- NETIF_F_HW_VLAN_RX;
-
- if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
- dev->features |= NETIF_F_IP_CSUM;
+ NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM;
ret = register_netdev(dev);
if (ret < 0)
@@ -3416,6 +3404,8 @@ static const struct ethtool_ops velocity_ethtool_ops = {
.get_settings = velocity_get_settings,
.set_settings = velocity_set_settings,
.get_drvinfo = velocity_get_drvinfo,
+ .set_tx_csum = ethtool_op_set_tx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
.get_wol = velocity_ethtool_get_wol,
.set_wol = velocity_ethtool_set_wol,
.get_msglevel = velocity_get_msglevel,
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index 22bfea4..cf10801 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -1423,7 +1423,6 @@ enum velocity_msg_level {
*/
#define VELOCITY_FLAGS_TAGGING 0x00000001UL
-#define VELOCITY_FLAGS_TX_CSUM 0x00000002UL
#define VELOCITY_FLAGS_RX_CSUM 0x00000004UL
#define VELOCITY_FLAGS_IP_ALIGN 0x00000008UL
#define VELOCITY_FLAGS_VAL_PKT_LEN 0x00000010UL
--
1.6.0.4
^ permalink raw reply related
* [PATCH v4 7/7] via-velocity: Bump version
From: Simon Kagstrom @ 2009-11-26 8:10 UTC (permalink / raw)
To: netdev; +Cc: davem, davej, shemminger, romieu
In-Reply-To: <20091126090429.39cb37ac@marrow.netinsight.se>
Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
---
drivers/net/via-velocity.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index cf10801..6b5fc51 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -29,7 +29,7 @@
#define VELOCITY_NAME "via-velocity"
#define VELOCITY_FULL_DRV_NAM "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"
-#define VELOCITY_VERSION "1.14"
+#define VELOCITY_VERSION "1.15"
#define VELOCITY_IO_SIZE 256
#define VELOCITY_NAPI_WEIGHT 64
--
1.6.0.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox