From 3dca9d2dc285faf1910d405b65df845cab061356 Mon Sep 17 00:00:00 2001 From: Stuart Hodgson Date: Fri, 30 Mar 2012 13:04:51 +0100 Subject: sfc: Do not attempt to flush queues if DMA is disabled efx_nic_fatal_interrupt() disables DMA before scheduling a reset. After this, we need not and *cannot* flush queues. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/efx.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 3cbfbffe3f00..5cc58a3b75ac 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -656,25 +656,30 @@ static void efx_stop_datapath(struct efx_nic *efx) struct efx_channel *channel; struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; + struct pci_dev *dev = efx->pci_dev; int rc; EFX_ASSERT_RESET_SERIALISED(efx); BUG_ON(efx->port_enabled); - rc = efx_nic_flush_queues(efx); - if (rc && EFX_WORKAROUND_7803(efx)) { - /* Schedule a reset to recover from the flush failure. The - * descriptor caches reference memory we're about to free, - * but falcon_reconfigure_mac_wrapper() won't reconnect - * the MACs because of the pending reset. */ - netif_err(efx, drv, efx->net_dev, - "Resetting to recover from flush failure\n"); - efx_schedule_reset(efx, RESET_TYPE_ALL); - } else if (rc) { - netif_err(efx, drv, efx->net_dev, "failed to flush queues\n"); - } else { - netif_dbg(efx, drv, efx->net_dev, - "successfully flushed all queues\n"); + /* Only perform flush if dma is enabled */ + if (dev->is_busmaster) { + rc = efx_nic_flush_queues(efx); + + if (rc && EFX_WORKAROUND_7803(efx)) { + /* Schedule a reset to recover from the flush failure. The + * descriptor caches reference memory we're about to free, + * but falcon_reconfigure_mac_wrapper() won't reconnect + * the MACs because of the pending reset. */ + netif_err(efx, drv, efx->net_dev, + "Resetting to recover from flush failure\n"); + efx_schedule_reset(efx, RESET_TYPE_ALL); + } else if (rc) { + netif_err(efx, drv, efx->net_dev, "failed to flush queues\n"); + } else { + netif_dbg(efx, drv, efx->net_dev, + "successfully flushed all queues\n"); + } } efx_for_each_channel(channel, efx) { -- cgit v1.2.3-59-g8ed1b From 3de4e30196f09ff2c096f2f8e17ebc9adda9db8d Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 5 Apr 2012 00:22:19 +0100 Subject: sfc: Fix missing cleanup in failure path of efx_pci_probe() We need to clear the private data pointer in the PCI device. Also reorder cleanup in efx_pci_remove() for symmetry. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/efx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 5cc58a3b75ac..8253d2155fe3 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -2497,8 +2497,8 @@ static void efx_pci_remove(struct pci_dev *pci_dev) efx_fini_io(efx); netif_dbg(efx, drv, efx->net_dev, "shutdown successful\n"); - pci_set_drvdata(pci_dev, NULL); efx_fini_struct(efx); + pci_set_drvdata(pci_dev, NULL); free_netdev(efx->net_dev); }; @@ -2700,6 +2700,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, fail2: efx_fini_struct(efx); fail1: + pci_set_drvdata(pci_dev, NULL); WARN_ON(rc > 0); netif_dbg(efx, drv, efx->net_dev, "initialisation failed. rc=%d\n", rc); free_netdev(net_dev); -- cgit v1.2.3-59-g8ed1b From da9ca505829f6c270b239536b1b169644d7cf072 Mon Sep 17 00:00:00 2001 From: David Riddoch Date: Wed, 11 Apr 2012 13:09:24 +0100 Subject: sfc: Fill RX rings completely full, rather than to 95% full There was no runtime control of the fast_fill_limit in any case, so purged that field. Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/net_driver.h | 3 --- drivers/net/ethernet/sfc/rx.c | 15 ++++----------- 2 files changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index f0385e1fb2d8..eaca447e2a2b 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -252,8 +252,6 @@ struct efx_rx_page_state { * @max_fill: RX descriptor maximum fill level (<= ring size) * @fast_fill_trigger: RX descriptor fill level that will trigger a fast fill * (<= @max_fill) - * @fast_fill_limit: The level to which a fast fill will fill - * (@fast_fill_trigger <= @fast_fill_limit <= @max_fill) * @min_fill: RX descriptor minimum non-zero fill level. * This records the minimum fill level observed when a ring * refill was triggered. @@ -274,7 +272,6 @@ struct efx_rx_queue { int removed_count; unsigned int max_fill; unsigned int fast_fill_trigger; - unsigned int fast_fill_limit; unsigned int min_fill; unsigned int min_overfill; unsigned int alloc_page_count; diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index 763fa2fe1a38..254fec81894e 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -78,11 +78,6 @@ static int rx_alloc_method = RX_ALLOC_METHOD_AUTO; */ static unsigned int rx_refill_threshold = 90; -/* This is the percentage fill level to which an RX queue will be refilled - * when the "RX refill threshold" is reached. - */ -static unsigned int rx_refill_limit = 95; - /* * RX maximum head room required. * @@ -342,7 +337,7 @@ static void efx_recycle_rx_buffer(struct efx_channel *channel, * efx_fast_push_rx_descriptors - push new RX descriptors quickly * @rx_queue: RX descriptor queue * This will aim to fill the RX descriptor queue up to - * @rx_queue->@fast_fill_limit. If there is insufficient atomic + * @rx_queue->@max_fill. If there is insufficient atomic * memory to do so, a slow fill will be scheduled. * * The caller must provide serialisation (none is used here). In practise, @@ -367,7 +362,7 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue) rx_queue->min_fill = fill_level; } - space = rx_queue->fast_fill_limit - fill_level; + space = rx_queue->max_fill - fill_level; if (space < EFX_RX_BATCH) goto out; @@ -375,7 +370,7 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue) "RX queue %d fast-filling descriptor ring from" " level %d to level %d using %s allocation\n", efx_rx_queue_index(rx_queue), fill_level, - rx_queue->fast_fill_limit, + rx_queue->max_fill, channel->rx_alloc_push_pages ? "page" : "skb"); do { @@ -681,7 +676,7 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue) void efx_init_rx_queue(struct efx_rx_queue *rx_queue) { struct efx_nic *efx = rx_queue->efx; - unsigned int max_fill, trigger, limit; + unsigned int max_fill, trigger; netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev, "initialising RX queue %d\n", efx_rx_queue_index(rx_queue)); @@ -695,11 +690,9 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue) /* Initialise limit fields */ max_fill = efx->rxq_entries - EFX_RXD_HEAD_ROOM; trigger = max_fill * min(rx_refill_threshold, 100U) / 100U; - limit = max_fill * min(rx_refill_limit, 100U) / 100U; rx_queue->max_fill = max_fill; rx_queue->fast_fill_trigger = trigger; - rx_queue->fast_fill_limit = limit; /* Set up RX descriptor ring */ rx_queue->enabled = true; -- cgit v1.2.3-59-g8ed1b From 64235187c2b32913fc41dfafc98e3a77ea7c0217 Mon Sep 17 00:00:00 2001 From: David Riddoch Date: Wed, 11 Apr 2012 13:12:41 +0100 Subject: sfc: By default refill RX rings as soon as space for a batch Previously we refilled with much larger batches, which caused large latency spikes. We now have many more much much smaller spikes! Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/rx.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index 254fec81894e..243e91f3dff9 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -76,7 +76,7 @@ static int rx_alloc_method = RX_ALLOC_METHOD_AUTO; /* This is the percentage fill level below which new RX descriptors * will be added to the RX descriptor ring. */ -static unsigned int rx_refill_threshold = 90; +static unsigned int rx_refill_threshold; /* * RX maximum head room required. @@ -363,8 +363,7 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue) } space = rx_queue->max_fill - fill_level; - if (space < EFX_RX_BATCH) - goto out; + EFX_BUG_ON_PARANOID(space < EFX_RX_BATCH); netif_vdbg(rx_queue->efx, rx_status, rx_queue->efx->net_dev, "RX queue %d fast-filling descriptor ring from" @@ -676,7 +675,7 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue) void efx_init_rx_queue(struct efx_rx_queue *rx_queue) { struct efx_nic *efx = rx_queue->efx; - unsigned int max_fill, trigger; + unsigned int max_fill, trigger, max_trigger; netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev, "initialising RX queue %d\n", efx_rx_queue_index(rx_queue)); @@ -689,7 +688,14 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue) /* Initialise limit fields */ max_fill = efx->rxq_entries - EFX_RXD_HEAD_ROOM; - trigger = max_fill * min(rx_refill_threshold, 100U) / 100U; + max_trigger = max_fill - EFX_RX_BATCH; + if (rx_refill_threshold != 0) { + trigger = max_fill * min(rx_refill_threshold, 100U) / 100U; + if (trigger > max_trigger) + trigger = max_trigger; + } else { + trigger = max_trigger; + } rx_queue->max_fill = max_fill; rx_queue->fast_fill_trigger = trigger; @@ -739,5 +745,5 @@ MODULE_PARM_DESC(rx_alloc_method, "Allocation method used for RX buffers"); module_param(rx_refill_threshold, uint, 0444); MODULE_PARM_DESC(rx_refill_threshold, - "RX descriptor ring fast/slow fill threshold (%)"); + "RX descriptor ring refill threshold (%)"); -- cgit v1.2.3-59-g8ed1b From c087bd2cfdaf334d7d0c32bd1fcc1a23d5b88973 Mon Sep 17 00:00:00 2001 From: Stuart Hodgson Date: Tue, 1 May 2012 18:50:43 +0100 Subject: sfc: Added support for new ethtool APIs for obtaining module eeprom Currently allows for SFP+ eeprom to be returned using the ethtool API. This can be extended in future to handle different eeprom formats and sizes Signed-off-by: Stuart Hodgson [bwh: Drop redundant validation, comment, whitespace] Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/ethtool.c | 35 ++++++++++++++++ drivers/net/ethernet/sfc/mcdi_phy.c | 76 +++++++++++++++++++++++++++++++++++ drivers/net/ethernet/sfc/net_driver.h | 5 +++ 3 files changed, 116 insertions(+) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index f22f45f515a8..b0a4558de248 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -1108,6 +1108,39 @@ static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev, return 0; } +static int efx_ethtool_get_module_eeprom(struct net_device *net_dev, + struct ethtool_eeprom *ee, + u8 *data) +{ + struct efx_nic *efx = netdev_priv(net_dev); + int ret; + + if (!efx->phy_op || !efx->phy_op->get_module_eeprom) + return -EOPNOTSUPP; + + mutex_lock(&efx->mac_lock); + ret = efx->phy_op->get_module_eeprom(efx, ee, data); + mutex_unlock(&efx->mac_lock); + + return ret; +} + +static int efx_ethtool_get_module_info(struct net_device *net_dev, + struct ethtool_modinfo *modinfo) +{ + struct efx_nic *efx = netdev_priv(net_dev); + int ret; + + if (!efx->phy_op || !efx->phy_op->get_module_info) + return -EOPNOTSUPP; + + mutex_lock(&efx->mac_lock); + ret = efx->phy_op->get_module_info(efx, modinfo); + mutex_unlock(&efx->mac_lock); + + return ret; +} + const struct ethtool_ops efx_ethtool_ops = { .get_settings = efx_ethtool_get_settings, .set_settings = efx_ethtool_set_settings, @@ -1137,4 +1170,6 @@ const struct ethtool_ops efx_ethtool_ops = { .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, .get_rxfh_indir = efx_ethtool_get_rxfh_indir, .set_rxfh_indir = efx_ethtool_set_rxfh_indir, + .get_module_info = efx_ethtool_get_module_info, + .get_module_eeprom = efx_ethtool_get_module_eeprom, }; diff --git a/drivers/net/ethernet/sfc/mcdi_phy.c b/drivers/net/ethernet/sfc/mcdi_phy.c index 7bcad899a936..13cb40fe90c1 100644 --- a/drivers/net/ethernet/sfc/mcdi_phy.c +++ b/drivers/net/ethernet/sfc/mcdi_phy.c @@ -739,6 +739,80 @@ static const char *efx_mcdi_phy_test_name(struct efx_nic *efx, return NULL; } +#define SFP_PAGE_SIZE 128 +#define SFP_NUM_PAGES 2 +static int efx_mcdi_phy_get_module_eeprom(struct efx_nic *efx, + struct ethtool_eeprom *ee, u8 *data) +{ + u8 outbuf[MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMAX]; + u8 inbuf[MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN]; + size_t outlen; + int rc; + unsigned int payload_len; + unsigned int space_remaining = ee->len; + unsigned int page; + unsigned int page_off; + unsigned int to_copy; + u8 *user_data = data; + + BUILD_BUG_ON(SFP_PAGE_SIZE * SFP_NUM_PAGES != ETH_MODULE_SFF_8079_LEN); + + page_off = ee->offset % SFP_PAGE_SIZE; + page = ee->offset / SFP_PAGE_SIZE; + + while (space_remaining && (page < SFP_NUM_PAGES)) { + MCDI_SET_DWORD(inbuf, GET_PHY_MEDIA_INFO_IN_PAGE, page); + + rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_MEDIA_INFO, + inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), + &outlen); + if (rc) + return rc; + + if (outlen < (MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST + + SFP_PAGE_SIZE)) + return -EIO; + + payload_len = MCDI_DWORD(outbuf, + GET_PHY_MEDIA_INFO_OUT_DATALEN); + if (payload_len != SFP_PAGE_SIZE) + return -EIO; + + /* Copy as much as we can into data */ + payload_len -= page_off; + to_copy = (space_remaining < payload_len) ? + space_remaining : payload_len; + + memcpy(user_data, + outbuf + page_off + + MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST, + to_copy); + + space_remaining -= to_copy; + user_data += to_copy; + page_off = 0; + page++; + } + + return 0; +} + +static int efx_mcdi_phy_get_module_info(struct efx_nic *efx, + struct ethtool_modinfo *modinfo) +{ + struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; + + switch (phy_cfg->media) { + case MC_CMD_MEDIA_SFP_PLUS: + modinfo->type = ETH_MODULE_SFF_8079; + modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; + return 0; + default: + return -EOPNOTSUPP; + } +} + const struct efx_phy_operations efx_mcdi_phy_ops = { .probe = efx_mcdi_phy_probe, .init = efx_port_dummy_op_int, @@ -751,4 +825,6 @@ const struct efx_phy_operations efx_mcdi_phy_ops = { .test_alive = efx_mcdi_phy_test_alive, .run_tests = efx_mcdi_phy_run_tests, .test_name = efx_mcdi_phy_test_name, + .get_module_eeprom = efx_mcdi_phy_get_module_eeprom, + .get_module_info = efx_mcdi_phy_get_module_info, }; diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index eaca447e2a2b..0e575359af17 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -519,6 +519,11 @@ struct efx_phy_operations { int (*test_alive) (struct efx_nic *efx); const char *(*test_name) (struct efx_nic *efx, unsigned int index); int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags); + int (*get_module_eeprom) (struct efx_nic *efx, + struct ethtool_eeprom *ee, + u8 *data); + int (*get_module_info) (struct efx_nic *efx, + struct ethtool_modinfo *modinfo); }; /** -- cgit v1.2.3-59-g8ed1b From ba62b2a8608ca52234fc8bea27bfebbdc4f98c2e Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 5 May 2012 01:36:50 +0100 Subject: sfc: Implement module EEPROM access for SFE4002 and SFN4112F Signed-off-by: Ben Hutchings --- drivers/net/ethernet/sfc/qt202x_phy.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers/net/ethernet') diff --git a/drivers/net/ethernet/sfc/qt202x_phy.c b/drivers/net/ethernet/sfc/qt202x_phy.c index 8a7caf88ffb6..326a28637f3c 100644 --- a/drivers/net/ethernet/sfc/qt202x_phy.c +++ b/drivers/net/ethernet/sfc/qt202x_phy.c @@ -449,6 +449,37 @@ static void qt202x_phy_remove(struct efx_nic *efx) efx->phy_data = NULL; } +static int qt202x_phy_get_module_info(struct efx_nic *efx, + struct ethtool_modinfo *modinfo) +{ + modinfo->type = ETH_MODULE_SFF_8079; + modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; + return 0; +} + +static int qt202x_phy_get_module_eeprom(struct efx_nic *efx, + struct ethtool_eeprom *ee, u8 *data) +{ + int mmd, reg_base, rc, i; + + if (efx->phy_type == PHY_TYPE_QT2025C) { + mmd = MDIO_MMD_PCS; + reg_base = 0xd000; + } else { + mmd = MDIO_MMD_PMAPMD; + reg_base = 0x8007; + } + + for (i = 0; i < ee->len; i++) { + rc = efx_mdio_read(efx, mmd, reg_base + ee->offset + i); + if (rc < 0) + return rc; + data[i] = rc; + } + + return 0; +} + const struct efx_phy_operations falcon_qt202x_phy_ops = { .probe = qt202x_phy_probe, .init = qt202x_phy_init, @@ -459,4 +490,6 @@ const struct efx_phy_operations falcon_qt202x_phy_ops = { .get_settings = qt202x_phy_get_settings, .set_settings = efx_mdio_set_settings, .test_alive = efx_mdio_test_alive, + .get_module_eeprom = qt202x_phy_get_module_eeprom, + .get_module_info = qt202x_phy_get_module_info, }; -- cgit v1.2.3-59-g8ed1b